From fba0d477050835683b87eaa54569137eb0e4df8b Mon Sep 17 00:00:00 2001 From: malsamiri Date: Tue, 7 Jul 2026 09:16:35 -0700 Subject: [PATCH 1/2] fix(release): resolve Intel entitlement merge conflict --- ...dex-x86_64-apple-darwin.entitlements.plist | 10 +++ .../select_codex_entitlements.sh | 34 +++++++++ .../test_macos_signing_entitlements.py | 76 +++++++++++++++++++ .github/workflows/rust-release.yml | 38 +++++++--- 4 files changed, 149 insertions(+), 9 deletions(-) create mode 100644 .github/scripts/macos-signing/codex-x86_64-apple-darwin.entitlements.plist create mode 100755 .github/scripts/macos-signing/select_codex_entitlements.sh create mode 100644 .github/scripts/test_macos_signing_entitlements.py diff --git a/.github/scripts/macos-signing/codex-x86_64-apple-darwin.entitlements.plist b/.github/scripts/macos-signing/codex-x86_64-apple-darwin.entitlements.plist new file mode 100644 index 000000000000..26b12f28868c --- /dev/null +++ b/.github/scripts/macos-signing/codex-x86_64-apple-darwin.entitlements.plist @@ -0,0 +1,10 @@ + + + + + com.apple.security.cs.allow-jit + + com.apple.security.cs.allow-unsigned-executable-memory + + + diff --git a/.github/scripts/macos-signing/select_codex_entitlements.sh b/.github/scripts/macos-signing/select_codex_entitlements.sh new file mode 100755 index 000000000000..3799ad25eca4 --- /dev/null +++ b/.github/scripts/macos-signing/select_codex_entitlements.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash + +set -euo pipefail + +if [[ $# -ne 2 ]]; then + echo "usage: $0 " >&2 + exit 2 +fi + +target="$1" +binary="$2" +script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +# Keep the unsigned-executable-memory exception scoped to Intel binaries that link V8. +case "${target}:${binary}" in + x86_64-apple-darwin:codex | \ + x86_64-apple-darwin:codex-app-server | \ + x86_64-apple-darwin:codex-code-mode-host) + entitlements="${script_dir}/codex-x86_64-apple-darwin.entitlements.plist" + ;; + aarch64-apple-darwin:codex | \ + aarch64-apple-darwin:codex-app-server | \ + aarch64-apple-darwin:codex-code-mode-host | \ + aarch64-apple-darwin:codex-responses-api-proxy | \ + x86_64-apple-darwin:codex-responses-api-proxy) + entitlements="${script_dir}/codex.entitlements.plist" + ;; + *) + echo "unsupported macOS signing target and binary: ${target} ${binary}" >&2 + exit 2 + ;; +esac + +printf '%s\n' "$entitlements" diff --git a/.github/scripts/test_macos_signing_entitlements.py b/.github/scripts/test_macos_signing_entitlements.py new file mode 100644 index 000000000000..bfd615e9b80a --- /dev/null +++ b/.github/scripts/test_macos_signing_entitlements.py @@ -0,0 +1,76 @@ +import plistlib +import subprocess +import unittest +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[2] +SIGNING_DIR = ROOT / ".github" / "scripts" / "macos-signing" +SELECTOR = SIGNING_DIR / "select_codex_entitlements.sh" +DEFAULT_ENTITLEMENTS = SIGNING_DIR / "codex.entitlements.plist" +INTEL_ENTITLEMENTS = ( + SIGNING_DIR / "codex-x86_64-apple-darwin.entitlements.plist" +) + + +class MacosSigningEntitlementsTest(unittest.TestCase): + def select(self, target: str, binary: str) -> Path: + result = subprocess.run( + ["bash", str(SELECTOR), target, binary], + check=True, + capture_output=True, + text=True, + ) + return Path(result.stdout.strip()) + + def test_intel_v8_binaries_allow_unsigned_executable_memory(self) -> None: + for binary in ["codex", "codex-app-server", "codex-code-mode-host"]: + with self.subTest(binary=binary): + self.assertEqual( + self.select("x86_64-apple-darwin", binary), + INTEL_ENTITLEMENTS, + ) + + def test_other_macos_release_binaries_keep_existing_entitlements(self) -> None: + target_binaries = [ + ("aarch64-apple-darwin", "codex"), + ("aarch64-apple-darwin", "codex-app-server"), + ("aarch64-apple-darwin", "codex-code-mode-host"), + ("aarch64-apple-darwin", "codex-responses-api-proxy"), + ("x86_64-apple-darwin", "codex-responses-api-proxy"), + ] + for target, binary in target_binaries: + with self.subTest(target=target, binary=binary): + self.assertEqual(self.select(target, binary), DEFAULT_ENTITLEMENTS) + + def test_selector_fails_closed_for_unknown_inputs(self) -> None: + for target, binary in [ + ("unknown-apple-darwin", "codex"), + ("x86_64-apple-darwin", "unknown"), + ]: + with self.subTest(target=target, binary=binary): + result = subprocess.run( + ["bash", str(SELECTOR), target, binary], + capture_output=True, + text=True, + ) + self.assertEqual(result.returncode, 2) + + def test_entitlement_profiles_are_least_privilege(self) -> None: + with DEFAULT_ENTITLEMENTS.open("rb") as file: + default = plistlib.load(file) + with INTEL_ENTITLEMENTS.open("rb") as file: + intel = plistlib.load(file) + + self.assertEqual(default, {"com.apple.security.cs.allow-jit": True}) + self.assertEqual( + intel, + { + "com.apple.security.cs.allow-jit": True, + "com.apple.security.cs.allow-unsigned-executable-memory": True, + }, + ) + + +if __name__ == "__main__": + unittest.main() diff --git a/.github/workflows/rust-release.yml b/.github/workflows/rust-release.yml index 93f03e63d125..847edeeee700 100644 --- a/.github/workflows/rust-release.yml +++ b/.github/workflows/rust-release.yml @@ -573,6 +573,12 @@ jobs: zstd -d --stdout "$unsigned_path" >"$signed_path" chmod 0755 "$signed_path" + entitlements="$( + .github/scripts/macos-signing/select_codex_entitlements.sh \ + "$TARGET" \ + "$binary" + )" + .github/scripts/macos-signing/sign_macos_code.sh \ --target "$signed_path" \ --identity unused \ @@ -580,7 +586,7 @@ jobs: --identifier "$binary" \ --options runtime \ --timestamp true \ - --entitlements .github/scripts/macos-signing/codex.entitlements.plist + --entitlements "$entitlements" mkdir -p "${report_dir}/${binary}" rcodesign print-signature-info "$signed_path" \ @@ -974,15 +980,29 @@ jobs: target="${{ matrix.target }}" packaged_dir="dist/${target}" - expected_entitlements="${GITHUB_WORKSPACE}/.github/scripts/macos-signing/codex.entitlements.plist" + case "$target" in + aarch64-apple-darwin) expected_arch="arm64" ;; + x86_64-apple-darwin) expected_arch="x86_64" ;; + *) + echo "Unexpected macOS target: $target" + exit 1 + ;; + esac verify_signed_binary() { local path="$1" - local actual_entitlements normalized_actual normalized_expected + local binary="$2" + local actual_entitlements expected_entitlements normalized_actual normalized_expected chmod 0755 "$path" + lipo "$path" -verify_arch "$expected_arch" codesign --verify --strict --verbose=2 "$path" + expected_entitlements="$( + "${GITHUB_WORKSPACE}/.github/scripts/macos-signing/select_codex_entitlements.sh" \ + "$target" \ + "$binary" + )" actual_entitlements="$(mktemp)" normalized_actual="$(mktemp)" normalized_expected="$(mktemp)" @@ -995,7 +1015,7 @@ jobs: for binary in ${{ matrix.binaries }}; do binary_path="${RUNNER_TEMP}/signed-binaries/${binary}" - verify_signed_binary "$binary_path" + verify_signed_binary "$binary_path" "$binary" # The app-server package contains the host, but its standalone archives # are omitted above to avoid duplicate release asset names. @@ -1007,11 +1027,11 @@ jobs: rm -rf "$direct_archive_dir" mkdir -p "$direct_archive_dir" tar -xzf "${packaged_dir}/${binary}-${target}.tar.gz" -C "$direct_archive_dir" - verify_signed_binary "${direct_archive_dir}/${binary}-${target}" + verify_signed_binary "${direct_archive_dir}/${binary}-${target}" "$binary" direct_zstd_path="${RUNNER_TEMP}/${binary}-${target}-from-zstd" zstd -d --stdout "${packaged_dir}/${binary}-${target}.zst" >"$direct_zstd_path" - verify_signed_binary "$direct_zstd_path" + verify_signed_binary "$direct_zstd_path" "$binary" done case "${{ matrix.bundle }}" in @@ -1033,8 +1053,8 @@ jobs: rm -rf "$package_dir" mkdir -p "$package_dir" tar -xzf "${packaged_dir}/${package_stem}-${target}.tar.gz" -C "$package_dir" - verify_signed_binary "${package_dir}/bin/${package_entrypoint}" - verify_signed_binary "${package_dir}/bin/codex-code-mode-host" + verify_signed_binary "${package_dir}/bin/${package_entrypoint}" "$package_entrypoint" + verify_signed_binary "${package_dir}/bin/codex-code-mode-host" "codex-code-mode-host" if [[ "${{ matrix.verify_dmg }}" != "true" ]]; then exit 0 @@ -1060,7 +1080,7 @@ jobs: trap cleanup_mount EXIT for binary in ${{ matrix.binaries }}; do - verify_signed_binary "${mount_dir}/${binary}" + verify_signed_binary "${mount_dir}/${binary}" "$binary" done cleanup_mount From 1d3efd4bf822234b7e34fe07a00cc2dd22c1c97c Mon Sep 17 00:00:00 2001 From: malsamiri Date: Tue, 7 Jul 2026 09:37:19 -0700 Subject: [PATCH 2/2] refactor(release): use per-binary macOS entitlements --- ...st => codex-app-server.entitlements.plist} | 0 .../codex-code-mode-host.entitlements.plist | 10 +++ ...dex-responses-api-proxy.entitlements.plist | 8 ++ .../macos-signing/codex.entitlements.plist | 2 + .../select_codex_entitlements.sh | 34 --------- .../test_macos_signing_entitlements.py | 73 +++++-------------- .github/workflows/rust-release.yml | 20 ++--- 7 files changed, 47 insertions(+), 100 deletions(-) rename .github/scripts/macos-signing/{codex-x86_64-apple-darwin.entitlements.plist => codex-app-server.entitlements.plist} (100%) create mode 100644 .github/scripts/macos-signing/codex-code-mode-host.entitlements.plist create mode 100644 .github/scripts/macos-signing/codex-responses-api-proxy.entitlements.plist delete mode 100755 .github/scripts/macos-signing/select_codex_entitlements.sh diff --git a/.github/scripts/macos-signing/codex-x86_64-apple-darwin.entitlements.plist b/.github/scripts/macos-signing/codex-app-server.entitlements.plist similarity index 100% rename from .github/scripts/macos-signing/codex-x86_64-apple-darwin.entitlements.plist rename to .github/scripts/macos-signing/codex-app-server.entitlements.plist diff --git a/.github/scripts/macos-signing/codex-code-mode-host.entitlements.plist b/.github/scripts/macos-signing/codex-code-mode-host.entitlements.plist new file mode 100644 index 000000000000..26b12f28868c --- /dev/null +++ b/.github/scripts/macos-signing/codex-code-mode-host.entitlements.plist @@ -0,0 +1,10 @@ + + + + + com.apple.security.cs.allow-jit + + com.apple.security.cs.allow-unsigned-executable-memory + + + diff --git a/.github/scripts/macos-signing/codex-responses-api-proxy.entitlements.plist b/.github/scripts/macos-signing/codex-responses-api-proxy.entitlements.plist new file mode 100644 index 000000000000..d35e43ae588c --- /dev/null +++ b/.github/scripts/macos-signing/codex-responses-api-proxy.entitlements.plist @@ -0,0 +1,8 @@ + + + + + com.apple.security.cs.allow-jit + + + diff --git a/.github/scripts/macos-signing/codex.entitlements.plist b/.github/scripts/macos-signing/codex.entitlements.plist index d35e43ae588c..26b12f28868c 100644 --- a/.github/scripts/macos-signing/codex.entitlements.plist +++ b/.github/scripts/macos-signing/codex.entitlements.plist @@ -4,5 +4,7 @@ com.apple.security.cs.allow-jit + com.apple.security.cs.allow-unsigned-executable-memory + diff --git a/.github/scripts/macos-signing/select_codex_entitlements.sh b/.github/scripts/macos-signing/select_codex_entitlements.sh deleted file mode 100755 index 3799ad25eca4..000000000000 --- a/.github/scripts/macos-signing/select_codex_entitlements.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - -if [[ $# -ne 2 ]]; then - echo "usage: $0 " >&2 - exit 2 -fi - -target="$1" -binary="$2" -script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" - -# Keep the unsigned-executable-memory exception scoped to Intel binaries that link V8. -case "${target}:${binary}" in - x86_64-apple-darwin:codex | \ - x86_64-apple-darwin:codex-app-server | \ - x86_64-apple-darwin:codex-code-mode-host) - entitlements="${script_dir}/codex-x86_64-apple-darwin.entitlements.plist" - ;; - aarch64-apple-darwin:codex | \ - aarch64-apple-darwin:codex-app-server | \ - aarch64-apple-darwin:codex-code-mode-host | \ - aarch64-apple-darwin:codex-responses-api-proxy | \ - x86_64-apple-darwin:codex-responses-api-proxy) - entitlements="${script_dir}/codex.entitlements.plist" - ;; - *) - echo "unsupported macOS signing target and binary: ${target} ${binary}" >&2 - exit 2 - ;; -esac - -printf '%s\n' "$entitlements" diff --git a/.github/scripts/test_macos_signing_entitlements.py b/.github/scripts/test_macos_signing_entitlements.py index bfd615e9b80a..e56d5f3a1b6a 100644 --- a/.github/scripts/test_macos_signing_entitlements.py +++ b/.github/scripts/test_macos_signing_entitlements.py @@ -1,74 +1,35 @@ import plistlib -import subprocess import unittest from pathlib import Path ROOT = Path(__file__).resolve().parents[2] SIGNING_DIR = ROOT / ".github" / "scripts" / "macos-signing" -SELECTOR = SIGNING_DIR / "select_codex_entitlements.sh" -DEFAULT_ENTITLEMENTS = SIGNING_DIR / "codex.entitlements.plist" -INTEL_ENTITLEMENTS = ( - SIGNING_DIR / "codex-x86_64-apple-darwin.entitlements.plist" +ALLOW_JIT = "com.apple.security.cs.allow-jit" +ALLOW_UNSIGNED_EXECUTABLE_MEMORY = ( + "com.apple.security.cs.allow-unsigned-executable-memory" ) class MacosSigningEntitlementsTest(unittest.TestCase): - def select(self, target: str, binary: str) -> Path: - result = subprocess.run( - ["bash", str(SELECTOR), target, binary], - check=True, - capture_output=True, - text=True, - ) - return Path(result.stdout.strip()) - - def test_intel_v8_binaries_allow_unsigned_executable_memory(self) -> None: + def load(self, binary: str) -> dict[str, bool]: + path = SIGNING_DIR / f"{binary}.entitlements.plist" + with path.open("rb") as file: + return plistlib.load(file) + + def test_v8_binaries_allow_unsigned_executable_memory(self) -> None: + expected = { + ALLOW_JIT: True, + ALLOW_UNSIGNED_EXECUTABLE_MEMORY: True, + } for binary in ["codex", "codex-app-server", "codex-code-mode-host"]: with self.subTest(binary=binary): - self.assertEqual( - self.select("x86_64-apple-darwin", binary), - INTEL_ENTITLEMENTS, - ) - - def test_other_macos_release_binaries_keep_existing_entitlements(self) -> None: - target_binaries = [ - ("aarch64-apple-darwin", "codex"), - ("aarch64-apple-darwin", "codex-app-server"), - ("aarch64-apple-darwin", "codex-code-mode-host"), - ("aarch64-apple-darwin", "codex-responses-api-proxy"), - ("x86_64-apple-darwin", "codex-responses-api-proxy"), - ] - for target, binary in target_binaries: - with self.subTest(target=target, binary=binary): - self.assertEqual(self.select(target, binary), DEFAULT_ENTITLEMENTS) - - def test_selector_fails_closed_for_unknown_inputs(self) -> None: - for target, binary in [ - ("unknown-apple-darwin", "codex"), - ("x86_64-apple-darwin", "unknown"), - ]: - with self.subTest(target=target, binary=binary): - result = subprocess.run( - ["bash", str(SELECTOR), target, binary], - capture_output=True, - text=True, - ) - self.assertEqual(result.returncode, 2) - - def test_entitlement_profiles_are_least_privilege(self) -> None: - with DEFAULT_ENTITLEMENTS.open("rb") as file: - default = plistlib.load(file) - with INTEL_ENTITLEMENTS.open("rb") as file: - intel = plistlib.load(file) + self.assertEqual(self.load(binary), expected) - self.assertEqual(default, {"com.apple.security.cs.allow-jit": True}) + def test_responses_proxy_keeps_existing_entitlements(self) -> None: self.assertEqual( - intel, - { - "com.apple.security.cs.allow-jit": True, - "com.apple.security.cs.allow-unsigned-executable-memory": True, - }, + self.load("codex-responses-api-proxy"), + {ALLOW_JIT: True}, ) diff --git a/.github/workflows/rust-release.yml b/.github/workflows/rust-release.yml index 847edeeee700..9fdd66637bf8 100644 --- a/.github/workflows/rust-release.yml +++ b/.github/workflows/rust-release.yml @@ -573,11 +573,11 @@ jobs: zstd -d --stdout "$unsigned_path" >"$signed_path" chmod 0755 "$signed_path" - entitlements="$( - .github/scripts/macos-signing/select_codex_entitlements.sh \ - "$TARGET" \ - "$binary" - )" + entitlements="${GITHUB_WORKSPACE}/.github/scripts/macos-signing/${binary}.entitlements.plist" + if [[ ! -f "$entitlements" ]]; then + echo "Entitlements file $entitlements not found" + exit 1 + fi .github/scripts/macos-signing/sign_macos_code.sh \ --target "$signed_path" \ @@ -998,11 +998,11 @@ jobs: lipo "$path" -verify_arch "$expected_arch" codesign --verify --strict --verbose=2 "$path" - expected_entitlements="$( - "${GITHUB_WORKSPACE}/.github/scripts/macos-signing/select_codex_entitlements.sh" \ - "$target" \ - "$binary" - )" + expected_entitlements="${GITHUB_WORKSPACE}/.github/scripts/macos-signing/${binary}.entitlements.plist" + if [[ ! -f "$expected_entitlements" ]]; then + echo "Expected entitlements file $expected_entitlements not found" + exit 1 + fi actual_entitlements="$(mktemp)" normalized_actual="$(mktemp)" normalized_expected="$(mktemp)"