






















@@ -13,6 +13,7 @@ import {
1313refreshCodexAppServerAuthTokens,
1414resolveCodexAppServerAuthAccountCacheKey,
1515resolveCodexAppServerAuthProfileId,
16+resolveCodexAppServerFallbackApiKeyCacheKey,
1617resolveCodexAppServerHomeDir,
1718resolveCodexAppServerNativeHomeDir,
1819} from "./auth-bridge.js";
@@ -172,6 +173,17 @@ async function writeCodexCliAuthFile(codexHome: string): Promise<void> {
172173);
173174}
174175176+async function writeCodexCliApiKeyAuthFile(codexHome: string): Promise<void> {
177+await fs.mkdir(codexHome, { recursive: true });
178+await fs.writeFile(
179+path.join(codexHome, "auth.json"),
180+`${JSON.stringify({
181+ auth_mode: "apikey",
182+ OPENAI_API_KEY: "cli-auth-json-api-key",
183+ })}\n`,
184+);
185+}
186+175187describe("bridgeCodexAppServerStartOptions", () => {
176188it("sets agent-owned CODEX_HOME without overriding HOME for local app-server launches", async () => {
177189const agentDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-codex-app-server-"));
@@ -1042,6 +1054,92 @@ describe("bridgeCodexAppServerStartOptions", () => {
10421054}
10431055});
104410561057+it("uses Codex CLI api-key auth.json when no auth profile or env key exists", async () => {
1058+const root = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-codex-app-server-"));
1059+const agentDir = path.join(root, "agent");
1060+const codexHome = path.join(root, "codex-cli");
1061+const request = vi.fn(async (method: string) => {
1062+if (method === "account/read") {
1063+return { account: null, requiresOpenaiAuth: true };
1064+}
1065+return { type: "apiKey" };
1066+});
1067+vi.stubEnv("CODEX_HOME", codexHome);
1068+vi.stubEnv("CODEX_API_KEY", "");
1069+vi.stubEnv("OPENAI_API_KEY", "");
1070+try {
1071+await writeCodexCliApiKeyAuthFile(codexHome);
1072+1073+await applyCodexAppServerAuthProfile({
1074+client: { request } as never,
1075+ agentDir,
1076+startOptions: createStartOptions({
1077+env: { CODEX_HOME: path.join(root, "isolated-codex-home") },
1078+}),
1079+});
1080+1081+expect(request).toHaveBeenNthCalledWith(1, "account/read", { refreshToken: false });
1082+expect(request).toHaveBeenNthCalledWith(2, "account/login/start", {
1083+type: "apiKey",
1084+apiKey: "cli-auth-json-api-key",
1085+});
1086+} finally {
1087+await fs.rm(root, { recursive: true, force: true });
1088+}
1089+});
1090+1091+it("includes Codex CLI api-key auth.json in fallback app-server cache keys", async () => {
1092+const root = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-codex-app-server-"));
1093+const codexHome = path.join(root, "codex-cli");
1094+try {
1095+await writeCodexCliApiKeyAuthFile(codexHome);
1096+1097+const first = resolveCodexAppServerFallbackApiKeyCacheKey({
1098+startOptions: createStartOptions(),
1099+baseEnv: { CODEX_HOME: codexHome },
1100+});
1101+await fs.writeFile(
1102+path.join(codexHome, "auth.json"),
1103+`${JSON.stringify({
1104+ auth_mode: "apikey",
1105+ OPENAI_API_KEY: "second-cli-auth-json-api-key",
1106+ })}\n`,
1107+);
1108+const second = resolveCodexAppServerFallbackApiKeyCacheKey({
1109+startOptions: createStartOptions(),
1110+baseEnv: { CODEX_HOME: codexHome },
1111+});
1112+1113+expect(first).toMatch(/^CODEX_AUTH_JSON:sha256:[a-f0-9]{64}$/);
1114+expect(second).toMatch(/^CODEX_AUTH_JSON:sha256:[a-f0-9]{64}$/);
1115+expect(second).not.toBe(first);
1116+expect(first).not.toContain("cli-auth-json-api-key");
1117+expect(second).not.toContain("second-cli-auth-json-api-key");
1118+} finally {
1119+await fs.rm(root, { recursive: true, force: true });
1120+}
1121+});
1122+1123+it("does not include Codex CLI api-key auth.json in websocket fallback cache keys", async () => {
1124+const root = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-codex-app-server-"));
1125+const codexHome = path.join(root, "codex-cli");
1126+try {
1127+await writeCodexCliApiKeyAuthFile(codexHome);
1128+1129+expect(
1130+resolveCodexAppServerFallbackApiKeyCacheKey({
1131+startOptions: createStartOptions({
1132+transport: "websocket",
1133+url: "ws://127.0.0.1:1455",
1134+}),
1135+baseEnv: { CODEX_HOME: codexHome },
1136+}),
1137+).toBeUndefined();
1138+} finally {
1139+await fs.rm(root, { recursive: true, force: true });
1140+}
1141+});
1142+10451143it("honors clearEnv before env API-key fallback", async () => {
10461144const agentDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-codex-app-server-"));
10471145const request = vi.fn(async (method: string) => {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。