feat(fs): legacy root-owned ownership detect + actionable worktree error (ORCH-057)
Follow-up ORCH-040: legacy root:root files in /repos broke worktree creation under uid 1000 with a raw "Permission denied" (agent never started, no diagnosis). Three additive, kill-switch-reversible layers; STAGE_TRANSITIONS / QG_CHECKS / check_* / machine-verdict keys / DB schema are byte-for-byte unchanged. - D1: ensure_worktree classifies the permission class and raises an actionable RuntimeError (cause + chown command + INFRA.md ref); non-permission errors keep the prior raw-stderr contract; kill-switch off -> contract 1:1 as before ORCH-057. - D2: new never-raise leaf src/fs_normalize.py — scan_ownership (TTL-cached, early-exit per root), applies()-first scope (empty CSV -> self-hosting only), opt-in normalize() that chowns ONLY when privileged (no-op under uid 1000). - D3: best-effort startup detect in main.lifespan (WARNING + Telegram on mismatch, never-fatal); read-only fs_ownership block in GET /queue; POST /fs-normalize/check. Claim is NOT blocked — the clear early outcome is delivered by D1 at launch. - Docs/config: .env.example flags + CHANGELOG (architecture README / adr-0031 / INFRA.md procedure already landed on the branch). - Tests: test_fs_normalize.py, test_git_worktree_perm.py, test_fs_normalize_startup.py, test_api_queue.py (TC-01..TC-12). Full suite green. Refs: ORCH-057 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
68
tests/test_api_queue.py
Normal file
68
tests/test_api_queue.py
Normal file
@@ -0,0 +1,68 @@
|
||||
"""ORCH-057 TC-12: GET /queue exposes the read-only fs_ownership block.
|
||||
|
||||
The block carries {enabled, target_uid, mismatch, roots_checked, roots_mismatch,
|
||||
sample_path, checked_at, ...} and /queue must not 5xx whether the layer is on or off.
|
||||
"""
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
import pytest
|
||||
|
||||
_test_db = os.path.join(tempfile.gettempdir(), "test_orchestrator_apiq.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"
|
||||
os.environ["ORCH_PLANE_WEBHOOK_SECRET"] = ""
|
||||
os.environ["ORCH_GITEA_WEBHOOK_SECRET"] = ""
|
||||
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from src import fs_normalize
|
||||
from src.main import app
|
||||
from src.db import init_db
|
||||
|
||||
client = TestClient(app)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def _db():
|
||||
if os.path.exists(_test_db):
|
||||
os.unlink(_test_db)
|
||||
init_db()
|
||||
fs_normalize.reset_cache()
|
||||
yield
|
||||
if os.path.exists(_test_db):
|
||||
os.unlink(_test_db)
|
||||
|
||||
|
||||
def test_tc12_queue_exposes_fs_ownership_block(monkeypatch):
|
||||
"""TC-12: GET /queue returns the fs_ownership block with the documented shape."""
|
||||
monkeypatch.setattr(fs_normalize.settings, "fs_normalize_enabled", True)
|
||||
r = client.get("/queue")
|
||||
assert r.status_code == 200
|
||||
body = r.json()
|
||||
assert "fs_ownership" in body
|
||||
block = body["fs_ownership"]
|
||||
for k in ("enabled", "target_uid", "mismatch", "roots_checked",
|
||||
"roots_mismatch", "sample_path", "checked_at"):
|
||||
assert k in block
|
||||
|
||||
|
||||
def test_tc12_queue_no_5xx_when_disabled(monkeypatch):
|
||||
"""TC-12: with the kill-switch off /queue still returns 200 (no 5xx)."""
|
||||
monkeypatch.setattr(fs_normalize.settings, "fs_normalize_enabled", False)
|
||||
fs_normalize.reset_cache()
|
||||
r = client.get("/queue")
|
||||
assert r.status_code == 200
|
||||
assert r.json()["fs_ownership"]["enabled"] is False
|
||||
|
||||
|
||||
def test_fs_normalize_check_endpoint():
|
||||
"""The optional POST /fs-normalize/check force-rescans and returns the snapshot."""
|
||||
r = client.post("/fs-normalize/check")
|
||||
assert r.status_code == 200
|
||||
body = r.json()
|
||||
assert body["ok"] is True
|
||||
assert "scan" in body and "mismatch" in body["scan"]
|
||||
assert "healing" in body
|
||||
Reference in New Issue
Block a user