← Files OpenAI DevelopersARCHIVED FILE
tests/openai-platform-api-key.test.mjs
49 KB · Nov 11, 2026 · 00:08 UTC
import { execFileSync, spawn, spawnSync } from "node:child_process";
import { webcrypto } from "node:crypto";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import assert from "node:assert/strict";
import { createInterface } from "node:readline";
import test from "node:test";
import { fileURLToPath } from "node:url";
const { subtle } = webcrypto;
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const MONOREPO_ROOT = path.resolve(__dirname, "../../../../..");
const SCRIPT = path.resolve(
__dirname,
"../scripts/openai-platform-api-key.mjs",
);
const SKILL = path.resolve(
__dirname,
"../skills/openai-platform-api-key/SKILL.md",
);
const SKILL_AGENT_METADATA = path.resolve(
__dirname,
"../skills/openai-platform-api-key/agents/openai.yaml",
);
const EVALS = path.resolve(
__dirname,
"../skills/openai-platform-api-key/references/evals.md",
);
const PLUGIN_MANIFEST = path.resolve(__dirname, "../.codex-plugin/plugin.json");
const MCP_MANIFEST = path.resolve(__dirname, "../.mcp.json");
const MCP_SERVER = path.resolve(__dirname, "../mcp/server.mjs");
const OPENAI_DOCS_SKILL = path.resolve(
MONOREPO_ROOT,
"skills/skills/openai-docs/SKILL.md",
);
const APPLIED_OPENAI_DOCS_SKILL = path.resolve(
MONOREPO_ROOT,
"lib/applied/applied_skills/applied_skills/example_skills/openai-docs/current/SKILL.md",
);
const PLUGIN_ICON = path.resolve(
__dirname,
"../assets/logo.png",
);
const APP_ICON = path.resolve(
MONOREPO_ROOT,
"chatgpt/web/public/images/ecosystem/apps/openai_platform/icon.png",
);
const SECRET = "sk-proj-test-secret-value";
const PROMO_DESTINATIONS = [
{ destination_type: "api_org", destination_account_id: "org-alpha", display_name: "Shared name" },
{ destination_type: "api_org", destination_account_id: "org-beta", display_name: "Shared name" },
];
function runScript(args) {
return execFileSync(process.execPath, [SCRIPT, ...args], {
encoding: "utf8",
stdio: ["ignore", "pipe", "pipe"],
});
}
function runScriptFailure(args) {
return spawnSync(process.execPath, [SCRIPT, ...args], {
encoding: "utf8",
stdio: ["ignore", "pipe", "pipe"],
});
}
function runMcpServer(requests) {
const result = spawnSync(process.execPath, [MCP_SERVER], {
encoding: "utf8",
input: `${requests.map((request) => JSON.stringify(request)).join("\n")}\n`,
stdio: ["pipe", "pipe", "pipe"],
timeout: 5_000,
});
assert.equal(result.status, 0, result.stderr);
assert.equal(result.stderr, "");
return result.stdout
.split(/\r?\n/u)
.filter((line) => line.trim().length > 0)
.map((line) => JSON.parse(line));
}
function openMcpServer(t) {
const server = spawn(process.execPath, [MCP_SERVER], { stdio: ["pipe", "pipe", "inherit"] });
const replies = createInterface({ input: server.stdout });
const messages = replies[Symbol.asyncIterator]();
t.after(() => {
replies.close();
server.kill();
});
return async (request) => {
server.stdin.write(`${JSON.stringify(request)}\n`);
const { value, done } = await messages.next();
assert.equal(done, false, "MCP server closed before replying");
return JSON.parse(value);
};
}
function promoToolCall(id = 2, args = { destinations: PROMO_DESTINATIONS }) {
return {
jsonrpc: "2.0",
id,
method: "tools/call",
params: { name: "confirm_api_credit_promo_org", arguments: args },
};
}
function elicitationReply(prompt, result) {
return { jsonrpc: "2.0", id: prompt.id, result };
}
async function openSharedServer(t) {
const exchange = openMcpServer(t);
let id = 0;
async function rpc(method, params) {
const message = await exchange({ jsonrpc: "2.0", id: ++id, method, params });
assert.equal(message.id, id);
return message;
}
const _meta = {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientCapabilities": { elicitation: { form: {} } },
};
const discovery = await rpc("server/discover", { _meta });
assert.deepEqual(discovery.result.supportedVersions, ["2026-07-28"]);
return { rpc, _meta };
}
test("shared calls bind the destination approval to the original chat and arguments", { timeout: 5000 }, async (t) => {
const { rpc, _meta } = await openSharedServer(t);
const makeCall = (chat) => ({
_meta: { ..._meta, threadId: chat, callId: "first-call" },
name: "confirm_openai_api_key_local_destination",
arguments: { workspacePath: path.resolve("/work", chat), targetPath: ".env", envName: "MY_KEY" },
});
const a = makeCall("a");
const b = makeCall("b");
const withArgs = (args) => ({ ...a, arguments: { ...a.arguments, ...args } });
const ask = async (call) => {
const { result } = await rpc("tools/call", call);
assert.equal(result.resultType, "input_required");
assert.equal(result.inputRequests.confirmation.method, "elicitation/create");
return result.requestState;
};
const stateA = await ask(a);
const stateB = await ask(b);
const withCapabilities = (elicitation) => ({
...a,
_meta: { ...a._meta, "io.modelcontextprotocol/clientCapabilities": { elicitation } },
});
await ask(withCapabilities({}));
const respond = (call, requestState, action, targetPath) => rpc("tools/call", {
...call, requestState, inputResponses: { confirmation: { action, content: { targetPath } } },
});
assert.equal((await rpc("tools/call", withCapabilities())).error.code, -32021);
assert.equal((await respond(withCapabilities({ url: {} }), stateA, "accept", ".env")).error.code, -32021);
assert.equal((await rpc("tools/call", withArgs({ workspacePath: "." }))).error.code, -32602);
for (const changed of [
{ ...a, _meta: b._meta },
{ ...a, _meta: { ...a._meta, callId: "second-call" } },
// Same displayed destination, but a broader workspace for an edited response.
withArgs({ workspacePath: path.resolve("/work"), targetPath: "a/.env" }),
withArgs({ targetPath: ".other" }),
withArgs({ envName: "OTHER_KEY" }),
]) {
assert.equal((await respond(changed, stateA, "accept", ".env")).error.code, -32602);
}
assert.equal((await respond(b, stateB, "decline")).result.structuredContent.status, "not_approved");
assert.equal((await respond(a, stateA, "accept", "../escape")).error.code, -32602);
const approved = await respond(a, stateA, "accept", ".env.local");
assert.deepEqual(approved.result.structuredContent, {
status: "approved", workspacePath: path.resolve("/work/a"),
targetPath: path.resolve("/work/a/.env.local"), envName: "MY_KEY",
});
assert.equal((await rpc("tools/call", { ...a, _meta: {} })).error.code, -32602);
assert.equal((await rpc("ping", { _meta: a._meta })).error.code, -32601);
});
test("shared credit confirmation binds the disclosure and retry ID to the selected organization", { timeout: 5000 }, async (t) => {
const { rpc, _meta } = await openSharedServer(t);
const promo = promoToolCall().params;
assert.match((await rpc("tools/call", { ...promo, _meta })).error.message, /threadId/);
// Direct app-server calls provide a thread ID without a model tool-call ID.
const call = { ...promo, _meta: { ..._meta, threadId: "a" } };
const picker = (await rpc("tools/call", call)).result;
assert.equal(picker.resultType, "input_required");
assert.equal(picker.inputRequests.organization.method, "elicitation/create");
const resume = (requestState, inputResponses, overrides = {}) => rpc("tools/call", {
...call, requestState, inputResponses, ...overrides,
});
const selectedOrg = { organization: { action: "accept", content: { destination_account_id: "org-beta" } } };
const acknowledge = { disclosure: { action: "accept", content: { acknowledged: true } } };
assert.equal((await resume(picker.requestState, acknowledge)).error?.code, -32602);
const disclosure = (await resume(picker.requestState, selectedOrg)).result;
assert.equal(disclosure.resultType, "input_required");
assert.equal(disclosure.inputRequests.disclosure.method, "elicitation/create");
assert.equal(disclosure.inputRequests.disclosure.params.requestedSchema.properties.acknowledged.default, false);
assert.notEqual(disclosure.requestState, picker.requestState);
assert.equal((await resume(picker.requestState, selectedOrg)).result.requestState, disclosure.requestState);
const forgedState = disclosure.requestState.replace(".disclosure.1.", ".disclosure.0.");
assert.notEqual(forgedState, disclosure.requestState);
assert.equal((await resume(forgedState, acknowledge)).error?.code, -32602);
const changedDestinations = { destinations: [...PROMO_DESTINATIONS].reverse() };
assert.equal((await resume(disclosure.requestState, acknowledge, { arguments: changedDestinations })).error?.code, -32602);
assert.equal((await resume(disclosure.requestState, acknowledge, { _meta: { ..._meta, threadId: "chat-b" } })).error?.code, -32602);
const unchecked = { disclosure: { action: "accept", content: { acknowledged: false } } };
const stopped = (await resume(disclosure.requestState, unchecked)).result;
assert.equal(stopped.resultType, "complete");
assert.deepEqual(stopped.structuredContent, { status: "not_approved" });
const approved = (await resume(disclosure.requestState, acknowledge)).result;
assert.equal(approved.resultType, "complete");
assert.deepEqual(approved.structuredContent, {
status: "approved",
link_arguments: {
destination_account_id: "org-beta",
operation_id: picker.requestState.split(".", 1)[0],
},
});
assert.deepEqual((await resume(disclosure.requestState, acknowledge)).result, approved);
const secondPicker = (await rpc("tools/call", call)).result;
const secondDisclosure = (await resume(secondPicker.requestState, selectedOrg)).result;
const secondApproval = (await resume(secondDisclosure.requestState, acknowledge)).result;
assert.notEqual(secondApproval.structuredContent.link_arguments.operation_id, approved.structuredContent.link_arguments.operation_id);
});
function base64url(bytes) {
return Buffer.from(bytes).toString("base64url");
}
async function encryptWithPublicJwk(publicJwk, plaintext) {
const publicKey = await subtle.importKey(
"jwk",
publicJwk,
{
name: "RSA-OAEP",
hash: "SHA-256",
},
false,
["encrypt"],
);
const ciphertext = await subtle.encrypt(
{
name: "RSA-OAEP",
},
publicKey,
new TextEncoder().encode(plaintext),
);
return base64url(ciphertext);
}
test("prepare writes private key locally and emits a public connector request", () => {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "openai-platform-helper-test-"));
const output = JSON.parse(runScript(["prepare", "--name", "Unit Test", "--dir", dir]));
const request = JSON.parse(fs.readFileSync(output.request_path, "utf8"));
const privateKey = JSON.parse(fs.readFileSync(output.private_key_path, "utf8"));
assert.equal(request.name, "Unit Test");
assert.deepEqual(Object.keys(request.recipient_public_key_jwk).sort(), ["e", "kty", "n"]);
assert.equal(request.recipient_public_key_jwk.kty, "RSA");
assert.equal(request.recipient_public_key_jwk.e, "AQAB");
assert.equal(Boolean(privateKey.d), true);
assert.equal(output.recipient_public_key_jwk.d, undefined);
});
test("skill documents picker lookup and local destination confirmation", () => {
const skill = fs.readFileSync(SKILL, "utf8");
assert.match(skill, /tool_search/);
assert.match(skill, /`open_codex_api_key_setup` tool/);
assert.match(skill, /call `open_codex_api_key_setup` directly with no arguments \(`\{\}`\)/);
assert.match(skill, /local destination confirmation/);
assert.match(skill, /OpenAI Developers MCP `confirm_openai_api_key_local_destination` tool/);
assert.match(skill, /if the picker tool is unavailable or fails before the widget opens/);
assert.match(skill, /`create_encrypted_openai_api_key`/);
assert.match(skill, /## Helper/);
});
test("plugin registers the onboarding confirmation tools", () => {
const pluginManifest = JSON.parse(fs.readFileSync(PLUGIN_MANIFEST, "utf8"));
const manifest = JSON.parse(fs.readFileSync(MCP_MANIFEST, "utf8"));
const responses = runMcpServer([
{
jsonrpc: "2.0",
id: 1,
method: "initialize",
params: {
protocolVersion: "2025-11-25",
capabilities: {},
clientInfo: { name: "openai-developers-test", version: "0.1.0" },
},
},
{
jsonrpc: "2.0",
id: 2,
method: "tools/list",
params: {},
},
]);
assert.equal(pluginManifest.mcpServers, "./.mcp.json");
assert.equal(pluginManifest.extensions["com.openai"].onboardingSkill, "./skills/setup/SKILL.md");
assert.deepEqual(manifest.mcpServers["openai-api-credit-promo"], {
type: "http",
url: "https://chatgpt.com/backend-api/product-account-links/mcp",
auth: "chatgpt",
enabled_tools: ["preview_api_credit_promo", "discover_api_orgs", "link_api_org"],
});
assert.equal(responses[1].result.tools[2].annotations.idempotentHint, false);
assert.deepEqual(
manifest.mcpServers["openai-api-key-local-confirmation"].args,
["./mcp/server.mjs"],
);
assert.equal(responses[0].result.serverInfo.name, "OpenAI Developers MCP");
assert.deepEqual(
responses[1].result.tools.map((tool) => tool.name),
["confirm_openai_api_key_local_destination", "choose_openai_api_key_setup", "confirm_api_credit_promo_org"],
);
});
test("native key setup choice returns only the developer's confirmed selection", () => {
for (const choice of ["create", "configured", "skip"]) {
const responses = runMcpServer([
{
jsonrpc: "2.0",
id: 2,
method: "tools/call",
params: { name: "choose_openai_api_key_setup", arguments: {} },
},
{
jsonrpc: "2.0",
id: "server-1",
result: { action: "accept", content: { setupChoice: choice } },
},
]);
const elicitation = responses.find((response) => response.method === "elicitation/create");
const result = responses.find((response) => response.id === 2);
const field = elicitation.params.requestedSchema.properties.setupChoice;
assert.equal(elicitation.params.mode, "form");
assert.deepEqual(field.oneOf, [
{ const: "create", title: "Create an API key" },
{ const: "configured", title: "I have an API key configured" },
{ const: "skip", title: "Skip" },
]);
assert.equal(Object.hasOwn(field, "default"), false);
assert.deepEqual(elicitation.params.requestedSchema.required, ["setupChoice"]);
assert.deepEqual(result.result.structuredContent, { status: "selected", choice });
}
});
test("native key setup choice does not select an option on dismissal or invalid input", () => {
for (const response of [
{ action: "cancel" },
{ action: "decline" },
{ action: "accept", content: {} },
{ action: "accept", content: { setupChoice: "unexpected" } },
]) {
const responses = runMcpServer([
{
jsonrpc: "2.0",
id: 2,
method: "tools/call",
params: { name: "choose_openai_api_key_setup", arguments: {} },
},
{ jsonrpc: "2.0", id: "server-1", result: response },
]);
assert.deepEqual(
responses.find((item) => item.id === 2).result.structuredContent,
{ status: "not_selected" },
);
}
});
test("promo disclosure requires an explicit checked acknowledgement", { timeout: 5_000 }, async (t) => {
const exchange = openMcpServer(t);
const cases = [
{ action: "accept", content: { acknowledged: false } },
{ action: "accept", content: {} },
{ action: "accept", content: { acknowledged: "true" } },
{ action: "cancel", content: { acknowledged: true } },
{ action: "decline" },
];
for (const [index, result] of cases.entries()) {
const picker = await exchange(promoToolCall(index + 1));
const disclosure = await exchange(elicitationReply(picker, {
action: "accept", content: { destination_account_id: "org-alpha" },
}));
const { requestedSchema } = disclosure.params;
assert.deepEqual(requestedSchema.required, ["acknowledged"]);
assert.equal(requestedSchema.properties.acknowledged.type, "boolean");
assert.equal(requestedSchema.properties.acknowledged.default, false);
const response = await exchange(elicitationReply(disclosure, result));
assert.deepEqual(response.result.structuredContent, { status: "not_approved" });
}
});
test("promo confirmation returns the selected org and a server-generated operation ID", { timeout: 5_000 }, async (t) => {
const exchange = openMcpServer(t);
const suppliedOperationId = "00000000-0000-4000-8000-000000000000";
const elicitation = await exchange(promoToolCall());
const schema = elicitation.params.requestedSchema;
assert.equal(elicitation.params.mode, "form");
assert.deepEqual(schema.properties.destination_account_id.oneOf, [
{ const: "org-alpha", title: "Shared name (org-alpha)" },
{ const: "org-beta", title: "Shared name (org-beta)" },
]);
assert.equal(Object.hasOwn(schema.properties.destination_account_id, "default"), false);
assert.deepEqual(Object.keys(schema.properties), ["destination_account_id"]);
assert.deepEqual(schema.required, ["destination_account_id"]);
const disclosure = await exchange(elicitationReply(elicitation, {
action: "accept",
content: { destination_account_id: "org-beta", operation_id: suppliedOperationId },
}));
const { result } = await exchange(elicitationReply(disclosure, {
action: "accept",
content: { acknowledged: true, destination_account_id: "org-alpha" },
}));
assert.equal(result.structuredContent.status, "approved");
const args = result.structuredContent.link_arguments;
assert.deepEqual(Object.keys(args).sort(), ["destination_account_id", "operation_id"]);
assert.equal(args.destination_account_id, "org-beta");
assert.match(args.operation_id, /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/);
assert.notEqual(args.operation_id, suppliedOperationId);
assert.deepEqual(JSON.parse(result.content[0].text), result.structuredContent);
});
test("promo cancellation and invalid selections never produce link arguments", { timeout: 5_000 }, async (t) => {
const exchange = openMcpServer(t);
const results = [
{ action: "cancel", content: { destination_account_id: "org-alpha" } },
{ action: "decline" },
{ action: "accept", content: {} },
{ action: "accept", content: { destination_account_id: "org-unlisted" } },
{ action: "accept", content: { destination_account_id: 123 } },
{ content: { destination_account_id: "org-alpha" } },
null,
];
for (const [index, result] of results.entries()) {
const picker = await exchange(promoToolCall(index + 1));
const response = await exchange(elicitationReply(picker, result));
assert.deepEqual(response.result.structuredContent, { status: "not_approved" });
}
});
test("promo confirmation rejects malformed or ambiguous destinations before showing a form", () => {
const destination = PROMO_DESTINATIONS[0];
const invalidArgs = [
null,
{},
{ destinations: [] },
{ destinations: {} },
{ destinations: [null] },
{ destinations: [{ ...destination, destination_type: "chatgpt_account" }] },
{ destinations: [{ ...destination, destination_account_id: "" }] },
{ destinations: [{ ...destination, destination_account_id: " org-alpha " }] },
{ destinations: [{ ...destination, destination_account_id: "x".repeat(129) }] },
{ destinations: [{ ...destination, display_name: null }] },
{ destinations: [destination, { ...destination, display_name: "Different name" }] },
{ destinations: PROMO_DESTINATIONS, operation_id: "caller-supplied" },
{ destinations: PROMO_DESTINATIONS, cadence: "monthly" },
];
const responses = runMcpServer(invalidArgs.map((args, index) => promoToolCall(index + 1, args)));
assert.equal(responses.length, invalidArgs.length);
for (const response of responses) {
assert.equal(response.error?.code, -32602);
}
});
test("each confirmed promo attempt gets its own operation ID", { timeout: 5_000 }, async (t) => {
const exchange = openMcpServer(t);
const firstPicker = await exchange(promoToolCall(1));
const secondPicker = await exchange(promoToolCall(2));
const secondDisclosure = await exchange(elicitationReply(secondPicker, {
action: "accept", content: { destination_account_id: "org-beta" },
}));
const firstDisclosure = await exchange(elicitationReply(firstPicker, {
action: "accept", content: { destination_account_id: "org-alpha" },
}));
const acknowledge = { action: "accept", content: { acknowledged: true } };
const secondReply = await exchange(elicitationReply(secondDisclosure, acknowledge));
const firstReply = await exchange(elicitationReply(firstDisclosure, acknowledge));
assert.equal(firstReply.id, 1);
assert.equal(secondReply.id, 2);
const first = firstReply.result.structuredContent.link_arguments;
const second = secondReply.result.structuredContent.link_arguments;
assert.equal(first.destination_account_id, "org-alpha");
assert.equal(second.destination_account_id, "org-beta");
assert.notEqual(first.operation_id, second.operation_id);
});
test("unsupported native forms do not authorize promo linking", () => {
const responses = runMcpServer([
promoToolCall(),
{ jsonrpc: "2.0", id: "server-1", error: { code: -32601, message: "Elicitation is unavailable" } },
]);
const reply = responses.find((item) => item.id === 2);
assert.ok(reply.error);
assert.equal(reply.result, undefined);
});
test("local destination confirmation suggests a path and accepts an override", () => {
const workspace = fs.mkdtempSync(path.join(os.tmpdir(), "openai-platform-mcp-test-"));
const responses = runMcpServer([
{
jsonrpc: "2.0",
id: 1,
method: "initialize",
params: {
protocolVersion: "2025-11-25",
capabilities: {},
clientInfo: { name: "openai-developers-test", version: "0.1.0" },
},
},
{
jsonrpc: "2.0",
id: 2,
method: "tools/call",
params: {
name: "confirm_openai_api_key_local_destination",
arguments: {
workspacePath: workspace,
targetPath: ".env.local",
envName: "OPENAI_API_KEY",
},
},
},
{
jsonrpc: "2.0",
id: "server-1",
result: {
action: "accept",
content: {
targetPath: ".env.test",
},
},
},
]);
const elicitation = responses.find((response) => response.method === "elicitation/create");
const result = responses.find((response) => response.id === 2);
const targetField = elicitation.params.requestedSchema.properties.targetPath;
assert.equal(elicitation.params.mode, "form");
assert.equal(targetField.default, path.join(workspace, ".env.local"));
assert.equal(Object.hasOwn(targetField, "description"), false);
assert.equal(result.result.structuredContent.status, "approved");
assert.equal(result.result.structuredContent.targetPath, path.join(workspace, ".env.test"));
});
test("local destination confirmation rejects an out-of-workspace override", () => {
const workspace = fs.mkdtempSync(path.join(os.tmpdir(), "openai-platform-mcp-test-"));
const responses = runMcpServer([
{
jsonrpc: "2.0",
id: 1,
method: "initialize",
params: {
protocolVersion: "2025-11-25",
capabilities: {},
clientInfo: { name: "openai-developers-test", version: "0.1.0" },
},
},
{
jsonrpc: "2.0",
id: 2,
method: "tools/call",
params: {
name: "confirm_openai_api_key_local_destination",
arguments: {
workspacePath: workspace,
targetPath: ".env.local",
},
},
},
{
jsonrpc: "2.0",
id: "server-1",
result: {
action: "accept",
content: {
targetPath: "../.env",
},
},
},
]);
const result = responses.find((response) => response.id === 2);
assert.equal(result.error.code, -32602);
assert.match(result.error.message, /inside the selected workspace/);
});
test("local destination confirmation stops when the developer cancels", () => {
const workspace = fs.mkdtempSync(path.join(os.tmpdir(), "openai-platform-mcp-test-"));
const responses = runMcpServer([
{
jsonrpc: "2.0",
id: 1,
method: "initialize",
params: {
protocolVersion: "2025-11-25",
capabilities: {},
clientInfo: { name: "openai-developers-test", version: "0.1.0" },
},
},
{
jsonrpc: "2.0",
id: 2,
method: "tools/call",
params: {
name: "confirm_openai_api_key_local_destination",
arguments: {
workspacePath: workspace,
targetPath: ".env.local",
},
},
},
{
jsonrpc: "2.0",
id: "server-1",
result: {
action: "cancel",
},
},
]);
const result = responses.find((response) => response.id === 2);
assert.equal(result.result.structuredContent.status, "not_approved");
assert.equal(result.result.structuredContent.action, "cancel");
});
test("skill metadata describes safe API key setup", () => {
const metadata = fs.readFileSync(SKILL_AGENT_METADATA, "utf8");
assert.match(metadata, /Create and configure OpenAI API keys safely/);
assert.doesNotMatch(metadata, /for any app, script, tool, or UI using AI or OpenAI API/);
assert.doesNotMatch(metadata, /allow_implicit_invocation/);
});
test("plugin and app tiles use the same OpenAI Platform logo", (t) => {
if (!fs.existsSync(APP_ICON)) {
t.skip("monorepo OpenAI Platform app icon is not available in this repository");
return;
}
assert.deepEqual(fs.readFileSync(PLUGIN_ICON), fs.readFileSync(APP_ICON));
});
test("skill asks before building API-backed apps when any usable key exists", () => {
const skill = fs.readFileSync(SKILL, "utf8");
const description = skill.match(/description: (.*)/)?.[1] ?? "";
assert.match(
description,
/Use when Codex is asked to build, run, test, debug, or configure an OpenAI-backed or provider-unspecified AI app, UI, script, CLI, generator, or tool/,
);
assert.match(
description,
/especially requests phrased only as "using AI" or generators driven by forms\/user input/,
);
assert.match(
description,
/also use for OPENAI_API_KEY or sk-proj setup/,
);
assert.match(
description,
/Treat this as the credential gate: inspect safely, ask reuse-vs-new before API work/,
);
assert.match(
skill,
/Use this skill as the credential gate for API-backed work, not as the app,\s+docs, or frontend implementation skill\./,
);
assert.match(
skill,
/Codex will build, implement, run, test, debug, or configure an app, script,\s+CLI, generator, UI, or tool that calls the OpenAI API, even before a live\s+request and even if a usable key already exists\./,
);
assert.match(
skill,
/The user asks Codex to build, implement, run, or configure an app, script, CLI,\s+generator, or tool that uses AI to produce outputs from user input\./,
);
assert.match(
skill,
/The user asks for an AI-powered app or UI that generates output from one or\s+more input fields, forms, prompts, files, or other user-provided values\./,
);
assert.match(
skill,
/The user says "using AI" in an app\/script\/build request and does not name a\s+different provider\./,
);
assert.match(
skill,
/The user only wants documentation, citations, model or API guidance,\s+conceptual explanation, or code examples without asking Codex to build, run,\s+configure, or debug an API-backed artifact\./,
);
assert.match(
skill,
/The user asks for a static frontend, visual mockup, design concept, or\s+placeholder UI with no API-backed behavior\./,
);
assert.match(
skill,
/The user only asks Codex to write a one-off output directly and no app,\s+script, generator, or API-backed tool is being built or run\./,
);
assert.match(
skill,
/The user names a different AI provider for the artifact\./,
);
assert.match(
skill,
/When another implementation skill also applies, run this skill first only to inspect\s+credentials safely and send the credential decision message\./,
);
assert.match(
skill,
/do not design UI, choose architecture, inspect API examples, write code, or run\s+smoke tests\./,
);
assert.match(
skill,
/Until reuse-existing-key vs create-new-key is resolved, it outranks design-first\s+and implementation-first flows, including\s+`build-web-apps:frontend-app-builder`;/,
);
assert.match(
skill,
/After the user answers, hand off to the appropriate implementation, docs, or\s+frontend skill\./,
);
assert.match(
skill,
/before building, implementing, running, testing, debugging, or configuring an app\s+or script that calls the OpenAI API, ask up front whether to reuse an existing\s+usable key or create a new one/,
);
assert.match(
skill,
/do not silently reuse a detected key for implementation, verification,\s+smoke tests, or other live requests just because the user did not ask about\s+credentials/,
);
assert.match(
skill,
/Before creating a key or writing any secret, obtain explicit confirmation\.\s+Prefer the hosted Platform picker plus local destination confirmation when it is\s+available; if it is unavailable, fall back to a typed local destination question,\s+then wait\./,
);
assert.match(
skill,
/When creation is the chosen path, confirm the destination file\/env var before writing\./,
);
assert.match(
skill,
/If the user has not already explicitly asked for a new key, ask whether to create one first\./,
);
assert.match(
skill,
/If API access is needed and no usable key is found, offer secure key provisioning\s+instead of leaving only placeholder docs or manual setup steps\./,
);
});
test("skill forbids credential inspection that can print secrets", () => {
const skill = fs.readFileSync(SKILL, "utf8");
assert.match(
skill,
/Never inspect credentials with commands that can print secret values, such as\s+`cat \.env\*`, `grep OPENAI_API_KEY \.env\*`, or `rg OPENAI_API_KEY \.env\*`\./,
);
assert.match(
skill,
/inspect env files only with no-output checks that reveal presence\/absence,\s+never with commands that echo matching lines or whole files/,
);
});
test("skill makes the key-choice gate impossible to miss", () => {
const skill = fs.readFileSync(SKILL, "utf8");
const credentialDecisionMessages = skill.slice(
skill.indexOf("## Credential Decision Messages"),
skill.indexOf("## Workflow"),
);
assert.match(skill, /## Mandatory First Step/);
assert.match(
skill,
/Before editing, testing, running, debugging, or configuring any code that calls\s+the OpenAI API:\s+1\. Inspect for a usable `OPENAI_API_KEY` without printing it\.\s+2\. Unless the user explicitly asked for a new key, ask whether to reuse an\s+existing key or create a new one\. If none exists, ask whether to create one\.\s+3\. Stop until the user answers\./,
);
assert.match(
skill,
/This applies even if:\s+- a usable key already exists\s+- no live API call will be made\s+- no secret will be written\s+- the task is "just create a script"/,
);
assert.match(
skill,
/Finding an existing key is not permission to proceed\. It only changes the\s+question you ask\./,
);
assert.match(
skill,
/The credential decision is a hard stop\. Before the user answers, do not create\s+directories, scaffold files, draft implementation plans, wire API-dependent\s+code, run smoke tests, or give placeholder\/manual key setup instructions\./,
);
assert.match(
skill,
/The\s+only allowed pre-gate work is safe repo convention discovery and credential\s+presence checks that do not print secrets\./,
);
assert.match(skill, /## Credential Decision Messages/);
assert.match(
credentialDecisionMessages,
/Required progress updates before or during credential inspection may be brief\s+and limited to saying that Codex is checking credentials or opening secure key\s+setup\./,
);
assert.match(
credentialDecisionMessages,
/They must not describe implementation plans, architecture, file choices,\s+local destination details, or credential conclusions before the credential\s+decision or picker handoff\./,
);
assert.match(
credentialDecisionMessages,
/After inspecting credentials, the next substantive user-facing message must be\s+the credential decision message\./,
);
assert.match(
credentialDecisionMessages,
/Existing usable key found, and the user did not explicitly ask for a new key:\s+make clear that the OpenAI API will power the app, script, or project, say that\s+an existing usable `OPENAI_API_KEY` was found without revealing it, then ask\s+whether to reuse that key or create a new one\./,
);
assert.match(
credentialDecisionMessages,
/No usable key found: make clear that the OpenAI API will power the app, script,\s+or project, say that no usable `OPENAI_API_KEY` was found, then ask whether to\s+create one securely\./,
);
assert.match(
credentialDecisionMessages,
/User explicitly asked for a new key: skip the reuse question and open the\s+Platform picker directly when available\./,
);
});
test("skill documents the connector-owned picker boundary", () => {
const skill = fs.readFileSync(SKILL, "utf8");
const workflow = skill.slice(skill.indexOf("## Workflow"), skill.indexOf("## Helper"));
assert.match(skill, /Prefer the hosted Platform picker/);
assert.match(skill, /`open_codex_api_key_setup`/);
assert.match(skill, /tool_search/);
assert.match(
skill,
/call `open_codex_api_key_setup` directly with no arguments \(`\{\}`\)\. Do not send a key name, local paths, workspace arguments, or target arrays\./,
);
assert.match(skill, /picker-confirmed `organization_id` and `project_id`/);
assert.doesNotMatch(workflow, /open_openai_api_key_setup/);
});
test("skill keeps deterministic mechanics out of the hosted-picker branch", () => {
const skill = fs.readFileSync(SKILL, "utf8");
const hostedPickerFlow = skill.slice(
skill.indexOf(" - Prefer the hosted Platform picker:"),
skill.indexOf(" - After the widget follow-up"),
);
assert.doesNotMatch(hostedPickerFlow, /recipient_public_key_jwk/);
assert.doesNotMatch(hostedPickerFlow, /encrypted_api_key\.ciphertext/);
});
test("skill keeps secure setup narration brief", () => {
const skill = fs.readFileSync(SKILL, "utf8");
assert.match(skill, /Keep user-facing messages concise\./);
assert.match(skill, /Do not narrate deterministic mechanics such as helper discovery/);
assert.match(
skill,
/say only that Codex will create the key securely and write it to the confirmed env file\./,
);
});
test("skill prefers ignored env files and warns before tracked secret writes", () => {
const skill = fs.readFileSync(SKILL, "utf8");
assert.match(skill, /Prefer ignored or untracked env files\./);
assert.match(skill, /The form shows the recommended location and lets the user replace it before continuing\./);
assert.match(skill, /If the local destination tool returns `approved`, use its returned `targetPath` exactly and do not ask a second destination question\./);
assert.match(skill, /ask exactly one short question and stop: `Save the new key to <path>\? Reply yes to continue, another workspace-relative env-file path to change it, or decline\.`/);
assert.match(
skill,
/Silently check whether the selected target is tracked\. If it is tracked, stop and obtain explicit confirmation that a secret will be written there\./,
);
});
test("eval matrix includes local picker boundary and two-field joke app use case", () => {
const evals = fs.readFileSync(EVALS, "utf8");
const k2RunnerRow = evals
.split(/\r?\n/u)
.find((line) => line.startsWith("| K2 |"));
assert.match(
evals,
/should open the Platform connector-owned picker with no arguments/,
);
assert.match(
evals,
/after any non-error picker launch, should not inspect or interpret its launch payload, make another tool call, or send a non-empty user-facing message in that turn/,
);
assert.match(
evals,
/brief progress updates should be allowed only when limited to credential-gate activity and should not describe implementation plans, architecture, file choices, local destination details, or credential conclusions before the credential decision or picker handoff/,
);
assert.match(k2RunnerRow, /brief progress updates should be allowed only when limited to credential-gate activity/);
assert.match(
evals,
/Grade the original case assertions as the product result\. Report runner-injected\s+freshness, artifact, and generic result-validity assertions separately/,
);
assert.match(evals, /### K5 - Two-field joke app/);
assert.match(
evals,
/build an app that generates jokes using AI when i input 2 fields\. the joke should use those fields/,
);
assert.match(
evals,
/should invoke the `openai-platform-api-key` skill even though the user did not\s+mention keys/,
);
assert.match(
evals,
/should stop at the credential decision point until the user answers and should not\s+require a two-field app plan or implementation in the same rollout/,
);
assert.match(
evals,
/if the rollout proceeds after a confirmed key decision, the app plan or implementation\s+should collect two user input fields and send both fields into the AI joke-generation request/,
);
});
test("openai-docs defers to API key skill for implementation tasks", (t) => {
const docsSkillPaths = [OPENAI_DOCS_SKILL, APPLIED_OPENAI_DOCS_SKILL].filter(
fs.existsSync,
);
if (docsSkillPaths.length === 0) {
t.skip("monorepo OpenAI docs skill paths are not available in this repository");
return;
}
for (const docsSkillPath of docsSkillPaths) {
const docsSkill = fs.readFileSync(docsSkillPath, "utf8");
assert.match(docsSkill, /## API Key Setup/);
assert.match(
docsSkill,
/For requests to build, run, configure, debug, or implement an API-backed app, script, CLI, generator, or tool, use `openai-platform-api-key` first when available\./,
);
assert.match(
docsSkill,
/use `openai-platform-api-key` first when available\. After that credential gate is resolved, return here for current docs as needed\./,
);
assert.match(
docsSkill,
/Use this skill directly for docs-only questions, citations, model\/API guidance, conceptual explanations, and examples that do not require building or running an API-backed artifact\./,
);
}
});
test("decrypt writes the API key to the env file without printing it", async () => {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "openai-platform-helper-test-"));
const output = JSON.parse(runScript(["prepare", "--dir", dir]));
const ciphertext = await encryptWithPublicJwk(output.recipient_public_key_jwk, SECRET);
const target = path.join(dir, ".env.local");
const decryptOutput = runScript([
"decrypt",
"--private-key",
output.private_key_path,
"--ciphertext",
ciphertext,
"--target",
target,
"--env-name",
"OPENAI_API_KEY",
"--workspace",
dir,
]);
assert.equal(decryptOutput.includes(SECRET), false);
assert.equal(fs.readFileSync(target, "utf8"), `OPENAI_API_KEY=${SECRET}\n`);
});
test("decrypt updates an existing env var without printing the API key", async () => {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "openai-platform-helper-test-"));
const output = JSON.parse(runScript(["prepare", "--dir", dir]));
const ciphertext = await encryptWithPublicJwk(output.recipient_public_key_jwk, SECRET);
const target = path.join(dir, ".env.local");
fs.writeFileSync(target, "OTHER=value\nOPENAI_API_KEY=old\n");
const decryptOutput = JSON.parse(
runScript([
"decrypt",
"--private-key",
output.private_key_path,
"--ciphertext",
ciphertext,
"--target",
target,
"--workspace",
dir,
]),
);
assert.equal(decryptOutput.updated_existing, true);
assert.equal(decryptOutput.wrote_plaintext_to_stdout, false);
assert.equal(fs.readFileSync(target, "utf8"), `OTHER=value\nOPENAI_API_KEY=${SECRET}\n`);
});
test("decrypt tightens permissions on an existing env file", async () => {
if (process.platform === "win32") {
return;
}
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "openai-platform-helper-test-"));
const output = JSON.parse(runScript(["prepare", "--dir", dir]));
const ciphertext = await encryptWithPublicJwk(output.recipient_public_key_jwk, SECRET);
const target = path.join(dir, ".env.local");
fs.writeFileSync(target, "OPENAI_API_KEY=old\n", { mode: 0o644 });
fs.chmodSync(target, 0o644);
runScript([
"decrypt",
"--private-key",
output.private_key_path,
"--ciphertext",
ciphertext,
"--target",
target,
"--workspace",
dir,
]);
assert.equal(fs.statSync(target).mode & 0o777, 0o600);
});
test("decrypt preserves export when updating an exported env var", async () => {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "openai-platform-helper-test-"));
const output = JSON.parse(runScript(["prepare", "--dir", dir]));
const ciphertext = await encryptWithPublicJwk(output.recipient_public_key_jwk, SECRET);
const target = path.join(dir, ".env.local");
fs.writeFileSync(target, "OTHER=value\nexport OPENAI_API_KEY=old\n");
const decryptOutput = JSON.parse(
runScript([
"decrypt",
"--private-key",
output.private_key_path,
"--ciphertext",
ciphertext,
"--target",
target,
"--workspace",
dir,
]),
);
assert.equal(decryptOutput.updated_existing, true);
assert.equal(decryptOutput.wrote_plaintext_to_stdout, false);
assert.equal(fs.readFileSync(target, "utf8"), `OTHER=value\nexport OPENAI_API_KEY=${SECRET}\n`);
});
test("decrypt rejects unsafe plaintext before writing env files", async () => {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "openai-platform-helper-test-"));
const output = JSON.parse(runScript(["prepare", "--dir", dir]));
const ciphertext = await encryptWithPublicJwk(
output.recipient_public_key_jwk,
"sk-proj-safe\nOTHER=value",
);
const target = path.join(dir, ".env.local");
const result = runScriptFailure([
"decrypt",
"--private-key",
output.private_key_path,
"--ciphertext",
ciphertext,
"--target",
target,
"--workspace",
dir,
]);
assert.notEqual(result.status, 0);
assert.match(result.stderr, /not a safe OpenAI API key literal/);
assert.equal(fs.existsSync(target), false);
});
test("decrypt rejects symlink env targets without writing through them", async () => {
if (process.platform === "win32") {
return;
}
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "openai-platform-helper-test-"));
const outsideDir = fs.mkdtempSync(path.join(os.tmpdir(), "openai-platform-outside-"));
const output = JSON.parse(runScript(["prepare", "--dir", dir]));
const ciphertext = await encryptWithPublicJwk(output.recipient_public_key_jwk, SECRET);
const target = path.join(dir, ".env.local");
const symlinkDestination = path.join(outsideDir, "tracked-file.ts");
fs.writeFileSync(symlinkDestination, "ORIGINAL\n");
fs.symlinkSync(symlinkDestination, target);
const result = runScriptFailure([
"decrypt",
"--private-key",
output.private_key_path,
"--ciphertext",
ciphertext,
"--target",
target,
"--workspace",
dir,
]);
assert.notEqual(result.status, 0);
assert.match(result.stderr, /symlink target/);
assert.equal(fs.readFileSync(symlinkDestination, "utf8"), "ORIGINAL\n");
});
test("decrypt rejects hard-linked env targets without writing through them", async () => {
if (process.platform === "win32") {
return;
}
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "openai-platform-helper-test-"));
const outsideDir = fs.mkdtempSync(path.join(os.tmpdir(), "openai-platform-outside-"));
const output = JSON.parse(runScript(["prepare", "--dir", dir]));
const ciphertext = await encryptWithPublicJwk(output.recipient_public_key_jwk, SECRET);
const target = path.join(dir, ".env.local");
const hardlinkDestination = path.join(outsideDir, "tracked-file.ts");
fs.writeFileSync(hardlinkDestination, "ORIGINAL\n");
try {
fs.linkSync(hardlinkDestination, target);
} catch {
return;
}
const result = runScriptFailure([
"decrypt",
"--private-key",
output.private_key_path,
"--ciphertext",
ciphertext,
"--target",
target,
"--workspace",
dir,
]);
assert.notEqual(result.status, 0);
assert.match(result.stderr, /hard-linked target/);
assert.equal(fs.readFileSync(hardlinkDestination, "utf8"), "ORIGINAL\n");
});
test("decrypt rejects targets outside the selected workspace", async () => {
const workspace = fs.mkdtempSync(path.join(os.tmpdir(), "openai-platform-helper-test-"));
const outsideDir = fs.mkdtempSync(path.join(os.tmpdir(), "openai-platform-outside-"));
const output = JSON.parse(runScript(["prepare", "--dir", workspace]));
const ciphertext = await encryptWithPublicJwk(output.recipient_public_key_jwk, SECRET);
const target = path.join(outsideDir, ".env.local");
const result = runScriptFailure([
"decrypt",
"--private-key",
output.private_key_path,
"--ciphertext",
ciphertext,
"--target",
target,
"--workspace",
workspace,
]);
assert.notEqual(result.status, 0);
assert.match(result.stderr, /inside the workspace/);
assert.equal(fs.existsSync(target), false);
});
test("decrypt rejects symlinked parent directories that escape the workspace", async () => {
if (process.platform === "win32") {
return;
}
const workspace = fs.mkdtempSync(path.join(os.tmpdir(), "openai-platform-helper-test-"));
const outsideDir = fs.mkdtempSync(path.join(os.tmpdir(), "openai-platform-outside-"));
const output = JSON.parse(runScript(["prepare", "--dir", workspace]));
const ciphertext = await encryptWithPublicJwk(output.recipient_public_key_jwk, SECRET);
const linkedParent = path.join(workspace, "linked-parent");
const target = path.join(linkedParent, ".env.local");
fs.symlinkSync(outsideDir, linkedParent, "dir");
const result = runScriptFailure([
"decrypt",
"--private-key",
output.private_key_path,
"--ciphertext",
ciphertext,
"--target",
target,
"--workspace",
workspace,
]);
assert.notEqual(result.status, 0);
assert.match(result.stderr, /inside the workspace/);
assert.equal(fs.existsSync(path.join(outsideDir, ".env.local")), false);
});
test("decrypt treats ciphertext values that start with hyphens as values", () => {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "openai-platform-helper-test-"));
const output = JSON.parse(runScript(["prepare", "--dir", dir]));
const target = path.join(dir, ".env.local");
const result = runScriptFailure([
"decrypt",
"--private-key",
output.private_key_path,
"--ciphertext",
"--AA",
"--target",
target,
"--workspace",
dir,
]);
assert.notEqual(result.status, 0);
assert.match(result.stderr, /Failed to decrypt encrypted API key/);
assert.doesNotMatch(result.stderr, /Provide --ciphertext or --encrypted-result/);
});
test("decrypt rejects unknown options and missing option values", () => {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "openai-platform-helper-test-"));
const output = JSON.parse(runScript(["prepare", "--dir", dir]));
const target = path.join(dir, ".env.local");
const unknown = runScriptFailure([
"decrypt",
"--private-key",
output.private_key_path,
"--ciphertext",
"abc",
"--target",
target,
"--workspace",
dir,
"--envname",
"FOO",
]);
assert.notEqual(unknown.status, 0);
assert.match(unknown.stderr, /Unknown option: --envname/);
const missing = runScriptFailure(["prepare", "--dir", "--name", "Unit Test"]);
assert.notEqual(missing.status, 0);
assert.match(missing.stderr, /Missing value for --dir/);
});
test("decrypt rejects impossible base64url lengths before decrypting", () => {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "openai-platform-helper-test-"));
const output = JSON.parse(runScript(["prepare", "--dir", dir]));
const target = path.join(dir, ".env.local");
const result = runScriptFailure([
"decrypt",
"--private-key",
output.private_key_path,
"--ciphertext",
"a",
"--target",
target,
"--workspace",
dir,
]);
assert.notEqual(result.status, 0);
assert.match(result.stderr, /Encrypted ciphertext must be base64url/);
});
test("decrypt accepts a structured connector result file", async () => {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "openai-platform-helper-test-"));
const output = JSON.parse(runScript(["prepare", "--dir", dir]));
const ciphertext = await encryptWithPublicJwk(output.recipient_public_key_jwk, SECRET);
const encryptedResultPath = path.join(dir, "connector-result.json");
const target = path.join(dir, ".env.local");
fs.writeFileSync(
encryptedResultPath,
JSON.stringify({
structuredContent: {
encrypted_api_key: {
version: 1,
ciphertext,
},
},
}),
);
const decryptOutput = runScript([
"decrypt",
"--private-key",
output.private_key_path,
"--encrypted-result",
encryptedResultPath,
"--target",
target,
"--workspace",
dir,
]);
assert.equal(decryptOutput.includes(SECRET), false);
assert.equal(fs.readFileSync(target, "utf8"), `OPENAI_API_KEY=${SECRET}\n`);
});
SHA-256: 910397b0d00b840ae80f09d6990af2f5f462f7f9e5742dc36c9e842fd9ff376d