feat: Pass 0b quality — negative actions, container detection, session object classes
All checks were successful
CI/CD / go-lint (push) Has been skipped
CI/CD / python-lint (push) Has been skipped
CI/CD / nodejs-lint (push) Has been skipped
CI/CD / test-go-ai-compliance (push) Successful in 33s
CI/CD / test-python-backend-compliance (push) Successful in 30s
CI/CD / test-python-document-crawler (push) Successful in 21s
CI/CD / test-python-dsms-gateway (push) Successful in 16s
CI/CD / validate-canonical-controls (push) Successful in 10s
CI/CD / Deploy (push) Successful in 2s
All checks were successful
CI/CD / go-lint (push) Has been skipped
CI/CD / python-lint (push) Has been skipped
CI/CD / nodejs-lint (push) Has been skipped
CI/CD / test-go-ai-compliance (push) Successful in 33s
CI/CD / test-python-backend-compliance (push) Successful in 30s
CI/CD / test-python-document-crawler (push) Successful in 21s
CI/CD / test-python-dsms-gateway (push) Successful in 16s
CI/CD / validate-canonical-controls (push) Successful in 10s
CI/CD / Deploy (push) Successful in 2s
4 error class fixes from AUTH-1052 quality review: 1. Prohibitive action types (prevent/exclude/forbid) for "dürfen keine", "verboten" etc. 2. Container object detection (Sitzungsverwaltung, Token-Schutz → _requires_decomposition) 3. Session-specific object classes (session, cookie, jwt, federated_assertion) 4. Session lifecycle actions (invalidate, issue, rotate, enforce) with templates + severity caps 76 new tests (303 total), all passing. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -459,7 +459,9 @@ def _split_compound_action(action: str) -> list[str]:
|
||||
# ── 2. Action Type Classification (18 types) ────────────────────────────
|
||||
|
||||
_ACTION_PRIORITY = [
|
||||
"prevent", "exclude", "forbid",
|
||||
"implement", "configure", "encrypt", "restrict_access",
|
||||
"enforce", "invalidate", "issue", "rotate",
|
||||
"monitor", "review", "assess", "audit",
|
||||
"test", "verify", "validate",
|
||||
"report", "notify", "train",
|
||||
@@ -470,7 +472,41 @@ _ACTION_PRIORITY = [
|
||||
]
|
||||
|
||||
_ACTION_KEYWORDS: list[tuple[str, str]] = [
|
||||
# Multi-word patterns first (longest match wins)
|
||||
# ── Negative / prohibitive actions (highest priority) ────
|
||||
("dürfen keine", "prevent"),
|
||||
("dürfen nicht", "prevent"),
|
||||
("darf keine", "prevent"),
|
||||
("darf nicht", "prevent"),
|
||||
("nicht zulässig", "forbid"),
|
||||
("nicht erlaubt", "forbid"),
|
||||
("nicht gestattet", "forbid"),
|
||||
("untersagt", "forbid"),
|
||||
("verboten", "forbid"),
|
||||
("nicht enthalten", "exclude"),
|
||||
("nicht übertragen", "prevent"),
|
||||
("nicht übermittelt", "prevent"),
|
||||
("nicht wiederverwendet", "prevent"),
|
||||
("nicht gespeichert", "prevent"),
|
||||
("verhindern", "prevent"),
|
||||
("unterbinden", "prevent"),
|
||||
("ausschließen", "exclude"),
|
||||
("vermeiden", "prevent"),
|
||||
("ablehnen", "exclude"),
|
||||
("zurückweisen", "exclude"),
|
||||
# ── Session / lifecycle actions ──────────────────────────
|
||||
("ungültig machen", "invalidate"),
|
||||
("invalidieren", "invalidate"),
|
||||
("widerrufen", "invalidate"),
|
||||
("session beenden", "invalidate"),
|
||||
("vergeben", "issue"),
|
||||
("ausstellen", "issue"),
|
||||
("erzeugen", "issue"),
|
||||
("generieren", "issue"),
|
||||
("rotieren", "rotate"),
|
||||
("erneuern", "rotate"),
|
||||
("durchsetzen", "enforce"),
|
||||
("erzwingen", "enforce"),
|
||||
# ── Multi-word patterns (longest match wins) ─────────────
|
||||
("aktuell halten", "maintain"),
|
||||
("aufrechterhalten", "maintain"),
|
||||
("sicherstellen", "ensure"),
|
||||
@@ -565,6 +601,15 @@ _ACTION_KEYWORDS: list[tuple[str, str]] = [
|
||||
("remediate", "remediate"),
|
||||
("perform", "perform"),
|
||||
("obtain", "obtain"),
|
||||
("prevent", "prevent"),
|
||||
("forbid", "forbid"),
|
||||
("exclude", "exclude"),
|
||||
("invalidate", "invalidate"),
|
||||
("revoke", "invalidate"),
|
||||
("issue", "issue"),
|
||||
("generate", "issue"),
|
||||
("rotate", "rotate"),
|
||||
("enforce", "enforce"),
|
||||
]
|
||||
|
||||
|
||||
@@ -627,11 +672,29 @@ _OBJECT_CLASS_KEYWORDS: dict[str, list[str]] = {
|
||||
"access_control": [
|
||||
"authentifizierung", "autorisierung", "zugriff",
|
||||
"berechtigung", "passwort", "kennwort", "anmeldung",
|
||||
"sso", "rbac", "session",
|
||||
"sso", "rbac",
|
||||
],
|
||||
"session": [
|
||||
"session", "sitzung", "sitzungsverwaltung", "session management",
|
||||
"session-id", "session-token", "idle timeout",
|
||||
"inaktivitäts-timeout", "inaktivitätszeitraum",
|
||||
"logout", "abmeldung",
|
||||
],
|
||||
"cookie": [
|
||||
"cookie", "session-cookie", "secure-flag", "httponly",
|
||||
"samesite", "cookie-attribut",
|
||||
],
|
||||
"jwt": [
|
||||
"jwt", "json web token", "bearer token",
|
||||
"jwt-algorithmus", "jwt-signatur",
|
||||
],
|
||||
"federated_assertion": [
|
||||
"assertion", "saml", "oidc", "openid",
|
||||
"föderiert", "federated", "identity provider",
|
||||
],
|
||||
"cryptographic_control": [
|
||||
"schlüssel", "zertifikat", "signatur", "kryptographi",
|
||||
"cipher", "hash", "token",
|
||||
"cipher", "hash", "token", "entropie",
|
||||
],
|
||||
"configuration": [
|
||||
"konfiguration", "einstellung", "parameter",
|
||||
@@ -1030,6 +1093,85 @@ _ACTION_TEMPLATES: dict[str, dict[str, list[str]]] = {
|
||||
"Gültigkeitsprüfung mit Zeitstempeln",
|
||||
],
|
||||
},
|
||||
# ── Prevent / Exclude / Forbid (negative norms) ────────────
|
||||
"prevent": {
|
||||
"test_procedure": [
|
||||
"Prüfung, dass {object} technisch verhindert wird",
|
||||
"Stichprobe: Versuch der verbotenen Aktion schlägt fehl",
|
||||
"Review der Konfiguration und Zugriffskontrollen",
|
||||
],
|
||||
"evidence": [
|
||||
"Konfigurationsnachweis der Präventionsmassnahme",
|
||||
"Testprotokoll der Negativtests",
|
||||
],
|
||||
},
|
||||
"exclude": {
|
||||
"test_procedure": [
|
||||
"Prüfung, dass {object} ausgeschlossen ist",
|
||||
"Stichprobe: Verbotene Inhalte/Aktionen sind nicht vorhanden",
|
||||
"Automatisierter Scan oder manuelle Prüfung",
|
||||
],
|
||||
"evidence": [
|
||||
"Scan-Ergebnis oder Prüfprotokoll",
|
||||
"Konfigurationsnachweis",
|
||||
],
|
||||
},
|
||||
"forbid": {
|
||||
"test_procedure": [
|
||||
"Prüfung, dass {object} untersagt und technisch blockiert ist",
|
||||
"Verifizierung der Richtlinie und technischen Durchsetzung",
|
||||
"Stichprobe: Versuch der untersagten Aktion wird abgelehnt",
|
||||
],
|
||||
"evidence": [
|
||||
"Richtlinie mit explizitem Verbot",
|
||||
"Technischer Nachweis der Blockierung",
|
||||
],
|
||||
},
|
||||
# ── Enforce / Invalidate / Issue / Rotate ────────────────
|
||||
"enforce": {
|
||||
"test_procedure": [
|
||||
"Prüfung der technischen Durchsetzung von {object}",
|
||||
"Stichprobe: Nicht-konforme Konfigurationen werden automatisch korrigiert oder abgelehnt",
|
||||
"Review der Enforcement-Regeln und Ausnahmen",
|
||||
],
|
||||
"evidence": [
|
||||
"Enforcement-Policy mit technischer Umsetzung",
|
||||
"Protokoll erzwungener Korrekturen oder Ablehnungen",
|
||||
],
|
||||
},
|
||||
"invalidate": {
|
||||
"test_procedure": [
|
||||
"Prüfung, dass {object} korrekt ungültig gemacht wird",
|
||||
"Stichprobe: Nach Invalidierung kein Zugriff mehr möglich",
|
||||
"Verifizierung der serverseitigen Bereinigung",
|
||||
],
|
||||
"evidence": [
|
||||
"Protokoll der Invalidierungsaktionen",
|
||||
"Testnachweis der Zugriffsverweigerung nach Invalidierung",
|
||||
],
|
||||
},
|
||||
"issue": {
|
||||
"test_procedure": [
|
||||
"Prüfung des Vergabeprozesses für {object}",
|
||||
"Verifizierung der kryptographischen Sicherheit und Entropie",
|
||||
"Stichprobe: Korrekte Vergabe unter definierten Bedingungen",
|
||||
],
|
||||
"evidence": [
|
||||
"Prozessdokumentation der Vergabe",
|
||||
"Nachweis der Entropie-/Sicherheitseigenschaften",
|
||||
],
|
||||
},
|
||||
"rotate": {
|
||||
"test_procedure": [
|
||||
"Prüfung des Rotationsprozesses für {object}",
|
||||
"Verifizierung der Rotationsfrequenz und automatischen Auslöser",
|
||||
"Stichprobe: Alte Artefakte nach Rotation ungültig",
|
||||
],
|
||||
"evidence": [
|
||||
"Rotationsrichtlinie mit Frequenz",
|
||||
"Rotationsprotokoll mit Zeitstempeln",
|
||||
],
|
||||
},
|
||||
# ── Approve / Remediate ───────────────────────────────────
|
||||
"approve": {
|
||||
"test_procedure": [
|
||||
@@ -1483,6 +1625,25 @@ _OBJECT_SYNONYMS: dict[str, str] = {
|
||||
"dienstleister": "vendor",
|
||||
"auftragsverarbeiter": "vendor",
|
||||
"drittanbieter": "vendor",
|
||||
# Session management synonyms (2026-03-28)
|
||||
"sitzung": "session",
|
||||
"sitzungsverwaltung": "session_mgmt",
|
||||
"session management": "session_mgmt",
|
||||
"session-id": "session_token",
|
||||
"sitzungstoken": "session_token",
|
||||
"session-token": "session_token",
|
||||
"idle timeout": "session_timeout",
|
||||
"inaktivitäts-timeout": "session_timeout",
|
||||
"inaktivitätszeitraum": "session_timeout",
|
||||
"abmeldung": "logout",
|
||||
"cookie-attribut": "cookie_security",
|
||||
"secure-flag": "cookie_security",
|
||||
"httponly": "cookie_security",
|
||||
"samesite": "cookie_security",
|
||||
"json web token": "jwt",
|
||||
"bearer token": "jwt",
|
||||
"föderierte assertion": "federated_assertion",
|
||||
"saml assertion": "federated_assertion",
|
||||
}
|
||||
|
||||
|
||||
@@ -1596,11 +1757,33 @@ _COMPOSITE_OBJECT_KEYWORDS: list[str] = [
|
||||
"soc 2", "soc2", "enisa", "kritis",
|
||||
]
|
||||
|
||||
# Container objects that are too broad for atomic controls.
|
||||
# These produce titles like "Sichere Sitzungsverwaltung umgesetzt" which
|
||||
# are not auditable — they encompass multiple sub-requirements.
|
||||
_CONTAINER_OBJECT_KEYWORDS: list[str] = [
|
||||
"sitzungsverwaltung", "session management", "session-management",
|
||||
"token-schutz", "tokenschutz",
|
||||
"authentifizierungsmechanismen", "authentifizierungsmechanismus",
|
||||
"sicherheitsmaßnahmen", "sicherheitsmassnahmen",
|
||||
"schutzmaßnahmen", "schutzmassnahmen",
|
||||
"zugriffskontrollmechanismen",
|
||||
"sicherheitsarchitektur",
|
||||
"sicherheitskontrollen",
|
||||
"datenschutzmaßnahmen", "datenschutzmassnahmen",
|
||||
"compliance-anforderungen",
|
||||
"risikomanagementprozess",
|
||||
]
|
||||
|
||||
_COMPOSITE_RE = re.compile(
|
||||
"|".join(_FRAMEWORK_KEYWORDS + _COMPOSITE_OBJECT_KEYWORDS),
|
||||
re.IGNORECASE,
|
||||
)
|
||||
|
||||
_CONTAINER_RE = re.compile(
|
||||
"|".join(_CONTAINER_OBJECT_KEYWORDS),
|
||||
re.IGNORECASE,
|
||||
)
|
||||
|
||||
|
||||
def _is_composite_obligation(obligation_text: str, object_: str) -> bool:
|
||||
"""Detect framework-level / composite obligations that are NOT atomic.
|
||||
@@ -1612,6 +1795,17 @@ def _is_composite_obligation(obligation_text: str, object_: str) -> bool:
|
||||
return bool(_COMPOSITE_RE.search(combined))
|
||||
|
||||
|
||||
def _is_container_object(object_: str) -> bool:
|
||||
"""Detect overly broad container objects that should not be atomic.
|
||||
|
||||
Objects like 'Sitzungsverwaltung' or 'Token-Schutz' encompass multiple
|
||||
sub-requirements and produce non-auditable controls.
|
||||
"""
|
||||
if not object_:
|
||||
return False
|
||||
return bool(_CONTAINER_RE.search(object_))
|
||||
|
||||
|
||||
# ── 7c. Output Validator (Negativregeln) ─────────────────────────────────
|
||||
|
||||
def _validate_atomic_control(
|
||||
@@ -1825,11 +2019,17 @@ def _compose_deterministic(
|
||||
atomic._deadline_hours = deadline_hours # type: ignore[attr-defined]
|
||||
atomic._frequency = frequency # type: ignore[attr-defined]
|
||||
|
||||
# ── Composite / Framework detection ───────────────────────
|
||||
# ── Composite / Framework / Container detection ────────────
|
||||
is_composite = _is_composite_obligation(obligation_text, object_)
|
||||
atomic._is_composite = is_composite # type: ignore[attr-defined]
|
||||
atomic._atomicity = "composite" if is_composite else "atomic" # type: ignore[attr-defined]
|
||||
atomic._requires_decomposition = is_composite # type: ignore[attr-defined]
|
||||
is_container = _is_container_object(object_)
|
||||
atomic._is_composite = is_composite or is_container # type: ignore[attr-defined]
|
||||
if is_composite:
|
||||
atomic._atomicity = "composite" # type: ignore[attr-defined]
|
||||
elif is_container:
|
||||
atomic._atomicity = "container" # type: ignore[attr-defined]
|
||||
else:
|
||||
atomic._atomicity = "atomic" # type: ignore[attr-defined]
|
||||
atomic._requires_decomposition = is_composite or is_container # type: ignore[attr-defined]
|
||||
|
||||
# ── Validate (log issues, never reject) ───────────────────
|
||||
validation_issues = _validate_atomic_control(atomic, action_type, object_class)
|
||||
@@ -3646,6 +3846,12 @@ _ACTION_SEVERITY_CAP: dict[str, str] = {
|
||||
"configure": "high",
|
||||
"monitor": "high",
|
||||
"enforce": "high",
|
||||
"prevent": "high",
|
||||
"exclude": "high",
|
||||
"forbid": "high",
|
||||
"invalidate": "high",
|
||||
"issue": "high",
|
||||
"rotate": "medium",
|
||||
}
|
||||
|
||||
# Severity ordering for cap comparison
|
||||
|
||||
Reference in New Issue
Block a user