fix(cli): sanitize deploy fallback warnings
- commit
- 292f2ecab8557053cff7246393008b9d525cd712
- author
- brice · · 2026-04-06 17:11 UTC
- parent
- 2f5cb8f
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
3 files · +34 -4
M internal/adapters/in/cli/deploy.go +2 -2
| @@ -97,10 +97,10 @@ func runDeploy(ctx context.Context, deployer deployer, isRemote bool, deployDoma | |||
| 97 | 97 | func handleLocalDeployFallback(err error, deployDomain string, out io.Writer, jsonOut bool) error { | |
| 98 | 98 | domain, localErr := sendDeploySignal(deployDomain) | |
| 99 | 99 | if localErr != nil { | |
| 100 | - | return fmt.Errorf("failed to deploy: remote error: %w; local fallback also failed: %v", err, localErr) | |
| 100 | + | return fmt.Errorf("failed to deploy: remote error: %w; local fallback also failed: %w", err, localErr) | |
| 101 | 101 | } | |
| 102 | 102 | ||
| 103 | - | warning := fmt.Sprintf("Remote deploy failed (%v), used local signal fallback", err) | |
| 103 | + | warning := sanitizeDeployLogLine(fmt.Sprintf("Remote deploy failed (%v), used local signal fallback", err)) | |
| 104 | 104 | if jsonOut { | |
| 105 | 105 | return writeJSON(out, map[string]string{ | |
| 106 | 106 | "warning": warning, | |
| @@ -97,10 +97,10 @@ func runDeploy(ctx context.Context, deployer deployer, isRemote bool, deployDoma | |||||
| 97 | func handleLocalDeployFallback(err error, deployDomain string, out io.Writer, jsonOut bool) error { | 97 | func handleLocalDeployFallback(err error, deployDomain string, out io.Writer, jsonOut bool) error { | ||
| 98 | domain, localErr := sendDeploySignal(deployDomain) | 98 | domain, localErr := sendDeploySignal(deployDomain) | ||
| 99 | if localErr != nil { | 99 | if localErr != nil { | ||
| 100 | - | return fmt.Errorf("failed to deploy: remote error: %w; local fallback also failed: %v", err, localErr) | 100 | + | return fmt.Errorf("failed to deploy: remote error: %w; local fallback also failed: %w", err, localErr) |
| 101 | } | 101 | } | ||
| 102 | 102 | ||||
| 103 | - | warning := fmt.Sprintf("Remote deploy failed (%v), used local signal fallback", err) | 103 | + | warning := sanitizeDeployLogLine(fmt.Sprintf("Remote deploy failed (%v), used local signal fallback", err)) |
| 104 | if jsonOut { | 104 | if jsonOut { | ||
| 105 | return writeJSON(out, map[string]string{ | 105 | return writeJSON(out, map[string]string{ | ||
| 106 | "warning": warning, | 106 | "warning": warning, | ||
M internal/adapters/in/cli/deploy_error_test.go +1 -2
| @@ -65,7 +65,6 @@ func TestFormatDeployFailure_SkipsEmptySanitizedLogsSection(t *testing.T) { | |||
| 65 | 65 | err := formatDeployFailure(root) | |
| 66 | 66 | ||
| 67 | 67 | require.Error(t, err) | |
| 68 | - | assert.Contains(t, err.Error(), "failed to deploy\nCause: health check failed") | |
| 69 | - | assert.NotContains(t, err.Error(), "Recent container logs:") | |
| 68 | + | assert.Equal(t, "failed to deploy\nCause: health check failed", err.Error()) | |
| 70 | 69 | assert.ErrorIs(t, err, root) | |
| 71 | 70 | } | |
| @@ -65,7 +65,6 @@ func TestFormatDeployFailure_SkipsEmptySanitizedLogsSection(t *testing.T) { | |||||
| 65 | err := formatDeployFailure(root) | 65 | err := formatDeployFailure(root) | ||
| 66 | 66 | ||||
| 67 | require.Error(t, err) | 67 | require.Error(t, err) | ||
| 68 | - | assert.Contains(t, err.Error(), "failed to deploy\nCause: health check failed") | 68 | + | assert.Equal(t, "failed to deploy\nCause: health check failed", err.Error()) |
| 69 | - | assert.NotContains(t, err.Error(), "Recent container logs:") | |||
| 70 | assert.ErrorIs(t, err, root) | 69 | assert.ErrorIs(t, err, root) | ||
| 71 | } | 70 | } | ||
M internal/adapters/in/cli/deploy_test.go +31 -0
| @@ -86,3 +86,34 @@ func TestRunDeploy_RemoteFallbackUsesJSONWhenRequested(t *testing.T) { | |||
| 86 | 86 | require.NoError(t, err) | |
| 87 | 87 | assert.JSONEq(t, `{"domain":"app.example.com","status":"success","warning":"Remote deploy failed (503 Service Unavailable: Registry Unavailable), used local signal fallback"}`, out.String()) | |
| 88 | 88 | } | |
| 89 | + | ||
| 90 | + | func TestHandleLocalDeployFallback_WrapsRemoteAndLocalErrors(t *testing.T) { | |
| 91 | + | originalSendDeploySignal := sendDeploySignal | |
| 92 | + | localErr := errors.New("local signal failed") | |
| 93 | + | sendDeploySignal = func(string) (string, error) { | |
| 94 | + | return "", localErr | |
| 95 | + | } | |
| 96 | + | defer func() { sendDeploySignal = originalSendDeploySignal }() | |
| 97 | + | ||
| 98 | + | remoteErr := errors.New("remote deploy failed") | |
| 99 | + | err := handleLocalDeployFallback(remoteErr, "app.example.com", &bytes.Buffer{}, false) | |
| 100 | + | ||
| 101 | + | require.Error(t, err) | |
| 102 | + | assert.Equal(t, "failed to deploy: remote error: remote deploy failed; local fallback also failed: local signal failed", err.Error()) | |
| 103 | + | assert.ErrorIs(t, err, remoteErr) | |
| 104 | + | assert.ErrorIs(t, err, localErr) | |
| 105 | + | } | |
| 106 | + | ||
| 107 | + | func TestRunDeploy_RemoteFallbackSanitizesWarning(t *testing.T) { | |
| 108 | + | originalSendDeploySignal := sendDeploySignal | |
| 109 | + | sendDeploySignal = func(string) (string, error) { | |
| 110 | + | return "app.example.com", nil | |
| 111 | + | } | |
| 112 | + | defer func() { sendDeploySignal = originalSendDeploySignal }() | |
| 113 | + | ||
| 114 | + | var out bytes.Buffer | |
| 115 | + | err := runDeploy(context.Background(), &deployTestDeployer{err: errors.New("503 Service Unavailable:\n\x1b[31mRegistry Unavailable\x1b[0m")}, true, "app.example.com", &out, true) | |
| 116 | + | ||
| 117 | + | require.NoError(t, err) | |
| 118 | + | assert.JSONEq(t, `{"domain":"app.example.com","status":"success","warning":"Remote deploy failed (503 Service Unavailable:Registry Unavailable), used local signal fallback"}`, out.String()) | |
| 119 | + | } | |
| @@ -86,3 +86,34 @@ func TestRunDeploy_RemoteFallbackUsesJSONWhenRequested(t *testing.T) { | |||||
| 86 | require.NoError(t, err) | 86 | require.NoError(t, err) | ||
| 87 | assert.JSONEq(t, `{"domain":"app.example.com","status":"success","warning":"Remote deploy failed (503 Service Unavailable: Registry Unavailable), used local signal fallback"}`, out.String()) | 87 | assert.JSONEq(t, `{"domain":"app.example.com","status":"success","warning":"Remote deploy failed (503 Service Unavailable: Registry Unavailable), used local signal fallback"}`, out.String()) | ||
| 88 | } | 88 | } | ||
| 89 | + | ||||
| 90 | + | func TestHandleLocalDeployFallback_WrapsRemoteAndLocalErrors(t *testing.T) { | |||
| 91 | + | originalSendDeploySignal := sendDeploySignal | |||
| 92 | + | localErr := errors.New("local signal failed") | |||
| 93 | + | sendDeploySignal = func(string) (string, error) { | |||
| 94 | + | return "", localErr | |||
| 95 | + | } | |||
| 96 | + | defer func() { sendDeploySignal = originalSendDeploySignal }() | |||
| 97 | + | ||||
| 98 | + | remoteErr := errors.New("remote deploy failed") | |||
| 99 | + | err := handleLocalDeployFallback(remoteErr, "app.example.com", &bytes.Buffer{}, false) | |||
| 100 | + | ||||
| 101 | + | require.Error(t, err) | |||
| 102 | + | assert.Equal(t, "failed to deploy: remote error: remote deploy failed; local fallback also failed: local signal failed", err.Error()) | |||
| 103 | + | assert.ErrorIs(t, err, remoteErr) | |||
| 104 | + | assert.ErrorIs(t, err, localErr) | |||
| 105 | + | } | |||
| 106 | + | ||||
| 107 | + | func TestRunDeploy_RemoteFallbackSanitizesWarning(t *testing.T) { | |||
| 108 | + | originalSendDeploySignal := sendDeploySignal | |||
| 109 | + | sendDeploySignal = func(string) (string, error) { | |||
| 110 | + | return "app.example.com", nil | |||
| 111 | + | } | |||
| 112 | + | defer func() { sendDeploySignal = originalSendDeploySignal }() | |||
| 113 | + | ||||
| 114 | + | var out bytes.Buffer | |||
| 115 | + | err := runDeploy(context.Background(), &deployTestDeployer{err: errors.New("503 Service Unavailable:\n\x1b[31mRegistry Unavailable\x1b[0m")}, true, "app.example.com", &out, true) | |||
| 116 | + | ||||
| 117 | + | require.NoError(t, err) | |||
| 118 | + | assert.JSONEq(t, `{"domain":"app.example.com","status":"success","warning":"Remote deploy failed (503 Service Unavailable:Registry Unavailable), used local signal fallback"}`, out.String()) | |||
| 119 | + | } | |||