Files
zero/internal/cli/exec_provider_hint_test.go
PierrunoYTandClaude Sonnet 5 2a062aa401 fix(auth): persist OpenRouter API key after login (#595)
* fix(auth): persist OpenRouter API key after login

zero auth openrouter minted a key but only printed it, leaving the
provider unusable unless the user manually exported it or edited
config by hand. Now the key is saved into the credential store, the
provider profile is created/activated, and stale inline/env key
fields are cleared. Auth-failure hints also now point at zero setup
and zero auth openrouter instead of the vaguer zero auth.

Co-Authored-By: Claude Sonnet 5 <[email protected]>

* fix(auth): sanitize minted key and roll back orphaned credential on save failure

Addresses PR review comments: trim the OpenRouter key right after
login so both the save path and the manual fallback instructions use
the sanitized value, and delete the just-written credential-store
entry if persisting the stored-key marker in config.json fails, so a
partial failure doesn't leave an orphaned secret.

Co-Authored-By: Claude Sonnet 5 <[email protected]>

---------

Co-authored-by: Claude Sonnet 5 <[email protected]>
2026-07-08 23:04:57 +08:00

51 lines
1.8 KiB
Go

package cli
import (
"bytes"
"strings"
"testing"
)
// A recognized provider error in text mode prints the raw message plus a one-line
// actionable hint; a non-provider error (or JSON mode) prints no hint.
func TestWriteExecProviderErrorAppendsHint(t *testing.T) {
t.Run("provider auth error gets a hint", func(t *testing.T) {
var stdout, stderr bytes.Buffer
code := writeExecProviderError(&stdout, &stderr, execOutputText, "provider_error",
"auth error: your API key is missing or invalid")
if code != exitProvider {
t.Fatalf("exit code = %d, want exitProvider", code)
}
out := stderr.String()
if !strings.Contains(out, "auth error:") {
t.Fatalf("expected raw message, got %q", out)
}
if !strings.Contains(out, "zero setup") || !strings.Contains(out, "zero auth openrouter") {
t.Fatalf("expected an actionable setup/auth hint, got %q", out)
}
})
t.Run("non-provider error gets no hint", func(t *testing.T) {
var stdout, stderr bytes.Buffer
writeExecProviderError(&stdout, &stderr, execOutputText, "sandbox_error",
"sandbox setup failed: permission denied")
out := stderr.String()
// Exactly one "[zero]" line — no spurious hint attached to a local error.
if n := strings.Count(out, "[zero]"); n != 1 {
t.Fatalf("expected exactly one [zero] line for a non-provider error, got %d:\n%s", n, out)
}
})
t.Run("json mode never appends a hint line", func(t *testing.T) {
var stdout, stderr bytes.Buffer
writeExecProviderError(&stdout, &stderr, execOutputJSON, "provider_error",
"auth error: bad key")
if stderr.Len() != 0 {
t.Fatalf("json mode must not write to stderr, got %q", stderr.String())
}
if strings.Contains(stdout.String(), "zero setup") {
t.Fatalf("json mode must not inject a hint into the structured payload, got %q", stdout.String())
}
})
}