From 65347e0a9c054890bab198ca1907229c470b9f3a Mon Sep 17 00:00:00 2001 From: luke2x <97411838+luke2x@users.noreply.github.com> Date: Sat, 10 Oct 2026 21:49:20 +0100 Subject: [PATCH 1/6] fix(codex): renew managed credentials in active processes --- .../src/provider/CodexManagedRuntime.test.ts | 92 ++++++++++++++++-- .../src/provider/CodexManagedRuntime.ts | 24 ++++- .../src/provider/CodexManagedTokenSource.ts | 94 +++++++++++++++++++ 3 files changed, 198 insertions(+), 12 deletions(-) create mode 100644 apps/server/src/provider/CodexManagedTokenSource.ts diff --git a/apps/server/src/provider/CodexManagedRuntime.test.ts b/apps/server/src/provider/CodexManagedRuntime.test.ts index cf95d981d8a5..58f160609a7a 100644 --- a/apps/server/src/provider/CodexManagedRuntime.test.ts +++ b/apps/server/src/provider/CodexManagedRuntime.test.ts @@ -1,5 +1,7 @@ -// @effect-diagnostics nodeBuiltinImport:off - checks the host's default Codex directory without writing to it. +// @effect-diagnostics nodeBuiltinImport:off globalFetchInEffect:off - checks the host's default Codex directory without writing to it. import * as NodeOS from "node:os"; +import * as NodeChildProcess from "node:child_process"; +import * as NodeUtil from "node:util"; import * as NodeServices from "@effect/platform-node/NodeServices"; import { assert, it } from "@effect/vitest"; import { CodexSettings, EnvironmentId, ProviderInstanceId } from "@t3tools/contracts"; @@ -16,12 +18,28 @@ import * as ServerSecretStore from "../auth/ServerSecretStore.ts"; import * as ServerEnvironment from "../environment/ServerEnvironment.ts"; import * as CodexInstallation from "./CodexInstallation.ts"; import { makeCodexManagedRuntime } from "./CodexManagedRuntime.ts"; +import { makeCodexManagedTokenSource } from "./CodexManagedTokenSource.ts"; import * as ProviderCredentialStore from "./ProviderCredentialStore.ts"; import { codexAppServerArgs } from "./codexLaunchArgs.ts"; import { resolveManagedCodexHomeLayout } from "./CodexManagedHome.ts"; const encodeJson = Schema.encodeEffect(Schema.fromJsonString(Schema.Unknown)); const decodeSettings = Schema.decodeSync(CodexSettings); +it.effect("closes the managed credential bridge with its provider scope", () => + Effect.gen(function* () { + const source = yield* makeCodexManagedTokenSource( + ProviderInstanceId.make("closed-codex"), + Effect.succeed({ accessToken: "dummy-token", clientId: "dummy-account" }), + ).pipe(Effect.scoped); + const reached = yield* Effect.promise(() => + fetch(source.url).then( + () => true, + () => false, + ), + ); + assert.isFalse(reached); + }), +); it.effect("managed home defaults to the global Codex home and honors configured home paths", () => Effect.gen(function* () { const path = yield* Path.Path; @@ -149,7 +167,54 @@ it.effect.each( ); assert.isFalse(yield* fs.exists(path.join(effective.config.homePath, "auth.json"))); } - assert.strictEqual(effective.environment.ACCESS_TOKEN, "dummy-owned-access"); + // Emulate the same app-server making later requests, without resolving + // or restarting its runtime. Run its configured credential command. + const requestToken = Effect.promise(async () => { + const argv = codexAppServerArgs(effective.config.launchArgs); + const prefix = "model_providers.openai_token_sharing.auth.args="; + const commandArgs = argv.find((value) => value.startsWith(prefix)); + if (commandArgs === undefined) return effective.environment.ACCESS_TOKEN; + const { stdout } = await NodeUtil.promisify(NodeChildProcess.execFile)( + process.execPath, + JSON.parse(commandArgs.slice(prefix.length)), + { env: effective.environment, timeout: 25_000 }, + ); + return stdout; + }); + assert.equal(yield* requestToken, "dummy-owned-access"); + const expired = { ...JSON.parse(json), expiresAt: 0 }; + yield* store.set(new TextEncoder().encode(JSON.stringify(expired))); + // A provider status read renews the saved token, as in the report. + assert.equal((yield* runtime.auth.access).accessToken, "dummy-renewed-access"); + assert.deepEqual( + yield* Effect.all([requestToken, requestToken], { concurrency: "unbounded" }), + ["dummy-renewed-access", "dummy-renewed-access"], + ); + assert.isUndefined(effective.environment.ACCESS_TOKEN); + assert.notInclude(JSON.stringify(effective.environment), "dummy-owned-access"); + const rejected = yield* Effect.promise(() => + fetch(effective.environment.T3CODE_MANAGED_CODEX_AUTH_URL!), + ); + assert.equal(rejected.status, 401); + yield* store.set( + new TextEncoder().encode( + JSON.stringify({ + ...expired, + clientId: "another-account", + expiresAt: (yield* Clock.currentTimeMillis) + 3_600_000, + }), + ), + ); + const switched = yield* Effect.promise(() => + fetch(effective.environment.T3CODE_MANAGED_CODEX_AUTH_URL!, { + headers: { + Authorization: `Bearer ${effective.environment.T3CODE_MANAGED_CODEX_AUTH_SECRET}`, + "X-T3-Codex-Account": effective.environment.T3CODE_MANAGED_CODEX_AUTH_ACCOUNT!, + }, + }), + ); + assert.equal(switched.status, 409); + assert.equal(yield* Effect.promise(() => switched.text()), ""); assert.isUndefined(effective.environment.OPENAI_API_KEY); assert.isUndefined(effective.environment.OPENAI_BASE_URL); assert.isUndefined(effective.environment.T3CODE_CODEX_LAUNCH_ARGS); @@ -192,19 +257,28 @@ it.effect.each( [ "https://auth.openai.com/.well-known/openid-configuration", "https://auth.openai.com/revoke", + "https://auth.openai.com/api/accounts/oauth/token", ].includes(request.url), ); return HttpClientResponse.fromWeb( request, request.url.endsWith("/revoke") ? new Response(null, { status: 200 }) - : Response.json({ - issuer: "https://auth.openai.com", - authorization_endpoint: "https://auth.openai.com/api/accounts/authorize", - token_endpoint: "https://auth.openai.com/api/accounts/oauth/token", - jwks_uri: "https://auth.openai.com/jwks", - revocation_endpoint: "https://auth.openai.com/revoke", - }), + : request.url.endsWith("/token") + ? Response.json({ + access_token: "dummy-renewed-access", + refresh_token: "dummy-rotated-refresh", + expires_in: 3600, + token_type: "Bearer", + scope: "chatgpt.tokens.use.direct", + }) + : Response.json({ + issuer: "https://auth.openai.com", + authorization_endpoint: "https://auth.openai.com/api/accounts/authorize", + token_endpoint: "https://auth.openai.com/api/accounts/oauth/token", + jwks_uri: "https://auth.openai.com/jwks", + revocation_endpoint: "https://auth.openai.com/revoke", + }), ); }), ), diff --git a/apps/server/src/provider/CodexManagedRuntime.ts b/apps/server/src/provider/CodexManagedRuntime.ts index f21cc6c3bcf3..371d02a97d29 100644 --- a/apps/server/src/provider/CodexManagedRuntime.ts +++ b/apps/server/src/provider/CodexManagedRuntime.ts @@ -4,8 +4,13 @@ import * as Effect from "effect/Effect"; import * as FileSystem from "effect/FileSystem"; import * as Path from "effect/Path"; import * as Schema from "effect/Schema"; +import * as Scope from "effect/Scope"; import * as ServerConfig from "../config.ts"; import * as CodexInstallation from "./CodexInstallation.ts"; +import { + makeCodexManagedTokenSource, + managedCodexTokenCommand, +} from "./CodexManagedTokenSource.ts"; import { makeCodexChatGptAuth } from "./CodexChatGptAuth.ts"; import { materializeCodexShadowHome } from "./Drivers/CodexHomeLayout.ts"; @@ -22,12 +27,15 @@ const managedCodexLaunchArgs = [ 'model_providers.openai_token_sharing.base_url="https://api.openai.com/v1"', 'model_providers.openai_token_sharing.model_catalog_url="https://api.openai.com/v1/models"', "features.api_key_model_discovery=true", - 'model_providers.openai_token_sharing.env_key="ACCESS_TOKEN"', + `model_providers.openai_token_sharing.auth.command=${JSON.stringify(process.execPath)}`, + `model_providers.openai_token_sharing.auth.args=${JSON.stringify(["-e", managedCodexTokenCommand])}`, + "model_providers.openai_token_sharing.auth.timeout_ms=25000", + "model_providers.openai_token_sharing.auth.refresh_interval_ms=30000", 'model_providers.openai_token_sharing.wire_api="responses"', "model_providers.openai_token_sharing.requires_openai_auth=false", "model_providers.openai_token_sharing.supports_websockets=false", ] - .map((value) => `-c '${value}'`) + .map((value) => `-c '${value.replaceAll("'", "'\"'\"'")}'`) .join(" "); export const makeCodexManagedRuntime = Effect.fn("makeCodexManagedRuntime")(function* (options: { @@ -47,6 +55,11 @@ export const makeCodexManagedRuntime = Effect.fn("makeCodexManagedRuntime")(func config.devUrl ?? `http://localhost:${config.port}`, ).toString(), }); + const scope = yield* Scope.Scope; + const tokenSource = yield* makeCodexManagedTokenSource(options.instanceId, auth.access).pipe( + Effect.provideService(Scope.Scope, scope), + Effect.cached, + ); const homeLayout = yield* resolveManagedCodexHomeLayout( config.stateDir, options.instanceId, @@ -65,6 +78,7 @@ export const makeCodexManagedRuntime = Effect.fn("makeCodexManagedRuntime")(func ), ); const credentials = yield* auth.access; + const source = yield* tokenSource; yield* materializeCodexShadowHome(homeLayout).pipe( Effect.provideService(FileSystem.FileSystem, fs), Effect.provideService(Path.Path, path), @@ -90,9 +104,13 @@ export const makeCodexManagedRuntime = Effect.fn("makeCodexManagedRuntime")(func // Ambient CLI overrides cannot redirect a T3-owned token to a different provider. const environment: NodeJS.ProcessEnv = { ...options.environment, - ACCESS_TOKEN: credentials.accessToken, + T3CODE_MANAGED_CODEX_AUTH_URL: source.url, + T3CODE_MANAGED_CODEX_AUTH_SECRET: source.secret, + T3CODE_MANAGED_CODEX_AUTH_ACCOUNT: credentials.clientId, + ...(process.versions.electron ? { ELECTRON_RUN_AS_NODE: "1" } : {}), CODEX_HOME: homePath, }; + delete environment.ACCESS_TOKEN; delete environment.T3CODE_CODEX_LAUNCH_ARGS; delete environment.OPENAI_API_KEY; delete environment.OPENAI_BASE_URL; diff --git a/apps/server/src/provider/CodexManagedTokenSource.ts b/apps/server/src/provider/CodexManagedTokenSource.ts new file mode 100644 index 000000000000..7a6c379841d6 --- /dev/null +++ b/apps/server/src/provider/CodexManagedTokenSource.ts @@ -0,0 +1,94 @@ +// @effect-diagnostics nodeBuiltinImport:off - scope-owned loopback bridge for Codex's credential command. +import * as NodeCrypto from "node:crypto"; +import * as NodeHttp from "node:http"; +import { ProviderSetupError, type ProviderInstanceId } from "@t3tools/contracts"; +import * as Effect from "effect/Effect"; + +// Codex invokes this command again when its cached bearer expires or receives a 401. +// The child receives a bridge credential, never a fixed copy of the provider token. +export const managedCodexTokenCommand = ` +fetch(process.env.T3CODE_MANAGED_CODEX_AUTH_URL, { + headers: { Authorization: "Bearer " + process.env.T3CODE_MANAGED_CODEX_AUTH_SECRET, + "X-T3-Codex-Account": process.env.T3CODE_MANAGED_CODEX_AUTH_ACCOUNT }, +}).then(async response => { + if (!response.ok) throw new Error(); + process.stdout.write(await response.text()); +}).catch(() => { + process.stderr.write("Could not renew managed Codex credentials.\\n"); + process.exitCode = 1; +}); +`; + +export const makeCodexManagedTokenSource = Effect.fn("makeCodexManagedTokenSource")(function* ( + instanceId: ProviderInstanceId, + access: Effect.Effect< + { readonly accessToken: string; readonly clientId: string }, + ProviderSetupError + >, +) { + const context = yield* Effect.context(); + const runPromise = Effect.runPromiseWith(context); + const secret = NodeCrypto.randomBytes(32).toString("base64url"); + const server = yield* Effect.acquireRelease( + Effect.tryPromise({ + try: () => + new Promise((resolve, reject) => { + const server = NodeHttp.createServer((request, response) => { + if (request.method !== "GET" || request.url !== "/token") { + response.writeHead(404).end(); + return; + } + if (request.headers.authorization !== `Bearer ${secret}`) { + response.writeHead(401).end(); + return; + } + const abort = new AbortController(); + response.once("close", () => abort.abort()); + void runPromise(access, { signal: abort.signal }).then( + (credentials) => { + if (response.destroyed) return; + if (request.headers["x-t3-codex-account"] !== credentials.clientId) { + response.writeHead(409).end(); + return; + } + if (!response.destroyed) + response + .writeHead(200, { + "content-type": "text/plain", + "cache-control": "no-store", + }) + .end(credentials.accessToken); + }, + () => { + if (!response.destroyed) response.writeHead(503).end(); + }, + ); + }); + server.once("error", reject); + server.listen(0, "127.0.0.1", () => resolve(server)); + }), + catch: () => + new ProviderSetupError({ + instanceId, + operation: "runtime", + detail: "Could not start the managed Codex credential bridge.", + }), + }), + (server) => + Effect.promise( + () => + new Promise((resolve) => { + server.closeAllConnections(); + server.close(() => resolve()); + }), + ), + ); + const address = server.address(); + if (address === null || typeof address === "string") + return yield* new ProviderSetupError({ + instanceId, + operation: "runtime", + detail: "Could not resolve the managed Codex credential bridge.", + }); + return { url: `http://127.0.0.1:${address.port}/token`, secret }; +}); From fd8db67407188129eb8e505b057a77a32aa43d1b Mon Sep 17 00:00:00 2001 From: luke <97411838+luke2x@users.noreply.github.com> Date: Sat, 10 Oct 2026 23:14:55 +0100 Subject: [PATCH 2/6] fix(codex): renew managed credentials through a T3 subcommand The credential command ran `process.execPath -e