File size: 4,996 Bytes
bc575bc | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | import { InMemoryModelsStore } from "@earendil-works/pi-ai";
import { describe, expect, test, vi } from "vitest";
import { parseArgs } from "../src/cli/args.ts";
import { AuthCommandError, isAuthCommandHelp, parseAuthCommand } from "../src/cli/auth-command.ts";
import { resolveCredentialForPrint } from "../src/cli/credential-print.ts";
import { AuthStorage } from "../src/core/auth-storage.ts";
import { ModelRuntime } from "../src/core/model-runtime.ts";
import { main } from "../src/main.ts";
async function createRuntime(credentials: AuthStorage): Promise<ModelRuntime> {
return ModelRuntime.create({
credentials,
modelsPath: null,
modelsStore: new InMemoryModelsStore(),
allowModelNetwork: false,
});
}
describe("credential print commands", () => {
test("prints a resolved API key", async () => {
const runtime = await createRuntime(AuthStorage.inMemory({ openai: { type: "api_key", key: "test-api-key" } }));
const args = parseArgs(["--provider", "openai"]);
await expect(resolveCredentialForPrint(args, runtime, "api_key")).resolves.toBe("test-api-key");
});
test("prints bearer tokens resolved from an Authorization header", async () => {
const runtime = await createRuntime(
AuthStorage.inMemory({
"kimi-coding": {
type: "oauth",
access: "header-test-token",
refresh: "test-refresh-token",
expires: Date.now() + 60 * 60 * 1000,
},
}),
);
const args = parseArgs(["--provider", "kimi-coding"]);
await expect(resolveCredentialForPrint(args, runtime, "bearer_token")).resolves.toBe("header-test-token");
});
test("refreshes an expired OAuth token before printing it", async () => {
const storage = AuthStorage.inMemory({
"openai-codex": {
type: "oauth",
access: "old-test-token",
refresh: "test-refresh-token",
expires: 0,
},
});
const runtime = await createRuntime(storage);
const refresh = vi.fn(async () => ({
type: "oauth" as const,
access: "fresh-test-token",
refresh: "test-refresh-token",
expires: Date.now() + 60 * 60 * 1000,
}));
const oauth = runtime.getProvider("openai-codex")?.auth.oauth;
if (!oauth) throw new Error("OpenAI Codex OAuth provider is not registered");
oauth.refresh = refresh;
const args = parseArgs(["--provider", "openai-codex"]);
await expect(resolveCredentialForPrint(args, runtime, "bearer_token")).resolves.toBe("fresh-test-token");
expect(refresh).toHaveBeenCalledOnce();
expect(await storage.read("openai-codex")).toMatchObject({ access: "fresh-test-token" });
});
test("reports unknown auth options like package commands", async () => {
const originalExitCode = process.exitCode;
const errorSpy = vi.spyOn(console, "error").mockImplementation(() => {});
try {
process.exitCode = undefined;
await main(["auth", "check", "--provider", "openai-codex", "--credentails"]);
const stderr = errorSpy.mock.calls.map(([message]) => String(message)).join("\n");
expect(stderr).toContain('Unknown option --credentails for "auth check".');
expect(stderr).toContain(
'Use "pi --help" or "pi auth check --provider <provider> [--json] [--credentials] [--no-refresh]".',
);
expect(process.exitCode).toBe(1);
} finally {
process.exitCode = originalExitCode;
errorSpy.mockRestore();
}
});
test("parses credential commands and rejects invalid arguments or credential types", async () => {
const runtime = await createRuntime(
AuthStorage.inMemory({
"openai-codex": {
type: "oauth",
access: "test-token-not-to-be-printed",
refresh: "test-refresh-token",
expires: Date.now() + 60 * 60 * 1000,
},
}),
);
expect(parseAuthCommand(["auth", "print-api-key", "--provider", "openai"])).toEqual({
kind: "api_key",
args: ["--provider", "openai"],
json: false,
credentials: false,
noRefresh: false,
});
expect(parseAuthCommand(["auth", "print-bearer-token"])).toMatchObject({ kind: "bearer_token" });
expect(parseAuthCommand(["auth", "print-bearer-token", "--min-expiry", "30m"])).toEqual({
kind: "bearer_token",
args: [],
json: false,
credentials: false,
noRefresh: false,
minExpiryMs: 30 * 60_000,
});
expect(() => parseAuthCommand(["auth", "print-api-key", "--min-expiry", "30m"])).toThrow(
"only supported by print-bearer-token",
);
expect(isAuthCommandHelp(["auth", "--help"])).toBe(true);
expect(isAuthCommandHelp(["auth", "print-api-key", "--help"])).toBe(true);
expect(isAuthCommandHelp(["auth", "print-bearer-token", "-h"])).toBe(true);
expect(isAuthCommandHelp(["auth", "check", "--help"])).toBe(true);
expect(() => parseAuthCommand(["auth", "unknown"])).toThrow(AuthCommandError);
await expect(resolveCredentialForPrint(parseArgs([]), runtime, "api_key")).rejects.toThrow(
"requires --provider <provider> or --model <model>",
);
await expect(
resolveCredentialForPrint(parseArgs(["--provider", "openai-codex"]), runtime, "api_key"),
).rejects.toThrow("configured with OAuth");
});
});
|