From d674fefd23887ca576e2712a0dbce13e621c9fb1 Mon Sep 17 00:00:00 2001 From: Tynan Daly Date: Tue, 12 May 2026 19:27:44 -0700 Subject: [PATCH] fix(root): stop loading .env at runtime (silent credential shadow) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- cmd/root.go | 12 +++++++++--- go.mod | 2 +- go.sum | 2 -- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index 9ae22a3..6e5061e 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -16,7 +16,6 @@ import ( runrt "github.com/hdresearch/vers-cli/internal/runtime" "github.com/hdresearch/vers-cli/internal/update" vers "github.com/hdresearch/vers-sdk-go" - "github.com/joho/godotenv" "github.com/spf13/cobra" ) @@ -196,8 +195,15 @@ interaction capabilities, and more.`, return nil } - // Load .env for the VERS_URL - godotenv.Load() + // NOTE: previously this called godotenv.Load() to pick up VERS_URL + // from a local .env for dev convenience. That had the side effect of + // silently shadowing the user's ~/.versrc credentials with a stale + // VERS_API_KEY whenever the user happened to be in a directory + // containing a .env file — with no warning about which credential + // source won. We now only honor the real environment and ~/.versrc. + // Devs who want .env-style loading can use direnv or `export $(cat + // .env | xargs)`. Tests load their own .env explicitly via + // test/testutil/helpers.go. // Initialize the client with API key if available apiKey, err := auth.GetAPIKey() diff --git a/go.mod b/go.mod index f79910a..be20756 100644 --- a/go.mod +++ b/go.mod @@ -24,7 +24,7 @@ require ( require ( github.com/hdresearch/vers-sdk-go v0.1.0-alpha.32 github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/spf13/pflag v1.0.6 // indirect + github.com/spf13/pflag v1.0.6 github.com/tidwall/gjson v1.18.0 // indirect github.com/tidwall/match v1.2.0 // indirect github.com/tidwall/pretty v1.2.1 // indirect diff --git a/go.sum b/go.sum index 85752c8..f77b84c 100644 --- a/go.sum +++ b/go.sum @@ -7,8 +7,6 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/jsonschema-go v0.2.3 h1:dkP3B96OtZKKFvdrUSaDkL+YDx8Uw9uC4Y+eukpCnmM= github.com/google/jsonschema-go v0.2.3/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE= -github.com/hdresearch/vers-sdk-go v0.1.0-alpha.31 h1:JXEU1lXHzfIpi5Aq5LQjtdSnZDGTqqTZK4TcbAJTfcQ= -github.com/hdresearch/vers-sdk-go v0.1.0-alpha.31/go.mod h1:aJoQGYzJHXdbj7uhCekUZaxbMu+XhVMOCtVQEdA0NFI= github.com/hdresearch/vers-sdk-go v0.1.0-alpha.32 h1:b1+KSJbLQgsC9KEnoQxrbHq/sxtHDM/cB1+XwHMYOBs= github.com/hdresearch/vers-sdk-go v0.1.0-alpha.32/go.mod h1:aJoQGYzJHXdbj7uhCekUZaxbMu+XhVMOCtVQEdA0NFI= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=