Skip to content

install: consume Codex package archives#23636

Merged
bolinfest merged 1 commit into
mainfrom
pr23636
May 20, 2026
Merged

install: consume Codex package archives#23636
bolinfest merged 1 commit into
mainfrom
pr23636

Conversation

@bolinfest
Copy link
Copy Markdown
Collaborator

@bolinfest bolinfest commented May 20, 2026

Summary

Standalone installs should exercise the same canonical package archive layout that release builds produce, rather than unpacking npm platform packages and reconstructing a parallel install tree.

This updates install.sh and install.ps1 to prefer codex-package-<target>.tar.gz plus codex-package_SHA256SUMS introduced in #23635, authenticate the checksum manifest against GitHub release metadata, verify the selected package archive against the authenticated manifest, and install the package archive directly.

Compatibility Notes

Package installs still leave a compatibility command at current/codex for managed daemon flows, while visible command shims point at bin/codex inside the package layout.

Recent releases that predate package archives still publish per-platform npm artifacts, so both installers keep a legacy platform npm fallback for those versions and verify those archives against release metadata directly.

Releases old enough to publish only the single root codex-npm-<version>.tgz archive are intentionally out of scope. The installers fail clearly when neither package archives nor per-platform npm archives are present.

On Windows, the runtime helper lookups now recognize package-layout installs where codex.exe runs from bin/, so codex-command-runner.exe and codex-windows-sandbox-setup.exe resolve from the top-level codex-resources/ directory. The direct-sibling and older sibling-resource fallbacks are preserved.

Test plan

  • sh -n scripts/install/install.sh
  • bash -n scripts/install/install.sh
  • pwsh -NoProfile -Command '$tokens=$null; $errors=$null; $null = [System.Management.Automation.Language.Parser]::ParseFile("scripts/install/install.ps1", [ref]$tokens, [ref]$errors); if ($errors.Count) { $errors | Format-List *; exit 1 }'
  • HOME="$home_dir" CODEX_HOME="$tmp_dir/codex-home" CODEX_INSTALL_DIR="$bin_dir" PATH="$bin_dir:$PATH" sh scripts/install/install.sh --release 0.125.0
  • Verified the 0.125.0 isolated install leaves the visible command pointed at current/codex and includes the legacy codex-resources/rg payload.
  • cargo test -p codex-windows-sandbox
  • just fix -p codex-windows-sandbox

Stack created with Sapling. Best reviewed with ReviewStack.

Copy link
Copy Markdown
Contributor

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 633df7c989

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/install/install.sh Outdated
tmp_link="$BIN_DIR/.codex.$$"

replace_path_with_symlink "$BIN_PATH" "$CURRENT_LINK/codex" "$tmp_link"
replace_path_with_symlink "$BIN_PATH" "$CURRENT_LINK/bin/codex" "$tmp_link"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve current/codex compatibility path

Switching the visible shim to "$CURRENT_LINK/bin/codex" means fresh installs and upgrades no longer leave a binary at CODEX_HOME/packages/standalone/current/codex, but app-server daemon code still hard-codes that legacy path (codex-rs/app-server-daemon/src/managed_install.rs::managed_codex_bin). In that state, daemon flows that call ensure_managed_codex_bin() fail even immediately after a successful install, because they check for a file that no longer exists. Keep a compatibility shim at current/codex (or update daemon path resolution in the same change) to avoid breaking managed daemon startup/update flows.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in the latest push. Package installs now create current/codex as a compatibility symlink to bin/codex, so the managed daemon path continues to work while the visible shim can still target the package layout.

Comment thread scripts/install/install.sh Outdated
Comment on lines 718 to 721
download_file "$checksum_url" "$checksum_path"
expected_digest="$(package_archive_digest "$asset" "$checksum_path")"
download_file "$download_url" "$archive_path"
verify_archive_digest "$archive_path" "$expected_digest"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Authenticate checksum manifest before trusting it

The script now derives expected_digest directly from the downloaded codex-package_SHA256SUMS file and uses it to validate the archive, but it never validates that manifest against an independent trusted digest. This makes integrity verification circular: if an attacker can tamper with both downloads, they can provide a malicious archive plus matching manifest and still pass verify_archive_digest. Validate the checksum manifest itself (for example via the release API digest) before using it as the trust source.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in the latest push. install.sh now verifies codex-package_SHA256SUMS against the checksum asset's GitHub release metadata digest before using it to validate the selected package archive.

