feat(use-case-compiler): MC-based compliance questionnaires with scoring
Build + Deploy / build-admin-compliance (push) Successful in 2m46s
Build + Deploy / build-backend-compliance (push) Successful in 26s
Build + Deploy / build-ai-sdk (push) Successful in 52s
Build + Deploy / build-developer-portal (push) Successful in 22s
Build + Deploy / build-tts (push) Successful in 16s
Build + Deploy / build-document-crawler (push) Successful in 12s
Build + Deploy / build-dsms-gateway (push) Successful in 20s
Build + Deploy / build-dsms-node (push) Successful in 16s
CI / branch-name (push) Has been skipped
CI / guardrail-integrity (push) Has been skipped
CI / loc-budget (push) Failing after 18s
CI / secret-scan (push) Has been skipped
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / nodejs-build (push) Successful in 3m16s
CI / dep-audit (push) Has been skipped
CI / sbom-scan (push) Has been skipped
CI / test-go (push) Successful in 1m0s
CI / test-python-backend (push) Successful in 41s
CI / test-python-document-crawler (push) Successful in 29s
CI / test-python-dsms-gateway (push) Successful in 23s
CI / validate-canonical-controls (push) Successful in 16s
Build + Deploy / trigger-orca (push) Successful in 2m36s

Implements the Use-Case Compiler that turns Master Controls into
interactive compliance audits. 5 templates (Vendor Check, SAST/DAST,
DSGVO, NIS2, CRA), deterministic + LLM question generation, scoring
engine with regulation/severity breakdown, and gap detection.

- Backend: 9 API endpoints, 22 unit tests (all pass)
- Frontend: Template selector, questionnaire, result dashboard
- Migration 027: usecase_audits + usecase_answers tables

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-05-12 13:49:16 +02:00
parent 74f00bbb0f
commit 06bfbd1dca
22 changed files with 3157 additions and 1 deletions
@@ -0,0 +1,92 @@
package usecase
// Score calculates a compliance score from answers and questions.
func Score(audit *Audit, answers []Answer) *ScoreResult {
result := &ScoreResult{
AuditID: audit.ID,
TotalQuestions: len(audit.Questions),
ByRegulation: make(map[string]RegulationScore),
BySeverity: make(map[string]SeverityScore),
}
answerMap := make(map[string]Answer)
for _, a := range answers {
answerMap[a.QuestionID] = a
}
for _, q := range audit.Questions {
a, answered := answerMap[q.ID]
if !answered {
continue
}
result.Answered++
passed := isPassed(a)
switch a.Status {
case AnswerStatusSkipped:
result.Skipped++
default:
if passed {
result.Passed++
} else {
result.Failed++
}
}
// By regulation
if q.Regulation != "" {
rs := result.ByRegulation[q.Regulation]
rs.Total++
if passed {
rs.Passed++
}
result.ByRegulation[q.Regulation] = rs
}
// By severity
sev := q.Severity
if sev == "" {
sev = "MEDIUM"
}
ss := result.BySeverity[sev]
ss.Total++
if passed {
ss.Passed++
} else {
ss.Failed++
}
result.BySeverity[sev] = ss
}
// Calculate scores
if result.Answered > 0 {
answerable := result.Answered - result.Skipped
if answerable > 0 {
result.ComplianceScore = float64(result.Passed) / float64(answerable) * 100
}
}
for reg, rs := range result.ByRegulation {
if rs.Total > 0 {
rs.Score = float64(rs.Passed) / float64(rs.Total) * 100
}
result.ByRegulation[reg] = rs
}
return result
}
// isPassed checks if an answer represents a pass.
func isPassed(a Answer) bool {
switch v := a.Value.(type) {
case bool:
return v
case string:
return v == "yes" || v == "true" || v == "ja"
case float64:
return v > 0
default:
return false
}
}