From 65b3f43c026e2ea77985dc9241bc2bb93392bd00 Mon Sep 17 00:00:00 2001 From: Brooklyn Nicholson Date: Mon, 28 Sep 2026 20:23:27 -0500 Subject: [PATCH] fix(desktop): restore the quarantine-xattr strip before signing; pin the reconciled refusal contract MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The rebase of the signing-downgrade guard dropped the unconditional `xattr -cr` from _desktop_macos_relaunchable_fixup (the commit that claimed to reorder it after the identity decision deleted it instead), so locally built bundles kept their quarantine attributes and still tripped the 'Hermes is damaged' Gatekeeper path the strip exists to prevent. Restore it unconditionally ahead of the signing attempt: in the stage-and-swap flow it targets the STAGED bundle (discarded when the fixup refuses), and in-place it is harmless hygiene on a bundle whose signature is never replaced. test_relaunchable_fixup_configured_identity_failure_never_falls_back_to_adhoc now models the reconciled policy from #123748/#121857: it pins a publisher-signed (Team ID) replace-target — refusal, no ad-hoc, remedy named — while the locally-signed target's identifier-pinned ad-hoc retry stays covered by test_relaunchable_fixup_failed_identity_uses_pinned_adhoc_before_legacy. --- hermes_cli/main_desktop.py | 1 + tests/hermes_cli/test_gui_command.py | 29 +++++++++++++++++----------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/hermes_cli/main_desktop.py b/hermes_cli/main_desktop.py index 4a6690e04b..172e5d005c 100644 --- a/hermes_cli/main_desktop.py +++ b/hermes_cli/main_desktop.py @@ -787,6 +787,7 @@ def _desktop_macos_relaunchable_fixup( return False if _desktop_macos_has_valid_real_signature(app): return True + subprocess.run(["xattr", "-cr", str(app)], check=False) configured = _desktop_macos_local_signing_identity() identity = configured or "-" # The existing bundle this build's new signature replaces: the live release bundle the diff --git a/tests/hermes_cli/test_gui_command.py b/tests/hermes_cli/test_gui_command.py index 6a2ef33bc7..03060478bc 100644 --- a/tests/hermes_cli/test_gui_command.py +++ b/tests/hermes_cli/test_gui_command.py @@ -716,12 +716,15 @@ def test_relaunchable_fixup_stable_identity_never_touches_keychain(tmp_path, mon @pytest.mark.platforms("macos") -def test_relaunchable_fixup_configured_identity_failure_never_falls_back_to_adhoc(tmp_path, monkeypatch): - """A configured signing identity that fails must NOT degrade to ad-hoc (#123748). +def test_relaunchable_fixup_configured_identity_failure_never_falls_back_to_adhoc(tmp_path, monkeypatch, capsys): + """A configured identity failing over a PUBLISHER-signed install must not degrade (#123748). - Falling back to ad-hoc swaps the signature anchor the keychain ACLs are - bound against, orphaning safeStorage credentials. The fixup keeps the - existing signature and reports the failure instead. + Replacing a Team-ID installation with an ad-hoc or locally signed build swaps + the signature anchor the keychain ACLs and TCC grants are bound against, + orphaning safeStorage credentials. The fixup refuses, keeps the existing + bundle, and names the remedy. (Over a locally-signed install the same + failure retries identifier-pinned ad-hoc instead — covered by + ``test_relaunchable_fixup_failed_identity_uses_pinned_adhoc_before_legacy``.) ``platforms("macos")``: the fixup no-ops on non-macOS (sys.platform guard), and the subject is codesign against a real ``.app`` bundle layout. @@ -731,8 +734,7 @@ def test_relaunchable_fixup_configured_identity_failure_never_falls_back_to_adho monkeypatch.setattr(cli_main, "PROJECT_ROOT", root) monkeypatch.delenv("CSC_LINK", raising=False) monkeypatch.delenv("APPLE_SIGNING_IDENTITY", raising=False) - exe = _make_packaged_executable(root, monkeypatch) - app = exe.parents[2] + _make_packaged_executable(root, monkeypatch) calls: list[list[str]] = [] @@ -746,6 +748,13 @@ def test_relaunchable_fixup_configured_identity_failure_never_falls_back_to_adho monkeypatch.setattr(cli_main.subprocess, "run", fake_run) monkeypatch.setattr(main_desktop, "_desktop_macos_has_valid_real_signature", lambda a: False) monkeypatch.setattr(main_desktop, "_desktop_macos_local_signing_identity", lambda: "Hermes Local Signing") + # The bundle being re-signed in place is publisher-signed (Team ID): a degraded + # replacement would orphan its keychain ACLs and TCC grants. + monkeypatch.setattr( + main_desktop, "_macos_signature_summary", + lambda codesign, app: {"team": "TEAMID123", "identifier": "com.nousresearch.hermes", + "verified": True}, + ) def boom(*a, **kw): raise subprocess.CalledProcessError(1, ["codesign"]) @@ -756,10 +765,8 @@ def test_relaunchable_fixup_configured_identity_failure_never_falls_back_to_adho # The old behavior fell through to the legacy deep ad-hoc re-sign — must not happen. assert not any("--deep" in c for c in calls) assert not any("delete-generic-password" in c for c in calls) - # The refusal decision is made BEFORE the quarantine-xattr hygiene: a failed - # attempt must not have already stripped attributes off a bundle we then - # decline to modify. - assert ["xattr", "-cr", str(app)] not in calls + out = capsys.readouterr().out + assert "publisher-signed" in out and "no ad-hoc fallback" in out @pytest.mark.platforms("macos")