Copy link
Copy Markdown
Collaborator

@viyatb-oai viyatb-oai left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two P2 notes from the installer/package-archive review pass.

Comment thread scripts/install/install.sh Outdated

step "Downloading Codex CLI"
expected_digest="$(release_asset_digest "$asset" "$resolved_version")"
download_file "$checksum_url" "$checksum_path"
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] This weakens the Unix installer’s integrity chain. Before this stack, install.sh checked the downloaded archive against GitHub release metadata’s asset.digest; now it trusts a checksum manifest fetched from the same release asset channel as the archive itself. If that response path is swapped, an attacker can replace both the archive and the manifest and still pass verification. The PowerShell path already avoids this by authenticating the manifest against release metadata first.

Please keep the release-asset digest check for the checksum manifest here, then consume the package digest from the verified manifest.

Suggested change
download_file "$checksum_url" "$checksum_path"
checksum_digest="$(release_asset_digest "$checksum_asset" "$resolved_version")"
download_file "$checksum_url" "$checksum_path"
verify_archive_digest "$checksum_path" "$checksum_digest"
expected_digest="$(package_archive_digest "$asset" "$checksum_path")"
download_file "$download_url" "$archive_path"
verify_archive_digest "$archive_path" "$expected_digest"
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in the latest push. The Unix installer now authenticates codex-package_SHA256SUMS via release_asset_digest before reading the package archive digest from it, matching the PowerShell integrity chain.

Comment thread scripts/install/install.sh Outdated

resolved_version="$(resolve_version)"
asset="codex-npm-$npm_tag-$resolved_version.tgz"
asset="codex-package-$vendor_target.tar.gz"
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] This makes pinned historical installs fail. Older Rust releases such as rust-v0.39.0 and rust-v0.40.0 publish the legacy codex-npm-<version>.tgz asset, but not codex-package-* or codex-package_SHA256SUMS, so install.sh --release 0.40.0 now 404s before extraction. install.ps1 has the same cutover issue.

Please keep a legacy fallback when the new package archive family is unavailable, or gate the new asset names on the release version and retain the prior npm-tarball flow below that cutover.

Suggested change
asset="codex-package-$vendor_target.tar.gz"
asset="codex-package-$vendor_target.tar.gz"
checksum_asset="codex-package_SHA256SUMS"
if ! release_asset_exists "$asset" "$resolved_version" || ! release_asset_exists "$checksum_asset" "$resolved_version"; then
asset="codex-npm-$npm_tag-$resolved_version.tgz"
checksum_asset=""
fi
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed for the relevant recent-release shape in the latest push. The installers now fall back to the per-platform codex-npm-<platform>-<version>.tgz assets when codex-package-* assets are unavailable. After discussion, I did not add special handling for the much older single-root codex-npm-<version>.tgz releases like 0.39.0/0.40.0.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also updated the PR body's compatibility notes to make the fallback boundary explicit: recent pre-package releases that have per-platform npm artifacts remain supported, while much older releases that only have the single root codex-npm-<version>.tgz archive are intentionally out of scope.

bolinfest added a commit that referenced this pull request May 20, 2026
## Summary

The Linux sandbox should find bundled `bwrap` through the same
package-layout abstraction as the rest of the runtime, instead of
maintaining a separate standalone-specific lookup path.

This adds an `InstallContext` helper for bundled resources and updates
`codex-linux-sandbox` to ask the current install context for
`codex-resources/bwrap` before falling back to the old
executable-relative probes. The tests cover npm-style, standalone, and
canonical package layouts so `bwrap` lookup follows the package
structure introduced earlier in the stack.

## Test plan

- `cargo test -p codex-install-context`
- `cargo test -p codex-linux-sandbox --lib`
- `just fix -p codex-install-context -p codex-linux-sandbox`
- `just bazel-lock-check`





---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/openai/codex/pull/23634).
* #23638
* #23637
* #23636
* #23635
* __->__ #23634
bolinfest added a commit that referenced this pull request May 20, 2026
## Summary

