import { createHash } from "node:crypto"; import { chmodSync, copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs"; import { homedir } from "node:os"; import { join } from "node:path"; import type { UniDeskConfig } from "./config"; import { rootPath } from "./config"; import { runSshCommandCapture, type SshCaptureResult } from "./ssh"; const g14K3sRoute = "G14:k3s"; const namespace = "platform-infra"; const serviceName = "sub2api"; const serviceDns = `${serviceName}.${namespace}.svc.cluster.local:8080`; const fieldManager = "unidesk-platform-infra"; const appSecretName = "sub2api-secrets"; const codexPoolConfigPath = rootPath("config", "platform-infra", "sub2api-codex-pool.yaml"); const defaultPoolGroupName = "unidesk-codex-pool"; const defaultPoolApiKeyName = "unidesk-codex-pool-api-key"; const defaultPoolApiKeySecretName = "sub2api-codex-pool-api-key"; const defaultPoolApiKeySecretKey = "API_KEY"; const defaultMinOwnerBalanceUsd = 1000; interface DisclosureOptions { full: boolean; raw: boolean; } interface SyncOptions extends DisclosureOptions { confirm: boolean; } interface ConfirmOptions extends DisclosureOptions { confirm: boolean; } interface CodexProfile { profile: string; accountName: string; configFile: string; authFile: string; provider: string; baseUrl: string; wireApi: string | null; model: string | null; envKey: string | null; apiKey: string | null; apiKeySource: "auth-json" | "env" | null; openaiResponsesWebSocketsV2Mode: OpenAIResponsesWebSocketsV2Mode | null; upstreamUserAgent: string | null; priority: number; capacity: number; authOpenAIKeyShape: string; ok: boolean; error: string | null; } type OpenAIResponsesWebSocketsV2Mode = "off" | "ctx_pool" | "passthrough"; interface CodexPoolConfig { groupName: string; apiKeyName: string; apiKeySecretName: string; apiKeySecretKey: string; minOwnerBalanceUsd: number; defaultAccountCapacity: number; profiles: CodexPoolProfileConfig[]; publicExposure: CodexPoolPublicExposureConfig; localCodex: CodexPoolLocalCodexConfig; } interface CodexPoolProfileConfig { profile: string; accountName: string | null; configFile: string; authFile: string; fallbackConfigFile: string | null; fallbackAuthFile: string | null; openaiResponsesWebSocketsV2Mode: OpenAIResponsesWebSocketsV2Mode | null; upstreamUserAgent: string | null; priority: number; capacity: number | null; } interface CodexPoolPublicExposureConfig { enabled: boolean; proxyName: string; configMapName: string; deploymentName: string; frpcImage: string; serverAddr: string; serverPort: number; remotePort: number; localIP: string; localPort: number; publicBaseUrl: string; masterBaseUrl: string; masterFrps: { configPath: string; containerName: string; }; } interface CodexPoolLocalCodexConfig { backupSuffix: string; providerName: string; wireApi: string; } export function codexPoolHelp(): unknown { const pool = readCodexPoolConfig(); return { command: "platform-infra sub2api codex-pool plan|sync|validate|expose|configure-local", output: "json", usage: [ "bun scripts/cli.ts platform-infra sub2api codex-pool plan", "bun scripts/cli.ts platform-infra sub2api codex-pool sync --confirm", "bun scripts/cli.ts platform-infra sub2api codex-pool validate [--full|--raw]", "bun scripts/cli.ts platform-infra sub2api codex-pool expose --confirm", "bun scripts/cli.ts platform-infra sub2api codex-pool configure-local --confirm", ], description: "Import YAML-selected ~/.codex API-key profiles into one Sub2API OpenAI pool, expose one unified API_KEY, and optionally configure this master server's ~/.codex consumer endpoint.", target: { route: g14K3sRoute, namespace, serviceDns, configPath: codexPoolConfigPath, poolGroupName: pool.groupName, poolApiKeySecretName: pool.apiKeySecretName, poolApiKeySecretKey: pool.apiKeySecretKey, publicBaseUrl: pool.publicExposure.enabled ? pool.publicExposure.publicBaseUrl : null, masterBaseUrl: pool.publicExposure.enabled ? pool.publicExposure.masterBaseUrl : null, secretValuesPrinted: false, }, }; } export async function runCodexPoolCommand(config: UniDeskConfig, args: string[]): Promise> { const [action = "plan"] = args; if (action === "plan") return codexPoolPlan(); if (action === "sync") return await codexPoolSync(config, parseSyncOptions(args.slice(1))); if (action === "validate") return await codexPoolValidate(config, parseDisclosureOptions(args.slice(1))); if (action === "expose") return await codexPoolExpose(config, parseConfirmOptions(args.slice(1))); if (action === "configure-local") return await codexPoolConfigureLocal(config, parseConfirmOptions(args.slice(1))); return { ok: false, error: "unsupported-platform-infra-sub2api-codex-pool-command", args, help: codexPoolHelp(), }; } function parseSyncOptions(args: string[]): SyncOptions { validateOptions(args, new Set(["--confirm", "--full", "--raw"])); const disclosure = parseDisclosureOptions(args.filter((arg) => arg !== "--confirm")); return { ...disclosure, confirm: args.includes("--confirm") }; } function parseConfirmOptions(args: string[]): ConfirmOptions { validateOptions(args, new Set(["--confirm", "--full", "--raw"])); const disclosure = parseDisclosureOptions(args.filter((arg) => arg !== "--confirm")); return { ...disclosure, confirm: args.includes("--confirm") }; } function parseDisclosureOptions(args: string[]): DisclosureOptions { validateOptions(args, new Set(["--full", "--raw"])); const raw = args.includes("--raw"); return { full: raw || args.includes("--full"), raw }; } function validateOptions(args: string[], booleanOptions: Set): void { for (const arg of args) { if (booleanOptions.has(arg)) continue; throw new Error(`unsupported option: ${arg}`); } } function codexPoolPlan(): Record { const pool = readCodexPoolConfig(); const profiles = collectCodexProfiles(); const ok = profiles.length > 0 && profiles.every((profile) => profile.ok); return { ok, action: "platform-infra-sub2api-codex-pool-plan", source: { directory: join(homedir(), ".codex"), configPattern: "YAML-selected config files under ~/.codex", authPattern: "YAML-selected auth files under ~/.codex", valuesPrinted: false, }, target: poolTarget(), config: { path: codexPoolConfigPath, pool, }, profiles: profiles.map(redactProfile), decision: { accountType: "openai/apikey", grouping: `All discovered Codex profiles are bound to one Sub2API group named ${pool.groupName}.`, unifiedApiKey: `The client-facing API_KEY is controlled by k3s Secret ${namespace}/${pool.apiKeySecretName}.${pool.apiKeySecretKey}.`, publicExposure: pool.publicExposure.enabled ? `Master server consumers use ${pool.publicExposure.masterBaseUrl}; FRP proxy ${pool.publicExposure.proxyName} maps public ${pool.publicExposure.publicBaseUrl} to ${pool.publicExposure.localIP}:${pool.publicExposure.localPort}.` : "Public FRP exposure is disabled by YAML.", idempotency: "sync reuses the group, account names, and k3s Secret when they already exist; credentials are updated from the current local Codex files; UniDesk-managed accounts removed from YAML are deleted from Sub2API.", configPolicy: "UniDesk-owned durable configuration remains YAML-first; local ~/.codex files and runtime Secrets are not committed.", }, next: ok ? { sync: "bun scripts/cli.ts platform-infra sub2api codex-pool sync --confirm" } : { fix: "Ensure every discovered config.toml profile has a base_url and either auth.json OPENAI_API_KEY or the configured env_key present in this shell." }, }; } async function codexPoolSync(config: UniDeskConfig, options: SyncOptions): Promise> { const pool = readCodexPoolConfig(); const profiles = collectCodexProfiles(); const planOk = profiles.length > 0 && profiles.every((profile) => profile.ok); if (!options.confirm || !planOk) { return { ...codexPoolPlan(), ok: !options.confirm ? planOk : false, mode: options.confirm ? "blocked-invalid-local-profile" : "dry-run", next: options.confirm ? { fix: "Repair invalid local Codex profiles, then rerun sync --confirm." } : { confirm: "bun scripts/cli.ts platform-infra sub2api codex-pool sync --confirm" }, }; } const payload = { pool: { groupName: pool.groupName, apiKeyName: pool.apiKeyName, apiKeySecretName: pool.apiKeySecretName, apiKeySecretKey: pool.apiKeySecretKey, minOwnerBalanceUsd: pool.minOwnerBalanceUsd, defaultAccountCapacity: pool.defaultAccountCapacity, }, profiles: profiles.map((profile) => ({ profile: profile.profile, accountName: profile.accountName, configFile: profile.configFile, authFile: profile.authFile, provider: profile.provider, baseUrl: profile.baseUrl, wireApi: profile.wireApi, model: profile.model, apiKey: profile.apiKey, apiKeySource: profile.apiKeySource, apiKeyFingerprint: fingerprint(profile.apiKey ?? ""), openaiResponsesWebSocketsV2Mode: profile.openaiResponsesWebSocketsV2Mode, upstreamUserAgent: profile.upstreamUserAgent, priority: profile.priority, capacity: profile.capacity, })), }; const result = await capture(config, g14K3sRoute, ["script"], syncScript(payload, pool)); const parsed = parseJsonOutput(result.stdout); if (options.raw) { return { ok: result.exitCode === 0 && boolField(parsed, "ok", false), action: "platform-infra-sub2api-codex-pool-sync", remote: compactCapture(result, { full: true }), parsed, }; } return { ok: result.exitCode === 0 && boolField(parsed, "ok", false), action: "platform-infra-sub2api-codex-pool-sync", local: { profiles: profiles.map(redactProfile), valuesPrinted: false, }, remote: parsed ?? compactCapture(result, { full: options.full || result.exitCode !== 0 }), next: { validate: "bun scripts/cli.ts platform-infra sub2api codex-pool validate", }, }; } async function codexPoolValidate(config: UniDeskConfig, options: DisclosureOptions): Promise> { const pool = readCodexPoolConfig(); const result = await capture(config, g14K3sRoute, ["script"], validateScript(pool)); const parsed = parseJsonOutput(result.stdout); if (options.raw) { return { ok: result.exitCode === 0 && boolField(parsed, "ok", false), action: "platform-infra-sub2api-codex-pool-validate", remote: compactCapture(result, { full: true }), parsed, }; } return { ok: result.exitCode === 0 && boolField(parsed, "ok", false), action: "platform-infra-sub2api-codex-pool-validate", summary: parsed, remote: compactCapture(result, { full: options.full || result.exitCode !== 0 }), }; } async function codexPoolExpose(config: UniDeskConfig, options: ConfirmOptions): Promise> { const pool = readCodexPoolConfig(); if (!pool.publicExposure.enabled) { return { ok: true, action: "platform-infra-sub2api-codex-pool-expose", mode: "disabled-by-yaml", target: poolTarget(pool), }; } if (!options.confirm) { return { ok: true, action: "platform-infra-sub2api-codex-pool-expose", mode: "dry-run", target: poolTarget(pool), publicExposure: publicExposureSummary(pool), next: { confirm: "bun scripts/cli.ts platform-infra sub2api codex-pool expose --confirm", }, }; } const masterResult = await applyMasterFrpsAllowPort(pool); const remoteResult = await capture(config, g14K3sRoute, ["script"], exposeScript(pool)); const parsed = parseJsonOutput(remoteResult.stdout); const publicProbe = await probePublicModels(pool, "without-api-key"); const ok = masterResult.ok && remoteResult.exitCode === 0 && boolField(parsed, "ok", false) && publicProbe.httpStatus === 401; if (options.raw) { return { ok, action: "platform-infra-sub2api-codex-pool-expose", masterFrps: masterResult, remote: compactCapture(remoteResult, { full: true }), parsed, publicProbe, }; } return { ok, action: "platform-infra-sub2api-codex-pool-expose", mode: "confirmed", publicExposure: publicExposureSummary(pool), masterFrps: masterResult, remote: parsed ?? compactCapture(remoteResult, { full: options.full || remoteResult.exitCode !== 0 }), publicProbe, next: { configureLocal: "bun scripts/cli.ts platform-infra sub2api codex-pool configure-local --confirm", validate: "bun scripts/cli.ts platform-infra sub2api codex-pool validate", }, }; } async function codexPoolConfigureLocal(config: UniDeskConfig, options: ConfirmOptions): Promise> { const pool = readCodexPoolConfig(); const codexDir = join(homedir(), ".codex"); const configPath = join(codexDir, "config.toml"); const authPath = join(codexDir, "auth.json"); const backupConfigPath = join(codexDir, `config.toml.${pool.localCodex.backupSuffix}`); const backupAuthPath = join(codexDir, `auth.json.${pool.localCodex.backupSuffix}`); if (!options.confirm) { return { ok: true, action: "platform-infra-sub2api-codex-pool-configure-local", mode: "dry-run", target: { codexDir, configPath, authPath, backupConfigPath, backupAuthPath, baseUrl: pool.publicExposure.masterBaseUrl, providerName: pool.localCodex.providerName, wireApi: pool.localCodex.wireApi, valuesPrinted: false, }, next: { confirm: "bun scripts/cli.ts platform-infra sub2api codex-pool configure-local --confirm", }, }; } if (!pool.publicExposure.enabled) throw new Error(`${codexPoolConfigPath}.publicExposure.enabled must be true before configure-local`); const keyResult = await fetchPoolApiKey(config, pool); if (keyResult.apiKey === null) { return { ok: false, action: "platform-infra-sub2api-codex-pool-configure-local", error: keyResult.error ?? "pool API key missing", valuesPrinted: false, }; } const writeResult = writeLocalCodexConfig(pool, keyResult.apiKey); const validateResult = await validatePublicGatewayWithKey(pool, keyResult.apiKey); return { ok: writeResult.ok && validateResult.ok, action: "platform-infra-sub2api-codex-pool-configure-local", mode: "confirmed", local: writeResult, validation: validateResult, apiKey: { secret: `${namespace}/${pool.apiKeySecretName}.${pool.apiKeySecretKey}`, keyPreview: apiKeyPreview(keyResult.apiKey), apiKeyFingerprint: fingerprint(keyResult.apiKey), valuesPrinted: false, }, }; } function collectCodexProfiles(): CodexProfile[] { const codexDir = join(homedir(), ".codex"); const pool = readCodexPoolConfig(); if (!existsSync(codexDir)) return []; const seenAccountNames = new Set(); const configs = pool.profiles.length > 0 ? pool.profiles : discoverCodexProfileConfigs(codexDir); return configs.map((entry) => { const resolved = resolveProfileFiles(codexDir, entry); const profile = entry.profile; const accountName = entry.accountName ?? uniqueAccountName(profile, seenAccountNames); seenAccountNames.add(accountName); const configFile = resolved.configFile; const authFile = resolved.authFile; const configPath = join(codexDir, configFile); const authPath = join(codexDir, authFile); const base: CodexProfile = { profile, accountName, configFile, authFile, provider: "", baseUrl: "", wireApi: null, model: null, envKey: null, apiKey: null, apiKeySource: null, openaiResponsesWebSocketsV2Mode: entry.openaiResponsesWebSocketsV2Mode, upstreamUserAgent: entry.upstreamUserAgent, priority: entry.priority, capacity: entry.capacity ?? pool.defaultAccountCapacity, authOpenAIKeyShape: existsSync(authPath) ? "unknown" : "missing", ok: false, error: null, }; try { if (!existsSync(configPath)) throw new Error(`config file ${configFile} is missing`); const parsed = Bun.TOML.parse(readFileSync(configPath, "utf8")) as unknown; if (!isRecord(parsed)) throw new Error("config is not a TOML object"); const providers = parsed.model_providers; if (!isRecord(providers)) throw new Error("model_providers is missing"); const provider = stringValue(parsed.model_provider) ?? Object.keys(providers)[0] ?? ""; if (provider === "") throw new Error("model_provider is missing"); const providerConfig = providers[provider]; if (!isRecord(providerConfig)) throw new Error(`model provider ${provider} is missing`); const baseUrl = normalizeBaseUrl(stringValue(providerConfig.base_url)); if (baseUrl === null) throw new Error(`model provider ${provider} base_url is missing or invalid`); base.provider = provider; base.baseUrl = baseUrl; base.envKey = stringValue(providerConfig.env_key); base.wireApi = stringValue(providerConfig.wire_api); base.model = stringValue(parsed.model); const auth = readAuthAPIKey(authPath); base.authOpenAIKeyShape = auth.shape; if (auth.apiKey !== null) { base.apiKey = auth.apiKey; base.apiKeySource = "auth-json"; } else if (base.envKey !== null && typeof process.env[base.envKey] === "string" && process.env[base.envKey]!.length > 0) { base.apiKey = process.env[base.envKey]!; base.apiKeySource = "env"; } if (base.apiKey === null || base.apiKey.length === 0) { throw new Error(base.envKey === null ? "auth OPENAI_API_KEY is missing or empty" : `auth OPENAI_API_KEY is missing and env ${base.envKey} is not present`); } base.ok = true; return base; } catch (error) { base.error = error instanceof Error ? error.message : String(error); return base; } }); } function discoverCodexProfileConfigs(codexDir: string): CodexPoolProfileConfig[] { return readdirSync(codexDir) .filter((file) => file === "config.toml" || file.startsWith("config.toml.")) .sort((a, b) => { if (a === "config.toml") return -1; if (b === "config.toml") return 1; return a.localeCompare(b); }) .map((configFile) => { const suffix = configFile === "config.toml" ? "" : configFile.slice("config.toml.".length); const profile = suffix === "" ? "default" : suffix; return { profile, accountName: null, configFile, authFile: suffix === "" ? "auth.json" : `auth.json.${suffix}`, fallbackConfigFile: null, fallbackAuthFile: null, openaiResponsesWebSocketsV2Mode: null, upstreamUserAgent: null, priority: 1, capacity: null, }; }); } function resolveProfileFiles(codexDir: string, profile: CodexPoolProfileConfig): { configFile: string; authFile: string } { const configFile = existsSync(join(codexDir, profile.configFile)) || profile.fallbackConfigFile === null ? profile.configFile : profile.fallbackConfigFile; const authFile = existsSync(join(codexDir, profile.authFile)) || profile.fallbackAuthFile === null ? profile.authFile : profile.fallbackAuthFile; return { configFile, authFile }; } function readCodexPoolConfig(): CodexPoolConfig { const defaults = defaultCodexPoolConfig(); if (!existsSync(codexPoolConfigPath)) return defaults; const parsed = Bun.YAML.parse(readFileSync(codexPoolConfigPath, "utf8")) as unknown; if (!isRecord(parsed)) throw new Error(`${codexPoolConfigPath} must contain a YAML object`); const pool = parsed.pool; if (!isRecord(pool)) throw new Error(`${codexPoolConfigPath}.pool must be a YAML object`); const config: CodexPoolConfig = { groupName: stringValue(pool.groupName) ?? defaults.groupName, apiKeyName: stringValue(pool.apiKeyName) ?? defaults.apiKeyName, apiKeySecretName: stringValue(pool.apiKeySecretName) ?? defaults.apiKeySecretName, apiKeySecretKey: stringValue(pool.apiKeySecretKey) ?? defaults.apiKeySecretKey, minOwnerBalanceUsd: numberValue(pool.minOwnerBalanceUsd) ?? defaults.minOwnerBalanceUsd, defaultAccountCapacity: readAccountCapacity(pool.defaultAccountCapacity, "pool.defaultAccountCapacity"), profiles: readProfileConfig(parsed.profiles, defaults.profiles), publicExposure: readPublicExposureConfig(parsed.publicExposure, defaults.publicExposure), localCodex: readLocalCodexConfig(parsed.localCodex, defaults.localCodex), }; validateKubernetesName(config.groupName, "pool.groupName", false); validateKubernetesName(config.apiKeySecretName, "pool.apiKeySecretName", true); if (!/^[A-Za-z_][A-Za-z0-9_]*$/u.test(config.apiKeySecretKey)) { throw new Error(`${codexPoolConfigPath}.pool.apiKeySecretKey must be a valid secret key name`); } if (config.minOwnerBalanceUsd <= 0) throw new Error(`${codexPoolConfigPath}.pool.minOwnerBalanceUsd must be > 0`); return config; } function defaultCodexPoolConfig(): CodexPoolConfig { return { groupName: defaultPoolGroupName, apiKeyName: defaultPoolApiKeyName, apiKeySecretName: defaultPoolApiKeySecretName, apiKeySecretKey: defaultPoolApiKeySecretKey, minOwnerBalanceUsd: defaultMinOwnerBalanceUsd, defaultAccountCapacity: 5, profiles: [], publicExposure: { enabled: false, proxyName: "platform-infra-sub2api", configMapName: "sub2api-frpc-config", deploymentName: "sub2api-frpc", frpcImage: "fatedier/frpc:v0.68.1", serverAddr: "74.48.78.17", serverPort: 7000, remotePort: 21880, localIP: serviceDns.split(":")[0], localPort: 8080, publicBaseUrl: "http://74.48.78.17:21880", masterBaseUrl: "http://127.0.0.1:21880", masterFrps: { configPath: "/opt/hwlab-frp/frps.dev.toml", containerName: "hwlab-frps-dev", }, }, localCodex: { backupSuffix: "pre-sub2api", providerName: "OpenAI", wireApi: "responses", }, }; } function readProfileConfig(value: unknown, defaults: CodexPoolProfileConfig[]): CodexPoolProfileConfig[] { if (!isRecord(value)) return defaults; const entries = value.entries; if (!Array.isArray(entries)) throw new Error(`${codexPoolConfigPath}.profiles.entries must be a YAML array`); return entries.map((entry, index) => { if (!isRecord(entry)) throw new Error(`${codexPoolConfigPath}.profiles.entries[${index}] must be an object`); const profile = stringValue(entry.profile); const configFile = stringValue(entry.configFile); const authFile = stringValue(entry.authFile); if (profile === null || configFile === null || authFile === null) { throw new Error(`${codexPoolConfigPath}.profiles.entries[${index}] requires profile, configFile, and authFile`); } const accountName = stringValue(entry.accountName); if (accountName !== null) validateKubernetesName(accountName, `profiles.entries[${index}].accountName`, false); validateCodexFileName(configFile, `profiles.entries[${index}].configFile`); validateCodexFileName(authFile, `profiles.entries[${index}].authFile`); const fallbackConfigFile = stringValue(entry.fallbackConfigFile); const fallbackAuthFile = stringValue(entry.fallbackAuthFile); if (fallbackConfigFile !== null) validateCodexFileName(fallbackConfigFile, `profiles.entries[${index}].fallbackConfigFile`); if (fallbackAuthFile !== null) validateCodexFileName(fallbackAuthFile, `profiles.entries[${index}].fallbackAuthFile`); const openaiResponsesWebSocketsV2Mode = readOpenAIResponsesWebSocketsV2Mode(entry.openaiResponsesWebSocketsV2Mode, `profiles.entries[${index}].openaiResponsesWebSocketsV2Mode`); const upstreamUserAgent = readUpstreamUserAgent(entry.upstreamUserAgent, `profiles.entries[${index}].upstreamUserAgent`); const priority = readAccountPriority(entry.priority, `profiles.entries[${index}].priority`); const capacity = entry.capacity === undefined || entry.capacity === null ? null : readAccountCapacity(entry.capacity, `profiles.entries[${index}].capacity`); return { profile, accountName, configFile, authFile, fallbackConfigFile, fallbackAuthFile, openaiResponsesWebSocketsV2Mode, upstreamUserAgent, priority, capacity, }; }); } function readOpenAIResponsesWebSocketsV2Mode(value: unknown, key: string): OpenAIResponsesWebSocketsV2Mode | null { if (value === undefined || value === null) return null; const text = stringValue(value); if (text === null) throw new Error(`${codexPoolConfigPath}.${key} must be a string`); if (text === "off" || text === "ctx_pool" || text === "passthrough") return text; throw new Error(`${codexPoolConfigPath}.${key} must be one of off, ctx_pool, passthrough`); } function readUpstreamUserAgent(value: unknown, key: string): string | null { if (value === undefined || value === null) return null; const text = stringValue(value); if (text === null) throw new Error(`${codexPoolConfigPath}.${key} must be a string`); if (text.length > 512) throw new Error(`${codexPoolConfigPath}.${key} must be at most 512 characters`); if (/[\r\n]/u.test(text)) throw new Error(`${codexPoolConfigPath}.${key} must not contain newlines`); return text; } function readAccountPriority(value: unknown, key: string): number { if (value === undefined || value === null) return 1; const priority = numberValue(value); if (priority === null || !Number.isInteger(priority) || priority < 0 || priority > 1000) { throw new Error(`${codexPoolConfigPath}.${key} must be an integer from 0 to 1000`); } return priority; } function readAccountCapacity(value: unknown, key: string): number { const capacity = numberValue(value); if (capacity === null || !Number.isInteger(capacity) || capacity < 1 || capacity > 1000) { throw new Error(`${codexPoolConfigPath}.${key} must be an integer from 1 to 1000`); } return capacity; } function readPublicExposureConfig(value: unknown, defaults: CodexPoolPublicExposureConfig): CodexPoolPublicExposureConfig { if (!isRecord(value)) return defaults; const masterFrpsValue = isRecord(value.masterFrps) ? value.masterFrps : {}; const config: CodexPoolPublicExposureConfig = { enabled: booleanValue(value.enabled) ?? defaults.enabled, proxyName: stringValue(value.proxyName) ?? defaults.proxyName, configMapName: stringValue(value.configMapName) ?? defaults.configMapName, deploymentName: stringValue(value.deploymentName) ?? defaults.deploymentName, frpcImage: stringValue(value.frpcImage) ?? defaults.frpcImage, serverAddr: stringValue(value.serverAddr) ?? defaults.serverAddr, serverPort: numberValue(value.serverPort) ?? defaults.serverPort, remotePort: numberValue(value.remotePort) ?? defaults.remotePort, localIP: stringValue(value.localIP) ?? defaults.localIP, localPort: numberValue(value.localPort) ?? defaults.localPort, publicBaseUrl: normalizeBaseUrl(stringValue(value.publicBaseUrl)) ?? defaults.publicBaseUrl, masterBaseUrl: normalizeBaseUrl(stringValue(value.masterBaseUrl)) ?? defaults.masterBaseUrl, masterFrps: { configPath: stringValue(masterFrpsValue.configPath) ?? defaults.masterFrps.configPath, containerName: stringValue(masterFrpsValue.containerName) ?? defaults.masterFrps.containerName, }, }; validateKubernetesName(config.configMapName, "publicExposure.configMapName", true); validateKubernetesName(config.deploymentName, "publicExposure.deploymentName", true); validateProxyName(config.proxyName, "publicExposure.proxyName"); validatePort(config.serverPort, "publicExposure.serverPort"); validatePort(config.remotePort, "publicExposure.remotePort"); validatePort(config.localPort, "publicExposure.localPort"); if (!/^[A-Za-z0-9._:/-]+$/u.test(config.frpcImage)) throw new Error(`${codexPoolConfigPath}.publicExposure.frpcImage has an unsupported format`); if (!/^[A-Za-z0-9._:-]+$/u.test(config.serverAddr)) throw new Error(`${codexPoolConfigPath}.publicExposure.serverAddr has an unsupported format`); if (!/^[A-Za-z0-9._:-]+$/u.test(config.localIP)) throw new Error(`${codexPoolConfigPath}.publicExposure.localIP has an unsupported format`); if (!config.masterFrps.configPath.startsWith("/")) throw new Error(`${codexPoolConfigPath}.publicExposure.masterFrps.configPath must be absolute`); validateProxyName(config.masterFrps.containerName, "publicExposure.masterFrps.containerName"); return config; } function readLocalCodexConfig(value: unknown, defaults: CodexPoolLocalCodexConfig): CodexPoolLocalCodexConfig { if (!isRecord(value)) return defaults; const config = { backupSuffix: stringValue(value.backupSuffix) ?? defaults.backupSuffix, providerName: stringValue(value.providerName) ?? defaults.providerName, wireApi: stringValue(value.wireApi) ?? defaults.wireApi, }; if (!/^[A-Za-z0-9._-]+$/u.test(config.backupSuffix)) throw new Error(`${codexPoolConfigPath}.localCodex.backupSuffix has an unsupported format`); validateProxyName(config.providerName, "localCodex.providerName"); validateProxyName(config.wireApi, "localCodex.wireApi"); return config; } function validateCodexFileName(value: string, key: string): void { if (!/^(config\.toml|config\.toml\.[A-Za-z0-9._-]+|auth\.json|auth\.json\.[A-Za-z0-9._-]+)$/u.test(value)) { throw new Error(`${codexPoolConfigPath}.${key} has an unsupported file name`); } } function validateProxyName(value: string, key: string): void { if (!/^[A-Za-z0-9._-]+$/u.test(value)) throw new Error(`${codexPoolConfigPath}.${key} has an unsupported format`); } function validatePort(value: number, key: string): void { if (!Number.isInteger(value) || value < 1 || value > 65535) throw new Error(`${codexPoolConfigPath}.${key} must be an integer port`); } function readAuthAPIKey(authPath: string): { apiKey: string | null; shape: string } { if (!existsSync(authPath)) return { apiKey: null, shape: "missing" }; const parsed = JSON.parse(readFileSync(authPath, "utf8")) as unknown; if (!isRecord(parsed)) return { apiKey: null, shape: "non-object" }; const value = parsed.OPENAI_API_KEY; const shape = value === null ? "null" : Array.isArray(value) ? "array" : typeof value; if (typeof value === "string" && value.length > 0) return { apiKey: value, shape }; return { apiKey: null, shape }; } function uniqueAccountName(profile: string, seen: Set): string { const normalized = profile .toLowerCase() .replace(/[^a-z0-9._-]+/gu, "-") .replace(/^-+|-+$/gu, "") || "default"; let candidate = `unidesk-codex-${normalized}`; let counter = 2; while (seen.has(candidate)) { candidate = `unidesk-codex-${normalized}-${counter}`; counter += 1; } seen.add(candidate); return candidate; } function redactProfile(profile: CodexProfile): Record { return { profile: profile.profile, accountName: profile.accountName, configFile: profile.configFile, authFile: profile.authFile, provider: profile.provider || null, baseUrl: profile.baseUrl || null, wireApi: profile.wireApi, model: profile.model, envKey: profile.envKey, apiKeySource: profile.apiKeySource, openaiResponsesWebSocketsV2Mode: profile.openaiResponsesWebSocketsV2Mode, upstreamUserAgent: profile.upstreamUserAgent, priority: profile.priority, capacity: profile.capacity, apiKeyPresent: profile.apiKey !== null && profile.apiKey.length > 0, apiKeyBytes: profile.apiKey === null ? 0 : Buffer.byteLength(profile.apiKey, "utf8"), apiKeyFingerprint: profile.apiKey === null ? null : fingerprint(profile.apiKey), authOpenAIKeyShape: profile.authOpenAIKeyShape, ok: profile.ok, error: profile.error, valuesPrinted: false, }; } function poolTarget(pool = readCodexPoolConfig()): Record { return { route: g14K3sRoute, namespace, service: serviceName, serviceDns, configPath: codexPoolConfigPath, groupName: pool.groupName, apiKeyName: pool.apiKeyName, apiKeySecret: `${namespace}/${pool.apiKeySecretName}.${pool.apiKeySecretKey}`, defaultAccountCapacity: pool.defaultAccountCapacity, valuesPrinted: false, }; } function publicExposureSummary(pool: CodexPoolConfig): Record { return { enabled: pool.publicExposure.enabled, proxyName: pool.publicExposure.proxyName, namespace, configMapName: pool.publicExposure.configMapName, deploymentName: pool.publicExposure.deploymentName, frpcImage: pool.publicExposure.frpcImage, frps: { serverAddr: pool.publicExposure.serverAddr, serverPort: pool.publicExposure.serverPort, remotePort: pool.publicExposure.remotePort, masterConfigPath: pool.publicExposure.masterFrps.configPath, masterContainerName: pool.publicExposure.masterFrps.containerName, }, upstream: { localIP: pool.publicExposure.localIP, localPort: pool.publicExposure.localPort, serviceDns, }, urls: { publicBaseUrl: pool.publicExposure.publicBaseUrl, masterBaseUrl: pool.publicExposure.masterBaseUrl, }, }; } async function applyMasterFrpsAllowPort(pool: CodexPoolConfig): Promise> { const path = pool.publicExposure.masterFrps.configPath; const port = pool.publicExposure.remotePort; const container = pool.publicExposure.masterFrps.containerName; if (!existsSync(path)) { return { ok: false, error: "master-frps-config-missing", path, valuesPrinted: false }; } const before = readFileSync(path, "utf8"); const alreadyAllowed = frpsAllowPortExists(before, port); let backupPath: string | null = null; let action = "kept-existing"; if (!alreadyAllowed) { const stamp = new Date().toISOString().replace(/[-:]/gu, "").replace(/\..*$/u, "Z"); backupPath = `${path}.bak-sub2api-${stamp}`; copyFileSync(path, backupPath); const next = before.replace(/\s*$/u, "") + `\n\n[[allowPorts]]\nstart = ${port}\nend = ${port}\n`; writeFileSync(path, next, "utf8"); chmodSync(path, statSync(backupPath).mode & 0o777); action = "added-allow-port"; } const restart = alreadyAllowed ? null : Bun.spawnSync(["docker", "restart", container]); const inspect = Bun.spawnSync(["docker", "inspect", "-f", "{{.State.Running}}", container]); const ok = alreadyAllowed || (restart?.exitCode === 0 && inspect.exitCode === 0 && String(inspect.stdout).trim() === "true"); return { ok, action, path, backupPath, remotePort: port, containerName: container, restart: restart === null ? null : { exitCode: restart.exitCode, stdoutTail: Buffer.from(restart.stdout).toString("utf8").slice(-1000), stderrTail: Buffer.from(restart.stderr).toString("utf8").slice(-1000), }, inspect: { exitCode: inspect.exitCode, running: String(inspect.stdout).trim() === "true", stderrTail: Buffer.from(inspect.stderr).toString("utf8").slice(-1000), }, valuesPrinted: false, }; } function frpsAllowPortExists(toml: string, port: number): boolean { const sections = toml.split(/(?=\[\[allowPorts\]\])/u); return sections.some((section) => { if (!section.includes("[[allowPorts]]")) return false; const start = section.match(/^\s*start\s*=\s*(\d+)\s*$/mu); const end = section.match(/^\s*end\s*=\s*(\d+)\s*$/mu); return Number(start?.[1]) === port && Number(end?.[1]) === port; }); } function exposeScript(pool: CodexPoolConfig): string { const manifest = frpcManifest(pool); const encoded = Buffer.from(manifest, "utf8").toString("base64"); return ` set -u tmp="$(mktemp -d)" trap 'rm -rf "$tmp"' EXIT manifest="$tmp/sub2api-frpc.yaml" printf '%s' '${encoded}' | base64 -d > "$manifest" ns_out="$tmp/ns.out" ns_err="$tmp/ns.err" apply_out="$tmp/apply.out" apply_err="$tmp/apply.err" rollout_out="$tmp/rollout.out" rollout_err="$tmp/rollout.err" kubectl get namespace ${namespace} >"$ns_out" 2>"$ns_err" ns_rc=$? apply_rc=1 rollout_rc=1 if [ "$ns_rc" -eq 0 ]; then kubectl apply --server-side --force-conflicts --field-manager=${fieldManager} -f "$manifest" >"$apply_out" 2>"$apply_err" apply_rc=$? if [ "$apply_rc" -eq 0 ]; then kubectl -n ${namespace} rollout status deployment/${pool.publicExposure.deploymentName} --timeout=30s >"$rollout_out" 2>"$rollout_err" rollout_rc=$? else printf '%s\\n' 'skipped because apply failed' >"$rollout_err" fi else : >"$apply_out" printf '%s\\n' 'skipped because namespace is missing' >"$apply_err" : >"$rollout_out" printf '%s\\n' 'skipped because namespace is missing' >"$rollout_err" fi pods_json="$tmp/pods.json" pods_err="$tmp/pods.err" kubectl -n ${namespace} get pods -l app.kubernetes.io/name=${pool.publicExposure.deploymentName} -o json >"$pods_json" 2>"$pods_err" pods_rc=$? logs_out="$tmp/logs.out" logs_err="$tmp/logs.err" kubectl -n ${namespace} logs deployment/${pool.publicExposure.deploymentName} --tail=80 >"$logs_out" 2>"$logs_err" logs_rc=$? python3 - "$tmp" "$ns_rc" "$apply_rc" "$rollout_rc" "$pods_rc" "$logs_rc" <<'PY' import json import os import sys tmp = sys.argv[1] ns_rc, apply_rc, rollout_rc, pods_rc, logs_rc = [int(value) for value in sys.argv[2:]] def text(name, limit=4000): path = os.path.join(tmp, name) try: return open(path, encoding="utf-8", errors="replace").read()[-limit:] except FileNotFoundError: return "" def load_json(name): path = os.path.join(tmp, name) try: return json.load(open(path, encoding="utf-8")) except Exception: return None pods_obj = load_json("pods.json") pods = [] if isinstance(pods_obj, dict): for item in pods_obj.get("items") or []: status = item.get("status") or {} statuses = status.get("containerStatuses") or [] pods.append({ "name": item.get("metadata", {}).get("name"), "phase": status.get("phase"), "ready": all(cs.get("ready") is True for cs in statuses) if statuses else False, "restarts": sum(int(cs.get("restartCount") or 0) for cs in statuses), }) logs = text("logs.out", 4000) payload = { "ok": ns_rc == 0 and apply_rc == 0 and rollout_rc == 0 and pods_rc == 0 and len(pods) > 0 and all(p["ready"] for p in pods), "namespace": "${namespace}", "proxy": { "name": "${pool.publicExposure.proxyName}", "remotePort": ${JSON.stringify(pool.publicExposure.remotePort)}, "publicBaseUrl": "${pool.publicExposure.publicBaseUrl}", "masterBaseUrl": "${pool.publicExposure.masterBaseUrl}", "localIP": "${pool.publicExposure.localIP}", "localPort": ${JSON.stringify(pool.publicExposure.localPort)}, }, "resources": { "configMap": "${pool.publicExposure.configMapName}", "deployment": "${pool.publicExposure.deploymentName}", "image": "${pool.publicExposure.frpcImage}", }, "steps": { "namespace": {"exitCode": ns_rc, "stdout": text("ns.out"), "stderr": text("ns.err")}, "apply": {"exitCode": apply_rc, "stdout": text("apply.out"), "stderr": text("apply.err")}, "rollout": {"exitCode": rollout_rc, "stdout": text("rollout.out"), "stderr": text("rollout.err")}, "pods": {"exitCode": pods_rc, "items": pods, "stderr": text("pods.err")}, "logs": { "exitCode": logs_rc, "startProxySuccess": "start proxy success" in logs, "stdoutTail": logs, "stderrTail": text("logs.err"), }, }, } print(json.dumps(payload, ensure_ascii=False, indent=2)) sys.exit(0 if payload["ok"] else 1) PY `; } function frpcManifest(pool: CodexPoolConfig): string { return `apiVersion: v1 kind: ConfigMap metadata: name: ${pool.publicExposure.configMapName} namespace: ${namespace} labels: app.kubernetes.io/name: ${pool.publicExposure.deploymentName} app.kubernetes.io/part-of: platform-infra app.kubernetes.io/managed-by: unidesk data: frpc.toml: | serverAddr = "${pool.publicExposure.serverAddr}" serverPort = ${pool.publicExposure.serverPort} loginFailExit = true [[proxies]] name = "${pool.publicExposure.proxyName}" type = "tcp" localIP = "${pool.publicExposure.localIP}" localPort = ${pool.publicExposure.localPort} remotePort = ${pool.publicExposure.remotePort} --- apiVersion: apps/v1 kind: Deployment metadata: name: ${pool.publicExposure.deploymentName} namespace: ${namespace} labels: app.kubernetes.io/name: ${pool.publicExposure.deploymentName} app.kubernetes.io/part-of: platform-infra app.kubernetes.io/managed-by: unidesk spec: replicas: 1 selector: matchLabels: app.kubernetes.io/name: ${pool.publicExposure.deploymentName} template: metadata: labels: app.kubernetes.io/name: ${pool.publicExposure.deploymentName} app.kubernetes.io/part-of: platform-infra app.kubernetes.io/managed-by: unidesk spec: containers: - name: frpc image: ${pool.publicExposure.frpcImage} imagePullPolicy: IfNotPresent args: - -c - /etc/frp/frpc.toml volumeMounts: - name: config mountPath: /etc/frp readOnly: true volumes: - name: config configMap: name: ${pool.publicExposure.configMapName} `; } async function fetchPoolApiKey(config: UniDeskConfig, pool: CodexPoolConfig): Promise<{ apiKey: string | null; error: string | null }> { const result = await capture(config, g14K3sRoute, ["script"], ` set -u kubectl -n ${namespace} get secret ${pool.apiKeySecretName} -o json `); if (result.exitCode !== 0) { return { apiKey: null, error: `read pool API key secret failed: ${result.stderr.slice(-1000)}` }; } const parsed = parseJsonOutput(result.stdout); const data = isRecord(parsed?.data) ? parsed.data : null; const encoded = typeof data?.[pool.apiKeySecretKey] === "string" ? data[pool.apiKeySecretKey] : null; if (encoded === null) return { apiKey: null, error: `${namespace}/${pool.apiKeySecretName}.${pool.apiKeySecretKey} missing` }; try { const apiKey = Buffer.from(encoded, "base64").toString("utf8"); return apiKey.length > 0 ? { apiKey, error: null } : { apiKey: null, error: "decoded API key is empty" }; } catch (error) { return { apiKey: null, error: error instanceof Error ? error.message : String(error) }; } } function writeLocalCodexConfig(pool: CodexPoolConfig, apiKey: string): Record { const codexDir = join(homedir(), ".codex"); mkdirSync(codexDir, { recursive: true, mode: 0o700 }); const configPath = join(codexDir, "config.toml"); const authPath = join(codexDir, "auth.json"); const backupConfigPath = join(codexDir, `config.toml.${pool.localCodex.backupSuffix}`); const backupAuthPath = join(codexDir, `auth.json.${pool.localCodex.backupSuffix}`); if (!existsSync(configPath)) throw new Error(`${configPath} missing`); if (!existsSync(authPath)) throw new Error(`${authPath} missing`); const configBackupAction = copyIfMissing(configPath, backupConfigPath); const authBackupAction = copyIfMissing(authPath, backupAuthPath); const currentToml = readFileSync(configPath, "utf8"); const nextToml = updateCodexConfigToml(currentToml, pool); writeFileSync(configPath, nextToml, { encoding: "utf8", mode: 0o600 }); chmodSync(configPath, 0o600); writeFileSync(authPath, `${JSON.stringify({ OPENAI_API_KEY: apiKey }, null, 2)}\n`, { encoding: "utf8", mode: 0o600 }); chmodSync(authPath, 0o600); return { ok: true, codexDir, config: { path: configPath, bytes: statSync(configPath).size, backupPath: backupConfigPath, backupAction: configBackupAction, backupBytes: statSync(backupConfigPath).size, }, auth: { path: authPath, bytes: statSync(authPath).size, backupPath: backupAuthPath, backupAction: authBackupAction, backupBytes: statSync(backupAuthPath).size, openaiApiKeyShape: "string", openaiApiKeyBytes: Buffer.byteLength(apiKey, "utf8"), openaiApiKeyFingerprint: fingerprint(apiKey), valuesPrinted: false, }, provider: { name: pool.localCodex.providerName, baseUrl: pool.publicExposure.masterBaseUrl, wireApi: pool.localCodex.wireApi, }, valuesPrinted: false, }; } function copyIfMissing(source: string, target: string): "created" | "kept-existing" { if (existsSync(target)) return "kept-existing"; copyFileSync(source, target); chmodSync(target, 0o600); return "created"; } function updateCodexConfigToml(current: string, pool: CodexPoolConfig): string { let next = upsertTopLevelTomlString(current, "model_provider", pool.localCodex.providerName); next = upsertProviderSection(next, pool.localCodex.providerName, pool.publicExposure.masterBaseUrl, pool.localCodex.wireApi); return next.endsWith("\n") ? next : `${next}\n`; } function upsertTopLevelTomlString(text: string, key: string, value: string): string { const lines = text.split(/\r?\n/u); const firstSection = lines.findIndex((line) => /^\s*\[/.test(line)); const end = firstSection === -1 ? lines.length : firstSection; for (let index = 0; index < end; index += 1) { if (new RegExp(`^\\s*${escapeRegExp(key)}\\s*=`).test(lines[index])) { lines[index] = `${key} = ${tomlString(value)}`; return lines.join("\n"); } } lines.splice(0, 0, `${key} = ${tomlString(value)}`); return lines.join("\n"); } function upsertProviderSection(text: string, providerName: string, baseUrl: string, wireApi: string): string { const header = `[model_providers.${providerName}]`; const lines = text.split(/\r?\n/u); const start = lines.findIndex((line) => line.trim() === header); const canonical = [ `name = ${tomlString(providerName)}`, `base_url = ${tomlString(baseUrl)}`, `wire_api = ${tomlString(wireApi)}`, "requires_openai_auth = true", ]; if (start === -1) { const needsBlank = lines.length > 0 && lines[lines.length - 1].trim() !== ""; return [...lines, ...(needsBlank ? [""] : []), header, ...canonical].join("\n"); } let end = lines.length; for (let index = start + 1; index < lines.length; index += 1) { if (/^\s*\[/.test(lines[index])) { end = index; break; } } const preserved = lines.slice(start + 1, end).filter((line) => { return !/^\s*(name|base_url|wire_api|requires_openai_auth|env_key)\s*=/u.test(line); }); const replacement = [header, ...canonical, ...preserved.filter((line) => line.trim() !== "")]; return [...lines.slice(0, start), ...replacement, ...lines.slice(end)].join("\n"); } async function validatePublicGatewayWithKey(pool: CodexPoolConfig, apiKey: string): Promise> { const probe = await probePublicModels(pool, "with-api-key", apiKey); return { ...probe, ok: probe.ok === true, apiKeyFingerprint: fingerprint(apiKey), keyPreview: apiKeyPreview(apiKey), valuesPrinted: false, }; } async function probePublicModels(pool: CodexPoolConfig, mode: "with-api-key" | "without-api-key", apiKey?: string): Promise> { const url = `${pool.publicExposure.masterBaseUrl.replace(/\/+$/u, "")}/v1/models`; const controller = new AbortController(); const timeout = setTimeout(() => controller.abort(), 8000); try { const response = await fetch(url, { method: "GET", headers: apiKey ? { Authorization: `Bearer ${apiKey}` } : undefined, signal: controller.signal, }); const body = await response.text(); let parsed: unknown = null; try { parsed = body.trim().length > 0 ? JSON.parse(body) : null; } catch { parsed = null; } const modelCount = isRecord(parsed) && Array.isArray(parsed.data) ? parsed.data.length : null; return { ok: response.ok, mode, method: "GET /v1/models", baseUrl: pool.publicExposure.masterBaseUrl, httpStatus: response.status, modelCount, bodyPreview: response.ok ? "" : body.slice(0, 500), valuesPrinted: false, }; } catch (error) { return { ok: false, mode, method: "GET /v1/models", baseUrl: pool.publicExposure.masterBaseUrl, httpStatus: 0, error: error instanceof Error ? error.message : String(error), valuesPrinted: false, }; } finally { clearTimeout(timeout); } } function apiKeyPreview(apiKey: string): string { if (apiKey.length <= 14) return "***"; return `${apiKey.slice(0, 10)}...${apiKey.slice(-4)}`; } function tomlString(value: string): string { return JSON.stringify(value); } function escapeRegExp(value: string): string { return value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&"); } function normalizeBaseUrl(value: string | null): string | null { if (value === null) return null; const trimmed = value.trim().replace(/\/+$/u, ""); if (trimmed.length === 0) return null; try { const parsed = new URL(trimmed); if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return null; return parsed.toString().replace(/\/+$/u, ""); } catch { return null; } } function stringValue(value: unknown): string | null { return typeof value === "string" && value.trim().length > 0 ? value.trim() : null; } function numberValue(value: unknown): number | null { if (typeof value === "number" && Number.isFinite(value)) return value; if (typeof value === "string" && value.trim().length > 0) { const parsed = Number(value); return Number.isFinite(parsed) ? parsed : null; } return null; } function booleanValue(value: unknown): boolean | null { if (typeof value === "boolean") return value; if (typeof value === "string") { if (value.trim() === "true") return true; if (value.trim() === "false") return false; } return null; } function validateKubernetesName(value: string, key: string, strictDns: boolean): void { const pattern = strictDns ? /^[a-z0-9]([-a-z0-9]*[a-z0-9])?$/u : /^[A-Za-z0-9]([A-Za-z0-9._-]*[A-Za-z0-9])?$/u; if (!pattern.test(value)) throw new Error(`${codexPoolConfigPath}.${key} has an unsupported format`); } function isRecord(value: unknown): value is Record { return typeof value === "object" && value !== null && !Array.isArray(value); } function fingerprint(value: string): string { return createHash("sha256").update(value).digest("hex").slice(0, 12); } function syncScript(payload: unknown, pool: CodexPoolConfig): string { const encoded = Buffer.from(JSON.stringify(payload), "utf8").toString("base64"); return remotePythonScript("sync", encoded, pool); } function validateScript(pool: CodexPoolConfig): string { return remotePythonScript("validate", "", pool); } function desiredAccountCapacityMap(pool: CodexPoolConfig): Record { const codexDir = join(homedir(), ".codex"); const seenAccountNames = new Set(); const configs = pool.profiles.length > 0 ? pool.profiles : discoverCodexProfileConfigs(codexDir); const capacities: Record = {}; for (const entry of configs) { const accountName = entry.accountName ?? uniqueAccountName(entry.profile, seenAccountNames); seenAccountNames.add(accountName); capacities[accountName] = entry.capacity ?? pool.defaultAccountCapacity; } return capacities; } function remotePythonScript(mode: "sync" | "validate", encodedPayload: string, pool: CodexPoolConfig): string { return ` set -u python3 - <<'PY' import base64 import json import secrets import string import subprocess import sys import time from urllib.parse import quote NAMESPACE = "${namespace}" SERVICE_NAME = "${serviceName}" SERVICE_DNS = "${serviceDns}" FIELD_MANAGER = "${fieldManager}" APP_SECRET_NAME = "${appSecretName}" POOL_GROUP_NAME = "${pool.groupName}" POOL_API_KEY_NAME = "${pool.apiKeyName}" POOL_API_KEY_SECRET_NAME = "${pool.apiKeySecretName}" POOL_API_KEY_SECRET_KEY = "${pool.apiKeySecretKey}" MIN_OWNER_BALANCE_USD = ${JSON.stringify(pool.minOwnerBalanceUsd)} POOL_DEFAULT_ACCOUNT_CAPACITY = ${JSON.stringify(pool.defaultAccountCapacity)} EXPECTED_ACCOUNT_CAPACITIES = ${JSON.stringify(desiredAccountCapacityMap(pool))} MODE = "${mode}" PAYLOAD_B64 = "${encodedPayload}" def run(cmd, input_bytes=None): return subprocess.run(cmd, input=input_bytes, stdout=subprocess.PIPE, stderr=subprocess.PIPE) def text(data, limit=4000): if isinstance(data, bytes): data = data.decode("utf-8", errors="replace") return data[-limit:] def kubectl(args, input_obj=None): if isinstance(input_obj, str): input_bytes = input_obj.encode("utf-8") else: input_bytes = input_obj return run(["kubectl", *args], input_bytes) def require_kubectl(args, input_obj=None, label="kubectl"): proc = kubectl(args, input_obj) if proc.returncode != 0: raise RuntimeError(f"{label} failed: {text(proc.stderr, 1000)}") return proc.stdout def kube_json(args, label): raw = require_kubectl([*args, "-o", "json"], label=label) return json.loads(raw.decode("utf-8")) def decode_secret_value(name, key): data = kube_json(["-n", NAMESPACE, "get", "secret", name], f"secret/{name}").get("data") or {} if key not in data: return None return base64.b64decode(data[key]).decode("utf-8") def get_config_value(name, key): data = kube_json(["-n", NAMESPACE, "get", "configmap", name], f"configmap/{name}").get("data") or {} value = data.get(key) return value if isinstance(value, str) and value else None def select_app_pod(): pods = kube_json(["-n", NAMESPACE, "get", "pods", "-l", "app.kubernetes.io/name=sub2api"], "sub2api pods").get("items") or [] for pod in pods: status = pod.get("status") or {} if status.get("phase") != "Running": continue statuses = status.get("containerStatuses") or [] if statuses and all(item.get("ready") is True for item in statuses): return pod["metadata"]["name"] if pods: return pods[0]["metadata"]["name"] raise RuntimeError("sub2api app pod not found") APP_POD = select_app_pod() def parse_curl_output(proc): stdout = proc.stdout.decode("utf-8", errors="replace") marker = "\\n__HTTP_CODE__:" pos = stdout.rfind(marker) if pos < 0: return { "ok": False, "httpStatus": 0, "json": None, "body": stdout, "stderr": text(proc.stderr, 1000), "transportExitCode": proc.returncode, } body = stdout[:pos] status_text = stdout[pos + len(marker):].strip() try: http_status = int(status_text[-3:]) except ValueError: http_status = 0 try: parsed = json.loads(body) if body.strip() else None except json.JSONDecodeError: parsed = None return { "ok": proc.returncode == 0 and 200 <= http_status < 300, "httpStatus": http_status, "json": parsed, "body": body, "stderr": text(proc.stderr, 1000), "transportExitCode": proc.returncode, } def curl_api(method, path, bearer=None, payload=None): body = b"" if payload is None else json.dumps(payload, separators=(",", ":")).encode("utf-8") script = r''' set -eu method="$1" url="$2" token="\${3:-}" tmp="$(mktemp)" trap 'rm -f "$tmp"' EXIT cat > "$tmp" if [ -n "$token" ]; then if [ "$method" = "GET" ] && [ ! -s "$tmp" ]; then curl -sS -w '\\n__HTTP_CODE__:%{http_code}' -X "$method" -H "Authorization: Bearer $token" "$url" else curl -sS -w '\\n__HTTP_CODE__:%{http_code}' -X "$method" -H 'Content-Type: application/json' -H "Authorization: Bearer $token" --data-binary @"$tmp" "$url" fi else if [ "$method" = "GET" ] && [ ! -s "$tmp" ]; then curl -sS -w '\\n__HTTP_CODE__:%{http_code}' -X "$method" "$url" else curl -sS -w '\\n__HTTP_CODE__:%{http_code}' -X "$method" -H 'Content-Type: application/json' --data-binary @"$tmp" "$url" fi fi ''' proc = run([ "kubectl", "-n", NAMESPACE, "exec", "-i", APP_POD, "--", "sh", "-c", script, "sh", method, f"http://127.0.0.1:8080{path}", bearer or "", ], body) return parse_curl_output(proc) def envelope_data(parsed): if isinstance(parsed, dict) and "data" in parsed: return parsed.get("data") return parsed def ensure_success(resp, label): parsed = resp.get("json") code = parsed.get("code") if isinstance(parsed, dict) else None if not resp.get("ok") or (code is not None and code != 0): message = parsed.get("message") if isinstance(parsed, dict) else text(resp.get("body", ""), 500) raise RuntimeError(f"{label} failed: http={resp.get('httpStatus')} message={message}") return envelope_data(parsed) def extract_items(data): if isinstance(data, list): return data if isinstance(data, dict): if isinstance(data.get("items"), list): return data["items"] for key in ("groups", "accounts", "api_keys", "keys"): if isinstance(data.get(key), list): return data[key] return [] def find_access_token(data): if isinstance(data, dict): for key in ("access_token", "token"): if isinstance(data.get(key), str) and data[key]: return data[key] for value in data.values(): token = find_access_token(value) if token: return token return None def login(): admin_email = get_config_value("sub2api-config", "ADMIN_EMAIL") or "admin@sub2api.platform-infra.local" admin_password = decode_secret_value(APP_SECRET_NAME, "ADMIN_PASSWORD") if not admin_password: raise RuntimeError("ADMIN_PASSWORD missing from sub2api-secrets") data = ensure_success(curl_api("POST", "/api/v1/auth/login", payload={"email": admin_email, "password": admin_password}), "admin login") token = find_access_token(data) if not token: raise RuntimeError("admin login response did not contain access_token") return admin_email, token def group_payload(): return { "name": POOL_GROUP_NAME, "description": "UniDesk-managed Codex API-key pool for G14 k3s internal Sub2API clients.", "platform": "openai", "rate_multiplier": 1, "is_exclusive": False, "subscription_type": "standard", "allow_messages_dispatch": True, "require_oauth_only": False, "require_privacy_set": False, "rpm_limit": 0, } def ensure_group(token): existing_data = ensure_success(curl_api("GET", "/api/v1/admin/groups/all?platform=openai", bearer=token), "list groups") existing = next((item for item in extract_items(existing_data) if item.get("name") == POOL_GROUP_NAME), None) payload = group_payload() if existing is None: created = ensure_success(curl_api("POST", "/api/v1/admin/groups", bearer=token, payload=payload), "create group") return created, "created" group_id = existing.get("id") if group_id is None: raise RuntimeError("existing group has no id") payload["status"] = "active" updated = ensure_success(curl_api("PUT", f"/api/v1/admin/groups/{group_id}", bearer=token, payload=payload), "update group") return updated if isinstance(updated, dict) else existing, "updated" def list_accounts(token): path = "/api/v1/admin/accounts?page=1&page_size=200&platform=openai&type=apikey&search=" + quote("unidesk-codex-") data = ensure_success(curl_api("GET", path, bearer=token), "list accounts") return extract_items(data) def account_payload(profile, group_id): extra = { "openai_responses_mode": "force_responses", "unidesk_codex_profile": profile["profile"], "unidesk_managed": True, } ws_mode = profile.get("openaiResponsesWebSocketsV2Mode") if ws_mode: extra["openai_apikey_responses_websockets_v2_mode"] = ws_mode extra["openai_apikey_responses_websockets_v2_enabled"] = ws_mode != "off" credentials = { "api_key": profile["apiKey"], "base_url": profile["baseUrl"], } upstream_user_agent = profile.get("upstreamUserAgent") if upstream_user_agent: credentials["user_agent"] = upstream_user_agent return { "name": profile["accountName"], "notes": f"UniDesk-managed Codex profile {profile['profile']} from {profile['configFile']} and {profile['authFile']}; secret source={profile['apiKeySource']}; fingerprint={profile['apiKeyFingerprint']}.", "platform": "openai", "type": "apikey", "credentials": credentials, "extra": extra, "concurrency": int(profile.get("capacity", 5) or 5), "priority": int(profile.get("priority", 1) or 1), "rate_multiplier": 1, "load_factor": 1, "group_ids": [group_id], "confirm_mixed_channel_risk": True, } def ensure_accounts(token, profiles, group_id): existing_accounts = list_accounts(token) existing = {item.get("name"): item for item in existing_accounts} desired_names = {profile["accountName"] for profile in profiles} results = [] for profile in profiles: payload = account_payload(profile, group_id) current = existing.get(profile["accountName"]) if current and current.get("id") is not None: account_id = current["id"] update_payload = dict(payload) update_payload.pop("platform", None) update_payload["status"] = "active" data = ensure_success(curl_api("PUT", f"/api/v1/admin/accounts/{account_id}", bearer=token, payload=update_payload), f"update account {profile['accountName']}") action = "updated" else: data = ensure_success(curl_api("POST", "/api/v1/admin/accounts", bearer=token, payload=payload), f"create account {profile['accountName']}") action = "created" results.append({ "profile": profile["profile"], "accountName": profile["accountName"], "accountId": data.get("id") if isinstance(data, dict) else None, "action": action, "baseUrl": profile["baseUrl"], "apiKeySource": profile["apiKeySource"], "apiKeyFingerprint": profile["apiKeyFingerprint"], "openaiResponsesWebSocketsV2Mode": profile.get("openaiResponsesWebSocketsV2Mode"), "priority": int(profile.get("priority", 1) or 1), "capacity": int(profile.get("capacity", 5) or 5), "runtimeConcurrency": data.get("concurrency") if isinstance(data, dict) else None, "upstreamUserAgentConfigured": bool(profile.get("upstreamUserAgent")), "valuesPrinted": False, }) prune_results = prune_removed_accounts(token, existing_accounts, desired_names) return results, prune_results def prune_removed_accounts(token, existing_accounts, desired_names): results = [] for account in existing_accounts: name = account.get("name") account_id = account.get("id") extra = account.get("extra") if isinstance(account.get("extra"), dict) else {} if not isinstance(name, str) or not name.startswith("unidesk-codex-"): continue if extra.get("unidesk_managed") is not True: continue if name in desired_names: continue if account_id is None: raise RuntimeError(f"removed account {name} has no id") ensure_success(curl_api("DELETE", f"/api/v1/admin/accounts/{account_id}", bearer=token), f"delete removed account {name}") results.append({ "accountName": name, "accountId": account_id, "profile": extra.get("unidesk_codex_profile"), "action": "deleted", "reason": "removed-from-yaml", "valuesPrinted": False, }) return results def generate_api_key(): alphabet = string.ascii_letters + string.digits return "sk-unidesk-codex-" + "".join(secrets.choice(alphabet) for _ in range(48)) def ensure_api_key_secret(group_id): existing = None try: existing = decode_secret_value(POOL_API_KEY_SECRET_NAME, POOL_API_KEY_SECRET_KEY) except Exception: existing = None api_key = existing if existing else generate_api_key() secret_action = "kept-existing" if existing else "created" manifest = { "apiVersion": "v1", "kind": "Secret", "metadata": { "name": POOL_API_KEY_SECRET_NAME, "namespace": NAMESPACE, "labels": { "app.kubernetes.io/name": "sub2api", "app.kubernetes.io/part-of": "platform-infra", "app.kubernetes.io/managed-by": "unidesk", "unidesk.ai/secret-purpose": "sub2api-codex-pool-api-key", }, }, "type": "Opaque", "stringData": { POOL_API_KEY_SECRET_KEY: api_key, "GROUP_ID": str(group_id), "GROUP_NAME": POOL_GROUP_NAME, "SERVICE_DNS": SERVICE_DNS, }, } proc = kubectl(["apply", "--server-side", "--force-conflicts", f"--field-manager={FIELD_MANAGER}", "-f", "-"], json.dumps(manifest)) if proc.returncode != 0: raise RuntimeError(f"apply API key secret failed: {text(proc.stderr, 1000)}") return api_key, secret_action, text(proc.stdout, 1000) def list_user_keys(token): data = ensure_success(curl_api("GET", "/api/v1/keys?page=1&page_size=200", bearer=token), "list user keys") return extract_items(data) def ensure_sub2api_api_key(token, api_key, group_id): keys = list_user_keys(token) existing = next((item for item in keys if item.get("key") == api_key), None) action = "kept-existing" if existing is None: existing = next((item for item in keys if item.get("name") == POOL_API_KEY_NAME), None) if existing is None or existing.get("key") != api_key: payload = { "name": POOL_API_KEY_NAME, "group_id": group_id, "custom_key": api_key, "quota": 0, "rate_limit_5h": 0, "rate_limit_1d": 0, "rate_limit_7d": 0, } created = ensure_success(curl_api("POST", "/api/v1/keys", bearer=token, payload=payload), "create pool API key") existing = created if isinstance(created, dict) else existing action = "created" elif existing.get("id") is not None and existing.get("group_id") != group_id: updated = ensure_success(curl_api("PUT", f"/api/v1/keys/{existing['id']}", bearer=token, payload={"name": POOL_API_KEY_NAME, "group_id": group_id}), "update pool API key group") existing = updated if isinstance(updated, dict) else existing action = "updated-group" return { "action": action, "id": existing.get("id") if isinstance(existing, dict) else None, "name": existing.get("name") if isinstance(existing, dict) else POOL_API_KEY_NAME, "groupId": existing.get("group_id") if isinstance(existing, dict) else group_id, "userId": existing.get("user_id") if isinstance(existing, dict) else None, } def get_admin_user(token, user_id): data = ensure_success(curl_api("GET", f"/api/v1/admin/users/{user_id}", bearer=token), "get API key owner") if not isinstance(data, dict): raise RuntimeError("API key owner response is not an object") return data def ensure_pool_owner_balance(token, user_id): user = get_admin_user(token, user_id) current = float(user.get("balance") or 0) if current >= MIN_OWNER_BALANCE_USD: return { "action": "kept-existing", "userId": user_id, "balanceBefore": current, "balanceAfter": current, "minimumBalanceUsd": MIN_OWNER_BALANCE_USD, } updated = ensure_success(curl_api("POST", f"/api/v1/admin/users/{user_id}/balance", bearer=token, payload={ "balance": MIN_OWNER_BALANCE_USD, "operation": "set", "notes": "UniDesk Sub2API Codex pool internal API key bootstrap balance.", }), "set API key owner balance") after = float(updated.get("balance") or MIN_OWNER_BALANCE_USD) if isinstance(updated, dict) else MIN_OWNER_BALANCE_USD return { "action": "set", "userId": user_id, "balanceBefore": current, "balanceAfter": after, "minimumBalanceUsd": MIN_OWNER_BALANCE_USD, } def validate_gateway(api_key): resp = curl_api("GET", "/v1/models", bearer=api_key) parsed = resp.get("json") model_count = None if isinstance(parsed, dict) and isinstance(parsed.get("data"), list): model_count = len(parsed["data"]) return { "ok": resp.get("ok"), "httpStatus": resp.get("httpStatus"), "transportExitCode": resp.get("transportExitCode"), "modelCount": model_count, "bodyPreview": text(resp.get("body", ""), 500) if not resp.get("ok") else "", "stderr": resp.get("stderr", ""), "method": "GET /v1/models", "serviceDns": SERVICE_DNS, "valuesPrinted": False, } def account_capacity_status(token): accounts = list_accounts(token) by_name = {item.get("name"): item for item in accounts if isinstance(item.get("name"), str)} items = [] missing = [] mismatched = [] for name in sorted(EXPECTED_ACCOUNT_CAPACITIES): expected = int(EXPECTED_ACCOUNT_CAPACITIES[name]) account = by_name.get(name) if account is None: missing.append(name) items.append({ "accountName": name, "accountId": None, "expectedCapacity": expected, "runtimeConcurrency": None, "ok": False, }) continue runtime = account.get("concurrency") ok = runtime == expected if not ok: mismatched.append(name) items.append({ "accountName": name, "accountId": account.get("id"), "expectedCapacity": expected, "runtimeConcurrency": runtime, "priority": account.get("priority"), "status": account.get("status"), "schedulable": account.get("schedulable"), "ok": ok, }) return { "ok": len(missing) == 0 and len(mismatched) == 0, "defaultAccountCapacity": POOL_DEFAULT_ACCOUNT_CAPACITY, "desired": len(EXPECTED_ACCOUNT_CAPACITIES), "missing": missing, "mismatched": mismatched, "items": items, "valuesPrinted": False, } def api_key_preview(api_key): if len(api_key) <= 14: return "***" return api_key[:10] + "..." + api_key[-4:] def run_sync(): payload = json.loads(base64.b64decode(PAYLOAD_B64).decode("utf-8")) profiles = payload.get("profiles") or [] if not profiles: raise RuntimeError("sync payload has no profiles") admin_email, token = login() group, group_action = ensure_group(token) group_id = group.get("id") if isinstance(group, dict) else None if group_id is None: raise RuntimeError("pool group id missing after ensure") account_results, pruned_account_results = ensure_accounts(token, profiles, group_id) capacity_status = account_capacity_status(token) api_key, secret_action, secret_apply_stdout = ensure_api_key_secret(group_id) api_key_result = ensure_sub2api_api_key(token, api_key, group_id) owner_balance = ensure_pool_owner_balance(token, api_key_result["userId"]) gateway = validate_gateway(api_key) return { "ok": gateway["ok"] is True and capacity_status["ok"] is True, "mode": "sync", "namespace": NAMESPACE, "serviceDns": SERVICE_DNS, "appPod": APP_POD, "admin": {"email": admin_email, "tokenPrinted": False}, "pool": {"name": POOL_GROUP_NAME, "id": group_id, "action": group_action, "platform": group.get("platform") if isinstance(group, dict) else "openai"}, "accounts": { "desired": len(profiles), "created": sum(1 for item in account_results if item["action"] == "created"), "updated": sum(1 for item in account_results if item["action"] == "updated"), "pruned": len(pruned_account_results), "items": account_results, "prunedItems": pruned_account_results, "valuesPrinted": False, }, "capacity": capacity_status, "apiKey": { "name": POOL_API_KEY_NAME, "secret": f"{NAMESPACE}/{POOL_API_KEY_SECRET_NAME}.{POOL_API_KEY_SECRET_KEY}", "secretAction": secret_action, "secretApply": secret_apply_stdout, "sub2apiAction": api_key_result["action"], "sub2apiId": api_key_result["id"], "groupId": api_key_result["groupId"], "userId": api_key_result["userId"], "keyPreview": api_key_preview(api_key), "valuesPrinted": False, }, "ownerBalance": owner_balance, "validation": {"gatewayModels": gateway}, } def run_validate(): api_key = decode_secret_value(POOL_API_KEY_SECRET_NAME, POOL_API_KEY_SECRET_KEY) if not api_key: raise RuntimeError(f"{POOL_API_KEY_SECRET_NAME}.{POOL_API_KEY_SECRET_KEY} missing") admin_email, token = login() key_item = next((item for item in list_user_keys(token) if item.get("key") == api_key), None) owner_balance = None if key_item is not None and key_item.get("user_id") is not None: owner_balance = ensure_pool_owner_balance(token, key_item["user_id"]) capacity_status = account_capacity_status(token) gateway = validate_gateway(api_key) return { "ok": gateway["ok"] is True and capacity_status["ok"] is True, "mode": "validate", "namespace": NAMESPACE, "serviceDns": SERVICE_DNS, "appPod": APP_POD, "admin": {"email": admin_email, "tokenPrinted": False}, "apiKey": { "secret": f"{NAMESPACE}/{POOL_API_KEY_SECRET_NAME}.{POOL_API_KEY_SECRET_KEY}", "sub2apiId": key_item.get("id") if isinstance(key_item, dict) else None, "userId": key_item.get("user_id") if isinstance(key_item, dict) else None, "keyPreview": api_key_preview(api_key), "valuesPrinted": False, }, "ownerBalance": owner_balance, "capacity": capacity_status, "validation": {"gatewayModels": gateway}, } try: result = run_sync() if MODE == "sync" else run_validate() except Exception as exc: result = { "ok": False, "mode": MODE, "namespace": NAMESPACE, "serviceDns": SERVICE_DNS, "appPod": globals().get("APP_POD"), "error": str(exc), "valuesPrinted": False, } print(json.dumps(result, ensure_ascii=False, indent=2)) sys.exit(0 if result.get("ok") else 1) PY `; } async function capture(config: UniDeskConfig, target: string, args: string[], input?: string): Promise { return await runSshCommandCapture(config, target, args, input); } function parseJsonOutput(stdout: string): Record | null { const trimmed = stdout.trim(); if (trimmed.length === 0) return null; const start = trimmed.indexOf("{"); const end = trimmed.lastIndexOf("}"); if (start === -1 || end === -1 || end <= start) return null; try { const parsed = JSON.parse(trimmed.slice(start, end + 1)) as unknown; return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) ? parsed as Record : null; } catch { return null; } } function boolField(value: Record | null, key: string, defaultValue: boolean): boolean { if (value === null) return defaultValue; const field = value[key]; return typeof field === "boolean" ? field : defaultValue; } function compactCapture(result: SshCaptureResult, options: { full?: boolean } = {}): Record { const full = options.full ?? false; return { exitCode: result.exitCode, stdoutBytes: Buffer.byteLength(result.stdout, "utf8"), stderrBytes: Buffer.byteLength(result.stderr, "utf8"), stdoutTail: full || result.exitCode !== 0 ? result.stdout.slice(-8000) : "", stderrTail: full || result.exitCode !== 0 ? result.stderr.slice(-4000) : "", }; }