feat: Anti-Fake-Evidence System (Phase 1-4b)

Implement full evidence integrity pipeline to prevent compliance theater:
- Confidence levels (E0-E4), truth status tracking, assertion engine
- Four-Eyes approval workflow, audit trail, reject endpoint
- Evidence distribution dashboard, LLM audit routes
- Traceability matrix (backend endpoint + Compliance Hub UI tab)
- Anti-fake badges, control status machine, normative patterns
- 2 migrations, 4 test suites, MkDocs documentation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-03-23 17:15:45 +01:00
parent 48ca0a6bef
commit e6201d5239
36 changed files with 5627 additions and 189 deletions

View File

@@ -487,6 +487,137 @@ class ControlRepository:
"compliance_score": round(score, 1),
}
def get_multi_dimensional_score(self) -> Dict[str, Any]:
"""
Calculate multi-dimensional compliance score (Anti-Fake-Evidence).
Returns 6 dimensions + hard_blocks + overall_readiness.
"""
from .models import (
EvidenceDB, RequirementDB, ControlMappingDB,
EvidenceConfidenceEnum, EvidenceTruthStatusEnum,
)
# Weight map for confidence levels
conf_weights = {"E0": 0.0, "E1": 0.25, "E2": 0.5, "E3": 0.75, "E4": 1.0}
validated_statuses = {"validated_internal", "accepted_by_auditor", "provided_to_auditor"}
controls = self.get_all()
total_controls = len(controls)
if total_controls == 0:
return {
"requirement_coverage": 0.0,
"evidence_strength": 0.0,
"validation_quality": 0.0,
"evidence_freshness": 0.0,
"control_effectiveness": 0.0,
"overall_readiness": 0.0,
"hard_blocks": ["Keine Controls vorhanden"],
}
# 1. requirement_coverage: % requirements linked to at least one control
total_reqs = self.db.query(func.count(RequirementDB.id)).scalar() or 0
linked_reqs = (
self.db.query(func.count(func.distinct(ControlMappingDB.requirement_id)))
.scalar() or 0
)
requirement_coverage = (linked_reqs / total_reqs * 100) if total_reqs > 0 else 0.0
# 2. evidence_strength: weighted average of evidence confidence
all_evidence = self.db.query(EvidenceDB).all()
if all_evidence:
total_weight = 0.0
for e in all_evidence:
conf_val = e.confidence_level.value if e.confidence_level else "E1"
total_weight += conf_weights.get(conf_val, 0.25)
evidence_strength = (total_weight / len(all_evidence)) * 100
else:
evidence_strength = 0.0
# 3. validation_quality: % evidence with truth_status >= validated_internal
if all_evidence:
validated_count = sum(
1 for e in all_evidence
if (e.truth_status.value if e.truth_status else "uploaded") in validated_statuses
)
validation_quality = (validated_count / len(all_evidence)) * 100
else:
validation_quality = 0.0
# 4. evidence_freshness: % evidence not expired and reviewed < 90 days
now = datetime.now()
if all_evidence:
fresh_count = 0
for e in all_evidence:
is_expired = e.valid_until and e.valid_until < now
is_stale = e.reviewed_at and (now - e.reviewed_at).days > 90 if hasattr(e, 'reviewed_at') and e.reviewed_at else False
if not is_expired and not is_stale:
fresh_count += 1
evidence_freshness = (fresh_count / len(all_evidence)) * 100
else:
evidence_freshness = 0.0
# 5. control_effectiveness: existing formula
passed = sum(1 for c in controls if c.status == ControlStatusEnum.PASS)
partial = sum(1 for c in controls if c.status == ControlStatusEnum.PARTIAL)
control_effectiveness = ((passed + partial * 0.5) / total_controls) * 100
# 6. overall_readiness: weighted composite
overall_readiness = (
0.20 * requirement_coverage +
0.25 * evidence_strength +
0.20 * validation_quality +
0.10 * evidence_freshness +
0.25 * control_effectiveness
)
# Hard blocks
hard_blocks = []
# Critical controls without any evidence
critical_no_evidence = []
for c in controls:
if c.status in (ControlStatusEnum.PASS, ControlStatusEnum.PARTIAL):
evidence_for_ctrl = [e for e in all_evidence if e.control_id == c.id]
if not evidence_for_ctrl:
critical_no_evidence.append(c.control_id)
if critical_no_evidence:
hard_blocks.append(
f"{len(critical_no_evidence)} Controls mit Status pass/partial haben keine Evidence: "
f"{', '.join(critical_no_evidence[:5])}"
)
# Controls with only E0/E1 evidence claiming pass
weak_evidence_pass = []
for c in controls:
if c.status == ControlStatusEnum.PASS:
evidence_for_ctrl = [e for e in all_evidence if e.control_id == c.id]
if evidence_for_ctrl:
max_conf = max(
conf_weights.get(
e.confidence_level.value if e.confidence_level else "E1", 0.25
)
for e in evidence_for_ctrl
)
if max_conf < 0.5: # Only E0 or E1
weak_evidence_pass.append(c.control_id)
if weak_evidence_pass:
hard_blocks.append(
f"{len(weak_evidence_pass)} Controls auf 'pass' haben nur E0/E1-Evidence: "
f"{', '.join(weak_evidence_pass[:5])}"
)
return {
"requirement_coverage": round(requirement_coverage, 1),
"evidence_strength": round(evidence_strength, 1),
"validation_quality": round(validation_quality, 1),
"evidence_freshness": round(evidence_freshness, 1),
"control_effectiveness": round(control_effectiveness, 1),
"overall_readiness": round(overall_readiness, 1),
"hard_blocks": hard_blocks,
}
class ControlMappingRepository:
"""Repository for requirement-control mappings."""