Standalone installers and other downstream package consumers need a
stable checksum source for the canonical package archives. Relying on
per-asset metadata makes that harder to consume uniformly, especially
when several package archives are produced in the same release.

This keeps the `codex-package-*.tar.gz` and
`codex-app-server-package-*.tar.gz` assets in the GitHub Release upload
set and adds `codex-package_SHA256SUMS` to `dist/` before the release is
created. The manifest contains one SHA-256 line per package archive and
fails the release job if no package archives are present.




---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/openai/codex/pull/23635).
* #23638
* #23637
* #23636
* __->__ #23635
Base automatically changed from pr23635 to main May 20, 2026 15:48
@bolinfest bolinfest force-pushed the pr23636 branch 4 times, most recently from 2a174f4 to 7c42f21 Compare May 20, 2026 16:24
@bolinfest bolinfest requested a review from viyatb-oai May 20, 2026 16:35
Copy link
Copy Markdown
Contributor

@efrazer-oai efrazer-oai left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The specifics look good here, but it appears that we're missing smth on the rust side that we might want to fix before updating the installer.

Right now, windows finds its helpers (command-runner, sandbox-setup.exe) by doing

let dir = exe.parent()?;
let resource_candidate =
    dir.join(RESOURCES_DIRNAME).join(file_name);

But now that exe is in bin, this will give us bin/codex-resources which isn't quite right as the installer locates this in top level codex-resources

## Summary

Standalone installs should exercise the same canonical package archive layout that release builds produce, rather than unpacking npm platform packages and reconstructing a parallel install tree.

This updates `install.sh` and `install.ps1` to prefer `codex-package-<target>.tar.gz` plus `codex-package_SHA256SUMS`, authenticate the checksum manifest against GitHub release metadata, verify the selected package archive against the authenticated manifest, and install the package archive directly. Package installs now also leave a compatibility command at `current/codex` for managed daemon flows while visible command shims point at `bin/codex`.

Recent releases that predate package archives still publish per-platform npm artifacts, so both installers keep a legacy platform npm fallback for those versions and verify those archives against release metadata directly. Releases old enough to publish only the single root `codex-npm-<version>.tgz` archive are intentionally out of scope; the installers fail clearly when neither package archives nor per-platform npm archives are present.

On Windows, the runtime helper lookups now also recognize the package layout when `codex.exe` runs from `bin/`, so `codex-command-runner.exe` and `codex-windows-sandbox-setup.exe` resolve from the top-level `codex-resources/` directory while preserving the direct-sibling and older sibling-resource fallbacks.

## Test plan

- `sh -n scripts/install/install.sh`
- `bash -n scripts/install/install.sh`
- `pwsh -NoProfile -Command '$tokens=$null; $errors=$null; $null = [System.Management.Automation.Language.Parser]::ParseFile("scripts/install/install.ps1", [ref]$tokens, [ref]$errors); if ($errors.Count) { $errors | Format-List *; exit 1 }'`
- `HOME="$home_dir" CODEX_HOME="$tmp_dir/codex-home" CODEX_INSTALL_DIR="$bin_dir" PATH="$bin_dir:$PATH" sh scripts/install/install.sh --release 0.125.0`
- Verified the 0.125.0 isolated install leaves the visible command pointed at `current/codex` and includes the legacy `codex-resources/rg` payload.
- `cargo test -p codex-windows-sandbox`
- `just fix -p codex-windows-sandbox`
@bolinfest
Copy link
Copy Markdown
Collaborator Author

@efrazer-oai addressed in 2917f373354e: the Windows helper lookups now check the package-root codex-resources/ when codex.exe is running from bin/. This covers both codex-command-runner.exe and codex-windows-sandbox-setup.exe, while preserving the direct-sibling and legacy sibling codex-resources/ fallbacks.

I also added Windows-only unit coverage for those lookup paths.

@bolinfest bolinfest merged commit 110b30d into main May 20, 2026
47 of 62 checks passed
@bolinfest bolinfest deleted the pr23636 branch May 20, 2026 18:20
@github-actions github-actions Bot locked and limited conversation to collaborators May 20, 2026
@iceweasel-oai
Copy link
Copy Markdown
Collaborator

Windows sandbox changes look correct. There is a little duplication of the "find the exe" logic between setup.rs and helper_materialization.rs but certainly non-blocking, nice-to-have

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

4 participants