feat: ship enterprise control and desktop governance
This commit is contained in:
123
tests/codex-desktop-integration-probe.test.mjs
Normal file
123
tests/codex-desktop-integration-probe.test.mjs
Normal file
@@ -0,0 +1,123 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import fs from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { spawn } from "node:child_process";
|
||||
|
||||
import { detectCodexDesktopIntegration } from "../scripts/codex-desktop-integration-probe.mjs";
|
||||
|
||||
const repoRoot = path.resolve(import.meta.dirname, "..");
|
||||
|
||||
async function makeFakeCodexApp() {
|
||||
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "boss-codex-app-"));
|
||||
const appPath = path.join(tempDir, "Codex.app");
|
||||
const contentsDir = path.join(appPath, "Contents");
|
||||
const resourcesDir = path.join(contentsDir, "Resources");
|
||||
await fs.mkdir(resourcesDir, { recursive: true });
|
||||
await fs.writeFile(
|
||||
path.join(contentsDir, "Info.plist"),
|
||||
`<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.openai.codex</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>26.429.30905</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>2345</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>Codex</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>codex</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
`,
|
||||
"utf8",
|
||||
);
|
||||
await fs.writeFile(
|
||||
path.join(resourcesDir, "app.asar"),
|
||||
"function copyThreadLink(id){return `codex://threads/${id}`} // no plugin host export",
|
||||
"utf8",
|
||||
);
|
||||
return { tempDir, appPath };
|
||||
}
|
||||
|
||||
test("detectCodexDesktopIntegration reports stable deeplink and bridge capabilities without patching app", async () => {
|
||||
const { tempDir, appPath } = await makeFakeCodexApp();
|
||||
try {
|
||||
const result = await detectCodexDesktopIntegration({
|
||||
appPath,
|
||||
bridgeEventsUrl: "http://127.0.0.1:4318/api/v1/codex-desktop/events",
|
||||
});
|
||||
|
||||
assert.equal(result.ok, true);
|
||||
assert.equal(result.app.bundleIdentifier, "com.openai.codex");
|
||||
assert.equal(result.app.shortVersion, "26.429.30905");
|
||||
assert.deepEqual(result.app.urlSchemes, ["codex"]);
|
||||
assert.deepEqual(result.capabilities.threadDeepLink, {
|
||||
supported: true,
|
||||
template: "codex://threads/{threadId}",
|
||||
evidence: "CFBundleURLSchemes contains codex and app resources contain codex://threads/",
|
||||
});
|
||||
assert.equal(result.capabilities.desktopBridgeSse.supported, true);
|
||||
assert.equal(result.capabilities.desktopBridgeSse.url, "http://127.0.0.1:4318/api/v1/codex-desktop/events");
|
||||
assert.equal(result.capabilities.inAppSubscription.supported, false);
|
||||
assert.equal(result.capabilities.packagePatch.supported, false);
|
||||
} finally {
|
||||
await fs.rm(tempDir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test("codex desktop refresh bridge daemon exposes capabilities from the integration probe", async () => {
|
||||
const { tempDir, appPath } = await makeFakeCodexApp();
|
||||
const child = spawn(process.execPath, [path.join(repoRoot, "scripts/codex-desktop-refresh-bridge-daemon.mjs")], {
|
||||
cwd: repoRoot,
|
||||
env: {
|
||||
...process.env,
|
||||
BOSS_CODEX_DESKTOP_BRIDGE_HOST: "127.0.0.1",
|
||||
BOSS_CODEX_DESKTOP_BRIDGE_PORT: "0",
|
||||
BOSS_CODEX_DESKTOP_APP_PATH: appPath,
|
||||
BOSS_CODEX_DESKTOP_REFRESH_DRY_RUN: "true",
|
||||
},
|
||||
stdio: ["ignore", "pipe", "pipe"],
|
||||
});
|
||||
try {
|
||||
const ready = await new Promise((resolve, reject) => {
|
||||
let buffer = "";
|
||||
const timer = setTimeout(() => reject(new Error("daemon not ready")), 4000);
|
||||
child.stdout.setEncoding("utf8");
|
||||
child.stdout.on("data", (chunk) => {
|
||||
buffer += chunk;
|
||||
const line = buffer.trim().split(/\r?\n/).at(-1);
|
||||
if (line) {
|
||||
try {
|
||||
clearTimeout(timer);
|
||||
resolve(JSON.parse(line));
|
||||
} catch {
|
||||
// wait
|
||||
}
|
||||
}
|
||||
});
|
||||
child.on("error", reject);
|
||||
});
|
||||
const response = await fetch(`http://${ready.host}:${ready.port}/api/v1/codex-desktop/capabilities`);
|
||||
const result = await response.json();
|
||||
|
||||
assert.equal(response.status, 200);
|
||||
assert.equal(result.ok, true);
|
||||
assert.equal(result.capabilities.threadDeepLink.supported, true);
|
||||
assert.equal(result.capabilities.packagePatch.supported, false);
|
||||
} finally {
|
||||
child.kill("SIGTERM");
|
||||
await fs.rm(tempDir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user