06bfbd1dca
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>
187 lines
4.1 KiB
Go
187 lines
4.1 KiB
Go
package usecase
|
|
|
|
import (
|
|
"testing"
|
|
)
|
|
|
|
func TestTemplates_AllPresent(t *testing.T) {
|
|
expected := []string{
|
|
"vendor_check_cloud",
|
|
"sast_dast_audit",
|
|
"dsgvo_quick_check",
|
|
"nis2_readiness",
|
|
"cra_product_check",
|
|
}
|
|
|
|
for _, id := range expected {
|
|
if _, ok := Templates[id]; !ok {
|
|
t.Errorf("Template %q missing from Templates map", id)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestTemplates_HaveQuestions(t *testing.T) {
|
|
for id, tmpl := range Templates {
|
|
if len(tmpl.Questions) == 0 {
|
|
t.Errorf("Template %q has no pre-defined questions", id)
|
|
}
|
|
if tmpl.Name == "" {
|
|
t.Errorf("Template %q has no name", id)
|
|
}
|
|
if len(tmpl.MCFilters) == 0 {
|
|
t.Errorf("Template %q has no MC filters", id)
|
|
}
|
|
if len(tmpl.Regulations) == 0 {
|
|
t.Errorf("Template %q has no regulations", id)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestTemplates_QuestionIDs_Unique(t *testing.T) {
|
|
for id, tmpl := range Templates {
|
|
seen := make(map[string]bool)
|
|
for _, q := range tmpl.Questions {
|
|
if seen[q.ID] {
|
|
t.Errorf("Template %q has duplicate question ID %q", id, q.ID)
|
|
}
|
|
seen[q.ID] = true
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestTemplateList_ReturnsAll(t *testing.T) {
|
|
list := TemplateList()
|
|
if len(list) != len(Templates) {
|
|
t.Errorf("TemplateList returned %d, expected %d", len(list), len(Templates))
|
|
}
|
|
}
|
|
|
|
func TestDeriveQuestion(t *testing.T) {
|
|
tests := []struct {
|
|
input string
|
|
want string
|
|
}{
|
|
{"encryption_at_rest", "Ist 'Encryption At Rest' implementiert und dokumentiert?"},
|
|
{"access_control", "Ist 'Access Control' implementiert und dokumentiert?"},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
got := deriveQuestion(tt.input)
|
|
if got != tt.want {
|
|
t.Errorf("deriveQuestion(%q) = %q, want %q", tt.input, got, tt.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestSplitCriteria(t *testing.T) {
|
|
tests := []struct {
|
|
input string
|
|
expect int
|
|
}{
|
|
{"", 0},
|
|
{"Single criteria", 1},
|
|
{"A | B | C", 3},
|
|
{"A|B", 2},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
got := splitCriteria(tt.input)
|
|
if got == nil && tt.expect == 0 {
|
|
continue
|
|
}
|
|
if len(got) != tt.expect {
|
|
t.Errorf("splitCriteria(%q) returned %d items, want %d", tt.input, len(got), tt.expect)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestNormalizeSeverity(t *testing.T) {
|
|
tests := []struct {
|
|
input string
|
|
want string
|
|
}{
|
|
{"HIGH", "HIGH"},
|
|
{"high", "HIGH"},
|
|
{"CRITICAL", "HIGH"},
|
|
{"medium", "MEDIUM"},
|
|
{"LOW", "LOW"},
|
|
{"unknown", "MEDIUM"},
|
|
{"", "MEDIUM"},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
got := normalizeSeverity(tt.input)
|
|
if got != tt.want {
|
|
t.Errorf("normalizeSeverity(%q) = %q, want %q", tt.input, got, tt.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestInferMCSeverity(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
want string
|
|
}{
|
|
{"encryption_at_rest_aes256", "HIGH"},
|
|
{"access_control_mfa", "HIGH"},
|
|
{"incident_response_plan", "HIGH"},
|
|
{"documentation_management", "MEDIUM"},
|
|
{"training_awareness", "MEDIUM"},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
got := inferMCSeverity(tt.name)
|
|
if got != tt.want {
|
|
t.Errorf("inferMCSeverity(%q) = %q, want %q", tt.name, got, tt.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestGenerateFromMC_SmallMC(t *testing.T) {
|
|
mc := MCInfo{
|
|
MasterControlID: "MC-123",
|
|
CanonicalName: "access_control_basic",
|
|
TotalControls: 3,
|
|
RegSource: "DSGVO",
|
|
}
|
|
|
|
questions := GenerateFromMC(mc)
|
|
if len(questions) != 1 {
|
|
t.Errorf("Expected 1 question for small MC, got %d", len(questions))
|
|
}
|
|
if questions[0].Severity != "HIGH" {
|
|
t.Errorf("Expected HIGH severity for access_control, got %s", questions[0].Severity)
|
|
}
|
|
}
|
|
|
|
func TestGenerateFromMC_MediumMC(t *testing.T) {
|
|
mc := MCInfo{
|
|
MasterControlID: "MC-456",
|
|
CanonicalName: "documentation_management",
|
|
TotalControls: 8,
|
|
RegSource: "NIS2",
|
|
}
|
|
|
|
questions := GenerateFromMC(mc)
|
|
if len(questions) != 2 {
|
|
t.Errorf("Expected 2 questions for medium MC, got %d", len(questions))
|
|
}
|
|
if questions[1].DependsOn == "" {
|
|
t.Error("Second question should depend on first")
|
|
}
|
|
}
|
|
|
|
func TestGenerateFromMC_LargeMC(t *testing.T) {
|
|
mc := MCInfo{
|
|
MasterControlID: "MC-789",
|
|
CanonicalName: "risk_management_framework",
|
|
TotalControls: 25,
|
|
RegSource: "NIS2",
|
|
}
|
|
|
|
questions := GenerateFromMC(mc)
|
|
if len(questions) != 3 {
|
|
t.Errorf("Expected 3 questions for large MC, got %d", len(questions))
|
|
}
|
|
}
|