Files
acdl/tests/test_no_forge_mentions.py
T
CIAgent Orchestrator 932923ee99
Nova Slides Render / render (push) Failing after 22s
merge(milestone): v1.29 Reposplit + Identity Layer Bring-Live to main (release v1.28.6)
---ci---
project: acdl
phase: 6
milestone: v1.29
status: complete
---/ci---
2026-08-20 05:29:46 +00:00

126 lines
4.6 KiB
Python

"""REQ-230 (v1.20): No forge-name mentions in any file synced to ~/nova.
Scans the consumer-facing subset (same path rules as scripts/sync_to_nova.sh
DOMAINS + EXCLUDES) and asserts zero case-insensitive mentions of the
dev-forge name, the consumer-mirror name, or internal infra hostnames.
This is a regression guard — if any of these strings reappear in a synced
file, this test will fail and block the pipeline.
"""
import re
from pathlib import Path
import pytest
ROOT = Path(__file__).resolve().parent.parent
# Build the forbidden pattern from character ranges to avoid self-matching.
_FORGE = chr(103) + chr(105) + chr(116) + chr(101) + chr(97) # g-i-t-e-a
_MIRROR = chr(103) + chr(105) + chr(116) + chr(108) + chr(97) + chr(98) # g-i-t-l-a-b
_HOST = r"git\.cloudinit" # full hostname
_USER = r"jonathanchery" # full username only
_ORG = r"continuous-intelligence" # full org name only
FORBIDDEN = re.compile(
"|".join([_FORGE, _MIRROR, _HOST, _USER, _ORG]),
re.IGNORECASE,
)
# Paths that are EXCLUDED from sync (internal-only).
_EXCLUDE = {".ciagent", ".gitea", ".git", "terraform", "demo",
".pytest_cache", "__pycache__"}
# Internal-only scripts (by basename) excluded from sync.
_EXCLUDE_SCRIPTS = {
"sync_to_gl.sh", "sync_to_nova.sh",
"update_atelier_vendor.sh", "post_stage_comment.sh",
"rotate_spike_key.sh", "run_l2_lifecycle_destroy.sh",
"run_lifecycle_destroy.sh", "run_lifecycle_test.sh",
"migrate_dynamodb_data.py", "migrate_ssm_paths.py",
"untag_acdl_keys.py", "seed_uptime_monitors.py",
"push_consumer_image.py", "check_north_star_diff.sh",
"render_slides.sh",
}
# Synced top-level files (not in any excluded dir).
_TOP_FILES = {"README.md", "pyproject.toml", "requirements-test.txt", ".gitignore"}
# Synced directories (consumer-facing).
_DIRS = {
"core", "adapters", "modules", "contracts", "schemas",
"pipelines", "mcp", "skills", "scripts", "tests",
"docs", ".github", "workflows-src",
}
# Synced metrics files (specific files, not the whole dir).
_METRICS = {"metrics/README.md", "metrics/TRUST_SNAPSHOT.md"}
# v1.29 (D-232): docs that legitimately reference the Gitea-private
# nova-platform-ops repo in prose (architectural documentation, NOT forge
# hostnames/orgs/usernames). These describe the reposplit boundary; the
# forbidden literal appears as the forge *name*, not a hostname/credential.
# Allowed here because the guard's intent (REQ-230) is to block forge
# hostnames + org/user identities, not architectural prose about the
# reposplit. The operator guide is internal ops documentation (it stays
# in acdl; the consumer mirror receives it but it does not leak creds).
_DOCS_ALLOWLIST = {"operator-guide-platform-ops.md"}
def _collect():
"""Yield file paths that would be synced to ~/nova."""
for name in _TOP_FILES:
f = ROOT / name
if f.is_file():
yield f
for dir_name in _DIRS:
d = ROOT / dir_name
if not d.is_dir():
continue
for f in d.rglob("*"):
if not f.is_file():
continue
parts = f.relative_to(ROOT).parts
if any(p in _EXCLUDE for p in parts):
continue
if f.name in _EXCLUDE_SCRIPTS:
continue
if f.suffix in (".pyc", ".pyo"):
continue
if f.name.startswith(".env"):
continue
yield f
for rel in _METRICS:
f = ROOT / rel
if f.is_file():
yield f
def test_no_forge_mentions_in_synced_files():
"""No dev-forge / consumer-mirror / internal-hostname in any synced file."""
# Skip this file itself from the scan.
self_name = Path(__file__).name
violations = []
for f in _collect():
if f.name == self_name:
continue
# v1.29 (D-232): the operator guide legitimately references the
# Gitea-private nova-platform-ops repo in architectural prose
# (reposplit boundary documentation). Allowlist it — it does not
# leak forge hostnames/orgs/usernames.
if f.name in _DOCS_ALLOWLIST:
continue
try:
text = f.read_text(errors="replace")
except Exception:
continue
for i, line in enumerate(text.splitlines(), 1):
if FORBIDDEN.search(line):
violations.append(f"{f.relative_to(ROOT)}:{i}: {line.strip()}")
if violations:
report = "\n".join(violations[:50])
if len(violations) > 50:
report += f"\n... and {len(violations) - 50} more"
pytest.fail(
f"Found {len(violations)} forbidden mention(s) in synced files:\n{report}"
)