mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 07:20:43 +00:00
146 lines
4.3 KiB
TypeScript
146 lines
4.3 KiB
TypeScript
import crypto from "node:crypto";
|
|
import fs from "node:fs/promises";
|
|
import os from "node:os";
|
|
import path from "node:path";
|
|
import { saveAuthProfileStore } from "openclaw/plugin-sdk/agent-runtime";
|
|
import { afterEach, describe, expect, it } from "vitest";
|
|
import { prepareOpenAICodexCliExecution } from "./openai-codex-cli-bridge.js";
|
|
|
|
describe("prepareOpenAICodexCliExecution", () => {
|
|
const tempDirs: string[] = [];
|
|
const resolveHashedCodexHome = (agentDir: string, profileId: string) =>
|
|
path.join(
|
|
agentDir,
|
|
"cli-auth",
|
|
"codex",
|
|
crypto.createHash("sha256").update(profileId).digest("hex").slice(0, 16),
|
|
);
|
|
|
|
afterEach(async () => {
|
|
await Promise.all(
|
|
tempDirs.splice(0).map((dir) => fs.rm(dir, { recursive: true, force: true })),
|
|
);
|
|
});
|
|
|
|
it("writes a private CODEX_HOME bridge from canonical OpenClaw oauth", async () => {
|
|
const agentDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-codex-cli-bridge-"));
|
|
tempDirs.push(agentDir);
|
|
saveAuthProfileStore(
|
|
{
|
|
version: 1,
|
|
profiles: {
|
|
"openai-codex:default": {
|
|
type: "oauth",
|
|
provider: "openai-codex",
|
|
access: "access-token",
|
|
refresh: "refresh-token",
|
|
expires: Date.now() + 60_000,
|
|
accountId: "acct-123",
|
|
idToken: "id-token",
|
|
},
|
|
},
|
|
},
|
|
agentDir,
|
|
{ filterExternalAuthProfiles: false },
|
|
);
|
|
|
|
const result = await prepareOpenAICodexCliExecution({
|
|
config: undefined,
|
|
workspaceDir: agentDir,
|
|
agentDir,
|
|
provider: "codex-cli",
|
|
modelId: "gpt-5.4",
|
|
authProfileId: "openai-codex:default",
|
|
});
|
|
|
|
expect(result).toMatchObject({
|
|
env: {
|
|
CODEX_HOME: expect.stringContaining(path.join(agentDir, "cli-auth", "codex")),
|
|
},
|
|
clearEnv: ["OPENAI_API_KEY"],
|
|
});
|
|
|
|
const authFile = JSON.parse(
|
|
await fs.readFile(path.join(result?.env?.CODEX_HOME ?? "", "auth.json"), "utf8"),
|
|
);
|
|
expect(authFile).toEqual({
|
|
auth_mode: "chatgpt",
|
|
tokens: {
|
|
id_token: "id-token",
|
|
access_token: "access-token",
|
|
refresh_token: "refresh-token",
|
|
account_id: "acct-123",
|
|
},
|
|
});
|
|
if (process.platform !== "win32") {
|
|
const authStat = await fs.stat(path.join(result?.env?.CODEX_HOME ?? "", "auth.json"));
|
|
expect(authStat.mode & 0o777).toBe(0o600);
|
|
}
|
|
});
|
|
|
|
it("returns null when there is no bridgeable canonical oauth credential", async () => {
|
|
const agentDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-codex-cli-bridge-"));
|
|
tempDirs.push(agentDir);
|
|
saveAuthProfileStore(
|
|
{
|
|
version: 1,
|
|
profiles: {
|
|
"openai-codex:default": {
|
|
type: "api_key",
|
|
provider: "openai-codex",
|
|
key: "sk-test",
|
|
},
|
|
},
|
|
},
|
|
agentDir,
|
|
{ filterExternalAuthProfiles: false },
|
|
);
|
|
|
|
await expect(
|
|
prepareOpenAICodexCliExecution({
|
|
config: undefined,
|
|
workspaceDir: agentDir,
|
|
agentDir,
|
|
provider: "codex-cli",
|
|
modelId: "gpt-5.4",
|
|
authProfileId: "openai-codex:default",
|
|
}),
|
|
).resolves.toBeNull();
|
|
});
|
|
|
|
it("refuses to overwrite a symlinked codex cli auth bridge file", async () => {
|
|
const agentDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-codex-cli-bridge-"));
|
|
tempDirs.push(agentDir);
|
|
const codexHome = resolveHashedCodexHome(agentDir, "openai-codex:default");
|
|
await fs.mkdir(codexHome, { recursive: true });
|
|
await fs.symlink(path.join(agentDir, "outside.txt"), path.join(codexHome, "auth.json"));
|
|
saveAuthProfileStore(
|
|
{
|
|
version: 1,
|
|
profiles: {
|
|
"openai-codex:default": {
|
|
type: "oauth",
|
|
provider: "openai-codex",
|
|
access: "access-token",
|
|
refresh: "refresh-token",
|
|
expires: Date.now() + 60_000,
|
|
},
|
|
},
|
|
},
|
|
agentDir,
|
|
{ filterExternalAuthProfiles: false },
|
|
);
|
|
|
|
await expect(
|
|
prepareOpenAICodexCliExecution({
|
|
config: undefined,
|
|
workspaceDir: agentDir,
|
|
agentDir,
|
|
provider: "codex-cli",
|
|
modelId: "gpt-5.4",
|
|
authProfileId: "openai-codex:default",
|
|
}),
|
|
).rejects.toThrow("must not be a symlink");
|
|
});
|
|
});
|