diff --git a/hermes_cli/main.py b/hermes_cli/main.py index 73c119fd7f3c..1b49aabd5033 100644 --- a/hermes_cli/main.py +++ b/hermes_cli/main.py @@ -6475,6 +6475,15 @@ def _desktop_macos_local_codesign( ent_main = desktop_dir / "electron" / "entitlements.mac.plist" ent_inherit = desktop_dir / "electron" / "entitlements.mac.inherit.plist" + if not (ent_main.exists() and ent_inherit.exists()): + # Hardened-runtime restrictions are enforced even for ad-hoc + # signatures. Signing with --options runtime but WITHOUT the allow-jit + # entitlements would leave Electron/V8 crashing on launch — strictly + # worse than the legacy plain ad-hoc sign. Bail out so the caller + # falls back to that legacy path instead. + raise FileNotFoundError( + f"desktop entitlement plists missing under {desktop_dir / 'electron'}" + ) def sign_path( path: Path, diff --git a/tests/hermes_cli/test_gui_command.py b/tests/hermes_cli/test_gui_command.py index 0a9653ac9c91..9c3f9d64c2fc 100644 --- a/tests/hermes_cli/test_gui_command.py +++ b/tests/hermes_cli/test_gui_command.py @@ -1170,6 +1170,24 @@ def test_desktop_macos_local_codesign_false_without_codesign(tmp_path, monkeypat assert cli_main._desktop_macos_local_codesign(app, desktop_dir=desktop_dir) is False +def test_desktop_macos_local_codesign_refuses_without_entitlements(tmp_path, monkeypatch): + """Hardened runtime without allow-jit bricks Electron — must raise, not sign. + + Hardened-runtime restrictions are enforced even for ad-hoc signatures, so + signing with --options runtime while the entitlement plists are missing + would produce a bundle that crashes on launch. The fixup catches the raise + and falls back to the legacy plain ad-hoc sign instead. + """ + desktop_dir = tmp_path / "apps" / "desktop" + app = _make_signable_app(desktop_dir) + (desktop_dir / "electron" / "entitlements.mac.plist").unlink() + calls = _collect_codesign_calls(monkeypatch) + + with pytest.raises(FileNotFoundError): + cli_main._desktop_macos_local_codesign(app, desktop_dir=desktop_dir) + assert calls == [] # nothing was signed with a runtime flag sans entitlements + + def test_relaunchable_fixup_noop_when_publisher_signing_configured(tmp_path, monkeypatch): root = _make_desktop_tree(tmp_path) monkeypatch.setattr(cli_main, "PROJECT_ROOT", root)