Discover env-only bedrock in credential fallback scan
- commit
- 323df7f6d3c462a452754afabea4a14184e8d483
- author
- patriceckhart · · 2026-06-08 13:17 UTC
- parent
- a7ef8c2
- signature
- unsigned
- refs
- tag: v0.2.17
2 files · +36 -1
M packages/agent/build.go +5 -1
| @@ -317,7 +317,11 @@ func Resolve(args Args, requireCred bool) (Resolved, error) { | |||
| 317 | 317 | // never shows a "not logged in" banner. | |
| 318 | 318 | userPickedProvider := args.Provider != "" | |
| 319 | 319 | if credErr != nil && !userPickedProvider && provName != "ollama" { | |
| 320 | - | for _, other := range []string{"anthropic", "openai", "openai-codex", "kimi", "deepseek", "google"} { | |
| 320 | + | // amazon-bedrock is included so an env-only bedrock setup | |
| 321 | + | // (AWS_BEARER_TOKEN_BEDROCK / AWS_PROFILE / IAM keys) is still | |
| 322 | + | // discovered when no config.json pins the provider, e.g. after | |
| 323 | + | // pointing ZOT_HOME at a fresh home dir. | |
| 324 | + | for _, other := range []string{"anthropic", "openai", "openai-codex", "kimi", "deepseek", "google", "amazon-bedrock"} { | |
| 321 | 325 | if other == provName { | |
| 322 | 326 | continue | |
| 323 | 327 | } | |
| @@ -317,7 +317,11 @@ func Resolve(args Args, requireCred bool) (Resolved, error) { | |||||
| 317 | // never shows a "not logged in" banner. | 317 | // never shows a "not logged in" banner. | ||
| 318 | userPickedProvider := args.Provider != "" | 318 | userPickedProvider := args.Provider != "" | ||
| 319 | if credErr != nil && !userPickedProvider && provName != "ollama" { | 319 | if credErr != nil && !userPickedProvider && provName != "ollama" { | ||
| 320 | - | for _, other := range []string{"anthropic", "openai", "openai-codex", "kimi", "deepseek", "google"} { | 320 | + | // amazon-bedrock is included so an env-only bedrock setup |
| 321 | + | // (AWS_BEARER_TOKEN_BEDROCK / AWS_PROFILE / IAM keys) is still | |||
| 322 | + | // discovered when no config.json pins the provider, e.g. after | |||
| 323 | + | // pointing ZOT_HOME at a fresh home dir. | |||
| 324 | + | for _, other := range []string{"anthropic", "openai", "openai-codex", "kimi", "deepseek", "google", "amazon-bedrock"} { | |||
| 321 | if other == provName { | 325 | if other == provName { | ||
| 322 | continue | 326 | continue | ||
| 323 | } | 327 | } | ||
M packages/agent/build_test.go +31 -0
| @@ -111,6 +111,37 @@ func TestResolveExplicitFlagStaleDoesNotRepairConfig(t *testing.T) { | |||
| 111 | 111 | } | |
| 112 | 112 | } | |
| 113 | 113 | ||
| 114 | + | // TestResolveEnvOnlyBedrockDiscoveredWithoutConfig reproduces issue | |
| 115 | + | // #15: pointing ZOT_HOME at a fresh dir drops the persisted | |
| 116 | + | // config.json (which pinned provider=amazon-bedrock). Resolve must | |
| 117 | + | // still discover bedrock from the AWS env vars instead of falling back | |
| 118 | + | // to anthropic and reporting "not logged in". | |
| 119 | + | func TestResolveEnvOnlyBedrockDiscoveredWithoutConfig(t *testing.T) { | |
| 120 | + | t.Setenv("ZOT_HOME", t.TempDir()) // fresh home: no config.json | |
| 121 | + | // Disable the Kimi CLI token fallback so a developer machine with a | |
| 122 | + | // real Kimi CLI login doesn't pre-empt bedrock in the scan. | |
| 123 | + | if err := SetKimiCLIFallbackDisabled(true); err != nil { | |
| 124 | + | t.Fatal(err) | |
| 125 | + | } | |
| 126 | + | t.Setenv("AWS_BEARER_TOKEN_BEDROCK", "test-bedrock-token") | |
| 127 | + | t.Setenv("AWS_REGION", "us-east-1") | |
| 128 | + | // Make sure no other provider's env credential pre-empts bedrock. | |
| 129 | + | for _, k := range []string{"ANTHROPIC_API_KEY", "ANTHROPIC_OAUTH_TOKEN", "OPENAI_API_KEY", "GEMINI_API_KEY", "GOOGLE_API_KEY", "DEEPSEEK_API_KEY", "KIMI_API_KEY", "MOONSHOT_API_KEY"} { | |
| 130 | + | t.Setenv(k, "") | |
| 131 | + | } | |
| 132 | + | ||
| 133 | + | r, err := Resolve(Args{}, true) | |
| 134 | + | if err != nil { | |
| 135 | + | t.Fatalf("Resolve errored with env-only bedrock: %v", err) | |
| 136 | + | } | |
| 137 | + | if r.Provider != "amazon-bedrock" { | |
| 138 | + | t.Fatalf("provider = %q, want amazon-bedrock", r.Provider) | |
| 139 | + | } | |
| 140 | + | if !r.HasCredential() { | |
| 141 | + | t.Fatalf("bedrock credential not resolved from env") | |
| 142 | + | } | |
| 143 | + | } | |
| 144 | + | ||
| 114 | 145 | func TestResolveOllamaUsesModelBaseURLBeforeDefault(t *testing.T) { | |
| 115 | 146 | t.Setenv("ZOT_HOME", t.TempDir()) | |
| 116 | 147 | provider.SetLiveModels(nil) | |
| @@ -111,6 +111,37 @@ func TestResolveExplicitFlagStaleDoesNotRepairConfig(t *testing.T) { | |||||
| 111 | } | 111 | } | ||
| 112 | } | 112 | } | ||
| 113 | 113 | ||||
| 114 | + | // TestResolveEnvOnlyBedrockDiscoveredWithoutConfig reproduces issue | |||
| 115 | + | // #15: pointing ZOT_HOME at a fresh dir drops the persisted | |||
| 116 | + | // config.json (which pinned provider=amazon-bedrock). Resolve must | |||
| 117 | + | // still discover bedrock from the AWS env vars instead of falling back | |||
| 118 | + | // to anthropic and reporting "not logged in". | |||
| 119 | + | func TestResolveEnvOnlyBedrockDiscoveredWithoutConfig(t *testing.T) { | |||
| 120 | + | t.Setenv("ZOT_HOME", t.TempDir()) // fresh home: no config.json | |||
| 121 | + | // Disable the Kimi CLI token fallback so a developer machine with a | |||
| 122 | + | // real Kimi CLI login doesn't pre-empt bedrock in the scan. | |||
| 123 | + | if err := SetKimiCLIFallbackDisabled(true); err != nil { | |||
| 124 | + | t.Fatal(err) | |||
| 125 | + | } | |||
| 126 | + | t.Setenv("AWS_BEARER_TOKEN_BEDROCK", "test-bedrock-token") | |||
| 127 | + | t.Setenv("AWS_REGION", "us-east-1") | |||
| 128 | + | // Make sure no other provider's env credential pre-empts bedrock. | |||
| 129 | + | for _, k := range []string{"ANTHROPIC_API_KEY", "ANTHROPIC_OAUTH_TOKEN", "OPENAI_API_KEY", "GEMINI_API_KEY", "GOOGLE_API_KEY", "DEEPSEEK_API_KEY", "KIMI_API_KEY", "MOONSHOT_API_KEY"} { | |||
| 130 | + | t.Setenv(k, "") | |||
| 131 | + | } | |||
| 132 | + | ||||
| 133 | + | r, err := Resolve(Args{}, true) | |||
| 134 | + | if err != nil { | |||
| 135 | + | t.Fatalf("Resolve errored with env-only bedrock: %v", err) | |||
| 136 | + | } | |||
| 137 | + | if r.Provider != "amazon-bedrock" { | |||
| 138 | + | t.Fatalf("provider = %q, want amazon-bedrock", r.Provider) | |||
| 139 | + | } | |||
| 140 | + | if !r.HasCredential() { | |||
| 141 | + | t.Fatalf("bedrock credential not resolved from env") | |||
| 142 | + | } | |||
| 143 | + | } | |||
| 144 | + | ||||
| 114 | func TestResolveOllamaUsesModelBaseURLBeforeDefault(t *testing.T) { | 145 | func TestResolveOllamaUsesModelBaseURLBeforeDefault(t *testing.T) { | ||
| 115 | t.Setenv("ZOT_HOME", t.TempDir()) | 146 | t.Setenv("ZOT_HOME", t.TempDir()) | ||
| 116 | provider.SetLiveModels(nil) | 147 | provider.SetLiveModels(nil) | ||