@@ -47,17 +47,7 @@ func TestShellVariableResolver_ResolveValue(t *testing.T) {
4747 envVars: map[string]string{},
4848 expectError: true,
4949 },
50− {
51− name: "shell command execution",
52− value: "$(echo hello)",
53− shellFunc: func(ctx context.Context, command string) (stdout, stderr string, err error) {
54− if command == "echo hello" {
55− return "hello\n", "", nil
56− }
57− return "", "", errors.New("unexpected command")
58− },
59− expected: "hello",
60− },
50+
6151 {
6252 name: "shell command with whitespace trimming",
6353 value: "$(echo ' spaced ')",
@@ -104,6 +94,171 @@ func TestShellVariableResolver_ResolveValue(t *testing.T) {
10494 }
10595}
10696
97+func TestShellVariableResolver_EnhancedResolveValue(t *testing.T) {
98+ tests := []struct {
99+ name string
100+ value string
101+ envVars map[string]string
102+ shellFunc func(ctx context.Context, command string) (stdout, stderr string, err error)
103+ expected string
104+ expectError bool
105+ }{
106+ {
107+ name: "command substitution within string",
108+ value: "Bearer $(echo token123)",
109+ shellFunc: func(ctx context.Context, command string) (stdout, stderr string, err error) {
110+ if command == "echo token123" {
111+ return "token123\n", "", nil
112+ }
113+ return "", "", errors.New("unexpected command")
114+ },
115+ expected: "Bearer token123",
116+ },
117+ {
118+ name: "environment variable within string",
119+ value: "Bearer $TOKEN",
120+ envVars: map[string]string{"TOKEN": "sk-ant-123"},
121+ expected: "Bearer sk-ant-123",
122+ },
123+ {
124+ name: "environment variable with braces within string",
125+ value: "Bearer ${TOKEN}",
126+ envVars: map[string]string{"TOKEN": "sk-ant-456"},
127+ expected: "Bearer sk-ant-456",
128+ },
129+ {
130+ name: "mixed command and environment substitution",
131+ value: "$USER-$(date +%Y)-$HOST",
132+ envVars: map[string]string{
133+ "USER": "testuser",
134+ "HOST": "localhost",
135+ },
136+ shellFunc: func(ctx context.Context, command string) (stdout, stderr string, err error) {
137+ if command == "date +%Y" {
138+ return "2024\n", "", nil
139+ }
140+ return "", "", errors.New("unexpected command")
141+ },
142+ expected: "testuser-2024-localhost",
143+ },
144+ {
145+ name: "multiple command substitutions",
146+ value: "$(echo hello) $(echo world)",
147+ shellFunc: func(ctx context.Context, command string) (stdout, stderr string, err error) {
148+ switch command {
149+ case "echo hello":
150+ return "hello\n", "", nil
151+ case "echo world":
152+ return "world\n", "", nil
153+ }
154+ return "", "", errors.New("unexpected command")
155+ },
156+ expected: "hello world",
157+ },
158+ {
159+ name: "nested parentheses in command",
160+ value: "$(echo $(echo inner))",
161+ shellFunc: func(ctx context.Context, command string) (stdout, stderr string, err error) {
162+ if command == "echo $(echo inner)" {
163+ return "nested\n", "", nil
164+ }
165+ return "", "", errors.New("unexpected command")
166+ },
167+ expected: "nested",
168+ },
169+ {
170+ name: "lone dollar with non-variable chars",
171+ value: "prefix$123suffix", // Numbers can't start variable names
172+ expectError: true,
173+ },
174+ {
175+ name: "dollar with special chars",
176+ value: "a$@b$#c", // Special chars aren't valid in variable names
177+ expectError: true,
178+ },
179+ {
180+ name: "empty environment variable substitution",
181+ value: "Bearer $EMPTY_VAR",
182+ envVars: map[string]string{},
183+ expectError: true,
184+ },
185+ {
186+ name: "unmatched command substitution opening",
187+ value: "Bearer $(echo test",
188+ expectError: true,
189+ },
190+ {
191+ name: "unmatched environment variable braces",
192+ value: "Bearer ${TOKEN",
193+ expectError: true,
194+ },
195+ {
196+ name: "command substitution with error",
197+ value: "Bearer $(false)",
198+ shellFunc: func(ctx context.Context, command string) (stdout, stderr string, err error) {
199+ return "", "", errors.New("command failed")
200+ },
201+ expectError: true,
202+ },
203+ {
204+ name: "complex real-world example",
205+ value: "Bearer $(cat /tmp/token.txt | base64 -w 0)",
206+ shellFunc: func(ctx context.Context, command string) (stdout, stderr string, err error) {
207+ if command == "cat /tmp/token.txt | base64 -w 0" {
208+ return "c2stYW50LXRlc3Q=\n", "", nil
209+ }
210+ return "", "", errors.New("unexpected command")
211+ },
212+ expected: "Bearer c2stYW50LXRlc3Q=",
213+ },
214+ {
215+ name: "environment variable with underscores and numbers",
216+ value: "Bearer $API_KEY_V2",
217+ envVars: map[string]string{"API_KEY_V2": "sk-test-123"},
218+ expected: "Bearer sk-test-123",
219+ },
220+ {
221+ name: "no substitution needed",
222+ value: "Bearer sk-ant-static-token",
223+ expected: "Bearer sk-ant-static-token",
224+ },
225+ {
226+ name: "incomplete variable at end",
227+ value: "Bearer $",
228+ expectError: true,
229+ },
230+ {
231+ name: "variable with invalid character",
232+ value: "Bearer $VAR-NAME", // Hyphen not allowed in variable names
233+ expectError: true,
234+ },
235+ {
236+ name: "multiple invalid variables",
237+ value: "$1$2$3",
238+ expectError: true,
239+ },
240+ }
241+
242+ for _, tt := range tests {
243+ t.Run(tt.name, func(t *testing.T) {
244+ testEnv := env.NewFromMap(tt.envVars)
245+ resolver := &shellVariableResolver{
246+ shell: &mockShell{execFunc: tt.shellFunc},
247+ env: testEnv,
248+ }
249+
250+ result, err := resolver.ResolveValue(tt.value)
251+
252+ if tt.expectError {
253+ assert.Error(t, err)
254+ } else {
255+ assert.NoError(t, err)
256+ assert.Equal(t, tt.expected, result)
257+ }
258+ })
259+ }
260+}
261+
107262func TestEnvironmentVariableResolver_ResolveValue(t *testing.T) {
108263 tests := []struct {
109264 name string