From 2063615d37b4c65c742b9aed654c3b61d3575d57 Mon Sep 17 00:00:00 2001 From: Benjamin Admin Date: Fri, 26 Jun 2026 10:35:49 +0200 Subject: [PATCH] feat: Capability Registry v1 API-Vertrag (#59) + Ownership-Modell finalisiert MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #59 (geschaerft, User): capabilities.json -> capability_registry_v1 (contract_version 1.0): stabile `cap.*`-IDs (NIE umbenennen) + 5 Vertragsfelder (description/guidance_basis/ realizes_obligations/required_procedures/evidence_patterns), PRODUKTNEUTRAL (keine Features). = stabiler API-Vertrag fuer die Product->Compliance-Schnittstelle (Feature->Capability, Session 3 mappt read-only dagegen). session_ownership_model_v1.md RESOLVED: Legal-Owner = Re-Ingest-Session (vergibt KEINE obligation_id, nur citation_span->legal_basis) · 4. Session -> Quality & Validation (nur Tests, KEINE Daten) · Compliance 2 Branches DAUERHAFT (A=Build, B=Runtime). 4-Bibliotheken- Zielbild (Legal/Product/Capability/Evidence). Co-Authored-By: Claude Opus 4.7 --- .../development/session_ownership_model_v1.md | 23 +++ obligations/capabilities.json | 134 +++++++++++------- .../stabilize_capability_registry.py | 65 +++++++++ 3 files changed, 173 insertions(+), 49 deletions(-) create mode 100644 scripts/obligation_discovery/stabilize_capability_registry.py diff --git a/docs-src/development/session_ownership_model_v1.md b/docs-src/development/session_ownership_model_v1.md index 6e323c13..1838df12 100644 --- a/docs-src/development/session_ownership_model_v1.md +++ b/docs-src/development/session_ownership_model_v1.md @@ -75,3 +75,26 @@ wir, was fehlt, wo interpretieren wir falsch?" NIS2/AI-Act/Data-Act-Runs verschoben (liefern Reuse-Kennzahlen, aber keine neue Produktfrage). KEINE weitere Datenmodell-Klasse (Freeze v1.0). Product Knowledge Graph hat Vorrang — er schließt die Lücke zwischen Kunden- und Regulierungssprache. + +## RESOLVED (2026-06-26, User-Entscheidung) — die 3 offenen Fragen geklärt, Vertrag final + +1. **Legal Knowledge Owner = die Re-Ingest-/Knowledge-Session.** Besitzt Parser/CELLAR/Span/Authority/ + Retrieval/Citation-API. **Vergibt KEINE `obligation_id`** — liefert nur `citation_span → legal_basis`; + die `obligation_id` entsteht im Compliance-Graph. Verhindert, dass dieselbe Pflicht zweimal modelliert wird. +2. **4. Session NICHT auflösen → umbenennen in „Quality & Validation".** Besitzt KEINE Daten/Registry — + NUR Tests: Golden/Regression/Precision/Recall/Halluzination/Benchmark/Hazard-Qualität/FMEA-Validierung. + Darf produktive Modelle NIE verändern; sagt nur „funktioniert / funktioniert nicht". → **4 Verantwort- + lichkeiten:** Legal *liefert* Wissen · Compliance *modelliert* Wissen · Product *liefert* Kontext · + Quality *prüft* alles. +3. **Compliance Execution bleibt 2 Branches (dauerhaft getrennt, NICHT mergen):** + - **Branch A** (`feat/obligation-aggregation`) = **BUILD**: Registry · Discovery · Ontology · Capabilities · + Procedures · Graph (ändert sich ~wöchentlich). + - **Branch B** (`feat/advisor-status`) = **RUNTIME / Execution Engine**: API · Advisor · Endpoint · Status · + Evidence · Reasoning (ändert sich ~täglich). + Unterschiedliche Geschwindigkeit → bewusst getrennt. + +**Plattform-Zielbild: 4 Bibliotheken** — `Legal Library → Product Library → Capability Library → +Evidence Library`; darauf sitzen Advisor · Runtime · Auditor · Ticket-System · CE-/CRA-/NIS2-/AI-Act- +Assistent — **alle auf derselben Wissensbasis**. Die **Capability Library/Registry ist der Dreh- und +Angelpunkt** zwischen Product- und Compliance-Graph → muss ein **stabiler, versionierter API-Vertrag** +sein (stabile `cap.*`-IDs, nie umbenennen; produktneutral). Das ist #59. diff --git a/obligations/capabilities.json b/obligations/capabilities.json index da4dc2c6..0578f7dd 100644 --- a/obligations/capabilities.json +++ b/obligations/capabilities.json @@ -1,7 +1,19 @@ { - "schema_version": "capability_layer_v1", - "model": "Modell C (docs-src/development/capability_model_v1.md)", - "note": "Capability = technische Faehigkeit (regulierungs-agnostisch). realized_by = Obligations, die sie erfuellt (n:m). guidance_basis hier KANONISCH hochgezogen aus den realisierten Obligations (die Obligation-Kopien bleiben vorerst als Legacy; Strip = Folge-Cleanup). Sicherheitsziele sind KEINE Capabilities -> cra_core.json.", + "schema_version": "capability_registry_v1", + "contract_version": "1.0", + "status": "stable_api_contract", + "note": "PRODUKTNEUTRALER Vertrag zwischen Product Knowledge Graph (Domaene 3, Feature->Capability) und Compliance Execution Graph (Domaene 2). Stabile cap.*-IDs NIE umbenennen. KEINE Business-Features hier (die besitzt die Product-Session). Siehe docs-src/development/session_ownership_model_v1.md + compliance_meta_model_v1.md (Freeze v1.0).", + "id_namespace": "cap.", + "contract_fields": [ + "id", + "name", + "description", + "guidance_basis", + "realizes_obligations", + "required_procedures", + "evidence_patterns", + "domains" + ], "dropped": { "access_control": "OVERLAP (credential_confidentiality <-> sbom_confidentiality), nicht materialisiert" }, @@ -16,19 +28,10 @@ ], "capabilities": [ { - "capability_id": "multi_factor_authentication", + "id": "cap.multi_factor_authentication", + "slug": "multi_factor_authentication", "name": "Multi-Factor Authentication", "description": "Mehrfaktor-Authentisierung als technische Faehigkeit (Besitz/Wissen/Inhaerenz).", - "type": "technical_capability", - "realized_by": [ - "mfa_required", - "privileged_op_reauth", - "remote_access_authentication", - "remote_access_mfa", - "remote_access_user_validation_ot", - "supplier_access_auth" - ], - "realizes_count": 6, "guidance_basis": [ { "source": "NIST", @@ -84,6 +87,20 @@ "role": "best_practice" } ], + "realizes_obligations": [ + "mfa_required", + "privileged_op_reauth", + "remote_access_authentication", + "remote_access_mfa", + "remote_access_user_validation_ot", + "supplier_access_auth" + ], + "required_procedures": [], + "evidence_patterns": [ + "iam_config_export", + "mfa_policy_export", + "auth_audit_log" + ], "domains": [ "authentication", "remote_access" @@ -93,17 +110,10 @@ } }, { - "capability_id": "session_management", + "id": "cap.session_management", + "slug": "session_management", "name": "Session Management", "description": "Sichere Sitzungsverwaltung: Timeouts, Bindung, Re-Auth, Beendigung.", - "type": "technical_capability", - "realized_by": [ - "reauth_after_inactivity", - "remote_session_management", - "session_binding_management", - "temporary_remote_access_mgmt" - ], - "realizes_count": 4, "guidance_basis": [ { "source": "NIST", @@ -126,6 +136,17 @@ "role": "best_practice" } ], + "realizes_obligations": [ + "reauth_after_inactivity", + "remote_session_management", + "session_binding_management", + "temporary_remote_access_mgmt" + ], + "required_procedures": [], + "evidence_patterns": [ + "session_config_export", + "timeout_policy_export" + ], "domains": [ "authentication", "remote_access" @@ -135,20 +156,10 @@ } }, { - "capability_id": "transport_encryption", + "id": "cap.transport_encryption", + "slug": "transport_encryption", "name": "Transport Encryption", "description": "Verschluesselter Transport (TLS, mutual-TLS, Zertifikats-Auth, VPN/Tunnel).", - "type": "technical_capability", - "realized_by": [ - "encrypted_auth_channel", - "mutual_authentication", - "reject_insecure_remote_protocols", - "remote_access_confidentiality_integrity", - "remote_access_encryption", - "service_to_service_auth", - "tls_certificate_auth" - ], - "realizes_count": 7, "guidance_basis": [ { "source": "BSI", @@ -181,6 +192,21 @@ "role": "best_practice" } ], + "realizes_obligations": [ + "encrypted_auth_channel", + "mutual_authentication", + "reject_insecure_remote_protocols", + "remote_access_confidentiality_integrity", + "remote_access_encryption", + "service_to_service_auth", + "tls_certificate_auth" + ], + "required_procedures": [], + "evidence_patterns": [ + "tls_config_export", + "cipher_scan", + "cert_inventory" + ], "domains": [ "authentication", "remote_access" @@ -190,15 +216,10 @@ } }, { - "capability_id": "code_signing", + "id": "cap.code_signing", + "slug": "code_signing", "name": "Code & Update Signing", "description": "Digitale Signatur + Integritaets-/Authentizitaetspruefung von Firmware/Software/Updates.", - "type": "technical_capability", - "realized_by": [ - "firmware_software_authentication", - "signed_update_integrity" - ], - "realizes_count": 2, "guidance_basis": [ { "source": "NIST", @@ -211,6 +232,16 @@ "role": "best_practice" } ], + "realizes_obligations": [ + "firmware_software_authentication", + "signed_update_integrity" + ], + "required_procedures": [], + "evidence_patterns": [ + "signature_verification_log", + "sbom", + "signing_key_policy" + ], "domains": [ "authentication", "updates" @@ -220,15 +251,10 @@ } }, { - "capability_id": "security_monitoring_alerting", + "id": "cap.security_monitoring_alerting", + "slug": "security_monitoring_alerting", "name": "Security Monitoring & Alerting", "description": "Anomalie-/Bedrohungserkennung und Alarmierung aus Logs/Telemetrie.", - "type": "technical_capability", - "realized_by": [ - "log_monitoring_alerting", - "remote_access_threat_detection" - ], - "realizes_count": 2, "guidance_basis": [ { "source": "NIST", @@ -241,6 +267,16 @@ "role": "best_practice" } ], + "realizes_obligations": [ + "log_monitoring_alerting", + "remote_access_threat_detection" + ], + "required_procedures": [], + "evidence_patterns": [ + "siem_config_export", + "alert_rule_export", + "monitoring_audit_log" + ], "domains": [ "logging", "remote_access" diff --git a/scripts/obligation_discovery/stabilize_capability_registry.py b/scripts/obligation_discovery/stabilize_capability_registry.py new file mode 100644 index 00000000..044f6386 --- /dev/null +++ b/scripts/obligation_discovery/stabilize_capability_registry.py @@ -0,0 +1,65 @@ +"""#59 — Capability Registry zum stabilen, versionierten API-Vertrag machen. + +Hebt obligations/capabilities.json auf `capability_registry_v1` (contract_version 1.0): +- stabile IDs `cap.` (NIE umbenennen) — der Join-Key für Product→Capability (Domäne 3 → Domäne 2). +- pro Capability die 5 Vertragsfelder: description · guidance_basis · realizes_obligations · + required_procedures · evidence_patterns. +- PRODUKTNEUTRAL: KEINE Business-Features hier (die besitzt der Product Knowledge Graph / Session 3). +Deterministisch, idempotent. Siehe docs-src/development/session_ownership_model_v1.md. +""" +from __future__ import annotations + +import json + +SRC = "obligations/capabilities.json" + +# v1-Evidence-Muster je Capability (refinebar; Schema ist stabil, Inhalt waechst). +EVIDENCE = { + "multi_factor_authentication": ["iam_config_export", "mfa_policy_export", "auth_audit_log"], + "session_management": ["session_config_export", "timeout_policy_export"], + "transport_encryption": ["tls_config_export", "cipher_scan", "cert_inventory"], + "code_signing": ["signature_verification_log", "sbom", "signing_key_policy"], + "security_monitoring_alerting": ["siem_config_export", "alert_rule_export", "monitoring_audit_log"], +} + + +def main() -> None: + src = json.load(open(SRC, encoding="utf-8")) + caps = [] + for c in src["capabilities"]: + slug = c.get("capability_id") or c["id"].split(".")[-1] + caps.append({ + "id": f"cap.{slug}", + "slug": slug, + "name": c.get("name", ""), + "description": c.get("description", ""), + "guidance_basis": c.get("guidance_basis", []), + "realizes_obligations": c.get("realized_by", c.get("realizes_obligations", [])), + "required_procedures": [], # TBD: Procedure-Registry je Capability (Folge-Block #59) + "evidence_patterns": EVIDENCE.get(slug, []), + "domains": c.get("domains", []), + "provenance": c.get("provenance", {}), + }) + out = { + "schema_version": "capability_registry_v1", + "contract_version": "1.0", + "status": "stable_api_contract", + "note": "PRODUKTNEUTRALER Vertrag zwischen Product Knowledge Graph (Domaene 3, Feature->Capability) " + "und Compliance Execution Graph (Domaene 2). Stabile cap.*-IDs NIE umbenennen. KEINE " + "Business-Features hier (die besitzt die Product-Session). Siehe " + "docs-src/development/session_ownership_model_v1.md + compliance_meta_model_v1.md (Freeze v1.0).", + "id_namespace": "cap.", + "contract_fields": ["id", "name", "description", "guidance_basis", "realizes_obligations", + "required_procedures", "evidence_patterns", "domains"], + "dropped": src.get("dropped", {}), + "candidate_capabilities_followup": src.get("candidate_capabilities_followup", []), + "capabilities": caps, + } + json.dump(out, open(SRC, "w", encoding="utf-8"), ensure_ascii=False, indent=1) + print(f"capability_registry_v1 (contract 1.0): {len(caps)} Capabilities") + for c in caps: + print(f" {c['id']:38s} realizes {len(c['realizes_obligations']):2d} | guidance {len(c['guidance_basis'])} | evidence {len(c['evidence_patterns'])}") + + +if __name__ == "__main__": + main()