Files
OpenShell/examples/codex-app-server/start-codex-app-server
Drew Newberry 1905069948 feat(sandbox): expose services during creation (#3439)
* feat(sandbox): expose services during creation

Signed-off-by: Drew Newberry <anewberry@nvidia.com>

* feat(providers): refresh Codex credentials in gateway

Signed-off-by: Drew Newberry <anewberry@nvidia.com>

* fix(cli): normalize create-time service URLs

Signed-off-by: Drew Newberry <anewberry@nvidia.com>

* fix(server): roll back failed service exposure

Signed-off-by: Drew Newberry <anewberry@nvidia.com>

* docs(example): simplify Codex provider setup

Signed-off-by: Drew Newberry <anewberry@nvidia.com>

* docs(example): separate provider setup commands

Signed-off-by: Drew Newberry <anewberry@nvidia.com>

* fix(sandbox): harden create-time service exposure

Signed-off-by: Drew Newberry <anewberry@nvidia.com>

* docs(example): bundle Codex provider profile

Signed-off-by: Drew Newberry <anewberry@nvidia.com>

* fix(example): allow npm-installed Codex binary

Signed-off-by: Drew Newberry <anewberry@nvidia.com>

---------

Signed-off-by: Drew Newberry <anewberry@nvidia.com>
2026-09-20 23:19:25 -07:00

70 lines
2.0 KiB
JavaScript

#!/usr/bin/env node
// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
const fs = require("fs");
const path = require("path");
const { spawn } = require("child_process");
const required = [
"CODEX_AUTH_ACCESS_TOKEN",
"CODEX_AUTH_ACCOUNT_ID",
];
for (const name of required) {
if (!process.env[name]) {
throw new Error(`missing required provider credential: ${name}`);
}
}
const b64u = (value) => Buffer.from(JSON.stringify(value)).toString("base64url");
const now = Math.floor(Date.now() / 1000);
const idToken = [
b64u({ alg: "none", typ: "JWT" }),
b64u({
iss: "https://auth.openai.com",
aud: "codex",
sub: "openshell-app-server",
email: "app-server@openshell.local",
iat: now,
exp: now + 3600,
}),
"placeholder",
].join(".");
const codexHome = path.join(process.env.HOME, ".codex");
fs.mkdirSync(codexHome, { recursive: true });
fs.writeFileSync(path.join(codexHome, "auth.json"), JSON.stringify({
// The gateway owns token refresh; Codex must not attempt to refresh these
// externally managed tokens itself.
auth_mode: "chatgptAuthTokens",
OPENAI_API_KEY: null,
tokens: {
// Provider values are opaque stable handles. Codex parses the ID token
// locally, so use a short-lived, non-secret identity placeholder for it.
id_token: idToken,
access_token: process.env.CODEX_AUTH_ACCESS_TOKEN,
refresh_token: "",
account_id: process.env.CODEX_AUTH_ACCOUNT_ID,
},
last_refresh: new Date().toISOString(),
}, null, 2), { mode: 0o600 });
const port = process.env.CODEX_APP_SERVER_PORT || "4500";
const server = spawn(
"codex",
["app-server", "--listen", `ws://127.0.0.1:${port}`],
{ stdio: "inherit" },
);
server.on("error", (error) => {
console.error(error);
process.exit(1);
});
server.on("exit", (code, signal) => {
if (signal) {
process.kill(process.pid, signal);
} else {
process.exit(code ?? 1);
}
});