Files
codex/.github/scripts/macos-signing/sign_macos_cli_package.py
T
Dmitriy Kovalenko cf2c04b325 Ship codex-exec-server in CLI and app-server packages (#57590)
## 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
2026-10-27 23:14:18 +00:00

192 lines
7.4 KiB
Python

"""Sign and verify macOS CLI packages using the shared AKV and native tools."""
import argparse
import os
import plistlib
import subprocess
import sys
from pathlib import Path
import provisioned_macos_cli_package as bundle
def main(configuration: bundle.ProfileConfiguration | None = None):
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("operation", choices=("sign", "verify"))
parser.add_argument("package", type=Path)
args, configuration = bundle.parse_profile_args(parser, configuration)
package = args.package.resolve(strict=True)
if not package.is_dir():
parser.error("package must be an extracted CLI package directory")
repo_root = os.environ.get("CODEX_REPO_ROOT")
if not repo_root:
parser.error("CODEX_REPO_ROOT must be set")
reports = Path(repo_root) / "signing-verification"
reports.mkdir(parents=True, exist_ok=True)
provisioned = os.environ.get("PROVISIONED_MACOS", "false") == "true"
if provisioned:
if args.operation == "sign":
configuration.validate_signing_certificate(
Path(os.environ["OAI_AKV_SIGNING_CERTIFICATE_PEM"])
)
bundle.prepare(package, reports, configuration)
else:
bundle.verify(package, reports, os.environ["TARGET"], configuration)
for relative in ("bin/codex", *bundle.HELPERS):
binary = package / relative
name = binary.name
target = binary
identifier = name
entitlements = bundle.SIGNING / f"{name}.entitlements.plist"
if provisioned and relative == "bin/codex":
binary = package / bundle.EXECUTABLE
target = package / bundle.APP
identifier = bundle.CODE_SIGNING_ID
entitlements = reports / "codex-provisioned-entitlements.plist"
if args.operation == "sign":
command = [
"bash",
str(bundle.SIGNING / "sign_macos_code.sh"),
"--target",
str(target),
"--identity",
"unused",
"--deep",
"false",
"--options",
"runtime",
"--timestamp",
"true",
]
if relative.startswith("bin/"):
command.extend(
["--identifier", identifier, "--entitlements", str(entitlements)]
)
else:
command.extend(["--identifier", f"com.openai.codex.{name}"])
subprocess.run(command, check=True)
with (reports / f"{name}-signature.yaml").open("wb") as output:
subprocess.run(
["rcodesign", "print-signature-info", str(binary)],
stdout=output,
check=True,
)
if not provisioned:
subprocess.run(
[
"bash",
str(bundle.SIGNING / "notarize_macos_binary_with_akv.sh"),
"--binary",
str(binary),
"--report-dir",
str(reports / name),
],
check=True,
)
else:
target_triple = os.environ["TARGET"]
architectures = {
"aarch64-apple-darwin": "arm64",
"x86_64-apple-darwin": "x86_64",
}
if target_triple not in architectures:
raise ValueError(f"Unexpected macOS target: {target_triple}")
subprocess.run(
["lipo", str(binary), "-verify_arch", architectures[target_triple]],
check=True,
)
# Preserve the CLI's existing login-keychain identity while checking
# its bundle/App ID and provisioning independently in bundle.verify.
requirement = (
"=anchor apple generic"
" and certificate 1[field.1.2.840.113635.100.6.2.6] exists"
" and certificate leaf[field.1.2.840.113635.100.6.1.13] exists"
)
if provisioned and relative == "bin/codex":
requirement += (
f' and identifier "{bundle.CODE_SIGNING_ID}"'
f' and certificate leaf[subject.OU] = "{configuration.team_id}"'
)
subprocess.run(
[
"codesign",
"--verify",
"--strict",
"--verbose=2",
"--test-requirement",
requirement,
str(target),
],
check=True,
)
signature = reports / f"{name}-signature.txt"
with signature.open("wb") as output:
subprocess.run(
["codesign", "-d", "--verbose=4", str(target)],
stderr=output,
check=True,
)
actual = reports / f"{name}-entitlements.plist"
with actual.open("wb") as output:
subprocess.run(
["codesign", "-d", "--entitlements", ":-", str(target)],
stdout=output,
check=True,
)
if relative.startswith("bin/"):
# Signing tools may omit the blob when no entitlements are requested.
if (
actual.stat().st_size == 0
and plistlib.loads(entitlements.read_bytes()) == {}
):
actual.write_bytes(entitlements.read_bytes())
expected = reports / f"{name}-expected.plist"
subprocess.run(
[
"plutil",
"-convert",
"xml1",
"-o",
str(expected),
str(entitlements),
],
check=True,
)
subprocess.run(["plutil", "-convert", "xml1", str(actual)], check=True)
subprocess.run(["diff", "-u", str(expected), str(actual)], check=True)
elif actual.stat().st_size:
raise ValueError(
f"Bundled helper {name} must not have signing entitlements"
)
if provisioned and args.operation == "sign":
archive = Path(os.environ["RUNNER_TEMP"]) / "provisioned-cli.zip"
subprocess.run(["zip", "-q", "-r", str(archive), "."], cwd=package, check=True)
command = [
sys.executable,
str(bundle.SIGNING / "notarize_with_akv.py"),
"--file",
str(archive),
"--report-log",
str(reports / "notarization-developer-log.json"),
"--max-wait-seconds",
"1200",
]
with (
(reports / "notarization.log").open("w") as output,
subprocess.Popen(
command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True
) as process,
):
assert process.stdout is not None
for line in process.stdout:
print(line, end="", flush=True)
output.write(line)
if returncode := process.wait():
raise subprocess.CalledProcessError(returncode, command)
if __name__ == "__main__":
main()