From 7054514e125a4e15edeccfb353a3ae1cee8684b6 Mon Sep 17 00:00:00 2001 From: Jon Langevin Date: Wed, 20 May 2026 03:08:33 -0400 Subject: [PATCH] fix(wfctl): forward gen.Name to provider_credential generator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SecretGen has a yaml `name:` field but bootstrapSecrets dropped it when building genConfig. v0.60.4 made name required for digitalocean.spaces, so every project's apply-prereq broke despite their deploy.prereq.yaml correctly setting it. Add gen.Name → genConfig["name"] propagation. Regression test asserts the generator receives the configured name. Co-Authored-By: Claude Opus 4.7 (1M context) --- cmd/wfctl/infra_bootstrap.go | 3 ++ cmd/wfctl/infra_bootstrap_secrets_test.go | 39 +++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/cmd/wfctl/infra_bootstrap.go b/cmd/wfctl/infra_bootstrap.go index 226d2ef9..e7bc3c92 100644 --- a/cmd/wfctl/infra_bootstrap.go +++ b/cmd/wfctl/infra_bootstrap.go @@ -611,6 +611,9 @@ var bootstrapSecrets = func(ctx context.Context, provider secrets.Provider, cfg if gen.Source != "" { genConfig["source"] = gen.Source } + if gen.Name != "" { + genConfig["name"] = gen.Name + } // --force-rotate path: for provider_credential, read the OLD access_key // BEFORE deleting so we can revoke it at the upstream provider after minting diff --git a/cmd/wfctl/infra_bootstrap_secrets_test.go b/cmd/wfctl/infra_bootstrap_secrets_test.go index 9779690b..ef511526 100644 --- a/cmd/wfctl/infra_bootstrap_secrets_test.go +++ b/cmd/wfctl/infra_bootstrap_secrets_test.go @@ -387,3 +387,42 @@ func TestBootstrapSecrets_ProviderCredential_RollbackOnFirstSetFailure(t *testin t.Errorf("rollback calls = %v; want one revoke of AK_FIRST", rev.calls) } } + +// TestBootstrapSecrets_ForwardsGenName is the regression test for the +// breakage caught during the gocodealone-multisite deploy: SecretGen +// has a `name:` field but bootstrapSecrets didn't propagate it into +// genConfig. provider_credential generators requiring a non-empty +// name (e.g. digitalocean.spaces post-v0.60.4) then failed every run +// because the config they received was missing the field. +func TestBootstrapSecrets_ForwardsGenName(t *testing.T) { + var capturedConfig map[string]any + withStubGenerator(t, func(_ context.Context, _ string, cfg map[string]any) (string, error) { + capturedConfig = cfg + out, _ := json.Marshal(map[string]string{ + "access_key": "AK", + "secret_key": "SK", + }) + return string(out), nil + }) + + p := &writeOnlyProvider{listOK: true} + cfg := &SecretsConfig{ + Generate: []SecretGen{ + { + Key: "SPACES", + Type: "provider_credential", + Source: "digitalocean.spaces", + Name: "multisite-deploy-key", + }, + }, + } + if _, _, err := bootstrapSecrets(context.Background(), p, cfg, nil); err != nil { + t.Fatalf("bootstrapSecrets: %v", err) + } + if got := capturedConfig["name"]; got != "multisite-deploy-key" { + t.Errorf("generator received name=%v want multisite-deploy-key (full config: %v)", got, capturedConfig) + } + if got := capturedConfig["source"]; got != "digitalocean.spaces" { + t.Errorf("generator received source=%v want digitalocean.spaces", got) + } +}