Skip to content

Commit c330b20

Browse files
committed
Fix CI migration secret handling and error parsing
1 parent 3247ee3 commit c330b20

File tree

5 files changed

+104
-27
lines changed

5 files changed

+104
-27
lines changed

pkg/api/ci.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"fmt"
88
"io"
99
"net/http"
10+
"strings"
1011
)
1112

1213
var baseURLFunc = getBaseURL
@@ -62,9 +63,18 @@ func ciRequest[T any](ctx context.Context, token, orgID, path string, payload in
6263

6364
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
6465
var errResp ErrorResponse
65-
if err := json.Unmarshal(body, &errResp); err == nil && !errResp.OK {
66+
if err := json.Unmarshal(body, &errResp); err == nil && strings.TrimSpace(errResp.Error) != "" {
6667
return nil, fmt.Errorf("%s", errResp.Error)
6768
}
69+
70+
var connectErr struct {
71+
Code string `json:"code"`
72+
Message string `json:"message"`
73+
}
74+
if err := json.Unmarshal(body, &connectErr); err == nil && strings.TrimSpace(connectErr.Message) != "" {
75+
return nil, fmt.Errorf("%s", connectErr.Message)
76+
}
77+
6878
return nil, fmt.Errorf("API error: status %d", resp.StatusCode)
6979
}
7080

pkg/api/ci_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"encoding/json"
66
"net/http"
77
"net/http/httptest"
8+
"strings"
89
"testing"
910
)
1011

@@ -302,6 +303,29 @@ func TestCIErrorHandling(t *testing.T) {
302303
}
303304
}
304305

