Newer
Older
gnexus-book / server / tests / test_docs_repository.py
from pathlib import Path

from app.config import Settings
from app.docs_repository import DocsRepository
from app.freshness import build_freshness_report
from app.validation import validate_repository


def _copy_schema_files(tmp_path: Path) -> None:
    schema_dir = tmp_path / "schemas"
    schema_dir.mkdir()
    source_schema = Settings().repo_root / "schemas"
    for schema in source_schema.glob("*.json"):
        (schema_dir / schema.name).write_text(schema.read_text(encoding="utf-8"), encoding="utf-8")


def _create_empty_inventory(tmp_path: Path) -> None:
    inventory_dir = tmp_path / "40-inventory"
    inventory_dir.mkdir()
    for name in [
        "backups",
        "databases",
        "domains",
        "hardware",
        "hosts",
        "networks",
        "services",
        "traffic-routes",
        "virtual-machines",
    ]:
        (inventory_dir / f"{name}.yml").write_text("---\n[]\n", encoding="utf-8")


def test_lists_docs_from_repo_root() -> None:
    repo_root = Path(__file__).resolve().parents[2]
    docs = DocsRepository(Settings(repo_root)).list_docs()

    paths = {doc["path"] for doc in docs}
    assert "10-systems/hardware/hp-proliant-dl380-g6.md" in paths
    assert "90-maintenance/documentation-rules.md" in paths


def test_reads_frontmatter() -> None:
    repo_root = Path(__file__).resolve().parents[2]
    doc = DocsRepository(Settings(repo_root)).read_doc("10-systems/hardware/hp-proliant-dl380-g6.md")

    assert doc["frontmatter"]["owner"] == "gmikcon"
    assert "KVM/QEMU" in doc["body"]


def test_freshness_report_has_no_missing_doc_links() -> None:
    repo_root = Path(__file__).resolve().parents[2]
    report = build_freshness_report(Settings(repo_root))

    missing_link_issues = [
        issue for issue in report["issues"] if issue["code"] == "missing-doc-link-target"
    ]
    assert missing_link_issues == []


def test_freshness_report_is_clean_for_knowledge_docs() -> None:
    repo_root = Path(__file__).resolve().parents[2]
    report = build_freshness_report(Settings(repo_root))

    assert report["status"] == "ok"
    assert report["issues"] == []


def test_validation_report_is_clean() -> None:
    repo_root = Path(__file__).resolve().parents[2]
    report = validate_repository(Settings(repo_root))

    assert report["status"] == "ok"
    assert report["issues"] == []


def test_validation_rejects_duplicate_inventory_ids(tmp_path: Path) -> None:
    _copy_schema_files(tmp_path)
    _create_empty_inventory(tmp_path)
    (tmp_path / "40-inventory" / "services.yml").write_text(
        "---\n"
        "- id: duplicate-service\n"
        "  name: Duplicate Service\n"
        "  type: application\n"
        "  status: active\n"
        "  host: unknown\n"
        "  domains: []\n"
        "  ports: []\n"
        "  criticality: low\n"
        "  docs: ../10-systems/example.md\n"
        "  last_reviewed: 2026-05-09\n"
        "- id: duplicate-service\n"
        "  name: Duplicate Service Copy\n"
        "  type: application\n"
        "  status: active\n"
        "  host: unknown\n"
        "  domains: []\n"
        "  ports: []\n"
        "  criticality: low\n"
        "  docs: ../10-systems/example.md\n"
        "  last_reviewed: 2026-05-09\n",
        encoding="utf-8",
    )
    docs_dir = tmp_path / "10-systems"
    docs_dir.mkdir()
    (docs_dir / "example.md").write_text(
        "---\n"
        "owner: gmikcon\n"
        "status: active\n"
        "last_reviewed: 2026-05-09\n"
        "review_interval: 90d\n"
        "confidence: medium\n"
        "source_of_truth: test\n"
        "---\n\n"
        "# Example\n",
        encoding="utf-8",
    )

    report = validate_repository(Settings(tmp_path))

    assert any(issue["code"] == "duplicate-inventory-id" for issue in report["issues"])


def test_validation_rejects_raw_secret_assignment(tmp_path: Path) -> None:
    _copy_schema_files(tmp_path)
    _create_empty_inventory(tmp_path)
    notes_dir = tmp_path / "90-maintenance"
    notes_dir.mkdir(exist_ok=True)
    (notes_dir / "unsafe.md").write_text(
        "---\n"
        "owner: gmikcon\n"
        "status: draft\n"
        "last_reviewed: 2026-05-09\n"
        "review_interval: 90d\n"
        "confidence: low\n"
        "source_of_truth: test\n"
        "---\n\n"
        "# Unsafe\n\n"
        "api_token: raw-token-value\n",
        encoding="utf-8",
    )

    report = validate_repository(Settings(tmp_path))

    assert any(issue["code"] == "possible-secret" for issue in report["issues"])