Spracherkennung für: .ts vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { upsertAuthProfile } from "openclaw/plugin-sdk/provider-auth";
import { afterEach, describe, expect, it, vi } from "vitest";
import {
applyCodexAppServerAuthProfile,
bridgeCodexAppServerStartOptions,
refreshCodexAppServerAuthTokens,
} from "./auth-bridge.js";
const oauthMocks = vi.hoisted(() => ({
refreshOpenAICodexToken: vi.fn(),
}));
const providerRuntimeMocks = vi.hoisted(() => ({
formatProviderAuthProfileApiKeyWithPlugin: vi.fn(),
refreshProviderOAuthCredentialWithPlugin: vi.fn(
async (params: { context: { refresh: string } }) => {
const refreshed = await oauthMocks.refreshOpenAICodexToken(params.context.refresh);
return refreshed
? {
...params.context,
...refreshed,
type: "oauth",
provider: "openai-codex",
}
: undefined;
},
),
}));
vi.mock("@mariozechner/pi-ai/oauth", () => ({
getOAuthApiKey: vi.fn(),
getOAuthProviders: () => [],
loginOpenAICodex: vi.fn(),
refreshOpenAICodexToken: oauthMocks.refreshOpenAICodexToken,
}));
vi.mock("../../../../src/plugins/provider-runtime.runtime.js", () => ({
formatProviderAuthProfileApiKeyWithPlugin:
providerRuntimeMocks.formatProviderAuthProfileApiKeyWithPlugin,
refreshProviderOAuthCredentialWithPlugin:
providerRuntimeMocks.refreshProviderOAuthCredentialWithPlugin,
}));
afterEach(() => {
vi.unstubAllEnvs();
oauthMocks.refreshOpenAICodexToken.mockReset();
providerRuntimeMocks.formatProviderAuthProfileApiKeyWithPlugin.mockReset();
providerRuntimeMocks.refreshProviderOAuthCredentialWithPlugin.mockClear();
});
describe("bridgeCodexAppServerStartOptions", () => {
it("leaves Codex app-server start options unchanged", async () => {
const agentDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-codex-app-server-"));
const startOptions = {
transport: "stdio" as const,
command: "codex",
args: ["app-server"],
headers: { authorization: "Bearer dev-token" },
env: { CODEX_HOME: "/tmp/source-codex-home", EXISTING: "1" },
clearEnv: ["FOO"],
};
try {
await expect(
bridgeCodexAppServerStartOptions({
startOptions,
agentDir,
authProfileId: "openai-codex:default",
}),
).resolves.toBe(startOptions);
await expect(fs.access(path.join(agentDir, "harness-auth"))).rejects.toMatchObject({
code: "ENOENT",
});
} finally {
await fs.rm(agentDir, { recursive: true, force: true });
}
});
it("applies an OpenAI Codex OAuth profile through app-server login", async () => {
const agentDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-codex-app-server-"));
const request = vi.fn(async () => ({ type: "chatgptAuthTokens" }));
try {
upsertAuthProfile({
agentDir,
profileId: "openai-codex:work",
credential: {
type: "oauth",
provider: "openai-codex",
access: "access-token",
refresh: "refresh-token",
expires: Date.now() + 24 * 60 * 60_000,
accountId: "account-123",
email: "codex@example.test",
},
});
await applyCodexAppServerAuthProfile({
client: { request } as never,
agentDir,
authProfileId: "openai-codex:work",
});
expect(request).toHaveBeenCalledWith("account/login/start", {
type: "chatgptAuthTokens",
accessToken: "access-token",
chatgptAccountId: "account-123",
chatgptPlanType: null,
});
} finally {
await fs.rm(agentDir, { recursive: true, force: true });
}
});
it("refreshes an expired OpenAI Codex OAuth profile before app-server login", async () => {
const agentDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-codex-app-server-"));
const request = vi.fn(async () => ({ type: "chatgptAuthTokens" }));
oauthMocks.refreshOpenAICodexToken.mockResolvedValueOnce({
access: "fresh-access-token",
refresh: "fresh-refresh-token",
expires: Date.now() + 60_000,
accountId: "account-456",
});
try {
upsertAuthProfile({
agentDir,
profileId: "openai-codex:work",
credential: {
type: "oauth",
provider: "openai-codex",
access: "expired-access-token",
refresh: "refresh-token",
expires: Date.now() - 60_000,
accountId: "account-123",
email: "codex@example.test",
},
});
await applyCodexAppServerAuthProfile({
client: { request } as never,
agentDir,
authProfileId: "openai-codex:work",
});
expect(oauthMocks.refreshOpenAICodexToken).toHaveBeenCalledWith("refresh-token");
expect(request).toHaveBeenCalledWith("account/login/start", {
type: "chatgptAuthTokens",
accessToken: "fresh-access-token",
chatgptAccountId: "account-456",
chatgptPlanType: null,
});
} finally {
await fs.rm(agentDir, { recursive: true, force: true });
}
});
it("applies an OpenAI Codex api-key profile backed by a secret ref", async () => {
const agentDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-codex-app-server-"));
const request = vi.fn(async () => ({ type: "apiKey" }));
vi.stubEnv("OPENAI_CODEX_API_KEY", "ref-backed-api-key");
try {
upsertAuthProfile({
agentDir,
profileId: "openai-codex:work",
credential: {
type: "api_key",
provider: "openai-codex",
keyRef: { source: "env", provider: "default", id: "OPENAI_CODEX_API_KEY" },
},
});
await applyCodexAppServerAuthProfile({
client: { request } as never,
agentDir,
authProfileId: "openai-codex:work",
});
expect(request).toHaveBeenCalledWith("account/login/start", {
type: "apiKey",
apiKey: "ref-backed-api-key",
});
} finally {
await fs.rm(agentDir, { recursive: true, force: true });
}
});
it("applies an OpenAI Codex token profile backed by a secret ref", async () => {
const agentDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-codex-app-server-"));
const request = vi.fn(async () => ({ type: "chatgptAuthTokens" }));
vi.stubEnv("OPENAI_CODEX_TOKEN", "ref-backed-access-token");
try {
upsertAuthProfile({
agentDir,
profileId: "openai-codex:work",
credential: {
type: "token",
provider: "openai-codex",
tokenRef: { source: "env", provider: "default", id: "OPENAI_CODEX_TOKEN" },
email: "codex@example.test",
},
});
await applyCodexAppServerAuthProfile({
client: { request } as never,
agentDir,
authProfileId: "openai-codex:work",
});
expect(request).toHaveBeenCalledWith("account/login/start", {
type: "chatgptAuthTokens",
accessToken: "ref-backed-access-token",
chatgptAccountId: "codex@example.test",
chatgptPlanType: null,
});
} finally {
await fs.rm(agentDir, { recursive: true, force: true });
}
});
it("accepts a legacy Codex auth-provider alias for app-server login", async () => {
const agentDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-codex-app-server-"));
const request = vi.fn(async () => ({ type: "chatgptAuthTokens" }));
try {
upsertAuthProfile({
agentDir,
profileId: "openai-codex:work",
credential: {
type: "token",
provider: "codex-cli",
token: "legacy-access-token",
email: "legacy-codex@example.test",
},
});
await applyCodexAppServerAuthProfile({
client: { request } as never,
agentDir,
authProfileId: "openai-codex:work",
});
expect(request).toHaveBeenCalledWith("account/login/start", {
type: "chatgptAuthTokens",
accessToken: "legacy-access-token",
chatgptAccountId: "legacy-codex@example.test",
chatgptPlanType: null,
});
} finally {
await fs.rm(agentDir, { recursive: true, force: true });
}
});
it("answers app-server ChatGPT token refresh requests from the bound profile", async () => {
const agentDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-codex-app-server-"));
oauthMocks.refreshOpenAICodexToken.mockResolvedValueOnce({
access: "refreshed-access-token",
refresh: "refreshed-refresh-token",
expires: Date.now() + 60_000,
accountId: "account-789",
});
try {
upsertAuthProfile({
agentDir,
profileId: "openai-codex:work",
credential: {
type: "oauth",
provider: "openai-codex",
access: "stale-access-token",
refresh: "refresh-token",
expires: Date.now() + 60_000,
accountId: "account-123",
email: "codex@example.test",
},
});
await expect(
refreshCodexAppServerAuthTokens({
agentDir,
authProfileId: "openai-codex:work",
}),
).resolves.toEqual({
accessToken: "refreshed-access-token",
chatgptAccountId: "account-789",
chatgptPlanType: null,
});
expect(oauthMocks.refreshOpenAICodexToken).toHaveBeenCalledWith("refresh-token");
} finally {
await fs.rm(agentDir, { recursive: true, force: true });
}
});
it("accepts a refreshed Codex OAuth credential when the stored provider is a legacy alias", async () => {
const agentDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-codex-app-server-"));
oauthMocks.refreshOpenAICodexToken.mockResolvedValueOnce({
access: "refreshed-alias-access-token",
refresh: "refreshed-alias-refresh-token",
expires: Date.now() + 60_000,
accountId: "account-alias",
});
try {
upsertAuthProfile({
agentDir,
profileId: "openai-codex:work",
credential: {
type: "oauth",
provider: "codex-cli",
access: "stale-alias-access-token",
refresh: "alias-refresh-token",
expires: Date.now() + 60_000,
accountId: "account-legacy",
email: "legacy-codex@example.test",
},
});
await expect(
refreshCodexAppServerAuthTokens({
agentDir,
authProfileId: "openai-codex:work",
}),
).resolves.toEqual({
accessToken: "refreshed-alias-access-token",
chatgptAccountId: "account-alias",
chatgptPlanType: null,
});
expect(oauthMocks.refreshOpenAICodexToken).toHaveBeenCalledWith("alias-refresh-token");
} finally {
await fs.rm(agentDir, { recursive: true, force: true });
}
});
it("preserves a stored ChatGPT plan type when building token login params", async () => {
const agentDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-codex-app-server-"));
const request = vi.fn(async () => ({ type: "chatgptAuthTokens" }));
try {
upsertAuthProfile({
agentDir,
profileId: "openai-codex:work",
credential: {
type: "oauth",
provider: "openai-codex",
access: "access-token",
refresh: "refresh-token",
expires: Date.now() + 24 * 60 * 60_000,
accountId: "account-123",
email: "codex@example.test",
chatgptPlanType: "pro",
} as never,
});
await applyCodexAppServerAuthProfile({
client: { request } as never,
agentDir,
authProfileId: "openai-codex:work",
});
expect(request).toHaveBeenCalledWith("account/login/start", {
type: "chatgptAuthTokens",
accessToken: "access-token",
chatgptAccountId: "account-123",
chatgptPlanType: "pro",
});
} finally {
await fs.rm(agentDir, { recursive: true, force: true });
}
});
});
¤ Dauer der Verarbeitung: 0.19 Sekunden
(vorverarbeitet am 2026-04-27)
¤
*© Formatika GbR, Deutschland
|
|