fix(auth): stabilize canonical provider merge precedence
This commit is contained in:
parent
8257f25fdc
commit
449e757b88
2 changed files with 68 additions and 2 deletions
|
|
@ -142,6 +142,7 @@ func normalizeStore(store *AuthStore) {
|
||||||
canonicalFlags := make(map[string]bool, len(store.Credentials))
|
canonicalFlags := make(map[string]bool, len(store.Credentials))
|
||||||
|
|
||||||
for provider, cred := range store.Credentials {
|
for provider, cred := range store.Credentials {
|
||||||
|
normalizedProvider := strings.ToLower(strings.TrimSpace(provider))
|
||||||
canonical := canonicalProvider(provider)
|
canonical := canonicalProvider(provider)
|
||||||
normalizedCred := cloneCredential(cred)
|
normalizedCred := cloneCredential(cred)
|
||||||
if normalizedCred != nil {
|
if normalizedCred != nil {
|
||||||
|
|
@ -153,7 +154,7 @@ func normalizeStore(store *AuthStore) {
|
||||||
|
|
||||||
current := normalized[canonical]
|
current := normalized[canonical]
|
||||||
currentCanonical := canonicalFlags[canonical]
|
currentCanonical := canonicalFlags[canonical]
|
||||||
candidateCanonical := provider == canonical
|
candidateCanonical := normalizedProvider == canonical
|
||||||
|
|
||||||
if shouldPreferCredential(normalizedCred, candidateCanonical, current, currentCanonical) {
|
if shouldPreferCredential(normalizedCred, candidateCanonical, current, currentCanonical) {
|
||||||
normalized[canonical] = mergeCredentials(normalizedCred, current)
|
normalized[canonical] = mergeCredentials(normalizedCred, current)
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,15 @@ import (
|
||||||
"runtime"
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/sipeed/picoclaw/pkg/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
func setTestAuthHome(t *testing.T) string {
|
func setTestAuthHome(t *testing.T) string {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
tmpDir := t.TempDir()
|
tmpDir := t.TempDir()
|
||||||
t.Setenv("PICOCLAW_HOME", filepath.Join(tmpDir, ".picoclaw"))
|
t.Setenv(config.EnvHome, filepath.Join(tmpDir, ".picoclaw"))
|
||||||
return tmpDir
|
return tmpDir
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -297,6 +299,69 @@ func TestLoadStoreMergesAntigravityAliasesPreferringNewerExpiry(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLoadStorePrefersCanonicalKeyWhenExpiryMatchesAlias(t *testing.T) {
|
||||||
|
tmpDir := setTestAuthHome(t)
|
||||||
|
|
||||||
|
expiresAt := time.Date(2026, 4, 16, 12, 0, 0, 0, time.UTC)
|
||||||
|
store := map[string]any{
|
||||||
|
"credentials": map[string]any{
|
||||||
|
"antigravity": map[string]any{
|
||||||
|
"access_token": "legacy-token",
|
||||||
|
"refresh_token": "legacy-refresh",
|
||||||
|
"expires_at": expiresAt.Format(time.RFC3339),
|
||||||
|
"provider": "antigravity",
|
||||||
|
"auth_method": "oauth",
|
||||||
|
"email": "legacy@example.com",
|
||||||
|
},
|
||||||
|
" Google-Antigravity ": map[string]any{
|
||||||
|
"access_token": "fresh-token",
|
||||||
|
"expires_at": expiresAt.Format(time.RFC3339),
|
||||||
|
"provider": " Google-Antigravity ",
|
||||||
|
"auth_method": "oauth",
|
||||||
|
"project_id": "project-2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
data, err := json.Marshal(store)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("json.Marshal() error: %v", err)
|
||||||
|
}
|
||||||
|
path := filepath.Join(tmpDir, ".picoclaw", "auth.json")
|
||||||
|
err = os.MkdirAll(filepath.Dir(path), 0o755)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("MkdirAll() error: %v", err)
|
||||||
|
}
|
||||||
|
err = os.WriteFile(path, data, 0o600)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("WriteFile() error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
loaded, err := LoadStore()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("LoadStore() error: %v", err)
|
||||||
|
}
|
||||||
|
if len(loaded.Credentials) != 1 {
|
||||||
|
t.Fatalf("credential count = %d, want 1", len(loaded.Credentials))
|
||||||
|
}
|
||||||
|
|
||||||
|
cred := loaded.Credentials["google-antigravity"]
|
||||||
|
if cred == nil {
|
||||||
|
t.Fatal("google-antigravity credential missing")
|
||||||
|
}
|
||||||
|
if cred.AccessToken != "fresh-token" {
|
||||||
|
t.Fatalf("AccessToken = %q, want %q", cred.AccessToken, "fresh-token")
|
||||||
|
}
|
||||||
|
if cred.RefreshToken != "legacy-refresh" {
|
||||||
|
t.Fatalf("RefreshToken = %q, want %q", cred.RefreshToken, "legacy-refresh")
|
||||||
|
}
|
||||||
|
if cred.Email != "legacy@example.com" {
|
||||||
|
t.Fatalf("Email = %q, want %q", cred.Email, "legacy@example.com")
|
||||||
|
}
|
||||||
|
if cred.ProjectID != "project-2" {
|
||||||
|
t.Fatalf("ProjectID = %q, want %q", cred.ProjectID, "project-2")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestSetCredentialReplacesLegacyAntigravityEntry(t *testing.T) {
|
func TestSetCredentialReplacesLegacyAntigravityEntry(t *testing.T) {
|
||||||
tmpDir := setTestAuthHome(t)
|
tmpDir := setTestAuthHome(t)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue