fix(coding-agent,ai): show env auth source in /login
This commit is contained in:
64
packages/coding-agent/test/auth-selector-status.test.ts
Normal file
64
packages/coding-agent/test/auth-selector-status.test.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import { describe, expect, test } from "vitest";
|
||||
import { getAuthSelectorIndicator } from "../src/modes/interactive/components/auth-selector-status.js";
|
||||
|
||||
describe("getAuthSelectorIndicator", () => {
|
||||
test("shows subscription configured when oauth matches the selector", () => {
|
||||
expect(
|
||||
getAuthSelectorIndicator("oauth", {
|
||||
type: "oauth",
|
||||
access: "access-token",
|
||||
refresh: "refresh-token",
|
||||
expires: Date.now() + 60_000,
|
||||
}),
|
||||
).toEqual({ kind: "configured", label: "subscription configured" });
|
||||
});
|
||||
|
||||
test("shows api key configured in the subscription selector when an api key is stored", () => {
|
||||
expect(
|
||||
getAuthSelectorIndicator("oauth", {
|
||||
type: "api_key",
|
||||
key: "sk-test",
|
||||
}),
|
||||
).toEqual({ kind: "configured-other", label: "api key configured" });
|
||||
});
|
||||
|
||||
test("shows api key configured when api key auth matches the selector", () => {
|
||||
expect(
|
||||
getAuthSelectorIndicator("api_key", {
|
||||
type: "api_key",
|
||||
key: "sk-test",
|
||||
}),
|
||||
).toEqual({ kind: "configured", label: "api key configured" });
|
||||
});
|
||||
|
||||
test("shows subscription configured in the api key selector when oauth is stored", () => {
|
||||
expect(
|
||||
getAuthSelectorIndicator("api_key", {
|
||||
type: "oauth",
|
||||
access: "access-token",
|
||||
refresh: "refresh-token",
|
||||
expires: Date.now() + 60_000,
|
||||
}),
|
||||
).toEqual({ kind: "configured-other", label: "subscription configured" });
|
||||
});
|
||||
|
||||
test("keeps env api key hints in the api key selector", () => {
|
||||
expect(
|
||||
getAuthSelectorIndicator("api_key", undefined, {
|
||||
configured: false,
|
||||
source: "environment",
|
||||
label: "ANTHROPIC_API_KEY",
|
||||
}),
|
||||
).toEqual({ kind: "environment", label: "ANTHROPIC_API_KEY" });
|
||||
});
|
||||
|
||||
test("ignores api key env hints in the subscription selector", () => {
|
||||
expect(
|
||||
getAuthSelectorIndicator("oauth", undefined, {
|
||||
configured: false,
|
||||
source: "environment",
|
||||
label: "ANTHROPIC_API_KEY",
|
||||
}),
|
||||
).toEqual({ kind: "unconfigured" });
|
||||
});
|
||||
});
|
||||
@@ -431,6 +431,26 @@ describe("AuthStorage", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("auth status", () => {
|
||||
test("does not expose stored API keys or OAuth tokens", () => {
|
||||
authStorage = AuthStorage.inMemory({
|
||||
anthropic: { type: "api_key", key: "secret-api-key" },
|
||||
openai: {
|
||||
type: "oauth",
|
||||
access: "secret-access-token",
|
||||
refresh: "secret-refresh-token",
|
||||
expires: Date.now() + 1000,
|
||||
},
|
||||
});
|
||||
|
||||
expect(authStorage.getAuthStatus("anthropic")).toEqual({ configured: true, source: "stored" });
|
||||
expect(authStorage.getAuthStatus("openai")).toEqual({ configured: true, source: "stored" });
|
||||
expect(JSON.stringify(authStorage.getAuthStatus("anthropic"))).not.toContain("secret-api-key");
|
||||
expect(JSON.stringify(authStorage.getAuthStatus("openai"))).not.toContain("secret-access-token");
|
||||
expect(JSON.stringify(authStorage.getAuthStatus("openai"))).not.toContain("secret-refresh-token");
|
||||
});
|
||||
});
|
||||
|
||||
describe("runtime overrides", () => {
|
||||
test("runtime override takes priority over auth.json", async () => {
|
||||
writeAuthJson({
|
||||
|
||||
59
packages/coding-agent/test/oauth-selector.test.ts
Normal file
59
packages/coding-agent/test/oauth-selector.test.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import { setKeybindings } from "@mariozechner/pi-tui";
|
||||
import stripAnsi from "strip-ansi";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||
import { AuthStorage } from "../src/core/auth-storage.js";
|
||||
import { KeybindingsManager } from "../src/core/keybindings.js";
|
||||
import { OAuthSelectorComponent } from "../src/modes/interactive/components/oauth-selector.js";
|
||||
import { getApiKeyProviderDisplayName, isApiKeyLoginProvider } from "../src/modes/interactive/interactive-mode.js";
|
||||
import { initTheme } from "../src/modes/interactive/theme/theme.js";
|
||||
|
||||
const originalOpenAiApiKey = process.env.OPENAI_API_KEY;
|
||||
|
||||
describe("OAuthSelectorComponent", () => {
|
||||
beforeAll(() => {
|
||||
initTheme("dark");
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
setKeybindings(new KeybindingsManager());
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
if (originalOpenAiApiKey === undefined) {
|
||||
delete process.env.OPENAI_API_KEY;
|
||||
} else {
|
||||
process.env.OPENAI_API_KEY = originalOpenAiApiKey;
|
||||
}
|
||||
});
|
||||
|
||||
it("keeps built-in API key providers separate from OAuth-only providers", () => {
|
||||
const oauthProviderIds = new Set(["anthropic", "github-copilot", "custom-oauth"]);
|
||||
const builtInProviderIds = new Set(["anthropic", "github-copilot", "amazon-bedrock", "openai"]);
|
||||
|
||||
expect(isApiKeyLoginProvider("anthropic", oauthProviderIds, builtInProviderIds)).toBe(true);
|
||||
expect(getApiKeyProviderDisplayName("anthropic")).toBe("Anthropic");
|
||||
expect(isApiKeyLoginProvider("openai", oauthProviderIds, builtInProviderIds)).toBe(true);
|
||||
expect(isApiKeyLoginProvider("github-copilot", oauthProviderIds, builtInProviderIds)).toBe(false);
|
||||
expect(isApiKeyLoginProvider("amazon-bedrock", oauthProviderIds, builtInProviderIds)).toBe(false);
|
||||
expect(isApiKeyLoginProvider("custom-oauth", oauthProviderIds, builtInProviderIds)).toBe(false);
|
||||
expect(isApiKeyLoginProvider("custom-api", oauthProviderIds, builtInProviderIds)).toBe(true);
|
||||
});
|
||||
|
||||
it("shows environment API key auth while keeping provider unconfigured", () => {
|
||||
process.env.OPENAI_API_KEY = "test-openai-key";
|
||||
const authStorage = AuthStorage.inMemory();
|
||||
const selector = new OAuthSelectorComponent(
|
||||
"login",
|
||||
authStorage,
|
||||
[{ id: "openai", name: "OpenAI", authType: "api_key" }],
|
||||
() => {},
|
||||
() => {},
|
||||
);
|
||||
|
||||
const output = stripAnsi(selector.render(120).join("\n"));
|
||||
|
||||
expect(output).toContain("OpenAI");
|
||||
expect(output).toContain("unconfigured");
|
||||
expect(output).toContain("env: OPENAI_API_KEY");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user