From ded05317fce385ba989d47c6bc7822783cc8bdbc Mon Sep 17 00:00:00 2001 From: Matt Wise Date: Mon, 6 Apr 2026 10:35:45 -0700 Subject: [PATCH 1/2] fix(auth): strip Bedrock/Vertex env vars when profile has SSO credentials When CLAUDE_CODE_USE_BEDROCK or CLAUDE_CODE_USE_VERTEX are set in the user's shell environment (e.g. from dotfiles), they leak through to Claude Code even for profiles authenticated via SSO/keychain. This causes Claude Code to use Bedrock routing instead of the Anthropic API. Strip these provider flags from the environment when the profile has keychain or file-based SSO credentials, since the user's intent is clearly to use the Anthropic API for that profile. Co-Authored-By: Claude Opus 4.6 (1M context) --- internal/claude/claude.go | 12 ++++++++++++ internal/claude/claude_test.go | 24 ++++++++++++++++++++++++ internal/cli/passthrough.go | 8 ++++++++ 3 files changed, 44 insertions(+) diff --git a/internal/claude/claude.go b/internal/claude/claude.go index 8d972e5..195810b 100644 --- a/internal/claude/claude.go +++ b/internal/claude/claude.go @@ -55,6 +55,18 @@ func BuildEnv(configDir string) []string { return env } +// UnsetEnv removes a named environment variable from an env slice. If the key +// is not present, the slice is returned unchanged. +func UnsetEnv(env []string, key string) []string { + prefix := key + "=" + for i, e := range env { + if len(e) >= len(prefix) && e[:len(prefix)] == prefix { + return append(env[:i], env[i+1:]...) + } + } + return env +} + // RunDirect executes the claude binary as a child process without a PTY // wrapper, connecting stdin/stdout/stderr directly. It returns the child's exit // code and any non-exit error. This is used by subcommands like "auth login" diff --git a/internal/claude/claude_test.go b/internal/claude/claude_test.go index 8e75bd2..3fdd324 100644 --- a/internal/claude/claude_test.go +++ b/internal/claude/claude_test.go @@ -102,6 +102,30 @@ func TestRunDirect_BinaryNotFound(t *testing.T) { assert.Error(t, err) } +func TestUnsetEnv_RemovesKey(t *testing.T) { + env := []string{"FOO=bar", "CLAUDE_CODE_USE_BEDROCK=1", "BAZ=qux"} + result := UnsetEnv(env, "CLAUDE_CODE_USE_BEDROCK") + assert.Equal(t, []string{"FOO=bar", "BAZ=qux"}, result) +} + +func TestUnsetEnv_KeyNotPresent(t *testing.T) { + env := []string{"FOO=bar", "BAZ=qux"} + result := UnsetEnv(env, "CLAUDE_CODE_USE_BEDROCK") + assert.Equal(t, []string{"FOO=bar", "BAZ=qux"}, result) +} + +func TestUnsetEnv_EmptyEnv(t *testing.T) { + result := UnsetEnv([]string{}, "FOO") + assert.Empty(t, result) +} + +func TestUnsetEnv_DoesNotMatchPrefix(t *testing.T) { + env := []string{"CLAUDE_CODE_USE_BEDROCK_EXTRA=1", "FOO=bar"} + result := UnsetEnv(env, "CLAUDE_CODE_USE_BEDROCK") + // Should not remove CLAUDE_CODE_USE_BEDROCK_EXTRA since it's a different key + assert.Equal(t, []string{"CLAUDE_CODE_USE_BEDROCK_EXTRA=1", "FOO=bar"}, result) +} + func TestBuildEnv_PreservesOtherVars(t *testing.T) { t.Setenv("MY_TEST_VAR_12345", "hello") diff --git a/internal/cli/passthrough.go b/internal/cli/passthrough.go index d7b9e72..8280dff 100644 --- a/internal/cli/passthrough.go +++ b/internal/cli/passthrough.go @@ -56,6 +56,14 @@ func runPassthrough(cmd *cobra.Command, _ []string) error { cfg := p.LoadConfig() env := claude.BuildEnv(p.ConfigDir) + + // When the profile has SSO credentials, strip provider flags that would + // override the auth method. The user's intent is to use the Anthropic API. + if authStatus == "keychain" || authStatus == "file" { + env = claude.UnsetEnv(env, "CLAUDE_CODE_USE_BEDROCK") + env = claude.UnsetEnv(env, "CLAUDE_CODE_USE_VERTEX") + } + env = setEnv(env, "CLAUDE_PROFILE_NAME", name) env = setEnv(env, "CLAUDE_PROFILE_AUTH", authStatus) env = setEnv(env, "CLAUDE_PROFILE_SUB", subType) From 73b6f8c31de11bf66706dbcfb8221acbb4abc777 Mon Sep 17 00:00:00 2001 From: Matt Wise Date: Mon, 6 Apr 2026 10:36:50 -0700 Subject: [PATCH 2/2] fix(version): allow ldflags to set Version at build time The Version variable was initialized via buildVersion(), which ran at program startup and overwrote the value injected by goreleaser's -X ldflags. Move the fallback into an init() that only runs when ldflags did not set Version. Co-Authored-By: Claude Opus 4.6 (1M context) --- internal/cli/passthrough.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/internal/cli/passthrough.go b/internal/cli/passthrough.go index 8280dff..048f45f 100644 --- a/internal/cli/passthrough.go +++ b/internal/cli/passthrough.go @@ -121,7 +121,13 @@ func extractClaudeArgs() []string { // Version is set at build time via -ldflags (e.g., -ldflags "-X ...cli.Version=1.2.3"). // Falls back to VCS info embedded by Go, or "dev" if neither is available. -var Version = buildVersion() +var Version string + +func init() { + if Version == "" { + Version = buildVersion() + } +} func buildVersion() string { info, ok := debug.ReadBuildInfo()