mirror of
https://github.com/openai/codex.git
synced 2026-10-29 19:08:43 +00:00
## What changed - Build and bundle the standalone executor in `bin/` for both package variants, and advertise its path through `execServer` in `codex-package.json`. - Include the executor in Cargo and Bazel release packaging, macOS signing and notarization, and Windows signing verification. Preserve prebuilt signed binaries during packaging. - Make installers detect a missing advertised executor while continuing to accept older packages without it. ## Testing Add coverage for executor archive contents and executable permissions, signed binary preservation, and macOS entitlement verification. Add package smoke tests for initialization, version reporting, filesystem and process sandbox enforcement, and startup error parity with `codex exec-server`. GitOrigin-RevId: 5c0027fc19f16cf9c2a5bb52dbd065a9776bc2af
283 lines
9.3 KiB
Python
283 lines
9.3 KiB
Python
"""Command-line interface for building Codex package directories."""
|
|
|
|
import argparse
|
|
import re
|
|
import tempfile
|
|
from pathlib import Path
|
|
|
|
from .archive import write_archive
|
|
from .cargo import build_source_binaries
|
|
from .layout import build_package_dir
|
|
from .layout import prepare_package_dir
|
|
from .layout import validate_package_dir
|
|
from .ripgrep import resolve_rg_bin
|
|
from .symbols import strip_binary
|
|
from .targets import PACKAGE_VARIANTS
|
|
from .targets import TARGET_SPECS
|
|
from .targets import PackageInputs
|
|
from .targets import default_target
|
|
from .targets import resolve_input_path
|
|
from .version import read_workspace_version
|
|
|
|
|
|
# Release pipelines run this builder with system Python, so avoid new dependencies.
|
|
SEMVER_PATTERN = re.compile(
|
|
r"(?P<major>0|[1-9][0-9]*)\."
|
|
r"(?P<minor>0|[1-9][0-9]*)\."
|
|
r"(?P<patch>0|[1-9][0-9]*)"
|
|
r"(?:-(?P<prerelease>[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?"
|
|
r"(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?"
|
|
)
|
|
|
|
|
|
def parse_package_version(value: str) -> str:
|
|
match = SEMVER_PATTERN.fullmatch(value)
|
|
if match is not None:
|
|
components = (match.group(name) for name in ("major", "minor", "patch"))
|
|
prerelease = match.group("prerelease") or ""
|
|
if all(int(component) <= 2**64 - 1 for component in components) and all(
|
|
not (part.isdigit() and len(part) > 1 and part.startswith("0"))
|
|
for part in prerelease.split(".")
|
|
):
|
|
return value
|
|
|
|
raise argparse.ArgumentTypeError(f"invalid semantic version: {value!r}")
|
|
|
|
|
|
def parse_args() -> argparse.Namespace:
|
|
return create_parser().parse_args()
|
|
|
|
|
|
def create_parser() -> argparse.ArgumentParser:
|
|
parser = argparse.ArgumentParser(
|
|
description="Build a canonical Codex package directory and optional archive.",
|
|
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
|
)
|
|
parser.add_argument(
|
|
"--target",
|
|
default=argparse.SUPPRESS,
|
|
choices=sorted(TARGET_SPECS),
|
|
help=(
|
|
"Rust target triple for the package. Defaults to the release target "
|
|
"for this host platform."
|
|
),
|
|
)
|
|
parser.add_argument(
|
|
"--variant",
|
|
choices=sorted(PACKAGE_VARIANTS),
|
|
default="codex",
|
|
help="Package variant to build.",
|
|
)
|
|
parser.add_argument(
|
|
"--package-version",
|
|
type=parse_package_version,
|
|
default=read_workspace_version(),
|
|
help="Semantic version to record in codex-package.json.",
|
|
)
|
|
parser.add_argument(
|
|
"--package-dir",
|
|
type=Path,
|
|
default=argparse.SUPPRESS,
|
|
help=(
|
|
"Output directory to create as the package root. Defaults to a new temporary directory."
|
|
),
|
|
)
|
|
parser.add_argument(
|
|
"--archive-output",
|
|
type=Path,
|
|
action="append",
|
|
default=[],
|
|
help=(
|
|
"Optional archive output path. May be repeated. Supported suffixes: "
|
|
".tar.gz, .tgz, .tar.zst, .zip."
|
|
),
|
|
)
|
|
parser.add_argument(
|
|
"--force",
|
|
action="store_true",
|
|
help="Replace an existing package directory or archive output.",
|
|
)
|
|
parser.add_argument(
|
|
"--cargo",
|
|
default="cargo",
|
|
help="Cargo executable to use for source-built package artifacts.",
|
|
)
|
|
parser.add_argument(
|
|
"--cargo-profile",
|
|
default="dev-small",
|
|
help=(
|
|
"Cargo profile for source-built package artifacts. Use release for release packages."
|
|
),
|
|
)
|
|
parser.add_argument(
|
|
"--strip",
|
|
choices=("auto", "all", "none"),
|
|
default="auto",
|
|
help=(
|
|
"Strip Unix first-party package binaries: auto strips source-built "
|
|
"release-profile inputs, all also strips other profiles and prebuilt "
|
|
"inputs, none preserves symbols. "
|
|
"Original inputs and third-party resources are never modified."
|
|
),
|
|
)
|
|
parser.add_argument(
|
|
"--strip-tool",
|
|
help="Target-compatible strip executable override, for example llvm-strip.",
|
|
)
|
|
parser.add_argument(
|
|
"--entrypoint-bin",
|
|
type=Path,
|
|
help=(
|
|
"Optional prebuilt entrypoint executable for the selected package "
|
|
"variant. If omitted, the entrypoint is built with Cargo."
|
|
),
|
|
)
|
|
parser.add_argument(
|
|
"--code-mode-host-bin",
|
|
type=Path,
|
|
help=(
|
|
"Optional prebuilt codex-code-mode-host executable. If omitted, "
|
|
"the host is built with Cargo."
|
|
),
|
|
)
|
|
parser.add_argument(
|
|
"--exec-server-bin",
|
|
type=Path,
|
|
help="Optional prebuilt codex-exec-server executable. If omitted, build it with Cargo.",
|
|
)
|
|
parser.add_argument(
|
|
"--bwrap-bin",
|
|
type=Path,
|
|
help=(
|
|
"Optional prebuilt Linux bwrap executable. If omitted for Linux "
|
|
"targets, bwrap is built with Cargo."
|
|
),
|
|
)
|
|
parser.add_argument(
|
|
"--codex-command-runner-bin",
|
|
type=Path,
|
|
help=(
|
|
"Optional prebuilt Windows codex-command-runner.exe executable. "
|
|
"If omitted for Windows targets, codex-command-runner is built "
|
|
"with Cargo."
|
|
),
|
|
)
|
|
parser.add_argument(
|
|
"--codex-windows-sandbox-setup-bin",
|
|
type=Path,
|
|
help=(
|
|
"Optional prebuilt Windows codex-windows-sandbox-setup.exe "
|
|
"executable. If omitted for Windows targets, "
|
|
"codex-windows-sandbox-setup is built with Cargo."
|
|
),
|
|
)
|
|
parser.add_argument(
|
|
"--rg-bin",
|
|
type=Path,
|
|
help=(
|
|
"Optional local ripgrep executable override instead of fetching from "
|
|
"scripts/codex_package/rg."
|
|
),
|
|
)
|
|
return parser
|
|
|
|
|
|
def main() -> int:
|
|
args = parse_args()
|
|
package_dir = assemble_package(args)
|
|
archive_package(package_dir, args)
|
|
return 0
|
|
|
|
|
|
def assemble_package(args: argparse.Namespace) -> Path:
|
|
"""Build the directory before optional downstream additions and archiving."""
|
|
spec = TARGET_SPECS[getattr(args, "target", None) or default_target()]
|
|
variant = PACKAGE_VARIANTS[args.variant]
|
|
package_dir_arg = getattr(args, "package_dir", None)
|
|
package_dir = (
|
|
package_dir_arg.resolve()
|
|
if package_dir_arg is not None
|
|
else Path(tempfile.mkdtemp(prefix="codex-package-")).resolve()
|
|
)
|
|
|
|
source_outputs = build_source_binaries(
|
|
spec,
|
|
variant,
|
|
cargo=args.cargo,
|
|
profile=args.cargo_profile,
|
|
entrypoint_bin=resolve_optional_input_path(
|
|
args.entrypoint_bin,
|
|
"prebuilt entrypoint executable",
|
|
"--entrypoint-bin",
|
|
),
|
|
code_mode_host_bin=resolve_optional_input_path(
|
|
args.code_mode_host_bin,
|
|
"prebuilt code-mode host executable",
|
|
"--code-mode-host-bin",
|
|
),
|
|
exec_server_bin=resolve_optional_input_path(
|
|
args.exec_server_bin,
|
|
"prebuilt executor executable",
|
|
"--exec-server-bin",
|
|
),
|
|
bwrap_bin=resolve_optional_input_path(
|
|
args.bwrap_bin,
|
|
"prebuilt Linux bwrap executable",
|
|
"--bwrap-bin",
|
|
),
|
|
codex_command_runner_bin=resolve_optional_input_path(
|
|
args.codex_command_runner_bin,
|
|
"prebuilt Windows codex-command-runner.exe executable",
|
|
"--codex-command-runner-bin",
|
|
),
|
|
codex_windows_sandbox_setup_bin=resolve_optional_input_path(
|
|
args.codex_windows_sandbox_setup_bin,
|
|
"prebuilt Windows codex-windows-sandbox-setup.exe executable",
|
|
"--codex-windows-sandbox-setup-bin",
|
|
),
|
|
)
|
|
inputs = PackageInputs(
|
|
entrypoint_bin=source_outputs.entrypoint_bin,
|
|
code_mode_host_bin=source_outputs.code_mode_host_bin,
|
|
exec_server_bin=source_outputs.exec_server_bin,
|
|
rg_bin=resolve_rg_bin(spec, args.rg_bin),
|
|
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, args.package_version, variant, spec, inputs)
|
|
for filename, prebuilt in (
|
|
(variant.entrypoint_name(spec), args.entrypoint_bin),
|
|
(f"codex-code-mode-host{spec.exe_suffix}", args.code_mode_host_bin),
|
|
(f"codex-exec-server{spec.exe_suffix}", args.exec_server_bin),
|
|
):
|
|
if args.strip == "all" or (
|
|
args.strip == "auto"
|
|
and args.cargo_profile == "release"
|
|
and prebuilt is None
|
|
):
|
|
strip_binary(package_dir / "bin" / filename, spec, tool=args.strip_tool)
|
|
validate_package_dir(package_dir, variant, spec)
|
|
return package_dir
|
|
|
|
|
|
def archive_package(package_dir: Path, args: argparse.Namespace) -> None:
|
|
for archive_output in args.archive_output:
|
|
archive_path = archive_output.resolve()
|
|
write_archive(package_dir, archive_path, force=args.force)
|
|
print(f"Built Codex package archive at {archive_path}")
|
|
|
|
print(f"Built Codex package directory at {package_dir}")
|
|
|
|
|
|
def resolve_optional_input_path(
|
|
explicit_path: Path | None,
|
|
description: str,
|
|
flag_name: str,
|
|
) -> Path | None:
|
|
if explicit_path is None:
|
|
return None
|
|
|
|
return resolve_input_path(explicit_path, description, flag_name)
|