"""ORCH-057 D1: actionable worktree error on a legacy-ownership permission failure. TC-01 / TC-02 (04-test-plan.yaml): a permission-class ``git worktree add`` / ``os.makedirs`` failure must surface an actionable RuntimeError (cause + healing command + INFRA.md ref), while a NON-permission failure keeps the prior raw-stderr contract (no meaning substitution). No real chown / no writes to /repos — failures are simulated via monkeypatched ``subprocess.run`` / ``os.makedirs``. """ import os import tempfile import pytest _test_db = os.path.join(tempfile.gettempdir(), "test_orchestrator_wt_perm.db") os.environ["ORCH_DB_PATH"] = _test_db os.environ["ORCH_REPOS_DIR"] = tempfile.gettempdir() os.environ["ORCH_GITEA_TOKEN"] = "test-token" os.environ["ORCH_PLANE_API_TOKEN"] = "test-token" from src import git_worktree from src.git_worktree import ensure_worktree class _R: """Minimal CompletedProcess stand-in.""" def __init__(self, returncode, stderr=""): self.returncode = returncode self.stderr = stderr self.stdout = "" @pytest.fixture def main_repo(tmp_path, monkeypatch): """A bare-minimum main clone dir so ensure_worktree gets past the existence check. repos_dir/ must be a directory; worktrees_dir points at a fresh tmp path. The actual git calls are monkeypatched per-test. """ repo = "orchestrator" repos_dir = tmp_path / "repos" (repos_dir / repo).mkdir(parents=True) monkeypatch.setattr(git_worktree.settings, "repos_dir", str(repos_dir)) monkeypatch.setattr(git_worktree.settings, "worktrees_dir", str(tmp_path / "repos" / "_wt")) monkeypatch.setattr(git_worktree.settings, "fs_normalize_enabled", True) return repo def test_tc01_permission_git_fatal_becomes_actionable(main_repo, monkeypatch): """TC-01: a git-fatal 'could not create leading directories / Permission denied' raises an actionable RuntimeError (diagnosis + chown), not the raw git stderr.""" perm_stderr = ( "fatal: could not create leading directories of " "'/repos/_wt/orchestrator/x': Permission denied" ) def fake_run(cmd, *a, **k): # fetch -> ok; worktree add (both forms) -> permission fatal. if "fetch" in cmd: return _R(0) if "worktree" in cmd and "add" in cmd: return _R(128, perm_stderr) return _R(0) monkeypatch.setattr(git_worktree.subprocess, "run", fake_run) with pytest.raises(RuntimeError) as ei: ensure_worktree(main_repo, "feature/x") msg = str(ei.value) # Actionable: names the cause + the healing command + the INFRA procedure... assert "legacy root-owned" in msg.lower() assert "chown" in msg.lower() assert "INFRA.md" in msg # ...and is NOT merely the raw "git worktree add failed" passthrough. assert "git worktree add failed" not in msg def test_tc01_makedirs_permission_error_becomes_actionable(main_repo, monkeypatch): """TC-01 (sibling path): a PermissionError from os.makedirs (creating the leading worktree dir) is also turned into the actionable RuntimeError.""" def fake_run(cmd, *a, **k): return _R(0) monkeypatch.setattr(git_worktree.subprocess, "run", fake_run) def boom(*a, **k): raise PermissionError(13, "Permission denied") monkeypatch.setattr(git_worktree.os, "makedirs", boom) with pytest.raises(RuntimeError) as ei: ensure_worktree(main_repo, "feature/x") assert "chown" in str(ei.value).lower() assert "legacy root-owned" in str(ei.value).lower() def test_tc02_non_permission_error_keeps_prior_contract(main_repo, monkeypatch): """TC-02: a NON-permission failure (e.g. a real branch conflict) keeps the prior raw-stderr 'git worktree add failed' message — no meaning substitution.""" conflict = "fatal: 'feature/x' is already checked out at '/repos/_wt/other'" def fake_run(cmd, *a, **k): if "fetch" in cmd: return _R(0) if "worktree" in cmd and "add" in cmd: return _R(128, conflict) return _R(0) monkeypatch.setattr(git_worktree.subprocess, "run", fake_run) with pytest.raises(RuntimeError) as ei: ensure_worktree(main_repo, "feature/x") msg = str(ei.value) assert "git worktree add failed" in msg assert "already checked out" in msg # The actionable diagnosis must NOT be injected for a non-permission error. assert "legacy root-owned" not in msg.lower() def test_tc02_killswitch_off_keeps_raw_contract_even_for_permission(main_repo, monkeypatch): """Kill-switch off (fs_normalize_enabled=False) -> the error contract is byte-for- byte as before ORCH-057 even for a permission failure (raw stderr passthrough).""" monkeypatch.setattr(git_worktree.settings, "fs_normalize_enabled", False) perm_stderr = "fatal: ...: Permission denied" def fake_run(cmd, *a, **k): if "fetch" in cmd: return _R(0) if "worktree" in cmd and "add" in cmd: return _R(128, perm_stderr) return _R(0) monkeypatch.setattr(git_worktree.subprocess, "run", fake_run) with pytest.raises(RuntimeError) as ei: ensure_worktree(main_repo, "feature/x") msg = str(ei.value) assert "git worktree add failed" in msg assert "legacy root-owned" not in msg.lower()