vaspera 2.12.0 → 2.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/CHANGELOG.md +79 -0
  2. package/dist/__tests__/antagonist-integration.test.d.ts +6 -0
  3. package/dist/__tests__/antagonist-integration.test.d.ts.map +1 -0
  4. package/dist/__tests__/antagonist-integration.test.js +239 -0
  5. package/dist/__tests__/antagonist-integration.test.js.map +1 -0
  6. package/dist/__tests__/siem-integration.test.d.ts +7 -0
  7. package/dist/__tests__/siem-integration.test.d.ts.map +1 -0
  8. package/dist/__tests__/siem-integration.test.js +285 -0
  9. package/dist/__tests__/siem-integration.test.js.map +1 -0
  10. package/dist/agents/antagonist/challenger.d.ts +46 -0
  11. package/dist/agents/antagonist/challenger.d.ts.map +1 -0
  12. package/dist/agents/antagonist/challenger.js +257 -0
  13. package/dist/agents/antagonist/challenger.js.map +1 -0
  14. package/dist/agents/antagonist/index.d.ts +31 -0
  15. package/dist/agents/antagonist/index.d.ts.map +1 -0
  16. package/dist/agents/antagonist/index.js +175 -0
  17. package/dist/agents/antagonist/index.js.map +1 -0
  18. package/dist/agents/antagonist/prioritizer.d.ts +27 -0
  19. package/dist/agents/antagonist/prioritizer.d.ts.map +1 -0
  20. package/dist/agents/antagonist/prioritizer.js +181 -0
  21. package/dist/agents/antagonist/prioritizer.js.map +1 -0
  22. package/dist/agents/antagonist/prompts.d.ts +12 -0
  23. package/dist/agents/antagonist/prompts.d.ts.map +1 -0
  24. package/dist/agents/antagonist/prompts.js +155 -0
  25. package/dist/agents/antagonist/prompts.js.map +1 -0
  26. package/dist/agents/antagonist/synthesizer.d.ts +34 -0
  27. package/dist/agents/antagonist/synthesizer.d.ts.map +1 -0
  28. package/dist/agents/antagonist/synthesizer.js +451 -0
  29. package/dist/agents/antagonist/synthesizer.js.map +1 -0
  30. package/dist/agents/antagonist/types.d.ts +145 -0
  31. package/dist/agents/antagonist/types.d.ts.map +1 -0
  32. package/dist/agents/antagonist/types.js +63 -0
  33. package/dist/agents/antagonist/types.js.map +1 -0
  34. package/dist/agents/index.d.ts +1 -0
  35. package/dist/agents/index.d.ts.map +1 -1
  36. package/dist/agents/index.js +2 -0
  37. package/dist/agents/index.js.map +1 -1
  38. package/dist/certification/consensus.test.js +2 -0
  39. package/dist/certification/consensus.test.js.map +1 -1
  40. package/dist/certification/store.d.ts.map +1 -1
  41. package/dist/certification/store.js +6 -1
  42. package/dist/certification/store.js.map +1 -1
  43. package/dist/certification/types.d.ts +1 -1
  44. package/dist/certification/types.d.ts.map +1 -1
  45. package/dist/certification/types.js +2 -0
  46. package/dist/certification/types.js.map +1 -1
  47. package/dist/index.d.ts.map +1 -1
  48. package/dist/index.js +460 -16
  49. package/dist/index.js.map +1 -1
  50. package/dist/persistence/__tests__/json-fallback.test.d.ts +5 -0
  51. package/dist/persistence/__tests__/json-fallback.test.d.ts.map +1 -0
  52. package/dist/persistence/__tests__/json-fallback.test.js +249 -0
  53. package/dist/persistence/__tests__/json-fallback.test.js.map +1 -0
  54. package/dist/persistence/__tests__/persistence.test.js.map +1 -1
  55. package/dist/persistence/db.d.ts +15 -0
  56. package/dist/persistence/db.d.ts.map +1 -1
  57. package/dist/persistence/db.js +59 -10
  58. package/dist/persistence/db.js.map +1 -1
  59. package/dist/persistence/index.d.ts +13 -4
  60. package/dist/persistence/index.d.ts.map +1 -1
  61. package/dist/persistence/index.js +139 -14
  62. package/dist/persistence/index.js.map +1 -1
  63. package/dist/persistence/json-fallback.d.ts +52 -0
  64. package/dist/persistence/json-fallback.d.ts.map +1 -0
  65. package/dist/persistence/json-fallback.js +283 -0
  66. package/dist/persistence/json-fallback.js.map +1 -0
  67. package/dist/sbom/provenance.test.js +2 -2
  68. package/dist/sbom/provenance.test.js.map +1 -1
  69. package/dist/sbom/signing.d.ts.map +1 -1
  70. package/dist/sbom/signing.js +5 -3
  71. package/dist/sbom/signing.js.map +1 -1
  72. package/dist/scanners/ai-code/index.d.ts.map +1 -1
  73. package/dist/scanners/ai-code/index.js +90 -2
  74. package/dist/scanners/ai-code/index.js.map +1 -1
  75. package/dist/scanners/ai-code/types.d.ts +12 -0
  76. package/dist/scanners/ai-code/types.d.ts.map +1 -1
  77. package/dist/scanners/eslint.d.ts.map +1 -1
  78. package/dist/scanners/eslint.js +45 -3
  79. package/dist/scanners/eslint.js.map +1 -1
  80. package/dist/scanners/scale/bottleneck-detector.d.ts +13 -2
  81. package/dist/scanners/scale/bottleneck-detector.d.ts.map +1 -1
  82. package/dist/scanners/scale/bottleneck-detector.js +199 -72
  83. package/dist/scanners/scale/bottleneck-detector.js.map +1 -1
  84. package/dist/scanners/types.d.ts +18 -1
  85. package/dist/scanners/types.d.ts.map +1 -1
  86. package/dist/scanners/types.js.map +1 -1
  87. package/dist/scanners/typescript.d.ts.map +1 -1
  88. package/dist/scanners/typescript.js +36 -4
  89. package/dist/scanners/typescript.js.map +1 -1
  90. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,84 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.14.0] - 2026-06-05
