Files
hermes-agent/tests/hermes_cli/test_macos_fda_guidance.py
T
Teknium be85903234 feat(macos): one-switch Full Disk Access guidance in doctor and setup
The last piece of the macOS permissions campaign (#52010 follow-up): macOS
prompts per-folder (Desktop, then Downloads, then Documents, ...) as the
agent touches each one — a drip-feed of dialogs on first use. ONE Full Disk
Access grant covers all of them permanently, and with the stable signing
identities merged this week it survives every update. Nothing in Hermes
taught users that.

- hermes doctor: check_macos_full_disk_access() — prompt-free probe (the
  FDA-gated TCC db dir returns EPERM without a dialog; TCC only prompts on
  protected-CATEGORY paths), reports granted state or prints the one-switch
  setup with the Privacy_AllFiles deep link.
- hermes setup: same probe at the end of onboarding — the moment users are
  primed to do system setup — silent when already granted, indeterminate,
  or non-macOS.
- docs: desktop.md TCC section now leads with the one-switch guidance.
- 7 tests (granted / denied / indeterminate / non-macOS, both surfaces).
2026-08-26 06:26:07 -07:00

98 lines
3.9 KiB
Python

"""macOS Full Disk Access onboarding guidance (issue #52010 follow-up).
One FDA grant silences every per-folder TCC prompt permanently. Doctor
reports the state and prints the one-switch setup; `hermes setup` surfaces
the same tip at onboarding. The probe must never itself trigger a prompt —
it reads the FDA-gated TCC db directory, which returns EPERM (no dialog)
without the grant.
"""
import io
import contextlib
import hermes_cli.doctor as doctor_mod
from hermes_cli.setup import _print_macos_fda_tip
def _capture(fn):
buf = io.StringIO()
with contextlib.redirect_stdout(buf):
fn()
return buf.getvalue()
class TestDoctorFdaCheck:
def test_silent_on_non_macos(self, monkeypatch):
monkeypatch.setattr(doctor_mod.sys, "platform", "linux")
out = _capture(doctor_mod.check_macos_full_disk_access)
assert out == ""
def test_granted_reports_ok(self, monkeypatch, tmp_path):
monkeypatch.setattr(doctor_mod.sys, "platform", "darwin")
tcc = tmp_path / "Library" / "Application Support" / "com.apple.TCC"
tcc.mkdir(parents=True)
monkeypatch.setattr(doctor_mod.Path, "home", classmethod(lambda cls: tmp_path))
out = _capture(doctor_mod.check_macos_full_disk_access)
assert "Full Disk Access granted" in out
assert "Privacy_AllFiles" not in out
def test_denied_prints_one_switch_guidance(self, monkeypatch, tmp_path):
monkeypatch.setattr(doctor_mod.sys, "platform", "darwin")
tcc = tmp_path / "Library" / "Application Support" / "com.apple.TCC"
tcc.mkdir(parents=True)
monkeypatch.setattr(doctor_mod.Path, "home", classmethod(lambda cls: tmp_path))
def _eperm(path):
raise PermissionError(13, "Operation not permitted", str(path))
monkeypatch.setattr(doctor_mod.os, "listdir", _eperm)
out = _capture(doctor_mod.check_macos_full_disk_access)
assert "Full Disk Access" in out
assert "Privacy_AllFiles" in out
assert "System Settings" in out
def test_indeterminate_probe_is_silent(self, monkeypatch, tmp_path):
"""Missing TCC dir (weird install) must not nag."""
monkeypatch.setattr(doctor_mod.sys, "platform", "darwin")
monkeypatch.setattr(doctor_mod.Path, "home", classmethod(lambda cls: tmp_path))
# tmp_path has no Library/Application Support/com.apple.TCC →
# FileNotFoundError (an OSError that is not PermissionError).
out = _capture(doctor_mod.check_macos_full_disk_access)
assert out == ""
class TestSetupFdaTip:
def test_silent_on_non_macos(self, monkeypatch):
import hermes_cli.setup as setup_mod
monkeypatch.setattr(setup_mod.sys, "platform", "linux")
out = _capture(_print_macos_fda_tip)
assert out == ""
def test_silent_when_already_granted(self, monkeypatch, tmp_path):
import hermes_cli.setup as setup_mod
monkeypatch.setattr(setup_mod.sys, "platform", "darwin")
tcc = tmp_path / "Library" / "Application Support" / "com.apple.TCC"
tcc.mkdir(parents=True)
monkeypatch.setattr(setup_mod.Path, "home", classmethod(lambda cls: tmp_path))
out = _capture(_print_macos_fda_tip)
assert out == ""
def test_tip_printed_when_denied(self, monkeypatch, tmp_path):
import hermes_cli.setup as setup_mod
monkeypatch.setattr(setup_mod.sys, "platform", "darwin")
tcc = tmp_path / "Library" / "Application Support" / "com.apple.TCC"
tcc.mkdir(parents=True)
monkeypatch.setattr(setup_mod.Path, "home", classmethod(lambda cls: tmp_path))
def _eperm(path):
raise PermissionError(13, "Operation not permitted", str(path))
monkeypatch.setattr(setup_mod.os, "listdir", _eperm)
out = _capture(_print_macos_fda_tip)
assert "Full Disk Access" in out
assert "Privacy_AllFiles" in out
assert "survives every Hermes update" in out