diff --git a/README.md b/README.md index f11d009..c58ee8c 100644 --- a/README.md +++ b/README.md @@ -108,7 +108,7 @@ jobs: | `working-directory` | Directory passed to `codex exec --cd`. Defaults to the repository root. | `""` | | `sandbox` | Legacy sandbox mode. Prefer `permission-profile: ":workspace"` for new workflows. Mutually exclusive with `permission-profile`. | `""` | | `permission-profile` | Built-in or configured [Codex permission profile](https://developers.openai.com/codex/permissions) selected through `default_permissions`. | `""` | -| `codex-version` | Version of `@openai/codex` to install. | `""` | +| `codex-version` | Version, tag, or range of `@openai/codex` to install. If unset, resolves the latest published version at run time; pin it for reproducible builds. | `""` | | `codex-args` | Extra arguments forwarded to `codex exec`. Accepts JSON arrays (`["--flag", "value"]`) or shell-style strings. | `""` | | `output-schema` | Inline schema contents written to a temp file and passed to `codex exec --output-schema`. Mutually exclusive with `output-schema-file`. | `""` | | `output-schema-file` | Schema file forwarded to `codex exec --output-schema`. Leave empty to skip passing the option. | `""` | @@ -185,6 +185,7 @@ See [Protecting your `OPENAI_API_KEY`](./docs/security.md#protecting-your-openai | Name | Description | | --------------- | --------------------------------------- | | `final-message` | Final message returned by `codex exec`. | +| `codex-version` | Exact `@openai/codex` version installed for the run. | As we saw in the example above, we took the `final-message` output of the `run_codex` step and made it an output of the `codex` job in the workflow: @@ -194,6 +195,7 @@ jobs: # ... outputs: final_message: ${{ steps.run_codex.outputs.final-message }} + codex_version: ${{ steps.run_codex.outputs.codex-version }} ``` ## Additional tips diff --git a/action.yml b/action.yml index ff7088b..c12ef06 100644 --- a/action.yml +++ b/action.yml @@ -41,7 +41,7 @@ inputs: required: false default: "" codex-version: - description: "Version of `@openai/codex` to install." + description: "Version, tag, or range of `@openai/codex` to install. Leave empty to resolve the latest published version at run time." required: false default: "" codex-args: @@ -124,6 +124,9 @@ outputs: final-message: description: "Raw output emitted by `codex exec`." value: ${{ steps.run_codex.outputs['final-message'] }} + codex-version: + description: "Exact installed `@openai/codex` version resolved for this run." + value: ${{ steps.resolve_codex_version.outputs.codex-version }} runs: using: "composite" steps: @@ -161,10 +164,24 @@ runs: --allow-users "$ALLOW_USERS" - name: Install Codex CLI + id: resolve_codex_version shell: bash env: CODEX_VERSION: ${{ inputs['codex-version'] }} - run: npm install -g "@openai/codex@${CODEX_VERSION}" + run: | + npm install -g "@openai/codex@${CODEX_VERSION}" + + codex_root="$(npm root -g)" + resolved_codex_version="$(node -p 'require(process.argv[1]).version' "$codex_root/@openai/codex/package.json")" + + echo "codex-version=$resolved_codex_version" >> "$GITHUB_OUTPUT" + echo "Installed Codex CLI version: $resolved_codex_version" + { + echo "### Codex CLI" + echo + echo "- Resolved version: \ +\`$resolved_codex_version\`" + } >> "$GITHUB_STEP_SUMMARY" - name: Install Codex Responses API proxy shell: bash diff --git a/test/actionHardening.test.mjs b/test/actionHardening.test.mjs index d8aed0f..e0d47bf 100644 --- a/test/actionHardening.test.mjs +++ b/test/actionHardening.test.mjs @@ -37,6 +37,27 @@ test("Responses proxy replaces inherited Node options without exposing its API k assert.doesNotMatch(step, /printenv PROXY_API_KEY\s*\|/); }); +test("action exposes the resolved codex version as an output", () => { + assert.match( + action, + /outputs:\n final-message:[\s\S]*\n codex-version:\n description: "Exact installed `@openai\/codex` version resolved for this run\."\n value: \$\{\{ steps\.resolve_codex_version\.outputs\.codex-version \}\}/ + ); +}); + +test("action reports the installed codex version without changing proxy resolution", () => { + const installCodexStep = actionStep("Install Codex CLI"); + const installProxyStep = actionStep("Install Codex Responses API proxy"); + + assert.match(installCodexStep, /id: resolve_codex_version/); + assert.match(installCodexStep, /resolved_codex_version=.*@openai\/codex\/package\.json/); + assert.match(installCodexStep, /echo "codex-version=\$resolved_codex_version" >> "\$GITHUB_OUTPUT"/); + assert.match(installCodexStep, /GITHUB_STEP_SUMMARY/); + assert.match( + installProxyStep, + /CODEX_VERSION: \$\{\{ inputs\['codex-version'\] \}\}/ + ); +}); + test( "Responses proxy environment removes unsafe Node options and its API key", { skip: process.platform === "win32" },