From b07bfd688aa3014b22bcc79882eadedd43379277 Mon Sep 17 00:00:00 2001 From: 686f6c61 <6115107+686f6c61@users.noreply.github.com> Date: Thu, 24 Sep 2026 23:23:21 +0200 Subject: [PATCH] fix(desktop): pin ad-hoc signing when the macOS identity fails A locked login keychain makes the configured identity unusable during an SSH update. Retry the identifier-pinned signer before the cdhash-only legacy deep sign so TCC grants and entitlements survive. --- hermes_cli/main_desktop.py | 14 ++++- tests/hermes_cli/test_gui_command.py | 89 ++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+), 1 deletion(-) diff --git a/hermes_cli/main_desktop.py b/hermes_cli/main_desktop.py index a4ad9940a5..c357d23ad5 100644 --- a/hermes_cli/main_desktop.py +++ b/hermes_cli/main_desktop.py @@ -727,11 +727,23 @@ def _desktop_macos_relaunchable_fixup( print(f" → macOS desktop signed with {label}; TCC grants persist across rebuilds") return True except Exception as exc: + # A configured cert can fail while the login keychain is locked (an SSH + # update). Identifier-pinned ad-hoc still keeps the designated requirement + # and entitlements; cdhash-only ``--deep --sign -`` is the last resort. if identity != "-": print( f" (warning: configured macOS signing identity failed: {identity!r}; " - "falling back to ad-hoc — TCC grants may need to be re-granted)" + "falling back to identifier-pinned ad-hoc)" ) + try: + if _desktop_macos_local_codesign(app, desktop_dir=desktop_dir, identity="-"): + print( + " → macOS desktop signed with stable ad-hoc identity; " + "TCC grants persist across rebuilds" + ) + return True + except Exception as adhoc_exc: + exc = adhoc_exc print(f" (warning: stable macOS signing failed ({exc}); using legacy ad-hoc sign)") return _macos_legacy_adhoc_resign(codesign, app) diff --git a/tests/hermes_cli/test_gui_command.py b/tests/hermes_cli/test_gui_command.py index f0b3815326..b5066c5223 100644 --- a/tests/hermes_cli/test_gui_command.py +++ b/tests/hermes_cli/test_gui_command.py @@ -810,6 +810,95 @@ def test_relaunchable_fixup_legacy_adhoc_success_still_verifies_and_never_delete assert not any("delete-generic-password" in c for c in calls) +def test_relaunchable_fixup_failed_identity_uses_pinned_adhoc_before_legacy(tmp_path, monkeypatch): + """A locked keychain must not skip identifier-pinned ad-hoc for cdhash-only. + + ``desktop.macos_signing_identity`` fails over SSH (login keychain locked). + The next try is the same inside-out signer with ``identity="-"``, which + keeps the identifier designated requirement and entitlements. Legacy + ``codesign --deep --sign -`` is only the last resort (#121857). + """ + root = _make_desktop_tree(tmp_path) + desktop_dir = root / "apps" / "desktop" + exe = desktop_dir / "release" / "mac-arm64" / "Hermes.app" / "Contents" / "MacOS" / "Hermes" + exe.parent.mkdir(parents=True) + exe.write_text("", encoding="utf-8") + + monkeypatch.setattr(sys, "platform", "darwin") + monkeypatch.delenv("CSC_LINK", raising=False) + monkeypatch.delenv("APPLE_SIGNING_IDENTITY", raising=False) + monkeypatch.setattr(main_desktop, "_desktop_macos_has_valid_real_signature", lambda _app: False) + monkeypatch.setattr( + main_desktop, "_desktop_macos_local_signing_identity", lambda: "Hermes Local Signing", + ) + + seen: list[str] = [] + + def fake_codesign(_app, *, desktop_dir, identity="-"): + seen.append(identity) + if identity != "-": + raise subprocess.CalledProcessError(1, ["codesign", "--sign", identity]) + return True + + calls: list[list[str]] = [] + + def fake_run(cmd, **kwargs): + calls.append(list(cmd)) + return subprocess.CompletedProcess(cmd, 0) + + monkeypatch.setattr(main_desktop, "_desktop_macos_local_codesign", fake_codesign) + monkeypatch.setattr( + main_desktop.shutil, "which", + lambda name: "/usr/bin/codesign" if name == "codesign" else None, + ) + monkeypatch.setattr(main_desktop.subprocess, "run", fake_run) + + assert main_desktop._desktop_macos_relaunchable_fixup(desktop_dir) is True + assert seen == ["Hermes Local Signing", "-"] + assert not any(cmd[:5] == ["/usr/bin/codesign", "--force", "--deep", "--sign", "-"] for cmd in calls) + + +def test_relaunchable_fixup_legacy_when_pinned_adhoc_also_fails(tmp_path, monkeypatch): + """Legacy deep ad-hoc still runs when identifier-pinned signing fails too.""" + root = _make_desktop_tree(tmp_path) + desktop_dir = root / "apps" / "desktop" + exe = desktop_dir / "release" / "mac-arm64" / "Hermes.app" / "Contents" / "MacOS" / "Hermes" + exe.parent.mkdir(parents=True) + exe.write_text("", encoding="utf-8") + app = exe.parents[2] + + monkeypatch.setattr(sys, "platform", "darwin") + monkeypatch.delenv("CSC_LINK", raising=False) + monkeypatch.delenv("APPLE_SIGNING_IDENTITY", raising=False) + monkeypatch.setattr(main_desktop, "_desktop_macos_has_valid_real_signature", lambda _app: False) + monkeypatch.setattr( + main_desktop, "_desktop_macos_local_signing_identity", lambda: "Hermes Local Signing", + ) + + seen: list[str] = [] + + def fake_codesign(_app, *, desktop_dir, identity="-"): + seen.append(identity) + raise subprocess.CalledProcessError(1, ["codesign", "--sign", identity]) + + calls: list[list[str]] = [] + + def fake_run(cmd, **kwargs): + calls.append(list(cmd)) + return subprocess.CompletedProcess(cmd, 0) + + monkeypatch.setattr(main_desktop, "_desktop_macos_local_codesign", fake_codesign) + monkeypatch.setattr( + main_desktop.shutil, "which", + lambda name: "/usr/bin/codesign" if name == "codesign" else None, + ) + monkeypatch.setattr(main_desktop.subprocess, "run", fake_run) + + assert main_desktop._desktop_macos_relaunchable_fixup(desktop_dir) is True + assert seen == ["Hermes Local Signing", "-"] + assert ["/usr/bin/codesign", "--force", "--deep", "--sign", "-", str(app)] in calls + + # --- desktop.* launch options (config.yaml) -------------------------------