detached 323df7f

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) {
317317 // never shows a "not logged in" banner.
318318 userPickedProvider := args.Provider != ""
319319 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"} {
321325 if other == provName {
322326 continue
323327 }
@@ -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 continue326 continue
323 }327 }
M packages/agent/build_test.go +31 -0
@@ -111,6 +111,37 @@ func TestResolveExplicitFlagStaleDoesNotRepairConfig(t *testing.T) {
111111 }
112112 }
113113
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+
114145 func TestResolveOllamaUsesModelBaseURLBeforeDefault(t *testing.T) {
115146 t.Setenv("ZOT_HOME", t.TempDir())
116147 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)

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 476

↑↓ moveenter openesc close