4
+
5
+ ### Added
6
+
7
+ #### Antagonist Agent
8
+ - New meta-analysis agent that runs after all other agents complete
9
+ - **Synthesis mode**: Chains findings into attack narratives mapped to MITRE ATT&CK kill chain
10
+ - **Challenger mode**: Internal critic that flags false positives, coverage gaps, and inconsistencies
11
+ - Prioritized remediation recommendations based on attack surface reduction
12
+ - New `antagonist_synthesize` tool - full analysis with narratives, challenges, and prioritization
13
+ - New `antagonist_challenge` tool - manually challenge specific findings
14
+
15
+ #### Attack Narrative Features
16
+ - Builds attack graphs from findings and exploit chains
17
+ - Maps vulnerabilities to 14 MITRE ATT&CK kill chain phases
18
+ - Identifies bottleneck findings that block multiple attack paths
19
+ - Generates human-readable attack stories with difficulty/likelihood ratings
20
+
21
+ #### Challenger Features
22
+ - Detects potential false positives (test files, low confidence, generic descriptions)
23
+ - Identifies untested attack vectors (17 categories tracked)
24
+ - Flags agents with zero findings as potentially incomplete
25
+ - Calculates coverage score across attack surface
26
+
27
+ ### Fixed
28
+ - Empty catch blocks in `store.ts` and `signing.ts` now log errors
29
+ - Antagonist agent integration test types corrected
30
+
31
+ ### Changed
32
+ - MCP tools increased from 108 to 110
33
+ - New agent type `antagonist` with weight 0.15 (informs but doesn't dominate consensus)
34
+ - Added to AGENT_VERIFICATION_MAP (verified by security, adversary, redteam)
35
+
36
+ ## [2.13.0] - 2026-06-04
37
+
38
+ ### Added
39
+
40
+ #### False Positive Feedback System
41
+ - New `feedback_submit` tool to mark findings as true/false positives
42
+ - New `feedback_report` tool to view FP rates by scanner and rule
43
+ - New `feedback_suppressions` tool to get rule suppression suggestions based on feedback
44
+ - Feedback stored in `.vaspera/fp-feedback.json` with full audit trail
45
+
46
+ #### Diff-Aware CI Scanning
47
+ - New `certification_scan_diff` tool scans only changed files (git diff)
48
+ - Estimates scan time savings vs full scan
49
+ - Auto-detects security-critical files that always get scanned
50
+
51
+ #### Standalone Autofix Preview
52
+ - `autofix_preview` now works without certification_id
53
+ - Provide file + pattern_id to preview fixes directly
54
+ - Use `autofix_list_patterns` to see available fix patterns
55
+
56
+ ### Fixed
57
+
58
+ #### Persistence DB Fallback
59
+ - Added JSON file fallback when SQLite is unavailable
60
+ - New `src/persistence/json-fallback.ts` with atomic writes
61
+ - Graceful degradation: warns but continues operating
62
+
63
+ #### scale_bottlenecks False Positives
64
+ - Added semantic analysis for workflow/pipeline patterns
65
+ - Confidence scoring (60-100) based on context
66
+ - Sequential workflows no longer flagged as N+1 queries
67
+
68
+ #### ai_code_verify Diagnostics
69
+ - Returns detailed diagnostics when 0 files found
70
+ - Shows which extensions were searched
71
+ - Reports which exclude patterns matched
72
+ - Suggests alternative file extensions
73
+
74
+ #### Scanner Error Messages
75
+ - Added `ScannerErrorDetails` with actionable suggestions
76
+ - tsc/eslint now report phase (init/scan/parse) and fix steps
77
+ - Full error output available for debugging
78
+
79
+ ### Changed
80
+ - MCP tools increased from 103 to 108
81
+
3
82
  ## 2.10.0
4
83
 
5
84
  ### Minor Changes
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Integration test for Antagonist Agent
3
+ * Tests the full pipeline on sample findings
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=antagonist-integration.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"antagonist-integration.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/antagonist-integration.test.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
@@ -0,0 +1,239 @@
1
+ /**
2
+ * Integration test for Antagonist Agent
3
+ * Tests the full pipeline on sample findings
4
+ */
5
+ import { describe, it, expect } from "vitest";
6
+ import { synthesizeNarrativesDeterministic } from "../agents/antagonist/synthesizer.js";
7
+ import { runChallengerDeterministic } from "../agents/antagonist/challenger.js";
8
+ import { prioritizeRemediations } from "../agents/antagonist/prioritizer.js";
9
+ import { DEFAULT_ANTAGONIST_CONFIG } from "../agents/antagonist/types.js";
10
+ // Sample findings that represent real security issues
11
+ const sampleFindings = [
12
+ {
13
+ id: "find-001",
14
+ severity: "high",
15
+ category: "command-injection",
16
+ description: "Potential command injection via unsanitized user input",
17
+ evidence: "spawn(cmd, [userInput])",
18
+ confidence: 85,
19
+ verifications: [],
20
+ created_at: new Date().toISOString(),
21
+ file: "src/scanners/custom.ts",
22
+ line: 42,
23
+ },
24
+ {
25
+ id: "find-002",
26
+ severity: "medium",
27
+ category: "hardcoded-secret",
28
+ description: "Hardcoded API key detected",
29
+ evidence: "const API_KEY = 'sk-...'",
30
+ confidence: 90,
31
+ verifications: [],
32
+ created_at: new Date().toISOString(),
33
+ file: "src/config.ts",
34
+ line: 15,
35
+ },
36
+ {
37
+ id: "find-003",
38
+ severity: "high",
39
+ category: "auth-bypass",
40
+ description: "Missing authentication check on admin endpoint",
41
+ evidence: "No auth middleware on /admin route",
42
+ confidence: 75,
43
+ verifications: [],
44
+ created_at: new Date().toISOString(),
45
+ file: "src/routes/admin.ts",
46
+ line: 8,
47
+ },
48
+ {
49
+ id: "find-004",
50
+ severity: "critical",
51
+ category: "sql-injection",
52
+ description: "SQL injection vulnerability in query builder",
53
+ evidence: "db.query(`SELECT * FROM users WHERE id = ${userId}`)",
54
+ confidence: 95,
55
+ verifications: [],
56
+ created_at: new Date().toISOString(),
57
+ file: "src/db/queries.ts",
58
+ line: 22,
59
+ },
60
+ {
61
+ id: "find-005",
62
+ severity: "low",
63
+ category: "xss",
64
+ description: "Potential XSS in user-generated content",
65
+ evidence: "innerHTML = userContent",
66
+ confidence: 60,
67
+ verifications: [],
68
+ created_at: new Date().toISOString(),
69
+ file: "src/components/Comment.tsx",
70
+ line: 55,
71
+ },
72
+ ];
73
+ // Sample exploit chains (matching ExploitChain type)
74
+ const sampleChains = [
75
+ {
76
+ id: "chain-001",
77
+ name: "Auth Bypass to Data Exfil",
78
+ steps: [
79
+ {
80
+ findingId: "find-003",
81
+ finding: sampleFindings[2],
82
+ role: "entry",
83
+ enables: "find-004",
84
+ techniques: ["T1190"],
85
+ },
86
+ {
87
+ findingId: "find-004",
88
+ finding: sampleFindings[3],
89
+ role: "target",
90
+ prerequisite: "find-003",
91
+ techniques: ["T1213"],
92
+ },
93
+ ],
94
+ totalSeverity: "critical",
95
+ originalSeverities: ["high", "critical"],
96
+ confidence: 85,
97
+ attackScenario: "Attacker bypasses auth, then exfiltrates data via SQL injection",
98
+ mitreAttackIds: ["T1190", "T1213"],
99
+ impact: "Data breach - full database access",
100
+ difficulty: "easy",
101
+ },
102
+ ];
103
+ // Agent summaries
104
+ const agentSummaries = {
105
+ security: { completed: true, findingCount: 5 },
106
+ reliability: { completed: true, findingCount: 2 },
107
+ typesafety: { completed: true, findingCount: 1 },
108
+ performance: { completed: true, findingCount: 0 },
109
+ quality: { completed: true, findingCount: 3 },
110
+ redteam: { completed: true, findingCount: 1 },
111
+ "agent-redteam": { completed: false, findingCount: 0 },
112
+ "agent-privacy": { completed: false, findingCount: 0 },
113
+ "agent-integrity": { completed: false, findingCount: 0 },
114
+ adversary: { completed: false, findingCount: 0 },
115
+ antagonist: { completed: false, findingCount: 0 },
116
+ };
117
+ // Test config with all required fields
118
+ const testConfig = {
119
+ ...DEFAULT_ANTAGONIST_CONFIG,
120
+ maxNarratives: 5,
121
+ minConfidence: 50,
122
+ challengeThreshold: 50,
123
+ };
124
+ describe("Antagonist Integration", () => {
125
+ describe("synthesizeNarrativesDeterministic", () => {
126
+ it("generates attack narratives from findings", () => {
127
+ const narratives = synthesizeNarrativesDeterministic(sampleFindings, sampleChains, [], testConfig);
128
+ expect(narratives.length).toBeGreaterThan(0);
129
+ expect(narratives[0]).toHaveProperty("id");
130
+ expect(narratives[0]).toHaveProperty("name");
131
+ expect(narratives[0]).toHaveProperty("phases");
132
+ expect(narratives[0]).toHaveProperty("narrative");
133
+ expect(narratives[0]).toHaveProperty("findingIds");
134
+ expect(narratives[0]).toHaveProperty("recommendations");
135
+ });
136
+ it("includes MITRE ATT&CK techniques", () => {
137
+ const narratives = synthesizeNarrativesDeterministic(sampleFindings, sampleChains, [], testConfig);
138
+ const narrativeWithTechniques = narratives.find((n) => n.mitreTechniques.length > 0);
139
+ expect(narrativeWithTechniques).toBeDefined();
140
+ });
141
+ it("maps findings to kill chain phases", () => {
142
+ const narratives = synthesizeNarrativesDeterministic(sampleFindings, sampleChains, [], testConfig);
143
+ const narrative = narratives[0];
144
+ expect(narrative.phases.length).toBeGreaterThan(0);
145
+ expect(narrative.phases[0]).toHaveProperty("phase");
146
+ expect(narrative.phases[0]).toHaveProperty("description");
147
+ });
148
+ it("prioritizes critical findings in narratives", () => {
149
+ const narratives = synthesizeNarrativesDeterministic(sampleFindings, sampleChains, [], testConfig);
150
+ const hasCritical = narratives.some((n) => n.findingIds.includes("find-004"));
151
+ expect(hasCritical).toBe(true);
152
+ });
153
+ });
154
+ describe("runChallengerDeterministic", () => {
155
+ it("identifies coverage gaps", () => {
156
+ const result = runChallengerDeterministic(sampleFindings, agentSummaries, testConfig);
157
+ expect(result.assessments).toBeDefined();
158
+ expect(result.gapAnalysis).toBeDefined();
159
+ expect(result.gapAnalysis).toHaveProperty("untestedAttackVectors");
160
+ expect(result.gapAnalysis).toHaveProperty("missingControls");
161
+ expect(result.gapAnalysis).toHaveProperty("coverageScore");
162
+ });
163
+ it("flags potential false positives", () => {
164
+ const findingsWithTestFile = [
165
+ ...sampleFindings,
166
+ {
167
+ id: "find-test",
168
+ severity: "medium",
169
+ category: "sql-injection",
170
+ description: "SQL injection in test",
171
+ evidence: "test code",
172
+ confidence: 60,
173
+ verifications: [],
174
+ created_at: new Date().toISOString(),
175
+ file: "src/__tests__/db.test.ts",
176
+ line: 10,
177
+ },
178
+ ];
179
+ const result = runChallengerDeterministic(findingsWithTestFile, agentSummaries, testConfig);
180
+ const testChallenge = result.assessments.find((c) => c.targetFindingId === "find-test" && c.type === "false_positive_likely");
181
+ expect(testChallenge).toBeDefined();
182
+ expect(testChallenge?.challenge).toContain("false positive");
183
+ });
184
+ it("warns about agents with zero findings", () => {
185
+ const summariesWithZero = {
186
+ ...agentSummaries,
187
+ performance: { completed: true, findingCount: 0 },
188
+ };
189
+ const result = runChallengerDeterministic(sampleFindings, summariesWithZero, testConfig);
190
+ const zeroFindingChallenge = result.assessments.find((c) => c.type === "missed_check" && c.targetAgent === "performance");
191
+ expect(zeroFindingChallenge).toBeDefined();
192
+ });
193
+ });
194
+ describe("prioritizeRemediations", () => {
195
+ it("generates prioritized remediation list", () => {
196
+ const narratives = synthesizeNarrativesDeterministic(sampleFindings, sampleChains, [], testConfig);
197
+ const prioritized = prioritizeRemediations(sampleFindings, narratives);
198
+ expect(prioritized.length).toBeGreaterThan(0);
199
+ expect(prioritized[0]).toHaveProperty("order");
200
+ expect(prioritized[0]).toHaveProperty("findingId");
201
+ expect(prioritized[0]).toHaveProperty("reason");
202
+ expect(prioritized[0]).toHaveProperty("effort");
203
+ expect(prioritized[0]).toHaveProperty("impact");
204
+ });
205
+ it("prioritizes critical findings first", () => {
206
+ const narratives = synthesizeNarrativesDeterministic(sampleFindings, sampleChains, [], testConfig);
207
+ const prioritized = prioritizeRemediations(sampleFindings, narratives);
208
+ const criticalPosition = prioritized.findIndex((p) => p.findingId === "find-004");
209
+ expect(criticalPosition).toBeLessThan(3);
210
+ });
211
+ it("considers bottleneck findings (appear in multiple narratives)", () => {
212
+ const narratives = synthesizeNarrativesDeterministic(sampleFindings, sampleChains, [], testConfig);
213
+ const prioritized = prioritizeRemediations(sampleFindings, narratives);
214
+ const hasBlocksNarratives = prioritized.some((p) => p.blocksNarratives && p.blocksNarratives.length > 0);
215
+ expect(hasBlocksNarratives).toBe(true);
216
+ });
217
+ });
218
+ describe("Full pipeline", () => {
219
+ it("runs complete antagonist analysis", () => {
220
+ const narratives = synthesizeNarrativesDeterministic(sampleFindings, sampleChains, [], testConfig);
221
+ const challengerResult = runChallengerDeterministic(sampleFindings, agentSummaries, testConfig);
222
+ const prioritized = prioritizeRemediations(sampleFindings, narratives);
223
+ expect(narratives.length).toBeGreaterThan(0);
224
+ expect(challengerResult.assessments).toBeDefined();
225
+ expect(challengerResult.gapAnalysis).toBeDefined();
226
+ expect(prioritized.length).toBeGreaterThan(0);
227
+ console.log("\n=== Antagonist Analysis Summary ===");
228
+ console.log(`Attack Narratives: ${narratives.length}`);
229
+ console.log(`Challenger Assessments: ${challengerResult.assessments.length}`);
230
+ console.log(`Coverage Score: ${challengerResult.gapAnalysis.coverageScore}%`);
231
+ console.log(`Prioritized Remediations: ${prioritized.length}`);
232
+ console.log("\nTop 3 Remediation Priorities:");
233
+ prioritized.slice(0, 3).forEach((p, i) => {
234
+ console.log(` ${i + 1}. ${p.findingId}: ${p.reason}`);
235
+ });
236
+ });
237
+ });
238
+ });
239
+ //# sourceMappingURL=antagonist-integration.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"antagonist-integration.test.js","sourceRoot":"","sources":["../../src/__tests__/antagonist-integration.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * SIEM Integration Tests
3
+ *
4
+ * Tests for SIEM event formatting and client registry.
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=siem-integration.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"siem-integration.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/siem-integration.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
@@ -0,0 +1,285 @@
1
+ /**
2
+ * SIEM Integration Tests
3
+ *
4
+ * Tests for SIEM event formatting and client registry.
5
+ */
6
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
7
+ import { formatAsCEF, formatAsJSON, formatForSplunk, formatForSentinel, formatForDatadog, mapSeverity, severityToCEF, createFindingEvent, createScanEvent, createCertificationEvent, getSIEMRegistry, closeSIEMRegistry, createSplunkClient, createDatadogClient, } from "../integrations/siem/index.js";
8
+ describe("SIEM Integration", () => {
9
+ describe("Severity Mapping", () => {
10
+ it("maps Vaspera severities to SIEM severities", () => {
11
+ expect(mapSeverity("critical")).toBe("critical");
12
+ expect(mapSeverity("high")).toBe("high");
13
+ expect(mapSeverity("medium")).toBe("medium");
14
+ expect(mapSeverity("low")).toBe("low");
15
+ expect(mapSeverity("info")).toBe("informational");
16
+ });
17
+ it("maps SIEM severity to CEF numeric values", () => {
18
+ expect(severityToCEF("critical")).toBe(10);
19
+ expect(severityToCEF("high")).toBe(8);
20
+ expect(severityToCEF("medium")).toBe(5);
21
+ expect(severityToCEF("low")).toBe(3);
22
+ expect(severityToCEF("informational")).toBe(1);
23
+ });
24
+ });
25
+ describe("Event Creation", () => {
26
+ it("creates finding events", () => {
27
+ const event = createFindingEvent("/test/project", "finding.new", {
28
+ findingId: "finding-001",
29
+ severity: "high",
30
+ category: "sql-injection",
31
+ file: "src/api.ts",
32
+ line: 42,
33
+ scanner: "semgrep",
34
+ ruleId: "sql-injection-001",
35
+ cweIds: ["CWE-89"],
36
+ description: "SQL injection vulnerability",
37
+ }, "cert-001");
38
+ expect(event.eventType).toBe("finding.new");
39
+ expect(event.severity).toBe("high");
40
+ expect(event.project).toBe("/test/project");
41
+ expect(event.certificationId).toBe("cert-001");
42
+ expect(event.source).toBe("vaspera");
43
+ expect(event.message).toContain("sql-injection");
44
+ expect(event.message).toContain("src/api.ts:42");
45
+ });
46
+ it("creates scan events", () => {
47
+ const event = createScanEvent("/test/project", "scan.completed", {
48
+ scanners: ["semgrep", "gitleaks"],
49
+ findingsCount: 5,
50
+ bySeverity: { critical: 1, high: 2, medium: 2, low: 0, info: 0 },
51
+ durationMs: 5000,
52
+ }, "cert-001");
53
+ expect(event.eventType).toBe("scan.completed");
54
+ expect(event.severity).toBe("critical");
55
+ expect(event.message).toContain("5 findings");
56
+ expect(event.message).toContain("1 critical");
57
+ });
58
+ it("creates certification events", () => {
59
+ const event = createCertificationEvent("/test/project", "certification.completed", {
60
+ certificationId: "cert-001",
61
+ level: "GOLD",
62
+ score: 85,
63
+ findingsCount: 5,
64
+ durationMs: 30000,
65
+ });
66
+ expect(event.eventType).toBe("certification.completed");
67
+ expect(event.severity).toBe("informational");
68
+ expect(event.message).toContain("GOLD");
69
+ expect(event.message).toContain("85");
70
+ });
71
+ });
72
+ describe("CEF Formatting", () => {
73
+ it("formats events as CEF", () => {
74
+ const event = {
75
+ timestamp: "2024-01-01T00:00:00.000Z",
76
+ eventType: "finding.new",
77
+ severity: "high",
78
+ project: "/test/project",
79
+ certificationId: "cert-001",
80
+ message: "SQL injection detected",
81
+ source: "vaspera",
82
+ data: {
83
+ findingId: "finding-001",
84
+ category: "sql-injection",
85
+ file: "src/api.ts",
86
+ line: 42,
87
+ },
88
+ };
89
+ const cef = formatAsCEF(event);
90
+ expect(cef).toContain("CEF:0");
91
+ expect(cef).toContain("Vaspera");
92
+ expect(cef).toContain("Hardening MCP");
93
+ expect(cef).toContain("VASP-001");
94
+ expect(cef).toContain("New Security Finding");
95
+ expect(cef).toContain("|8|");
96
+ });
97
+ it("escapes special characters in CEF", () => {
98
+ const event = {
99
+ timestamp: "2024-01-01T00:00:00.000Z",
100
+ eventType: "finding.new",
101
+ severity: "medium",
102
+ project: "/test/project",
103
+ message: "Message with | pipe and = equals",
104
+ source: "vaspera",
105
+ data: {},
106
+ };
107
+ const cef = formatAsCEF(event);
108
+ expect(cef).toContain("\\|");
109
+ expect(cef).toContain("\\=");
110
+ });
111
+ });
112
+ describe("JSON Formatting", () => {
113
+ it("formats events as JSON", () => {
114
+ const event = {
115
+ timestamp: "2024-01-01T00:00:00.000Z",
116
+ eventType: "finding.new",
117
+ severity: "high",
118
+ project: "/test/project",
119
+ message: "SQL injection detected",
120
+ source: "vaspera",
121
+ data: { findingId: "finding-001" },
122
+ };
123
+ const json = formatAsJSON(event);
124
+ expect(json).toHaveProperty("@timestamp", "2024-01-01T00:00:00.000Z");
125
+ expect(json).toHaveProperty("event");
126
+ expect(json.event.action).toBe("finding.new");
127
+ expect(json.event.severity).toBe(8);
128
+ });
129
+ });
130
+ describe("Splunk Formatting", () => {
131
+ it("formats events for Splunk HEC", () => {
132
+ const event = {
133
+ timestamp: "2024-01-01T00:00:00.000Z",
134
+ eventType: "scan.completed",
135
+ severity: "informational",
136
+ project: "/test/project",
137
+ message: "Scan completed",
138
+ source: "vaspera",
139
+ data: {},
140
+ };
141
+ const splunk = formatForSplunk(event, {
142
+ index: "security",
143
+ source: "vaspera:test",
144
+ host: "test-host",
145
+ });
146
+ expect(splunk).toHaveProperty("time");
147
+ expect(splunk).toHaveProperty("host", "test-host");
148
+ expect(splunk).toHaveProperty("source", "vaspera:test");
149
+ expect(splunk).toHaveProperty("index", "security");
150
+ expect(splunk).toHaveProperty("event");
151
+ });
152
+ });
153
+ describe("Sentinel Formatting", () => {
154
+ it("formats events for Microsoft Sentinel", () => {
155
+ const event = {
156
+ timestamp: "2024-01-01T00:00:00.000Z",
157
+ eventType: "finding.new",
158
+ severity: "critical",
159
+ project: "/test/project",
160
+ certificationId: "cert-001",
161
+ message: "Critical finding",
162
+ source: "vaspera",
163
+ data: { category: "secrets" },
164
+ };
165
+ const sentinel = formatForSentinel(event);
166
+ expect(sentinel).toHaveProperty("TimeGenerated", "2024-01-01T00:00:00.000Z");
167
+ expect(sentinel).toHaveProperty("EventType_s", "finding.new");
168
+ expect(sentinel).toHaveProperty("Severity_s", "critical");
169
+ expect(sentinel).toHaveProperty("Project_s", "/test/project");
170
+ expect(sentinel).toHaveProperty("CertificationId_g", "cert-001");
171
+ });
172
+ });
173
+ describe("Datadog Formatting", () => {
174
+ it("formats events for Datadog", () => {
175
+ const event = {
176
+ timestamp: "2024-01-01T00:00:00.000Z",
177
+ eventType: "finding.new",
178
+ severity: "high",
179
+ project: "/test/project",
180
+ message: "High severity finding",
181
+ source: "vaspera",
182
+ data: {},
183
+ };
184
+ const datadog = formatForDatadog(event, {
185
+ service: "my-service",
186
+ env: "production",
187
+ tags: ["team:security"],
188
+ });
189
+ expect(datadog).toHaveProperty("ddsource", "vaspera");
190
+ expect(datadog).toHaveProperty("service", "my-service");
191
+ expect(datadog).toHaveProperty("status", "error");
192
+ expect(datadog.ddtags).toContain("project:/test/project");
193
+ expect(datadog.ddtags).toContain("env:production");
194
+ expect(datadog.ddtags).toContain("team:security");
195
+ });
196
+ it("maps severity to Datadog status", () => {
197
+ const criticalEvent = {
198
+ timestamp: new Date().toISOString(),
199
+ eventType: "finding.new",
200
+ severity: "critical",
201
+ project: "/test",
202
+ message: "Critical",
203
+ source: "vaspera",
204
+ data: {},
205
+ };
206
+ const lowEvent = {
207
+ timestamp: new Date().toISOString(),
208
+ eventType: "finding.new",
209
+ severity: "low",
210
+ project: "/test",
211
+ message: "Low",
212
+ source: "vaspera",
213
+ data: {},
214
+ };
215
+ const critical = formatForDatadog(criticalEvent);
216
+ const low = formatForDatadog(lowEvent);
217
+ expect(critical.status).toBe("emergency");
218
+ expect(low.status).toBe("info");
219
+ });
220
+ });
221
+ describe("SIEM Registry", () => {
222
+ beforeEach(async () => {
223
+ await closeSIEMRegistry();
224
+ });
225
+ afterEach(async () => {
226
+ await closeSIEMRegistry();
227
+ });
228
+ it("registers and retrieves clients", () => {
229
+ const registry = getSIEMRegistry();
230
+ const client = createSplunkClient({
231
+ endpoint: "https://splunk.example.com:8088",
232
+ token: "test-token",
233
+ index: "security",
234
+ });
235
+ registry.register("test-splunk", client);
236
+ const retrieved = registry.get("test-splunk");
237
+ expect(retrieved).toBeDefined();
238
+ expect(retrieved?.provider).toBe("splunk");
239
+ });
240
+ it("lists all registered clients", () => {
241
+ const registry = getSIEMRegistry();
242
+ registry.register("splunk-1", createSplunkClient({ endpoint: "https://splunk.example.com", token: "t1" }));
243
+ registry.register("datadog-1", createDatadogClient({ apiKey: "api-key-1" }));
244
+ const list = registry.list();
245
+ expect(list).toHaveLength(2);
246
+ expect(list.find((c) => c.name === "splunk-1")?.provider).toBe("splunk");
247
+ expect(list.find((c) => c.name === "datadog-1")?.provider).toBe("datadog");
248
+ });
249
+ it("unregisters clients", async () => {
250
+ const registry = getSIEMRegistry();
251
+ registry.register("test", createSplunkClient({ endpoint: "https://splunk.example.com", token: "t" }));
252
+ expect(registry.get("test")).toBeDefined();
253
+ await registry.unregister("test");
254
+ expect(registry.get("test")).toBeUndefined();
255
+ });
256
+ it("closes all clients", async () => {
257
+ const registry = getSIEMRegistry();
258
+ registry.register("s1", createSplunkClient({ endpoint: "https://splunk.example.com", token: "t1" }));
259
+ registry.register("d1", createDatadogClient({ apiKey: "api-key-1" }));
260
+ expect(registry.list()).toHaveLength(2);
261
+ await registry.closeAll();
262
+ expect(registry.list()).toHaveLength(0);
263
+ });
264
+ });
265
+ describe("Event Type Mapping", () => {
266
+ it("generates correct signature IDs for event types", () => {
267
+ const findingEvent = createFindingEvent("/test", "finding.new", {
268
+ findingId: "f1",
269
+ severity: "high",
270
+ category: "test",
271
+ });
272
+ const cef = formatAsCEF(findingEvent);
273
+ expect(cef).toContain("VASP-001");
274
+ const scanEvent = createScanEvent("/test", "scan.completed", {
275
+ scanners: ["test"],
276
+ findingsCount: 0,
277
+ bySeverity: { critical: 0, high: 0, medium: 0, low: 0, info: 0 },
278
+ durationMs: 100,
279
+ });
280
+ const scanCef = formatAsCEF(scanEvent);
281
+ expect(scanCef).toContain("VASP-011");
282
+ });
283
+ });
284
+ });
285
+ //# sourceMappingURL=siem-integration.test.js.map