"""Bundled mSCP / Lynis resolution (no upstream clones).""" from __future__ import annotations from pathlib import Path from applepy.bootstrap_compliance import lynis_bundled_executable from applepy.checks import compliance from applepy.context import RunContext from applepy.mscp import resolve_mscp_root def _fake_pkg_root(tmp_path: Path) -> Path: pkg = tmp_path / "pkg" pkg.mkdir() (pkg / "__init__.py").write_text("", encoding="utf-8") return pkg def test_resolve_mscp_root_uses_bundled_layout(tmp_path: Path, monkeypatch) -> None: import applepy pkg = _fake_pkg_root(tmp_path) mroot = pkg / "data" / "macos_security" (mroot / "baselines").mkdir(parents=True) (mroot / "scripts").mkdir() (mroot / "scripts" / "generate_guidance.py").write_text("#\n", encoding="utf-8") monkeypatch.setattr(applepy, "__file__", str(pkg / "__init__.py")) monkeypatch.delenv("APPLEPY_MACOS_SECURITY_ROOT", raising=False) got = resolve_mscp_root(tmp_path / "home", tmp_path / "cwd") assert got is not None assert got.resolve() == mroot.resolve() def test_resolve_mscp_root_env_beats_bundled(tmp_path: Path, monkeypatch) -> None: import applepy pkg = _fake_pkg_root(tmp_path) bundled = pkg / "data" / "macos_security" (bundled / "baselines").mkdir(parents=True) (bundled / "scripts").mkdir() (bundled / "scripts" / "generate_guidance.py").write_text("#\n", encoding="utf-8") env_root = tmp_path / "from_env" (env_root / "baselines").mkdir(parents=True) (env_root / "scripts").mkdir() (env_root / "scripts" / "generate_guidance.py").write_text("#\n", encoding="utf-8") monkeypatch.setattr(applepy, "__file__", str(pkg / "__init__.py")) monkeypatch.setenv("APPLEPY_MACOS_SECURITY_ROOT", str(env_root)) got = resolve_mscp_root(tmp_path / "home", tmp_path / "cwd") assert got is not None assert got.resolve() == env_root.resolve() def test_lynis_bundled_executable(tmp_path: Path, monkeypatch) -> None: import applepy pkg = _fake_pkg_root(tmp_path) ldir = pkg / "data" / "lynis" ldir.mkdir(parents=True) script = ldir / "lynis" script.write_text("#!/bin/sh\necho\n", encoding="utf-8") monkeypatch.setattr(applepy, "__file__", str(pkg / "__init__.py")) got = lynis_bundled_executable() assert got is not None assert got.resolve() == script.resolve() def test_resolve_lynis_prefers_path_after_which(tmp_path: Path, monkeypatch) -> None: import applepy pkg = _fake_pkg_root(tmp_path) ldir = pkg / "data" / "lynis" ldir.mkdir(parents=True) bundled_script = ldir / "lynis" bundled_script.write_text("#\n", encoding="utf-8") monkeypatch.setattr(applepy, "__file__", str(pkg / "__init__.py")) def fake_run_text(cmd: list[str], timeout: int = 30, cwd=None): if cmd[:2] == ["/usr/bin/which", "lynis"]: return 0, "/usr/local/bin/lynis\n", "" raise AssertionError(f"unexpected cmd: {cmd}") monkeypatch.setattr(compliance, "run_text", fake_run_text) assert compliance._resolve_lynis_executable() == "/usr/local/bin/lynis" def test_resolve_lynis_falls_back_to_bundled(tmp_path: Path, monkeypatch) -> None: import applepy pkg = _fake_pkg_root(tmp_path) ldir = pkg / "data" / "lynis" ldir.mkdir(parents=True) bundled_script = ldir / "lynis" bundled_script.write_text("#\n", encoding="utf-8") monkeypatch.setattr(applepy, "__file__", str(pkg / "__init__.py")) def fake_run_text(cmd: list[str], timeout: int = 30, cwd=None): if cmd[:2] == ["/usr/bin/which", "lynis"]: return 1, "", "" raise AssertionError(f"unexpected cmd: {cmd}") monkeypatch.setattr(compliance, "run_text", fake_run_text) assert compliance._resolve_lynis_executable() == str(bundled_script.resolve()) def test_truncate_lynis_evidence_short_unchanged() -> None: s = "a" * 100 assert compliance._truncate_lynis_evidence(s) == s def test_check_lynis_run_uses_lynis_install_root_as_cwd(tmp_path: Path, monkeypatch) -> None: """Lynis discovers ./include from pwd; cwd must be the directory that contains the script.""" nest = tmp_path / "opt" / "lynis" nest.mkdir(parents=True) script = nest / "lynis" script.write_text("#!/bin/sh\necho ok\n", encoding="utf-8") script.chmod(0o755) monkeypatch.setattr(compliance, "_resolve_lynis_executable", lambda: str(script)) captured: dict[str, object] = {} def capture_run(cmd: list[str], timeout: float = 400, cwd=None): captured["cwd"] = cwd captured["cmd"] = cmd return 0, "ok", "" monkeypatch.setattr(compliance, "run_text", capture_run) ctx = RunContext(home=tmp_path, output_dir=tmp_path, phase="unprivileged", dry_run=False) compliance.check_lynis_run(ctx) assert captured["cwd"] == str(nest.resolve()) assert captured["cmd"][0] == str(script) def test_truncate_lynis_evidence_long_inserts_ellipsis() -> None: s = "x" * 50_000 out = compliance._truncate_lynis_evidence(s, max_chars=1000) assert "omitted" in out assert len(out) < len(s) def test_cap_mscp_transcript_truncates(monkeypatch) -> None: monkeypatch.setenv("APPLEPY_MSCP_COMPLIANCE_LOG_MAX", "8192") long = "Z" * 20_000 out = compliance._cap_mscp_transcript("stdout", long) assert "truncated" in out assert len(out) < len(long)