From fd62d42429e603024d90c7f638b87db5e7853bbc Mon Sep 17 00:00:00 2001 From: kdcokenny Date: Thu, 1 Oct 2026 14:08:20 +0000 Subject: [PATCH] fix(codex): respect CODEX_HOME --- registry/coder-labs/modules/codex/README.md | 14 +++-- .../coder-labs/modules/codex/main.test.ts | 56 +++++++++++++++++++ .../modules/codex/scripts/install.sh.tftpl | 2 +- 3 files changed, 65 insertions(+), 7 deletions(-) diff --git a/registry/coder-labs/modules/codex/README.md b/registry/coder-labs/modules/codex/README.md index d37243353..39811f4a3 100644 --- a/registry/coder-labs/modules/codex/README.md +++ b/registry/coder-labs/modules/codex/README.md @@ -13,7 +13,7 @@ Install and configure the [Codex CLI](https://github.com/openai/codex) in your w ```tf module "codex" { source = "registry.coder.com/coder-labs/codex/coder" - version = "5.4.1" + version = "5.4.2" agent_id = coder_agent.main.id openai_api_key = var.openai_api_key } @@ -33,7 +33,7 @@ locals { module "codex" { source = "registry.coder.com/coder-labs/codex/coder" - version = "5.4.1" + version = "5.4.2" agent_id = coder_agent.main.id workdir = local.codex_workdir openai_api_key = var.openai_api_key @@ -64,7 +64,7 @@ resource "coder_app" "codex" { ```tf module "codex" { source = "registry.coder.com/coder-labs/codex/coder" - version = "5.4.1" + version = "5.4.2" agent_id = coder_agent.main.id workdir = "/home/coder/project" enable_ai_gateway = true @@ -88,7 +88,7 @@ When `enable_ai_gateway = true`, the module configures Codex to use the `aigatew ```tf module "codex" { source = "registry.coder.com/coder-labs/codex/coder" - version = "5.4.1" + version = "5.4.2" agent_id = coder_agent.main.id workdir = "/home/coder/project" openai_api_key = var.openai_api_key @@ -116,7 +116,7 @@ module "codex" { ``` > [!NOTE] -> Servers configured through `mcp` or `mcp_config_remote_path` are appended to `~/.codex/config.toml`, so they apply to every Codex session in the workspace. Each remote URL should return a body in Codex's native TOML format, e.g.: +> Servers configured through `mcp` or `mcp_config_remote_path` are appended to `$CODEX_HOME/config.toml` (default: `~/.codex/config.toml`), so they apply to every Codex session in the workspace. Each remote URL should return a body in Codex's native TOML format, e.g.: > > ```toml > [mcp_servers.my-tool] @@ -134,7 +134,7 @@ The module exposes the `scripts` output: an ordered list of `coder exp sync` nam ```tf module "codex" { source = "registry.coder.com/coder-labs/codex/coder" - version = "5.4.1" + version = "5.4.2" agent_id = coder_agent.main.id openai_api_key = var.openai_api_key } @@ -157,6 +157,8 @@ resource "coder_script" "post_codex" { ## Configuration +The module writes configuration to `$CODEX_HOME/config.toml` when `CODEX_HOME` is non-empty, and to `$HOME/.codex/config.toml` otherwise. Set `CODEX_HOME` in the environment used by both the install script and the Codex CLI. + When no custom `base_config_toml` is provided, the module uses a minimal default with `preferred_auth_method = "apikey"`. For advanced options, see [Codex config docs](https://developers.openai.com/codex/config-advanced). When `openai_api_key` is set, the module authenticates with `codex login --with-api-key` over standard input. The key remains in the `OPENAI_API_KEY` workspace environment variable and is not rendered into the install script or written to `auth.json` by the module. diff --git a/registry/coder-labs/modules/codex/main.test.ts b/registry/coder-labs/modules/codex/main.test.ts index daf348fa6..a0de25c22 100644 --- a/registry/coder-labs/modules/codex/main.test.ts +++ b/registry/coder-labs/modules/codex/main.test.ts @@ -14,6 +14,7 @@ import { runTerraformApply, runTerraformInit, TerraformState, + writeFileContainer, } from "~test"; import { extractCoderEnvVars, @@ -393,6 +394,61 @@ describe("codex", async () => { expect(resp).not.toContain("model_reasoning_effort"); }); + test("CODEX_HOME uses a custom directory containing spaces", async () => { + const codexHome = "/home/coder/state/codex home"; + const baseConfig = 'model_reasoning_effort = "medium"'; + const { id, scripts } = await setup({ + moduleVariables: { + base_config_toml: baseConfig, + }, + }); + const defaultConfig = "/home/coder/.codex/config.toml"; + const original = 'model_reasoning_effort = "high"\n'; + expect( + (await execContainer(id, ["mkdir", "-p", path.dirname(defaultConfig)])) + .exitCode, + ).toBe(0); + await writeFileContainer(id, defaultConfig, original); + + await runScripts(id, scripts, { CODEX_HOME: codexHome }); + const config = await readFileContainer(id, `${codexHome}/config.toml`); + expect(config).toContain(baseConfig); + expect(await readFileContainer(id, defaultConfig)).toBe(original); + }); + + test.each([ + ["unset", undefined], + ["empty", ""], + ])( + "CODEX_HOME %s falls back to HOME/.codex with spaces", + async (_scenario, codexHome) => { + const userHome = "/home/coder/home with spaces"; + const { id, scripts } = await setup(); + await runScripts(id, scripts); + + // Run the materialized install script directly to isolate config paths + // from coder-utils' shell wrapper and explicitly unset CODEX_HOME. + const result = await execContainer(id, [ + "env", + "-u", + "CODEX_HOME", + `HOME=${userHome}`, + ...(codexHome === undefined ? [] : [`CODEX_HOME=${codexHome}`]), + "/home/coder/.coder-modules/coder-labs/codex/scripts/install.sh", + ]); + if (result.exitCode !== 0) { + console.log(result.stdout); + console.log(result.stderr); + } + expect(result.exitCode).toBe(0); + const config = await readFileContainer( + id, + `${userHome}/.codex/config.toml`, + ); + expect(config).toContain('preferred_auth_method = "apikey"'); + }, + ); + test("pre-post-install-scripts", async () => { const { id, scripts } = await setup({ moduleVariables: { diff --git a/registry/coder-labs/modules/codex/scripts/install.sh.tftpl b/registry/coder-labs/modules/codex/scripts/install.sh.tftpl index d29419576..0f81a7dc2 100644 --- a/registry/coder-labs/modules/codex/scripts/install.sh.tftpl +++ b/registry/coder-labs/modules/codex/scripts/install.sh.tftpl @@ -130,7 +130,7 @@ EOF } function populate_config_toml() { - local config_path="$HOME/.codex/config.toml" + local config_path="$${CODEX_HOME:-$HOME/.codex}/config.toml" mkdir -p "$(dirname "$${config_path}")" local MANAGED_START="# >>> coder-managed: codex module >>>"