Files
orchestrator/tests/test_api_queue.py
claude-bot a98d605477 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>
2026-06-10 03:03:34 +03:00

69 lines
2.2 KiB
Python

"""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