Skip to content

Commit 597f2b8

Browse files
authored
test: add regression tests for config secrets protection (#11061)
1 parent 1404861 commit 597f2b8

File tree

1 file changed

+164
-0
lines changed

1 file changed

+164
-0
lines changed

test/cli/config_secrets_test.go

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
package cli
2+
3+
import (
4+
"strings"
5+
"testing"
6+
7+
"github.com/ipfs/kubo/test/cli/harness"
8+
"github.com/stretchr/testify/assert"
9+
"github.com/tidwall/sjson"
10+
)
11+
12+
func TestConfigSecrets(t *testing.T) {
13+
t.Parallel()
14+
15+
t.Run("Identity.PrivKey protection", func(t *testing.T) {
16+
t.Parallel()
17+
18+
t.Run("Identity.PrivKey is concealed in config show", func(t *testing.T) {
19+
t.Parallel()
20+
node := harness.NewT(t).NewNode().Init()
21+
22+
// Read the actual config file to get the real PrivKey
23+
configFile := node.ReadFile(node.ConfigFile())
24+
assert.Contains(t, configFile, "PrivKey")
25+
26+
// config show should NOT contain the PrivKey
27+
configShow := node.RunIPFS("config", "show").Stdout.String()
28+
assert.NotContains(t, configShow, "PrivKey")
29+
})
30+
31+
t.Run("Identity.PrivKey cannot be read via ipfs config", func(t *testing.T) {
32+
t.Parallel()
33+
node := harness.NewT(t).NewNode().Init()
34+
35+
// Attempting to read Identity.PrivKey should fail
36+
res := node.RunIPFS("config", "Identity.PrivKey")
37+
assert.Equal(t, 1, res.ExitCode())
38+
assert.Contains(t, res.Stderr.String(), "cannot show or change private key")
39+
})
40+
41+
t.Run("Identity.PrivKey cannot be read via ipfs config Identity", func(t *testing.T) {
42+
t.Parallel()
43+
node := harness.NewT(t).NewNode().Init()
44+
45+
// Attempting to read Identity section should fail (it contains PrivKey)
46+
res := node.RunIPFS("config", "Identity")
47+
assert.Equal(t, 1, res.ExitCode())
48+
assert.Contains(t, res.Stderr.String(), "cannot show or change private key")
49+
})
50+
51+
t.Run("Identity.PrivKey cannot be set via config replace", func(t *testing.T) {
52+
t.Parallel()
53+
// Key rotation must be done in offline mode via the dedicated `ipfs key rotate` command.
54+
// This test ensures PrivKey cannot be changed via config replace.
55+
node := harness.NewT(t).NewNode().Init()
56+
57+
configShow := node.RunIPFS("config", "show").Stdout.String()
58+
59+
// Try to inject a PrivKey via config replace
60+
configJSON := MustVal(sjson.Set(configShow, "Identity.PrivKey", "CAASqAkwggSkAgEAAo"))
61+
node.WriteBytes("new-config", []byte(configJSON))
62+
res := node.RunIPFS("config", "replace", "new-config")
63+
assert.Equal(t, 1, res.ExitCode())
64+
assert.Contains(t, res.Stderr.String(), "setting private key")
65+
})
66+
67+
t.Run("Identity.PrivKey is preserved when re-injecting config", func(t *testing.T) {
68+
t.Parallel()
69+
node := harness.NewT(t).NewNode().Init()
70+
71+
// Read the original config file
72+
originalConfig := node.ReadFile(node.ConfigFile())
73+
assert.Contains(t, originalConfig, "PrivKey")
74+
75+
// Extract the PrivKey value for comparison
76+
var origPrivKey string
77+
assert.Contains(t, originalConfig, "PrivKey")
78+
// Simple extraction - find the PrivKey line
79+
for _, line := range strings.Split(originalConfig, "\n") {
80+
if strings.Contains(line, "\"PrivKey\":") {
81+
origPrivKey = line
82+
break
83+
}
84+
}
85+
assert.NotEmpty(t, origPrivKey)
86+
87+
// Get config show output (which should NOT contain PrivKey)
88+
configShow := node.RunIPFS("config", "show").Stdout.String()
89+
assert.NotContains(t, configShow, "PrivKey")
90+
91+
// Re-inject the config via config replace
92+
node.WriteBytes("config-show", []byte(configShow))
93+
node.IPFS("config", "replace", "config-show")
94+
95+
// The PrivKey should still be in the config file
96+
newConfig := node.ReadFile(node.ConfigFile())
97+
assert.Contains(t, newConfig, "PrivKey")
98+
99+
// Verify the PrivKey line is the same
100+
var newPrivKey string
101+
for _, line := range strings.Split(newConfig, "\n") {
102+
if strings.Contains(line, "\"PrivKey\":") {
103+
newPrivKey = line
104+
break
105+
}
106+
}
107+
assert.Equal(t, origPrivKey, newPrivKey, "PrivKey should be preserved")
108+
})
109+
})
110+
111+
t.Run("TLS security validation", func(t *testing.T) {
112+
t.Parallel()
113+
114+
t.Run("AutoConf.TLSInsecureSkipVerify defaults to false", func(t *testing.T) {
115+
t.Parallel()
116+
node := harness.NewT(t).NewNode().Init()
117+
118+
// Check the default value in a fresh init
119+
res := node.RunIPFS("config", "AutoConf.TLSInsecureSkipVerify")
120+
// Field may not exist (exit code 1) or be false/empty (exit code 0)
121+
// Both are acceptable as they mean "not true"
122+
output := res.Stdout.String()
123+
assert.NotContains(t, output, "true", "default should not be true")
124+
})
125+
126+
t.Run("AutoConf.TLSInsecureSkipVerify can be set to true", func(t *testing.T) {
127+
t.Parallel()
128+
node := harness.NewT(t).NewNode().Init()
129+
130+
// Set to true
131+
node.IPFS("config", "AutoConf.TLSInsecureSkipVerify", "true", "--json")
132+
133+
// Verify it was set
134+
res := node.RunIPFS("config", "AutoConf.TLSInsecureSkipVerify")
135+
assert.Equal(t, 0, res.ExitCode())
136+
assert.Contains(t, res.Stdout.String(), "true")
137+
})
138+
139+
t.Run("HTTPRetrieval.TLSInsecureSkipVerify defaults to false", func(t *testing.T) {
140+
t.Parallel()
141+
node := harness.NewT(t).NewNode().Init()
142+
143+
// Check the default value in a fresh init
144+
res := node.RunIPFS("config", "HTTPRetrieval.TLSInsecureSkipVerify")
145+
// Field may not exist (exit code 1) or be false/empty (exit code 0)
146+
// Both are acceptable as they mean "not true"
147+
output := res.Stdout.String()
148+
assert.NotContains(t, output, "true", "default should not be true")
149+
})
150+
151+
t.Run("HTTPRetrieval.TLSInsecureSkipVerify can be set to true", func(t *testing.T) {
152+
t.Parallel()
153+
node := harness.NewT(t).NewNode().Init()
154+
155+
// Set to true
156+
node.IPFS("config", "HTTPRetrieval.TLSInsecureSkipVerify", "true", "--json")
157+
158+
// Verify it was set
159+
res := node.RunIPFS("config", "HTTPRetrieval.TLSInsecureSkipVerify")
160+
assert.Equal(t, 0, res.ExitCode())
161+
assert.Contains(t, res.Stdout.String(), "true")
162+
})
163+
})
164+
}

0 commit comments

Comments
 (0)