Skip to content

fix(root): stop loading .env at runtime (silent credential shadow)#204

Merged
AlephNotation merged 1 commit into
mainfrom
ty/fix-dotenv-credential-shadowing
May 13, 2026
Merged

fix(root): stop loading .env at runtime (silent credential shadow)#204
AlephNotation merged 1 commit into
mainfrom
ty/fix-dotenv-credential-shadowing

Conversation

@AlephNotation
Copy link
Copy Markdown
Contributor

Summary

Removes the unconditional godotenv.Load() in PersistentPreRunE. It was originally added as a dev convenience for picking up VERS_URL from a local .env, but it also reads VERS_API_KEY, which silently shadows the user's ~/.versrc whenever they happen to run vers in a directory containing a .env file — with no warning about which credential source the SDK actually used.

Repro

  1. Have a valid org-scoped key in ~/.versrc.
  2. cd into a directory with a .env containing a stale VERS_API_KEY (e.g. this repo — there's been one checked in locally for months).
  3. Run vers status.

Expected: VMs for the org the ~/.versrc key belongs to.
Actual: VMs for whatever identity the stale .env key happens to belong to — usually a different org. No indication anywhere that .env won.

Took ~20 minutes of debugging (including vers status --verbose to read the wire-level Authorization header) to discover .env was the credential source. The Verbose log shows the third, mystery key being sent:

Authorization: Bearer ef90fd52-...   # neither ~/.versrc nor VERS_API_KEY env

Why removal (not a flag)

  • The CLI ships to end users; reading arbitrary .env from the user's cwd is a footgun, not a feature.
  • Tests already load their own .env explicitly via test/testutil/helpers.go — runtime removal does not affect them.
  • Devs who want .env loading have direnv or export $(cat .env | xargs).
  • A flag (VERS_USE_DOTENV=1) would still leave the door open to credential shadowing for anyone who set it once and forgot.

If we want this back

Make it opt-in and visible:

  1. Gate it behind VERS_USE_DOTENV=1 (or similar).
  2. Emit a stderr line whenever .env contributes a credential or base URL, so the credential source is never invisible.

Happy to do that as a follow-up if anyone leans on the current behavior.

Related AX gaps surfaced by this debugging session

Not fixed here, worth tracking separately:

  • No vers whoami to show "you are user X in org Y, talking to api.vers.sh." Five seconds of identity output would have caught this immediately.
  • VERS_ORG=hdr-is vers status is accepted silently and does nothing when the API key isn't valid for that org. Should either scope the call or error.
  • vers status gives no indication of which org's VMs it's listing.

PersistentPreRunE called godotenv.Load() on every command to pick up
VERS_URL from a local .env for dev convenience. The side effect was
that any stale VERS_API_KEY in a .env file in the user's cwd would
silently override their ~/.versrc — with no warning about which
credential source the SDK actually used.

Repro: be in a directory with a .env containing a stale VERS_API_KEY,
run any 'vers' command. The CLI authenticates as the stale key's
identity instead of the configured user, returning a foreign org's
VMs. Took ~20 minutes of debugging (including 'vers status --verbose'
to see the wire-level Authorization header) to discover the .env was
the credential source.

Removal rationale:
- The CLI ships to end users; reading arbitrary .env from cwd is a
  footgun, not a feature.
- Tests already load their own .env explicitly via
  test/testutil/helpers.go — runtime removal does not affect them.
- Devs who want .env loading have direnv or 'export $(cat .env | xargs)'.

If we want to restore this behavior we should:
1. Gate it behind an explicit opt-in (e.g. VERS_USE_DOTENV=1).
2. Emit a stderr line when .env contributes a credential or base URL,
   so the credential source is always visible.
@AlephNotation AlephNotation merged commit 23ff608 into main May 13, 2026
11 of 12 checks passed
@AlephNotation AlephNotation deleted the ty/fix-dotenv-credential-shadowing branch May 13, 2026 05:13
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