869e7aeb1e
The cookie agent loaded 100 controls, 11 of which have no COOKIE_POLICY in applicable_artifacts -- Security/TOM/Audit (PROCESS) or Banner-behaviour (BEHAVIOR) controls that produce nonsense findings against a cookie policy (e.g. "TOMs not documented"). Add a cookie classification gate (analogous to the DSE gate, keyed on COOKIE_POLICY, without the needs_review carve-out since the artifact signal is decisive and the set is inventory-verified). Controls are routed out, not deleted. Effect vs Opus-GT: FP 16->11, FN 179->159; the remaining FN=159 over-rescue is a separate (judge/criteria) question, not routing. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
43 lines
1.7 KiB
Python
43 lines
1.7 KiB
Python
"""Tests for the cookie-policy applicability gate: controls without a
|
|
COOKIE_POLICY artifact are routed out of the findings scan (not deleted),
|
|
and the gate is fail-safe (no DSN -> no filter)."""
|
|
import pytest
|
|
|
|
from compliance.services.specialist_agents.cookie_policy._classification_gate import (
|
|
apply_gate, load_cookie_gate,
|
|
)
|
|
|
|
|
|
def test_apply_gate_splits_kept_and_routed():
|
|
controls = [
|
|
{"control_id": "COOK-1", "title": "Kategorien"},
|
|
{"control_id": "TOM-1", "title": "Verschlüsselung"},
|
|
{"control_id": "BAN-1", "title": "Consent vor Setzen"},
|
|
]
|
|
gate = {
|
|
"TOM-1": {"obligation_type": "TECHNICAL", "check_intent": "DIRECT_TECHNICAL",
|
|
"applicable_artifacts": ["TOM", "AUDIT"]},
|
|
"BAN-1": {"obligation_type": "TECHNICAL", "check_intent": "DIRECT_TECHNICAL",
|
|
"applicable_artifacts": ["COOKIE_BANNER", "SYSTEMSCAN"]},
|
|
}
|
|
kept, routed = apply_gate(controls, gate)
|
|
assert [c["control_id"] for c in kept] == ["COOK-1"]
|
|
assert {c["control_id"] for c in routed} == {"TOM-1", "BAN-1"}
|
|
# routed entries carry title + classification metadata for downstream routing
|
|
tom = next(c for c in routed if c["control_id"] == "TOM-1")
|
|
assert tom["title"] == "Verschlüsselung"
|
|
assert tom["applicable_artifacts"] == ["TOM", "AUDIT"]
|
|
|
|
|
|
def test_apply_gate_empty_gate_keeps_all():
|
|
controls = [{"control_id": "A"}, {"control_id": "B"}]
|
|
kept, routed = apply_gate(controls, {})
|
|
assert len(kept) == 2 and routed == []
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_load_cookie_gate_no_dsn_is_failsafe(monkeypatch):
|
|
monkeypatch.delenv("DATABASE_URL", raising=False)
|
|
monkeypatch.delenv("COMPLIANCE_DATABASE_URL", raising=False)
|
|
assert await load_cookie_gate("") == {}
|