package: include zsh fork in Codex package

Summary:
- add a checked-in codex-zsh DotSlash manifest for supported Unix targets
- fetch the matching zsh fork artifact during package builds and install it at codex-resources/zsh/bin/zsh when available
- expose the bundled zsh fork through install-context and use it as the runtime zsh path for packaged installs
- remove the user/profile zsh_path config override now that the fork is package-managed
- update app-server zsh-fork integration tests to spawn from a temporary package layout instead of configuring zsh_path directly
- use copyfile for package executable staging so local package smoke tests do not preserve platform-specific source metadata

Test Plan:
- just fmt
- just write-config-schema
- just fix -p codex-config -p codex-core -p codex-exec
- just fix -p codex-app-server
- python3 -m py_compile scripts/codex_package/cli.py scripts/codex_package/layout.py scripts/codex_package/zsh.py
- python3 -m unittest discover scripts/codex_package
- cargo test -p codex-core default_zsh_path_sets_runtime_zsh_path
- cargo test -p codex-core session_new_fails_when_zsh_fork_enabled_without_packaged_zsh
- cargo test -p codex-core restricted_read_implicitly_allows_helper_executables
- cargo test -p codex-config
- cargo test -p codex-app-server turn_start_shell_zsh_fork_executes_command_v2
- cargo test -p codex-app-server turn_start_shell_zsh_fork
This commit is contained in:
Michael Bolin
2026-05-22 16:12:20 -07:00
parent 7924743c38
commit 72eb55f540
27 changed files with 280 additions and 49 deletions
+7
View File
@@ -13,6 +13,7 @@ The builder creates a canonical Codex package directory:
│ └── <entrypoint>[.exe]
├── codex-resources
│ ├── bwrap # Linux only
│ ├── zsh/bin/zsh # supported Unix targets only
│ ├── codex-command-runner.exe # Windows only
│ └── codex-windows-sandbox-setup.exe # Windows only
└── codex-path
@@ -67,3 +68,9 @@ DotSlash manifest at `scripts/codex_package/rg`. Downloaded archives are cached
under `$TMPDIR/codex-package/<target>-rg` and are reused only after the recorded
size and SHA-256 digest have been verified. Pass `--rg-bin` to use a local
ripgrep executable instead.
The patched zsh fork used by `shell_zsh_fork` is fetched from the DotSlash
manifest at `scripts/codex_package/codex-zsh` when the selected target has a
matching prebuilt artifact. Downloaded archives are cached under
`$TMPDIR/codex-package/<target>-zsh` and installed at
`codex-resources/zsh/bin/zsh`.
+3 -1
View File
@@ -15,6 +15,7 @@ from .targets import TARGET_SPECS
from .targets import PackageInputs
from .targets import default_target
from .targets import resolve_input_path
from .zsh import resolve_zsh_bin
from .version import read_workspace_version
@@ -161,13 +162,14 @@ def main() -> int:
inputs = PackageInputs(
entrypoint_bin=source_outputs.entrypoint_bin,
rg_bin=resolve_rg_bin(spec, args.rg_bin),
zsh_bin=resolve_zsh_bin(spec),
bwrap_bin=source_outputs.bwrap_bin,
codex_command_runner_bin=source_outputs.codex_command_runner_bin,
codex_windows_sandbox_setup_bin=source_outputs.codex_windows_sandbox_setup_bin,
)
prepare_package_dir(package_dir, force=args.force)
build_package_dir(package_dir, version, variant, spec, inputs)
validate_package_dir(package_dir, variant, spec)
validate_package_dir(package_dir, variant, spec, include_zsh=inputs.zsh_bin is not None)
for archive_output in args.archive_output:
archive_path = archive_output.resolve()
+43
View File
@@ -0,0 +1,43 @@
#!/usr/bin/env dotslash
{
"name": "codex-zsh",
"platforms": {
"macos-aarch64": {
"size": 358776,
"hash": "sha256",
"digest": "c6dbb063a0135b947ab1cacc655b2b750874699472f412ec7daba97543a90c3c",
"format": "tar.gz",
"path": "codex-zsh/bin/zsh",
"providers": [
{
"url": "https://github.com/openai/codex/releases/download/rust-v0.132.0/codex-zsh-aarch64-apple-darwin.tar.gz"
}
]
},
"linux-x86_64": {
"size": 433413,
"hash": "sha256",
"digest": "5f42d9fc8e9c8c399a727512002906006ae9de966ea7b3d87ca36b47efc59938",
"format": "tar.gz",
"path": "codex-zsh/bin/zsh",
"providers": [
{
"url": "https://github.com/openai/codex/releases/download/rust-v0.132.0/codex-zsh-x86_64-unknown-linux-musl.tar.gz"
}
]
},
"linux-aarch64": {
"size": 411653,
"hash": "sha256",
"digest": "6c6e32c297425db02b4dbffb10925895875d14647fc3eb2f18767be97dc6a945",
"format": "tar.gz",
"path": "codex-zsh/bin/zsh",
"providers": [
{
"url": "https://github.com/openai/codex/releases/download/rust-v0.132.0/codex-zsh-aarch64-unknown-linux-musl.tar.gz"
}
]
}
}
}
+16 -1
View File
@@ -8,6 +8,7 @@ from pathlib import Path
from .targets import PackageInputs
from .targets import PackageVariant
from .targets import TargetSpec
from .zsh import ZSH_RESOURCE_PATH
LAYOUT_VERSION = 1
@@ -50,6 +51,13 @@ def build_package_dir(
)
copy_executable(inputs.rg_bin, path_dir / spec.rg_name, is_windows=spec.is_windows)
if inputs.zsh_bin is not None:
copy_executable(
inputs.zsh_bin,
resources_dir / ZSH_RESOURCE_PATH,
is_windows=False,
)
if inputs.bwrap_bin is not None:
copy_executable(inputs.bwrap_bin, resources_dir / "bwrap", is_windows=False)
@@ -83,6 +91,8 @@ def validate_package_dir(
package_dir: Path,
variant: PackageVariant,
spec: TargetSpec,
*,
include_zsh: bool,
) -> None:
required_dirs = [
Path("bin"),
@@ -122,6 +132,11 @@ def validate_package_dir(
]
executable_files = list(required_files)
if include_zsh:
zsh_path = Path("codex-resources") / ZSH_RESOURCE_PATH
required_files.append(zsh_path)
executable_files.append(zsh_path)
if spec.is_linux:
required_files.append(Path("codex-resources") / "bwrap")
executable_files.append(Path("codex-resources") / "bwrap")
@@ -148,7 +163,7 @@ def validate_package_dir(
def copy_executable(src: Path, dest: Path, *, is_windows: bool) -> None:
dest.parent.mkdir(parents=True, exist_ok=True)
shutil.copy2(src, dest)
shutil.copyfile(src, dest)
if not is_windows:
mode = dest.stat().st_mode
dest.chmod(mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
+1
View File
@@ -40,6 +40,7 @@ class PackageVariant:
class PackageInputs:
entrypoint_bin: Path
rg_bin: Path
zsh_bin: Path | None
bwrap_bin: Path | None
codex_command_runner_bin: Path | None
codex_windows_sandbox_setup_bin: Path | None
+22
View File
@@ -0,0 +1,22 @@
"""Fetch the patched zsh fork used by shell_zsh_fork."""
from pathlib import Path
from .dotslash import fetch_dotslash_executable
from .targets import REPO_ROOT
from .targets import TargetSpec
ZSH_MANIFEST = REPO_ROOT / "scripts" / "codex_package" / "codex-zsh"
ZSH_RESOURCE_PATH = Path("zsh") / "bin" / "zsh"
def resolve_zsh_bin(spec: TargetSpec) -> Path | None:
return fetch_dotslash_executable(
spec,
manifest_path=ZSH_MANIFEST,
artifact_label="codex-zsh",
cache_key=f"{spec.target}-zsh",
dest_name="zsh",
missing_ok=True,
)