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.
- package/CHANGELOG.md +79 -0
- package/dist/__tests__/antagonist-integration.test.d.ts +6 -0
- package/dist/__tests__/antagonist-integration.test.d.ts.map +1 -0
- package/dist/__tests__/antagonist-integration.test.js +239 -0
- package/dist/__tests__/antagonist-integration.test.js.map +1 -0
- package/dist/__tests__/siem-integration.test.d.ts +7 -0
- package/dist/__tests__/siem-integration.test.d.ts.map +1 -0
- package/dist/__tests__/siem-integration.test.js +285 -0
- package/dist/__tests__/siem-integration.test.js.map +1 -0
- package/dist/agents/antagonist/challenger.d.ts +46 -0
- package/dist/agents/antagonist/challenger.d.ts.map +1 -0
- package/dist/agents/antagonist/challenger.js +257 -0
- package/dist/agents/antagonist/challenger.js.map +1 -0
- package/dist/agents/antagonist/index.d.ts +31 -0
- package/dist/agents/antagonist/index.d.ts.map +1 -0
- package/dist/agents/antagonist/index.js +175 -0
- package/dist/agents/antagonist/index.js.map +1 -0
- package/dist/agents/antagonist/prioritizer.d.ts +27 -0
- package/dist/agents/antagonist/prioritizer.d.ts.map +1 -0
- package/dist/agents/antagonist/prioritizer.js +181 -0
- package/dist/agents/antagonist/prioritizer.js.map +1 -0
- package/dist/agents/antagonist/prompts.d.ts +12 -0
- package/dist/agents/antagonist/prompts.d.ts.map +1 -0
- package/dist/agents/antagonist/prompts.js +155 -0
- package/dist/agents/antagonist/prompts.js.map +1 -0
- package/dist/agents/antagonist/synthesizer.d.ts +34 -0
- package/dist/agents/antagonist/synthesizer.d.ts.map +1 -0
- package/dist/agents/antagonist/synthesizer.js +451 -0
- package/dist/agents/antagonist/synthesizer.js.map +1 -0
- package/dist/agents/antagonist/types.d.ts +145 -0
- package/dist/agents/antagonist/types.d.ts.map +1 -0
- package/dist/agents/antagonist/types.js +63 -0
- package/dist/agents/antagonist/types.js.map +1 -0
- package/dist/agents/index.d.ts +1 -0
- package/dist/agents/index.d.ts.map +1 -1
- package/dist/agents/index.js +2 -0
- package/dist/agents/index.js.map +1 -1
- package/dist/certification/consensus.test.js +2 -0
- package/dist/certification/consensus.test.js.map +1 -1
- package/dist/certification/store.d.ts.map +1 -1
- package/dist/certification/store.js +6 -1
- package/dist/certification/store.js.map +1 -1
- package/dist/certification/types.d.ts +1 -1
- package/dist/certification/types.d.ts.map +1 -1
- package/dist/certification/types.js +2 -0
- package/dist/certification/types.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +460 -16
- package/dist/index.js.map +1 -1
- package/dist/persistence/__tests__/json-fallback.test.d.ts +5 -0
- package/dist/persistence/__tests__/json-fallback.test.d.ts.map +1 -0
- package/dist/persistence/__tests__/json-fallback.test.js +249 -0
- package/dist/persistence/__tests__/json-fallback.test.js.map +1 -0
- package/dist/persistence/__tests__/persistence.test.js.map +1 -1
- package/dist/persistence/db.d.ts +15 -0
- package/dist/persistence/db.d.ts.map +1 -1
- package/dist/persistence/db.js +59 -10
- package/dist/persistence/db.js.map +1 -1
- package/dist/persistence/index.d.ts +13 -4
- package/dist/persistence/index.d.ts.map +1 -1
- package/dist/persistence/index.js +139 -14
- package/dist/persistence/index.js.map +1 -1
- package/dist/persistence/json-fallback.d.ts +52 -0
- package/dist/persistence/json-fallback.d.ts.map +1 -0
- package/dist/persistence/json-fallback.js +283 -0
- package/dist/persistence/json-fallback.js.map +1 -0
- package/dist/sbom/provenance.test.js +2 -2
- package/dist/sbom/provenance.test.js.map +1 -1
- package/dist/sbom/signing.d.ts.map +1 -1
- package/dist/sbom/signing.js +5 -3
- package/dist/sbom/signing.js.map +1 -1
- package/dist/scanners/ai-code/index.d.ts.map +1 -1
- package/dist/scanners/ai-code/index.js +90 -2
- package/dist/scanners/ai-code/index.js.map +1 -1
- package/dist/scanners/ai-code/types.d.ts +12 -0
- package/dist/scanners/ai-code/types.d.ts.map +1 -1
- package/dist/scanners/eslint.d.ts.map +1 -1
- package/dist/scanners/eslint.js +45 -3
- package/dist/scanners/eslint.js.map +1 -1
- package/dist/scanners/scale/bottleneck-detector.d.ts +13 -2
- package/dist/scanners/scale/bottleneck-detector.d.ts.map +1 -1
- package/dist/scanners/scale/bottleneck-detector.js +199 -72
- package/dist/scanners/scale/bottleneck-detector.js.map +1 -1
- package/dist/scanners/types.d.ts +18 -1
- package/dist/scanners/types.d.ts.map +1 -1
- package/dist/scanners/types.js.map +1 -1
- package/dist/scanners/typescript.d.ts.map +1 -1
- package/dist/scanners/typescript.js +36 -4
- package/dist/scanners/typescript.js.map +1 -1
- 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 @@
|
|
|
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 @@
|
|
|
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
|