306+
func TestCIErrorHandlingConnectMessage(t *testing.T) {
307+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
308+
w.WriteHeader(http.StatusBadRequest)
309+
json.NewEncoder(w).Encode(map[string]string{
310+
"code": "invalid_argument",
311+
"message": "invalid secret value",
312+
})
313+
}))
314+
defer server.Close()
315+
316+
oldBaseURLFunc := baseURLFunc
317+
baseURLFunc = func() string { return server.URL }
318+
defer func() { baseURLFunc = oldBaseURLFunc }()
319+
320+
err := CIAddSecret(context.Background(), "test-token", "test-org", "SECRET", "value")
321+
if err == nil {
322+
t.Fatal("expected error for non-200 response")
323+
}
324+
if !strings.Contains(err.Error(), "invalid secret value") {
325+
t.Fatalf("expected connect message in error, got %q", err.Error())
326+
}
327+
}
328+
305329
func TestCIDepotOrgHeader(t *testing.T) {
306330
headerReceived := ""
307331
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

pkg/ci/migrate/secrets.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ import (
99
)
1010

1111
var (
12-
secretRegex = regexp.MustCompile(`\$\{\{\s*secrets\.([A-Za-z_][A-Za-z0-9_]*)\s*[}\s|]`)
13-
variableRegex = regexp.MustCompile(`\$\{\{\s*vars\.([A-Za-z_][A-Za-z0-9_]*)\s*[}\s|]`)
12+
secretRegex = regexp.MustCompile(`\$\{\{\s*secrets\.([A-Za-z_][A-Za-z0-9_]*)(?:\s|[^A-Za-z0-9_.]|$)`)
13+
variableRegex = regexp.MustCompile(`\$\{\{\s*vars\.([A-Za-z_][A-Za-z0-9_]*)(?:\s|[^A-Za-z0-9_.]|$)`)
1414
)
1515

1616
// DetectSecretsFromFile scans a file's raw content for ${{ secrets.X }} references.

pkg/ci/migrate/secrets_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,17 @@ func TestDetectSecretsFromFileWithDefaultExpression(t *testing.T) {
2828
assertStringSliceEqual(t, secrets, []string{"X"})
2929
}
3030

31+
func TestDetectSecretsFromFileWithOperatorNoSpaces(t *testing.T) {
32+
path := writeTempTextFile(t, t.TempDir(), "operator.yml", "if: ${{ secrets.DEPLOY_KEY!='' }}\n")
33+
34+
secrets, err := DetectSecretsFromFile(path)
35+
if err != nil {
36+
t.Fatalf("DetectSecretsFromFile failed: %v", err)
37+
}
38+
39+
assertStringSliceEqual(t, secrets, []string{"DEPLOY_KEY"})
40+
}
41+
3142
func TestDetectSecretsFromFileNoFalsePositive(t *testing.T) {
3243
path := writeTempTextFile(t, t.TempDir(), "env.yml", "value: ${{ env.SOME_VAR }}\n")
3344

@@ -52,6 +63,17 @@ func TestDetectVariablesFromFile(t *testing.T) {
5263
assertStringSliceEqual(t, variables, []string{"MY_VAR"})
5364
}
5465

66+
func TestDetectVariablesFromFileWithOperatorNoSpaces(t *testing.T) {
67+
path := writeTempTextFile(t, t.TempDir(), "vars-operator.yml", "if: ${{ vars.ENV&&true }}\n")
68+
69+
variables, err := DetectVariablesFromFile(path)
70+
if err != nil {
71+
t.Fatalf("DetectVariablesFromFile failed: %v", err)
72+
}
73+
74+
assertStringSliceEqual(t, variables, []string{"ENV"})
75+
}
76+
5577
func TestDetectSecretsFromFileMultipleDeduplicated(t *testing.T) {
5678
path := writeTempTextFile(t, t.TempDir(), "multi.yml", "a: ${{ secrets.A }}\nb: ${{ secrets.B }}\nc: ${{ secrets.A }}\n")
5779

pkg/cmd/ci/migrate.go

Lines changed: 45 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -223,27 +223,50 @@ func runMigrate(ctx context.Context, opts migrateOptions) error {
223223
return err
224224
}
225225

226-
if opts.yes {
227-
if len(secretAssignments) > 0 {
228-
orgID, token, err := resolveMigrationAuth(ctx, opts)
229-
if err != nil {
230-
return err
231-
}
226+
authResolved := false
227+
var orgID, token string
228+
resolveAuth := func() (string, string, error) {
229+
if authResolved {
230+
return orgID, token, nil
231+
}
232232

233-
secretNames := make([]string, 0, len(secretAssignments))
234-
for name := range secretAssignments {
235-
secretNames = append(secretNames, name)
236-
}
237-
sort.Strings(secretNames)
233+
var err error
234+
orgID, token, err = resolveMigrationAuth(ctx, opts)
235+
if err != nil {
236+
return "", "", err
237+
}
238+
authResolved = true
239+
return orgID, token, nil
240+
}
238241

239-
for _, name := range secretNames {
240-
if err := api.CIAddSecret(ctx, token, orgID, name, secretAssignments[name]); err != nil {
241-
return fmt.Errorf("failed to configure secret %s: %w", name, err)
242-
}
243-
configuredSecrets = append(configuredSecrets, name)
242+
configureSecret := func(name, value string) error {
243+
orgID, token, err := resolveAuth()
244+
if err != nil {
245+
return err
246+
}
247+
248+
if err := api.CIAddSecret(ctx, token, orgID, name, value); err != nil {
249+
return fmt.Errorf("failed to configure secret %s: %w", name, err)
250+
}
251+
configuredSecrets = append(configuredSecrets, name)
252+
return nil
253+
}
254+
255+
if len(secretAssignments) > 0 {
256+
secretNames := make([]string, 0, len(secretAssignments))
257+
for name := range secretAssignments {
258+
secretNames = append(secretNames, name)
259+
}
260+
sort.Strings(secretNames)
261+
262+
for _, name := range secretNames {
263+
if err := configureSecret(name, secretAssignments[name]); err != nil {
264+
return err
244265
}
245266
}
267+
}
246268

269+
if opts.yes {
247270
missingSecrets := make([]string, 0)
248271
for _, name := range detectedSecrets {
249272
if _, ok := secretAssignments[name]; !ok {
@@ -256,12 +279,11 @@ func runMigrate(ctx context.Context, opts migrateOptions) error {
256279
warnings = append(warnings, fmt.Sprintf("configure missing secrets with `depot ci secrets add <NAME> --value <VALUE>` (missing: %s)", strings.Join(missingSecrets, ", ")))
257280
}
258281
} else if len(detectedSecrets) > 0 {
259-
orgID, token, err := resolveMigrationAuth(ctx, opts)
260-
if err != nil {
261-
return err
262-
}
263-
264282
for _, name := range detectedSecrets {
283+
if _, ok := secretAssignments[name]; ok {
284+
continue
285+
}
286+
265287
value, err := promptForCISecret(fmt.Sprintf("Enter value for secret '%s' (leave empty to skip): ", name))
266288
if err != nil {
267289
return fmt.Errorf("failed to read value for secret %s: %w", name, err)
@@ -271,10 +293,9 @@ func runMigrate(ctx context.Context, opts migrateOptions) error {
271293
continue
272294
}
273295

274-
if err := api.CIAddSecret(ctx, token, orgID, name, value); err != nil {
275-
return fmt.Errorf("failed to configure secret %s: %w", name, err)
296+
if err := configureSecret(name, value); err != nil {
297+
return err
276298
}
277-
configuredSecrets = append(configuredSecrets, name)
278299
}
279300
}
280301

0 commit comments

Comments
 (0)