feat(ci): G12 leak-guard — enforce the Agent Platform Port seam (R4, #113)
All checks were successful
G12 Leak-Guard / leak-guard (pull_request) Successful in 5s
All checks were successful
G12 Leak-Guard / leak-guard (pull_request) Successful in 5s
המאכף האוטומטי של 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>
This commit is contained in:
54
mcp-server/tests/test_platform_port_leak_guard.py
Normal file
54
mcp-server/tests/test_platform_port_leak_guard.py
Normal file
@@ -0,0 +1,54 @@
|
||||
"""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)
|
||||
Reference in New Issue
Block a user