Spaces:
Sleeping
Sleeping
| """Tests for backend/core/gatekeeper_detect.py (Phase 1 Wave 3, issue #54). | |
| Covers :func:`is_app_quarantined`'s detection across platforms, missing | |
| ``xattr`` binary, timeouts, and the bundle-path walk. Also asserts the | |
| :func:`quarantine_status` payload shape that the React ErrorBoundary | |
| consumes via /system/quarantine-status. | |
| """ | |
| import subprocess | |
| import sys | |
| import pytest | |
| def detect(): | |
| """Import the module fresh — it has no module-level state, but this | |
| keeps tests stable if any future refactor adds caching.""" | |
| import importlib | |
| from core import gatekeeper_detect | |
| importlib.reload(gatekeeper_detect) | |
| return gatekeeper_detect | |
| def test_returns_false_on_non_macos(monkeypatch, detect): | |
| """On any non-Darwin platform the function returns False without ever | |
| invoking xattr.""" | |
| monkeypatch.setattr(sys, "platform", "linux") | |
| def _explode(*args, **kwargs): # pragma: no cover — should never be called | |
| raise AssertionError("subprocess.run must not be called on non-darwin") | |
| monkeypatch.setattr(subprocess, "run", _explode) | |
| assert detect.is_app_quarantined() is False | |
| # Status payload also reflects it. | |
| status = detect.quarantine_status() | |
| assert status["quarantined"] is False | |
| assert status["error_class"] is None | |
| def test_returns_true_when_xattr_lists_quarantine(monkeypatch, detect): | |
| """On Darwin with a quarantined bundle, xattr stdout contains | |
| ``com.apple.quarantine`` → returns True.""" | |
| monkeypatch.setattr(sys, "platform", "darwin") | |
| class _Result: | |
| stdout = "com.apple.quarantine: 0083;6450c4b8;Chrome;\nother.attr: 1\n" | |
| stderr = "" | |
| returncode = 0 | |
| monkeypatch.setattr(subprocess, "run", lambda *a, **kw: _Result()) | |
| # Provide an explicit bundle path so we do not depend on sys.executable. | |
| assert detect.is_app_quarantined("/Applications/Fake.app") is True | |
| def test_returns_false_when_xattr_absent(monkeypatch, detect): | |
| """xattr returns empty stdout → not quarantined.""" | |
| monkeypatch.setattr(sys, "platform", "darwin") | |
| class _Result: | |
| stdout = "" | |
| stderr = "" | |
| returncode = 0 | |
| monkeypatch.setattr(subprocess, "run", lambda *a, **kw: _Result()) | |
| assert detect.is_app_quarantined("/Applications/Fake.app") is False | |
| def test_returns_false_when_xattr_binary_missing(monkeypatch, detect): | |
| """FileNotFoundError (xattr not on PATH) → safe False, no crash.""" | |
| monkeypatch.setattr(sys, "platform", "darwin") | |
| def _raise(*a, **kw): | |
| raise FileNotFoundError("xattr not found") | |
| monkeypatch.setattr(subprocess, "run", _raise) | |
| assert detect.is_app_quarantined("/Applications/Fake.app") is False | |
| def test_returns_false_on_timeout(monkeypatch, detect): | |
| """xattr timeout → safe False, log warning, do not propagate.""" | |
| monkeypatch.setattr(sys, "platform", "darwin") | |
| def _raise(*a, **kw): | |
| raise subprocess.TimeoutExpired(cmd=["xattr"], timeout=5) | |
| monkeypatch.setattr(subprocess, "run", _raise) | |
| assert detect.is_app_quarantined("/Applications/Fake.app") is False | |
| def test_quarantine_status_shape(monkeypatch, detect): | |
| """quarantine_status() returns the keys the frontend ErrorBoundary | |
| expects: quarantined, bundle_path, error_class.""" | |
| monkeypatch.setattr(sys, "platform", "darwin") | |
| class _Result: | |
| stdout = "com.apple.quarantine: 0083;6450c4b8;Chrome;" | |
| stderr = "" | |
| returncode = 0 | |
| monkeypatch.setattr(subprocess, "run", lambda *a, **kw: _Result()) | |
| # Force the bundle resolver to return a known path so the assertion | |
| # below isn't platform-dependent. | |
| monkeypatch.setattr(detect, "_resolve_app_bundle_path", lambda: "/Applications/Fake.app") | |
| status = detect.quarantine_status() | |
| assert set(status.keys()) == {"quarantined", "bundle_path", "error_class"} | |
| assert status["quarantined"] is True | |
| assert status["bundle_path"] == "/Applications/Fake.app" | |
| assert status["error_class"] == detect.ERROR_CLASS == "GATEKEEPER_QUARANTINE" | |
| def test_returns_false_when_not_inside_app_bundle(monkeypatch, detect): | |
| """Dev runs (sys.executable not inside a .app) → returns False without | |
| invoking xattr.""" | |
| monkeypatch.setattr(sys, "platform", "darwin") | |
| monkeypatch.setattr(sys, "executable", "/usr/local/bin/python3.12") | |
| def _explode(*args, **kwargs): # pragma: no cover | |
| raise AssertionError("subprocess.run must not be called for dev runs") | |
| monkeypatch.setattr(subprocess, "run", _explode) | |
| # Call without passing bundle_path so _resolve_app_bundle_path runs. | |
| assert detect.is_app_quarantined() is False | |