release/npm: bundle standalone bwrap on Linux (#21257)

This commit is contained in:
Michael Bolin
2026-05-05 18:21:52 -07:00
committed by GitHub
parent db22c91e61
commit a736cb55a2
7 changed files with 72 additions and 17 deletions
+12
View File
@@ -84,6 +84,18 @@
} }
} }
}, },
"bwrap": {
"platforms": {
"linux-x86_64": {
"regex": "^bwrap-x86_64-unknown-linux-musl\\.zst$",
"path": "bwrap"
},
"linux-aarch64": {
"regex": "^bwrap-aarch64-unknown-linux-musl\\.zst$",
"path": "bwrap"
}
}
},
"codex-command-runner": { "codex-command-runner": {
"platforms": { "platforms": {
"windows-x86_64": { "windows-x86_64": {
+2
View File
@@ -52,10 +52,12 @@ jobs:
CODEX_VERSION=0.125.0 CODEX_VERSION=0.125.0
WORKFLOW_URL="https://github.com/openai/codex/actions/runs/24901475298" WORKFLOW_URL="https://github.com/openai/codex/actions/runs/24901475298"
OUTPUT_DIR="${RUNNER_TEMP}" OUTPUT_DIR="${RUNNER_TEMP}"
# This reused workflow predates the standalone bwrap artifact.
python3 ./scripts/stage_npm_packages.py \ python3 ./scripts/stage_npm_packages.py \
--release-version "$CODEX_VERSION" \ --release-version "$CODEX_VERSION" \
--workflow-url "$WORKFLOW_URL" \ --workflow-url "$WORKFLOW_URL" \
--package codex \ --package codex \
--allow-missing-native-component bwrap \
--output-dir "$OUTPUT_DIR" --output-dir "$OUTPUT_DIR"
PACK_OUTPUT="${OUTPUT_DIR}/codex-npm-${CODEX_VERSION}.tgz" PACK_OUTPUT="${OUTPUT_DIR}/codex-npm-${CODEX_VERSION}.tgz"
echo "pack_output=$PACK_OUTPUT" >> "$GITHUB_OUTPUT" echo "pack_output=$PACK_OUTPUT" >> "$GITHUB_OUTPUT"
+4 -10
View File
@@ -96,7 +96,7 @@ jobs:
target: x86_64-unknown-linux-musl target: x86_64-unknown-linux-musl
bundle: primary bundle: primary
artifact_name: x86_64-unknown-linux-musl artifact_name: x86_64-unknown-linux-musl
binaries: "codex codex-responses-api-proxy" binaries: "codex codex-responses-api-proxy bwrap"
build_dmg: "false" build_dmg: "false"
- runner: ubuntu-24.04 - runner: ubuntu-24.04
target: x86_64-unknown-linux-musl target: x86_64-unknown-linux-musl
@@ -108,7 +108,7 @@ jobs:
target: aarch64-unknown-linux-musl target: aarch64-unknown-linux-musl
bundle: primary bundle: primary
artifact_name: aarch64-unknown-linux-musl artifact_name: aarch64-unknown-linux-musl
binaries: "codex codex-responses-api-proxy" binaries: "codex codex-responses-api-proxy bwrap"
build_dmg: "false" build_dmg: "false"
- runner: ubuntu-24.04-arm - runner: ubuntu-24.04-arm
target: aarch64-unknown-linux-musl target: aarch64-unknown-linux-musl
@@ -255,7 +255,7 @@ jobs:
with: with:
target: ${{ matrix.target }} target: ${{ matrix.target }}
- if: ${{ contains(matrix.target, 'linux') }} - if: ${{ contains(matrix.target, 'linux') && matrix.bundle == 'primary' }}
name: Build bwrap and export digest name: Build bwrap and export digest
shell: bash shell: bash
run: | run: |
@@ -296,7 +296,7 @@ jobs:
with: with:
target: ${{ matrix.target }} target: ${{ matrix.target }}
artifacts-dir: ${{ github.workspace }}/codex-rs/target/${{ matrix.target }}/release artifacts-dir: ${{ github.workspace }}/codex-rs/target/${{ matrix.target }}/release
binaries: ${{ matrix.binaries }} bwrap binaries: ${{ matrix.binaries }}
- if: ${{ runner.os == 'macOS' }} - if: ${{ runner.os == 'macOS' }}
name: MacOS code signing (binaries) name: MacOS code signing (binaries)
@@ -379,12 +379,6 @@ jobs:
fi fi
done done
if [[ "${{ matrix.target }}" == *linux* && "${{ matrix.bundle }}" == "primary" ]]; then
cp "target/${{ matrix.target }}/release/bwrap" "$dest/bwrap-${{ matrix.target }}"
cp "target/${{ matrix.target }}/release/bwrap.sigstore" \
"$dest/bwrap-${{ matrix.target }}.sigstore"
fi
if [[ "${{ matrix.build_dmg }}" == "true" ]]; then if [[ "${{ matrix.build_dmg }}" == "true" ]]; then
cp target/${{ matrix.target }}/release/codex-${{ matrix.target }}.dmg "$dest/codex-${{ matrix.target }}.dmg" cp target/${{ matrix.target }}/release/codex-${{ matrix.target }}.dmg "$dest/codex-${{ matrix.target }}.dmg"
fi fi
+18 -2
View File
@@ -69,8 +69,8 @@ PACKAGE_EXPANSIONS: dict[str, list[str]] = {
PACKAGE_NATIVE_COMPONENTS: dict[str, list[str]] = { PACKAGE_NATIVE_COMPONENTS: dict[str, list[str]] = {
"codex": [], "codex": [],
"codex-linux-x64": ["codex", "rg"], "codex-linux-x64": ["bwrap", "codex", "rg"],
"codex-linux-arm64": ["codex", "rg"], "codex-linux-arm64": ["bwrap", "codex", "rg"],
"codex-darwin-x64": ["codex", "rg"], "codex-darwin-x64": ["codex", "rg"],
"codex-darwin-arm64": ["codex", "rg"], "codex-darwin-arm64": ["codex", "rg"],
"codex-win32-x64": ["codex", "rg", "codex-windows-sandbox-setup", "codex-command-runner"], "codex-win32-x64": ["codex", "rg", "codex-windows-sandbox-setup", "codex-command-runner"],
@@ -87,6 +87,7 @@ PACKAGE_TARGET_FILTERS: dict[str, str] = {
PACKAGE_CHOICES = tuple(PACKAGE_NATIVE_COMPONENTS) PACKAGE_CHOICES = tuple(PACKAGE_NATIVE_COMPONENTS)
COMPONENT_DEST_DIR: dict[str, str] = { COMPONENT_DEST_DIR: dict[str, str] = {
"bwrap": "codex-resources",
"codex": "codex", "codex": "codex",
"codex-responses-api-proxy": "codex-responses-api-proxy", "codex-responses-api-proxy": "codex-responses-api-proxy",
"codex-windows-sandbox-setup": "codex", "codex-windows-sandbox-setup": "codex",
@@ -137,6 +138,16 @@ def parse_args() -> argparse.Namespace:
type=Path, type=Path,
help="Directory containing pre-installed native binaries to bundle (vendor root).", help="Directory containing pre-installed native binaries to bundle (vendor root).",
) )
parser.add_argument(
"--allow-missing-native-component",
dest="allow_missing_native_components",
action="append",
default=[],
help=(
"Native component that may be absent from --vendor-src. Intended for CI "
"compatibility with older artifact workflows; releases should not use this."
),
)
return parser.parse_args() return parser.parse_args()
@@ -177,6 +188,7 @@ def main() -> int:
staging_dir, staging_dir,
native_components, native_components,
target_filter={target_filter} if target_filter else None, target_filter={target_filter} if target_filter else None,
allow_missing_components=set(args.allow_missing_native_components),
) )
if release_version: if release_version:
@@ -365,12 +377,14 @@ def copy_native_binaries(
staging_dir: Path, staging_dir: Path,
components: list[str], components: list[str],
target_filter: set[str] | None = None, target_filter: set[str] | None = None,
allow_missing_components: set[str] | None = None,
) -> None: ) -> None:
vendor_src = vendor_src.resolve() vendor_src = vendor_src.resolve()
if not vendor_src.exists(): if not vendor_src.exists():
raise RuntimeError(f"Vendor source directory not found: {vendor_src}") raise RuntimeError(f"Vendor source directory not found: {vendor_src}")
components_set = {component for component in components if component in COMPONENT_DEST_DIR} components_set = {component for component in components if component in COMPONENT_DEST_DIR}
allow_missing_components = allow_missing_components or set()
if not components_set: if not components_set:
return return
@@ -399,6 +413,8 @@ def copy_native_binaries(
src_component_dir = target_dir / dest_dir_name src_component_dir = target_dir / dest_dir_name
if not src_component_dir.exists(): if not src_component_dir.exists():
if component in allow_missing_components:
continue
raise RuntimeError( raise RuntimeError(
f"Missing native component '{component}' in vendor source: {src_component_dir}" f"Missing native component '{component}' in vendor source: {src_component_dir}"
) )
+10 -2
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
"""Install Codex native binaries (Rust CLI plus ripgrep helpers).""" """Install Codex native binaries (Rust CLI, bwrap, and ripgrep helpers)."""
import argparse import argparse
from contextlib import contextmanager from contextlib import contextmanager
@@ -42,8 +42,15 @@ class BinaryComponent:
WINDOWS_TARGETS = tuple(target for target in BINARY_TARGETS if "windows" in target) WINDOWS_TARGETS = tuple(target for target in BINARY_TARGETS if "windows" in target)
LINUX_TARGETS = tuple(target for target in BINARY_TARGETS if "linux" in target)
BINARY_COMPONENTS = { BINARY_COMPONENTS = {
"bwrap": BinaryComponent(
artifact_prefix="bwrap",
dest_dir="codex-resources",
binary_basename="bwrap",
targets=LINUX_TARGETS,
),
"codex": BinaryComponent( "codex": BinaryComponent(
artifact_prefix="codex", artifact_prefix="codex",
dest_dir="codex", dest_dir="codex",
@@ -135,7 +142,7 @@ def parse_args() -> argparse.Namespace:
choices=tuple(list(BINARY_COMPONENTS) + ["rg"]), choices=tuple(list(BINARY_COMPONENTS) + ["rg"]),
help=( help=(
"Limit installation to the specified components." "Limit installation to the specified components."
" May be repeated. Defaults to codex, codex-windows-sandbox-setup," " May be repeated. Defaults to bwrap, codex, codex-windows-sandbox-setup,"
" codex-command-runner, and rg." " codex-command-runner, and rg."
), ),
) )
@@ -159,6 +166,7 @@ def main() -> int:
vendor_dir.mkdir(parents=True, exist_ok=True) vendor_dir.mkdir(parents=True, exist_ok=True)
components = args.components or [ components = args.components or [
"bwrap",
"codex", "codex",
"codex-windows-sandbox-setup", "codex-windows-sandbox-setup",
"codex-command-runner", "codex-command-runner",
+9 -1
View File
@@ -596,6 +596,10 @@ install_release() {
cp "$vendor_root/path/rg" "$stage_release/codex-resources/rg" cp "$vendor_root/path/rg" "$stage_release/codex-resources/rg"
chmod 0755 "$stage_release/codex" chmod 0755 "$stage_release/codex"
chmod 0755 "$stage_release/codex-resources/rg" chmod 0755 "$stage_release/codex-resources/rg"
if [ -f "$vendor_root/codex-resources/bwrap" ]; then
cp "$vendor_root/codex-resources/bwrap" "$stage_release/codex-resources/bwrap"
chmod 0755 "$stage_release/codex-resources/bwrap"
fi
if [ -e "$release_dir" ] || [ -L "$release_dir" ]; then if [ -e "$release_dir" ] || [ -L "$release_dir" ]; then
rm -rf "$release_dir" rm -rf "$release_dir"
@@ -611,7 +615,11 @@ release_dir_is_complete() {
[ -d "$release_dir" ] && [ -d "$release_dir" ] &&
[ -x "$release_dir/codex" ] && [ -x "$release_dir/codex" ] &&
[ -x "$release_dir/codex-resources/rg" ] && [ -x "$release_dir/codex-resources/rg" ] &&
[ "$(basename "$release_dir")" = "$expected_version-$expected_target" ] [ "$(basename "$release_dir")" = "$expected_version-$expected_target" ] &&
case "$expected_target" in
*linux*) [ -x "$release_dir/codex-resources/bwrap" ] ;;
*) true ;;
esac
} }
update_current_link() { update_current_link() {
+17 -2
View File
@@ -58,6 +58,16 @@ def parse_args() -> argparse.Namespace:
action="store_true", action="store_true",
help="Retain temporary staging directories instead of deleting them.", help="Retain temporary staging directories instead of deleting them.",
) )
parser.add_argument(
"--allow-missing-native-component",
dest="allow_missing_native_components",
action="append",
default=[],
help=(
"Native component that may be absent from reused workflow artifacts. "
"Intended for CI compatibility only; release staging should not use this."
),
)
return parser.parse_args() return parser.parse_args()
@@ -147,6 +157,8 @@ def main() -> int:
packages = expand_packages(list(args.packages)) packages = expand_packages(list(args.packages))
native_components = collect_native_components(packages) native_components = collect_native_components(packages)
allow_missing_native_components = set(args.allow_missing_native_components)
native_components_to_install = native_components - allow_missing_native_components
vendor_temp_root: Path | None = None vendor_temp_root: Path | None = None
vendor_src: Path | None = None vendor_src: Path | None = None
@@ -155,12 +167,12 @@ def main() -> int:
final_messages = [] final_messages = []
try: try:
if native_components: if native_components_to_install:
workflow_url, resolved_head_sha = resolve_workflow_url( workflow_url, resolved_head_sha = resolve_workflow_url(
args.release_version, args.workflow_url args.release_version, args.workflow_url
) )
vendor_temp_root = Path(tempfile.mkdtemp(prefix="npm-native-", dir=runner_temp)) vendor_temp_root = Path(tempfile.mkdtemp(prefix="npm-native-", dir=runner_temp))
install_native_components(workflow_url, native_components, vendor_temp_root) install_native_components(workflow_url, native_components_to_install, vendor_temp_root)
vendor_src = vendor_temp_root / "vendor" vendor_src = vendor_temp_root / "vendor"
if resolved_head_sha: if resolved_head_sha:
@@ -185,6 +197,9 @@ def main() -> int:
if vendor_src is not None: if vendor_src is not None:
cmd.extend(["--vendor-src", str(vendor_src)]) cmd.extend(["--vendor-src", str(vendor_src)])
for component in sorted(allow_missing_native_components):
cmd.extend(["--allow-missing-native-component", component])
try: try:
run_command(cmd) run_command(cmd)
finally: finally: