master
go 164 lines 5.46 KB
Raw
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.SplitSeq(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.SplitSeq(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 }