Files
nousresearch--hermes-agent/tests/test_desktop_mac_entitlements.py
wehub-resource-sync b4fbd6fe9f
Deploy Site / deploy-vercel (push) Has been skipped
Deploy Site / deploy-docs (push) Has been skipped
Build Skills Index / build-index (push) Has been skipped
CI / Deny unrelated histories (push) Has been skipped
CI / Detect affected areas (push) Successful in 27m35s
CI / OSV scan (push) Failing after 4s
CI / Build&Test Docker image (push) Successful in 9s
CI / Supply-chain scan (push) Has been skipped
CI / Lint Docker scripts (push) Failing after 5m13s
CI / Check contributors (push) Failing after 12m8s
CI / Docs Site (push) Failing after 12m8s
CI / TypeScript (push) Failing after 12m8s
CI / Python lints (push) Failing after 12m9s
CI / Python tests (push) Failing after 12m9s
CI / Check uv.lock (push) Failing after 23m22s
CI / CI timing report (push) Has been cancelled
Build Skills Index / trigger-deploy (push) Has been cancelled
CI / All required checks pass (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 11:56:03 +08:00

77 lines
3.0 KiB
Python

"""Regression for #37718: macOS microphone entitlement must be inherited.
Hermes Desktop signs with ``hardenedRuntime: true`` and points electron-builder
at two entitlement files (see ``apps/desktop/package.json``):
* ``entitlements`` → ``electron/entitlements.mac.plist`` (the main app), and
* ``entitlementsInherit`` → ``electron/entitlements.mac.inherit.plist`` (the
Electron Helper / Setup processes).
Under the hardened runtime, the process that actually opens the microphone is a
Helper, which inherits the *inherit* plist. ``com.apple.security.device.audio-input``
lived only in the main plist, so macOS' TCC layer refused the microphone with::
Prompting policy for hardened runtime; service: kTCCServiceMicrophone
requires entitlement com.apple.security.device.audio-input but it is missing
and never showed the permission prompt. These tests pin that every device
entitlement granted to the main app is also granted to the inherited helpers.
"""
from __future__ import annotations
import plistlib
from pathlib import Path
import pytest
REPO_ROOT = Path(__file__).resolve().parent.parent
ELECTRON_DIR = REPO_ROOT / "apps" / "desktop" / "electron"
MAIN_PLIST = ELECTRON_DIR / "entitlements.mac.plist"
INHERIT_PLIST = ELECTRON_DIR / "entitlements.mac.inherit.plist"
DEVICE_PREFIX = "com.apple.security.device."
def _load(plist: Path) -> dict:
assert plist.is_file(), f"missing entitlements file: {plist}"
with plist.open("rb") as fh:
return plistlib.load(fh)
def test_inherit_plist_grants_microphone() -> None:
"""The helper-inherited plist must grant audio-input (regression #37718)."""
inherit = _load(INHERIT_PLIST)
assert inherit.get("com.apple.security.device.audio-input") is True, (
"entitlements.mac.inherit.plist must grant "
"`com.apple.security.device.audio-input`; without it the hardened-runtime "
"Helper process is denied the microphone and no TCC prompt appears (#37718)."
)
def test_device_entitlements_are_inherited() -> None:
"""Every device.* entitlement on the main app must also be inherited."""
main = _load(MAIN_PLIST)
inherit = _load(INHERIT_PLIST)
main_device = {
key: val
for key, val in main.items()
if key.startswith(DEVICE_PREFIX) and val is True
}
missing = [key for key in main_device if inherit.get(key) is not True]
assert not missing, (
"Device entitlements present in entitlements.mac.plist but missing from "
f"entitlements.mac.inherit.plist: {missing}. Helper/Setup processes inherit "
"the latter under hardenedRuntime, so any device access the app needs must "
"be listed in both (#37718)."
)
@pytest.mark.parametrize("plist", [MAIN_PLIST, INHERIT_PLIST])
def test_entitlement_files_are_valid_plists(plist: Path) -> None:
"""Both entitlement files must remain well-formed plist dictionaries."""
data = _load(plist)
assert isinstance(data, dict) and data, f"{plist.name} should be a non-empty dict"