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,173 @@
|
||||
package usecase
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
func TestScore_AllPassed(t *testing.T) {
|
||||
audit := &Audit{
|
||||
ID: uuid.New(),
|
||||
Questions: []Question{
|
||||
{ID: "Q1", Severity: "HIGH", Regulation: "DSGVO"},
|
||||
{ID: "Q2", Severity: "MEDIUM", Regulation: "NIS2"},
|
||||
{ID: "Q3", Severity: "LOW", Regulation: "DSGVO"},
|
||||
},
|
||||
}
|
||||
answers := []Answer{
|
||||
{QuestionID: "Q1", Value: true, Status: AnswerStatusAnswered},
|
||||
{QuestionID: "Q2", Value: true, Status: AnswerStatusAnswered},
|
||||
{QuestionID: "Q3", Value: true, Status: AnswerStatusAnswered},
|
||||
}
|
||||
|
||||
result := Score(audit, answers)
|
||||
|
||||
if result.ComplianceScore != 100 {
|
||||
t.Errorf("Expected 100%% score, got %.1f%%", result.ComplianceScore)
|
||||
}
|
||||
if result.Passed != 3 {
|
||||
t.Errorf("Expected 3 passed, got %d", result.Passed)
|
||||
}
|
||||
if result.Failed != 0 {
|
||||
t.Errorf("Expected 0 failed, got %d", result.Failed)
|
||||
}
|
||||
}
|
||||
|
||||
func TestScore_MixedResults(t *testing.T) {
|
||||
audit := &Audit{
|
||||
ID: uuid.New(),
|
||||
Questions: []Question{
|
||||
{ID: "Q1", Severity: "HIGH", Regulation: "DSGVO"},
|
||||
{ID: "Q2", Severity: "HIGH", Regulation: "DSGVO"},
|
||||
{ID: "Q3", Severity: "MEDIUM", Regulation: "NIS2"},
|
||||
{ID: "Q4", Severity: "LOW", Regulation: "NIS2"},
|
||||
},
|
||||
}
|
||||
answers := []Answer{
|
||||
{QuestionID: "Q1", Value: true, Status: AnswerStatusAnswered},
|
||||
{QuestionID: "Q2", Value: false, Status: AnswerStatusAnswered},
|
||||
{QuestionID: "Q3", Value: true, Status: AnswerStatusAnswered},
|
||||
{QuestionID: "Q4", Value: false, Status: AnswerStatusAnswered},
|
||||
}
|
||||
|
||||
result := Score(audit, answers)
|
||||
|
||||
if result.ComplianceScore != 50 {
|
||||
t.Errorf("Expected 50%% score, got %.1f%%", result.ComplianceScore)
|
||||
}
|
||||
if result.Passed != 2 {
|
||||
t.Errorf("Expected 2 passed, got %d", result.Passed)
|
||||
}
|
||||
if result.Failed != 2 {
|
||||
t.Errorf("Expected 2 failed, got %d", result.Failed)
|
||||
}
|
||||
|
||||
// Check regulation breakdown
|
||||
dsgvo := result.ByRegulation["DSGVO"]
|
||||
if dsgvo.Total != 2 || dsgvo.Passed != 1 {
|
||||
t.Errorf("DSGVO: expected 1/2, got %d/%d", dsgvo.Passed, dsgvo.Total)
|
||||
}
|
||||
|
||||
nis2 := result.ByRegulation["NIS2"]
|
||||
if nis2.Total != 2 || nis2.Passed != 1 {
|
||||
t.Errorf("NIS2: expected 1/2, got %d/%d", nis2.Passed, nis2.Total)
|
||||
}
|
||||
}
|
||||
|
||||
func TestScore_WithSkipped(t *testing.T) {
|
||||
audit := &Audit{
|
||||
ID: uuid.New(),
|
||||
Questions: []Question{
|
||||
{ID: "Q1", Severity: "HIGH"},
|
||||
{ID: "Q2", Severity: "MEDIUM"},
|
||||
},
|
||||
}
|
||||
answers := []Answer{
|
||||
{QuestionID: "Q1", Value: true, Status: AnswerStatusAnswered},
|
||||
{QuestionID: "Q2", Value: nil, Status: AnswerStatusSkipped},
|
||||
}
|
||||
|
||||
result := Score(audit, answers)
|
||||
|
||||
if result.Skipped != 1 {
|
||||
t.Errorf("Expected 1 skipped, got %d", result.Skipped)
|
||||
}
|
||||
if result.ComplianceScore != 100 {
|
||||
t.Errorf("Expected 100%% (1 passed / 1 answerable), got %.1f%%", result.ComplianceScore)
|
||||
}
|
||||
}
|
||||
|
||||
func TestScore_NoAnswers(t *testing.T) {
|
||||
audit := &Audit{
|
||||
ID: uuid.New(),
|
||||
Questions: []Question{
|
||||
{ID: "Q1", Severity: "HIGH"},
|
||||
},
|
||||
}
|
||||
|
||||
result := Score(audit, nil)
|
||||
|
||||
if result.ComplianceScore != 0 {
|
||||
t.Errorf("Expected 0%% score, got %.1f%%", result.ComplianceScore)
|
||||
}
|
||||
if result.Answered != 0 {
|
||||
t.Errorf("Expected 0 answered, got %d", result.Answered)
|
||||
}
|
||||
}
|
||||
|
||||
func TestScore_BySeverity(t *testing.T) {
|
||||
audit := &Audit{
|
||||
ID: uuid.New(),
|
||||
Questions: []Question{
|
||||
{ID: "Q1", Severity: "HIGH"},
|
||||
{ID: "Q2", Severity: "HIGH"},
|
||||
{ID: "Q3", Severity: "MEDIUM"},
|
||||
},
|
||||
}
|
||||
answers := []Answer{
|
||||
{QuestionID: "Q1", Value: true, Status: AnswerStatusAnswered},
|
||||
{QuestionID: "Q2", Value: false, Status: AnswerStatusAnswered},
|
||||
{QuestionID: "Q3", Value: true, Status: AnswerStatusAnswered},
|
||||
}
|
||||
|
||||
result := Score(audit, answers)
|
||||
|
||||
high := result.BySeverity["HIGH"]
|
||||
if high.Total != 2 || high.Passed != 1 || high.Failed != 1 {
|
||||
t.Errorf("HIGH: expected 1/2 (1 fail), got %d/%d (%d fail)",
|
||||
high.Passed, high.Total, high.Failed)
|
||||
}
|
||||
|
||||
med := result.BySeverity["MEDIUM"]
|
||||
if med.Total != 1 || med.Passed != 1 {
|
||||
t.Errorf("MEDIUM: expected 1/1, got %d/%d", med.Passed, med.Total)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsPassed_BoolValues(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
value interface{}
|
||||
expect bool
|
||||
}{
|
||||
{"true bool", true, true},
|
||||
{"false bool", false, false},
|
||||
{"yes string", "yes", true},
|
||||
{"no string", "no", false},
|
||||
{"ja string", "ja", true},
|
||||
{"positive float", float64(1), true},
|
||||
{"zero float", float64(0), false},
|
||||
{"nil value", nil, false},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
a := Answer{Value: tt.value, Status: AnswerStatusAnswered}
|
||||
got := isPassed(a)
|
||||
if got != tt.expect {
|
||||
t.Errorf("isPassed(%v) = %v, want %v", tt.value, got, tt.expect)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user