Files
legal-ai/mcp-server/tests/test_platform_port_leak_guard.py
Chaim d2b622f28e
All checks were successful
G12 Leak-Guard / leak-guard (pull_request) Successful in 5s
feat(ci): G12 leak-guard — enforce the Agent Platform Port seam (R4, #113)
המאכף האוטומטי של INV-G12 (docs/spec/X15 §4). שני כללים קשיחים:
1. mcp-server/src (שכבת-האינטליגנציה) ללא סמלי-Paperclip — allowlist מנומק לפי
   substring ל-6 ההפניות הלגיטימיות (pm2-bridge + הערות-מקור company_id).
2. import seam — רק web/agent_platform_port.py (+ קבצי-המעטפת) מייבאים paperclip_*.

מימוש קנוני אחד (scripts/leak_guard.py, stdlib-בלבד), משותף לשלושה אכיפנים (G2):
• CI hard gate: .gitea/workflows/leak-guard.yaml (pull_request + push→main)
• pytest: mcp-server/tests/test_platform_port_leak_guard.py (כולל self-test שמוודא
  שה-guard תופס הזרקה — לא ירקב)
• hook בזמן-אמת: spec-guard.sh בודק את התוכן-הנכתב (new_string/content) על כתיבה
  ל-mcp-server/src ומזהיר על הזרקת-Paperclip (לא-deduped); תזכורת-הספ עודכנה ל-G1–G12.

מחריג קבצים-נוצרים (web-ui types.ts) ומעטפת מוצהרת; הפרונט מחוץ להיקף-האינטליגנציה
(ממצא R3). עודכן scripts/SCRIPTS.md.

אימות: סריקה נקייה exit 0; הזרקת pc.sh ל-mcp-server → exit 1; seam-violation ב-web → exit 1;
hook מזהיר על mcp-server ומזכיר-ספ על web; pytest 3 passed; bash -n + YAML תקינים.

Invariants: G12 (אכיפה), G2 (מאכף יחיד לשלושה צרכנים).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 09:40:42 +00:00

55 lines
1.9 KiB
Python

"""CI fitness-test for INV-G12 (docs/spec/X15 §4 / R4) — the Agent Platform Port.
Hard gate: the intelligence layer (``mcp-server/src``) must contain ZERO
Paperclip-specific symbols, and only ``web/agent_platform_port.py`` (+ the shell
itself) may import the Paperclip client. The check lives in
``scripts/leak_guard.py`` (one canonical implementation, shared with the
interactive ``spec-guard.sh`` hook); this test runs it and fails the build on any
violation.
Runs OFFLINE — pure source scan, no DB / no imports of the app.
"""
from __future__ import annotations
import importlib.util
from pathlib import Path
REPO = Path(__file__).resolve().parents[2]
_GUARD = REPO / "scripts" / "leak_guard.py"
def _load_guard():
spec = importlib.util.spec_from_file_location("leak_guard", _GUARD)
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod) # type: ignore[union-attr]
return mod
def test_leak_guard_script_exists() -> None:
assert _GUARD.is_file(), "scripts/leak_guard.py is missing (R4)"
def test_intelligence_layer_is_platform_clean() -> None:
"""No Paperclip symbols in mcp-server/src; import seam intact (INV-G12)."""
guard = _load_guard()
violations = guard.scan()
assert not violations, (
"INV-G12 leak-guard found Platform Port violations:\n"
+ "\n".join(f"{v}" for v in violations)
)
def test_guard_detects_an_injected_intelligence_leak(tmp_path: Path) -> None:
"""The guard must FAIL on a planted Paperclip symbol (so it can't rot)."""
guard = _load_guard()
probe = REPO / "mcp-server" / "src" / "legal_mcp" / "_leakguard_selftest.py"
probe.write_text('BAD = "use pc.sh wakeup directly"\n', encoding="utf-8")
try:
violations = guard.scan()
assert any("_leakguard_selftest.py" in v for v in violations), (
"leak-guard failed to detect a planted intelligence-layer leak"
)
finally:
probe.unlink(missing_ok=True)