Preserve the provisioned macOS CLI's code-signing identity (#46495)

## Why

Existing login-keychain access rules identify the CLI as `codex`. Packaging it in an app bundle must preserve that code-signing identifier independently of the bundle identifier and provisioned App ID.

## What changed

- Sign the provisioned CLI with the identifier `codex`, retaining `com.openai.codex.cli` as its bundle identifier.
- Require the expected signing identifier and team during signature verification, and reject unexpected bundle identifiers, executable names, or package types.
- Document the identity distinction and keychain compatibility limits.

## Testing

Extend signing-driver tests to check the signing identifier, verification requirement, bundle metadata, and provisioned entitlements, and to reject altered bundle identity fields. These tests use generated credentials and stubbed native tools; they do not verify runtime keychain access or credential recovery.

GitOrigin-RevId: ab00072e48189551adb0e70008210fee6d36241d
This commit is contained in:
riley-oai
2026-09-18 02:53:21 +00:00
committed by copyberry
parent 6d29cc6bac
commit c0e1b78253
5 changed files with 134 additions and 10 deletions

View File

@@ -1,8 +1,9 @@
"""Exercise package signing and native verification with generated credentials."""
"""Exercise signing orchestration with generated credentials and stubbed native tools."""
import itertools
import json
import os
import plistlib
import shutil
import ssl
import subprocess
@@ -172,6 +173,9 @@ class MacosSigningTests(ProvisioningTestCase):
)
],
)
self.assertEqual(
signing[0][signing[0].index("--identifier") + 1], "codex"
)
self.assertEqual(
signing[0][signing[0].index("--entitlements") + 1],
str(
@@ -208,7 +212,49 @@ class MacosSigningTests(ProvisioningTestCase):
],
)
if provisioned:
verification = [
call
for call in calls
if call[0] == "codesign" and "--test-requirement" in call
]
cli_verification = verification[0]
self.assertEqual(cli_verification[-1], str(package / bundle.APP))
requirement = cli_verification[
cli_verification.index("--test-requirement") + 1
]
self.assertIn(' and identifier "codex"', requirement)
self.assertIn(
' and certificate leaf[subject.OU] = "TESTTEAM01"', requirement
)
with zipfile.ZipFile(root / "provisioned-cli.zip") as archive:
info = plistlib.loads(
archive.read("CodexCLI.app/Contents/Info.plist")
)
self.assertEqual(
info["CFBundleIdentifier"], "com.openai.codex.cli"
)
self.assertEqual(info["CFBundleExecutable"], "codex")
self.assertEqual(
plistlib.loads(
(
root
/ "signing-verification/codex-provisioned-entitlements.plist"
).read_bytes()
),
{
**plistlib.loads(
(
Path(env["MOCK_SIGNING_SCRIPTS"])
/ "codex.entitlements.plist"
).read_bytes()
),
"com.apple.application-identifier": "TESTTEAM01.com.openai.codex.cli",
"com.apple.developer.team-identifier": "TESTTEAM01",
"keychain-access-groups": [
"TESTTEAM01.com.openai.codex.cli"
],
},
)
self.assertEqual(
archive.read(
"CodexCLI.app/Contents/embedded.provisionprofile"
@@ -225,6 +271,28 @@ class MacosSigningTests(ProvisioningTestCase):
)
)
def test_provisioned_verification_rejects_changed_bundle_identity(self):
for field, value in (
("CFBundleIdentifier", "codex"),
("CFBundleExecutable", "another-codex"),
("CFBundlePackageType", "BNDL"),
):
with self.subTest(field=field), tempfile.TemporaryDirectory() as directory:
root = Path(directory).resolve()
package, driver, env = self.fixture(root, True)
signed = self.run_driver(driver, "sign", package, env)
self.assertEqual(signed.returncode, 0, signed.stderr)
info_path = package / bundle.APP / "Contents/Info.plist"
info = plistlib.loads(info_path.read_bytes())
info[field] = value
info_path.write_bytes(plistlib.dumps(info))
result = self.run_driver(driver, "verify", package, env)
self.assertNotEqual(result.returncode, 0)
self.assertIn(
"Unexpected provisioned CLI bundle identity or executable",
result.stderr,
)
def test_signing_and_notarization_failures_stop_the_driver(self):
for tool in ("sign_macos_code.sh", "notarize_with_akv.py"):
with self.subTest(tool=tool), tempfile.TemporaryDirectory() as directory: