Files
2026-07-11 08:59:21 -04:00

106 lines
3.2 KiB
Python

#!/usr/bin/env python3
"""Small documentation hygiene check for AMPG."""
from __future__ import annotations
import re
import sys
from pathlib import Path
from urllib.parse import unquote
ROOT = Path(__file__).resolve().parents[1]
LINK_RE = re.compile(r"(?<!!)\[[^\]]+\]\(([^)]+)\)")
FORBIDDEN_PUBLIC_TERMS = (
"wowrace",
"wowngeon",
"smirk-monorepo",
"medusa-multi-tenant-platform",
"ai-gen-bot",
)
SECRET_PATTERNS = (
("private key block", re.compile(r"-----BEGIN [A-Z0-9 ]*PRIVATE KEY-----")),
("open ssh private key block", re.compile(r"-----BEGIN OPENSSH PRIVATE KEY-----")),
("aws access key", re.compile(r"\bAKIA[0-9A-Z]{16}\b")),
("github token", re.compile(r"\bgh[pousr]_[A-Za-z0-9_]{20,}\b")),
("slack token", re.compile(r"\bxox[baprs]-[A-Za-z0-9-]{10,}\b")),
(
"assigned secret",
re.compile(
r"(?i)\b(api[_-]?key|secret|password|token)\s*=\s*['\"][^'\"]{8,}['\"]"
),
),
)
def iter_markdown() -> list[Path]:
return sorted(
path
for path in ROOT.rglob("*.md")
if ".git" not in path.parts
and "docs/generated" not in str(path)
and "private" not in path.parts
and "dist" not in path.parts
)
def has_status_header(text: str) -> bool:
return any(line.startswith("> Status:") for line in text.splitlines()[:6])
def local_link_target(source: Path, raw_target: str) -> Path | None:
target = raw_target.strip()
if not target or target.startswith("#"):
return None
if "://" in target or target.startswith(("mailto:", "tel:")):
return None
target = target.split("#", 1)[0]
if not target:
return None
return (source.parent / unquote(target)).resolve()
def main() -> int:
errors: list[str] = []
files = iter_markdown()
checked_links = 0
for path in files:
rel = path.relative_to(ROOT)
text = path.read_text(encoding="utf-8")
if not has_status_header(text):
errors.append(f"{rel}: missing > Status: header in first 6 lines")
lower_text = text.lower()
for term in FORBIDDEN_PUBLIC_TERMS:
if term in lower_text:
errors.append(f"{rel}: public docs contain private target term {term!r}")
for label, pattern in SECRET_PATTERNS:
if pattern.search(text):
errors.append(f"{rel}: public docs may contain {label}")
for match in LINK_RE.finditer(text):
target = local_link_target(path, match.group(1))
if target is None:
continue
checked_links += 1
try:
target.relative_to(ROOT)
except ValueError:
errors.append(f"{rel}: link escapes repo -> {match.group(1)}")
continue
if not target.exists():
errors.append(f"{rel}: broken link -> {match.group(1)}")
if errors:
for error in errors:
print(f"DOCS_CHECK status=error message={error}")
print(f"DOCS_CHECK status=fail files={len(files)} links={checked_links}")
return 1
print(f"DOCS_CHECK status=ok files={len(files)} links={checked_links}")
return 0
if __name__ == "__main__":
sys.exit(main())