mirror of
https://github.com/Twigpine/zero.git
synced 2026-11-10 05:01:28 -10:00
* 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]>
51 lines
1.8 KiB
Go
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())
|
|
}
|
|
})
|
|
}
|