test_pilot_least_privilege.py
python
sha256:a78e7e5a8740e03315f325d19edeb3aa1b306b3337d04abbaa9a9e0f3bbeb7a1
docs: MuseHub-first before ISR #74 — staging solidify NEXT
Human
2 days ago
| 1 | """Security: pilot least-privilege and no secret leak (§K6.9 / §K6.10).""" |
| 2 | |
| 3 | from __future__ import annotations |
| 4 | |
| 5 | import re |
| 6 | from pathlib import Path |
| 7 | |
| 8 | from adapters.config import load_config |
| 9 | from adapters.errors import ConfigError |
| 10 | from adapters.factory import create_adapter |
| 11 | from cli.docs_paths import validate_muse_working_dir |
| 12 | from tests.support import PILOT, make_runner, ok, run_cli, seed_pilot_tree |
| 13 | |
| 14 | |
| 15 | def test_muse_only_zero_git_calls(tmp_path: Path) -> None: |
| 16 | (tmp_path / "musehub").mkdir() |
| 17 | config = load_config(PILOT / "config-musehub.yaml") |
| 18 | muse_cwd = (tmp_path / "musehub").resolve() |
| 19 | runner = make_runner( |
| 20 | { |
| 21 | f"muse -C {muse_cwd} branch --show-current": ok("main"), |
| 22 | f"muse -C {muse_cwd} status --porcelain": ok(""), |
| 23 | } |
| 24 | ) |
| 25 | adapter = create_adapter(config, tmp_path, runner=runner) |
| 26 | adapter.status() |
| 27 | adapter.mirror(dry_run=True) |
| 28 | head = adapter.read_head("origin/main") |
| 29 | assert "git forbidden" in str(head).lower() or "forbidden" in str(head).lower() |
| 30 | assert not any(command.startswith("git ") for command, _cwd in runner.calls) |
| 31 | |
| 32 | |
| 33 | def test_working_dir_escape_exit_two(tmp_path: Path) -> None: |
| 34 | try: |
| 35 | validate_muse_working_dir(tmp_path, "../../etc") |
| 36 | raised = False |
| 37 | except ConfigError: |
| 38 | raised = True |
| 39 | assert raised |
| 40 | |
| 41 | |
| 42 | def test_migrate_outputs_free_of_secrets_and_abs_paths(tmp_path: Path, capsys) -> None: |
| 43 | seed_pilot_tree( |
| 44 | tmp_path, |
| 45 | handover_rel="docs/OVERSEER-HANDOVER.md", |
| 46 | handover_text="# H\n", |
| 47 | roadmap_rel="docs/ROADMAP.md", |
| 48 | roadmap_text="# R\n", |
| 49 | ) |
| 50 | code = run_cli( |
| 51 | [ |
| 52 | "init", |
| 53 | "--migrate", |
| 54 | "--from-config", |
| 55 | str(PILOT / "config-scooling.yaml"), |
| 56 | "--non-interactive", |
| 57 | "--json", |
| 58 | ], |
| 59 | cwd=tmp_path, |
| 60 | json_mode=True, |
| 61 | ) |
| 62 | assert code == 0 |
| 63 | captured = capsys.readouterr() |
| 64 | combined = captured.out + captured.err |
| 65 | assert "AKIA" not in combined |
| 66 | assert "token=" not in combined.lower() |
| 67 | # Absolute machine paths banned in CLI streams |
| 68 | assert str(tmp_path.resolve()) not in combined |
| 69 | |
| 70 | |
| 71 | def test_include_preserved_absent_from_default_pilot_docs() -> None: |
| 72 | runbook = Path("docs/MIGRATE-EXISTING-REPO.md").read_text(encoding="utf-8") |
| 73 | assert "--force --include-preserved" in runbook |
| 74 | assert "Never" in runbook or "never" in runbook |
| 75 | assert "pilot-forbidden" in runbook.lower() or "never" in runbook.lower() |
| 76 | # Default sync examples must not recommend the combo |
| 77 | assert re.search(r"Never.*--force --include-preserved", runbook, re.I | re.S) |
File History
2 commits
sha256:a78e7e5a8740e03315f325d19edeb3aa1b306b3337d04abbaa9a9e0f3bbeb7a1
docs: MuseHub-first before ISR #74 — staging solidify NEXT
Human
2 days ago
sha256:4671b7f787ddbe63ced31c895b688c77ab495653b65a730b423329f26b3c1439
feat: K1-P1 complete — agent provenance, build-verification…
Sonnet 4.6
patch
53 days ago