Skip to content

Create the Google Secret Manager client only when a mapping uses GSM#35

Open
nullzone wants to merge 3 commits into
vimeo:masterfrom
nullzone:master
Open

Create the Google Secret Manager client only when a mapping uses GSM#35
nullzone wants to merge 3 commits into
vimeo:masterfrom
nullzone:master

Conversation

@nullzone

Copy link
Copy Markdown
Contributor

Problem

main() builds a Google Secret Manager client unconditionally at startup (secretmanager.NewClient(ctx)), regardless of whether any mapping sources from GSM. The Google SDK resolves Application Default Credentials eagerly at construction, so GCP credentials become a hard startup requirement for every deployment — including pure-Vault ones that never touch GSM.

On a non-GCP cluster (e.g. Vault-only reflection on-prem) pentagon dies at startup with:

unable to get GSM client: credentials: could not find default credentials

(exit code 32), even though the GSM client is never used.

Fix

Build the GSM client lazily: only call secretmanager.NewClient when at least one mapping has SourceType == GSMSourceType. When no mapping uses GSM the client stays nil and is never dereferenced — Reflector.getGSMSecret is only reached for GSM-sourced mappings — so Vault-only deployments no longer need any GCP credential.

Behaviour

  • Vault-only config, no GCP credentials: starts normally (previously exit 32).
  • Config with a gsm mapping: unchanged — a missing/invalid credential still fails fast at startup.

Testing

  • go test ./... passes.
  • Verified manually: a Vault-only config now reaches the reflection step with no GCP credentials present; a config with a gsm mapping still requires the GSM client.

nullzone added 2 commits June 12, 2026 10:56
main() unconditionally builds a Google Secret Manager client via secretmanager.NewClient(ctx) at startup, regardless of whether any mapping actually sources from GSM. Because the Google SDK resolves Application Default Credentials eagerly at construction time, this makes GCP credentials a hard startup requirement for every deployment, including pure-Vault ones that never touch GSM.

On a non-GCP environment (e.g. Vault-only secret reflection in an on-prem/other-cloud cluster) pentagon therefore dies at startup with:

      unable to get GSM client: credentials: could not find default credentials

  and exits 32, even though the GSM client is never used.

  Build the GSM client lazily: scan the configured mappings and only call secretmanager.NewClient when at least one mapping has SourceType == GSMSourceType. When no mapping uses GSM the client stays nil and is never dereferenced (Reflector.getGSMSecret is only reached for GSM-sourced mappings), so Vault-only deployments no longer require any GCP credential. Behaviour is unchanged when GSM mappings are present: a missing/invalid credential still fails fast.
Create the GSM client only when a mapping uses GSM

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 8f49f34. Configure here.

Comment thread pentagon/main.go Outdated
if err != nil {
log.Printf("unable to get GSM client: %s", err)
os.Exit(32)
var gsmClient *secretmanager.Client

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typed nil pointer creates non-nil interface value

Low Severity

gsmClient is declared as *secretmanager.Client (a concrete type). When no GSM mappings exist, this typed nil pointer is passed to NewReflector, which expects the gsm.SecretAccessor interface. In Go, a typed nil pointer wrapped in an interface produces a non-nil interface value. So Reflector.gsmClient will not be nil — it will be a non-nil interface holding a nil pointer. Any future nil guard on r.gsmClient would incorrectly pass, and calling a method on it would panic. Declaring gsmClient as gsm.SecretAccessor instead would preserve a true nil interface when unused.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 8f49f34. Configure here.

  Declare gsmClient as gsm.SecretAccessor instead of the concrete
  *secretmanager.Client. A typed nil pointer assigned to an interface
  yields a non-nil interface value wrapping a nil pointer, so when no
  mapping uses GSM the previous code left Reflector.gsmClient non-nil,
  silently defeating any nil check and panicking if a method were called.

  Construction and Close() use a concrete *secretmanager.Client local that
  is then assigned to the interface variable, since SecretAccessor exposes
  only AccessSecretVersion (no Close).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant