Skip to content

Commit fd0af9f

Browse files
cristimclaude
andauthored
fix(cli): delete the minted GCP key when the credentials upload panics (#2233)
The deferred cleanup in uploadGCPCredentialsFile only deleted the remote key when err was non-nil; during a panic the named err is still nil, so the local file was removed while the key stayed active in GCP. Track completion and treat a non-completed nil-error exit as an abort: delete the key, report the outcome on stderr (the return value is lost) and let the panic keep propagating. Also assert that a failed local removal after a successful upload does not delete the stored key remotely. Refs #2117 Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 700ff43 commit fd0af9f

2 files changed

Lines changed: 42 additions & 0 deletions

File tree

‎cmd/configure_gcp.go‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,14 +191,25 @@ func runConfigureGCP(cmd *cobra.Command, args []string) error {
191191
// removed on every path, and on failure the remote key is deleted via
192192
// deleteKey so it does not stay active. Cleanup failures are returned.
193193
func uploadGCPCredentialsFile(ctx context.Context, store SecretsStore, stackName, credsFile, mintedKeyName string, deleteKey func(context.Context, string) error) (creds GCPCredentials, err error) {
194+
done := false
194195
if mintedKeyName != "" {
195196
defer func() {
197+
// A panic or Goexit leaves the named err nil and done false; the
198+
// return value is lost, so report the outcome on stderr. The panic
199+
// keeps propagating.
200+
aborted := err == nil && !done
201+
if aborted {
202+
err = errors.New("upload aborted before completion")
203+
}
196204
if err != nil {
197205
err = deleteMintedGCPKeyRemotely(err, mintedKeyName, deleteKey)
198206
}
199207
if rmErr := removeMintedGCPKey(credsFile); rmErr != nil {
200208
err = errors.Join(err, rmErr)
201209
}
210+
if aborted {
211+
fmt.Fprintln(os.Stderr, err)
212+
}
202213
}()
203214
}
204215

@@ -211,6 +222,7 @@ func uploadGCPCredentialsFile(ctx context.Context, store SecretsStore, stackName
211222
return GCPCredentials{}, err
212223
}
213224

225+
done = true
214226
return creds, nil
215227
}
216228

‎cmd/configure_gcp_test.go‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,36 @@ func TestUploadGCPCredentialsFile_RemovalFailureReported(t *testing.T) {
382382
_, err := uploadGCPCredentialsFile(context.Background(), NewMockSecretsStore(), "stack", keyFile, keyName, m.DeleteKey)
383383
require.Error(t, err)
384384
assert.Contains(t, err.Error(), "failed to remove the minted key file")
385+
assert.False(t, m.deleteCalled, "the upload succeeded, so the stored key must stay active in GCP")
386+
}
387+
388+
func TestUploadGCPCredentialsFile_PanicDeletesRemoteKey(t *testing.T) {
389+
keyFile, keyName := mintTestGCPKey(t)
390+
store := NewMockSecretsStore()
391+
store.updateSecretFunc = func(context.Context, string, string) error { panic("store crashed") }
392+
m := &mockGCPKeyProvisioner{}
393+
394+
assert.Panics(t, func() {
395+
_, _ = uploadGCPCredentialsFile(context.Background(), store, "stack", keyFile, keyName, m.DeleteKey)
396+
})
397+
assert.True(t, m.deleteCalled, "the minted key must be deleted from GCP when the upload panics")
398+
assert.Equal(t, testMintedKeyName, m.deletedKeyName)
399+
assertMintedKeyGone(t, keyFile)
400+
}
401+
402+
func TestUploadGCPCredentialsFile_PanicReportsFailedRemoteDelete(t *testing.T) {
403+
keyFile, keyName := mintTestGCPKey(t)
404+
store := NewMockSecretsStore()
405+
store.updateSecretFunc = func(context.Context, string, string) error { panic("store crashed") }
406+
m := &mockGCPKeyProvisioner{deleteErr: errors.New("delete 500")}
407+
408+
_, stderr := captureRealStd(t, func() {
409+
assert.Panics(t, func() {
410+
_, _ = uploadGCPCredentialsFile(context.Background(), store, "stack", keyFile, keyName, m.DeleteKey)
411+
})
412+
})
413+
assert.Contains(t, stderr, gcloudDeleteKeyCommand(testMintedKeyName))
414+
assertMintedKeyGone(t, keyFile)
385415
}
386416

387417
func TestUploadGCPCredentialsFile_OperatorFileKept(t *testing.T) {

0 commit comments

Comments
 (0)