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
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:
@@ -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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user