qa360 1.0.4 → 1.1.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/dist/commands/history.js +1 -1
- package/dist/commands/pack.js +1 -1
- package/dist/commands/run.d.ts +1 -1
- package/dist/commands/run.d.ts.map +1 -1
- package/dist/commands/run.js +1 -1
- package/dist/commands/secrets.js +1 -1
- package/dist/commands/serve.js +1 -1
- package/dist/commands/verify.js +1 -1
- package/dist/core/adapters/gitleaks-secrets.d.ts +115 -0
- package/dist/core/adapters/gitleaks-secrets.d.ts.map +1 -0
- package/dist/core/adapters/gitleaks-secrets.js +410 -0
- package/dist/core/adapters/k6-perf.d.ts +86 -0
- package/dist/core/adapters/k6-perf.d.ts.map +1 -0
- package/dist/core/adapters/k6-perf.js +398 -0
- package/dist/core/adapters/osv-deps.d.ts +124 -0
- package/dist/core/adapters/osv-deps.d.ts.map +1 -0
- package/dist/core/adapters/osv-deps.js +372 -0
- package/dist/core/adapters/playwright-api.d.ts +82 -0
- package/dist/core/adapters/playwright-api.d.ts.map +1 -0
- package/dist/core/adapters/playwright-api.js +252 -0
- package/dist/core/adapters/playwright-ui.d.ts +115 -0
- package/dist/core/adapters/playwright-ui.d.ts.map +1 -0
- package/dist/core/adapters/playwright-ui.js +346 -0
- package/dist/core/adapters/semgrep-sast.d.ts +100 -0
- package/dist/core/adapters/semgrep-sast.d.ts.map +1 -0
- package/dist/core/adapters/semgrep-sast.js +322 -0
- package/dist/core/adapters/zap-dast.d.ts +134 -0
- package/dist/core/adapters/zap-dast.d.ts.map +1 -0
- package/dist/core/adapters/zap-dast.js +424 -0
- package/dist/core/hooks/compose.d.ts +62 -0
- package/dist/core/hooks/compose.d.ts.map +1 -0
- package/dist/core/hooks/compose.js +225 -0
- package/dist/core/hooks/runner.d.ts +69 -0
- package/dist/core/hooks/runner.d.ts.map +1 -0
- package/dist/core/hooks/runner.js +303 -0
- package/dist/core/index.d.ts +74 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +39 -0
- package/dist/core/pack/migrator.d.ts +52 -0
- package/dist/core/pack/migrator.d.ts.map +1 -0
- package/dist/core/pack/migrator.js +304 -0
- package/dist/core/pack/validator.d.ts +43 -0
- package/dist/core/pack/validator.d.ts.map +1 -0
- package/dist/core/pack/validator.js +292 -0
- package/dist/core/proof/bundle.d.ts +138 -0
- package/dist/core/proof/bundle.d.ts.map +1 -0
- package/dist/core/proof/bundle.js +160 -0
- package/dist/core/proof/canonicalize.d.ts +48 -0
- package/dist/core/proof/canonicalize.d.ts.map +1 -0
- package/dist/core/proof/canonicalize.js +105 -0
- package/dist/core/proof/index.d.ts +14 -0
- package/dist/core/proof/index.d.ts.map +1 -0
- package/dist/core/proof/index.js +18 -0
- package/dist/core/proof/schema.d.ts +218 -0
- package/dist/core/proof/schema.d.ts.map +1 -0
- package/dist/core/proof/schema.js +263 -0
- package/dist/core/proof/signer.d.ts +112 -0
- package/dist/core/proof/signer.d.ts.map +1 -0
- package/dist/core/proof/signer.js +226 -0
- package/dist/core/proof/verifier.d.ts +98 -0
- package/dist/core/proof/verifier.d.ts.map +1 -0
- package/dist/core/proof/verifier.js +302 -0
- package/dist/core/runner/phase3-runner.d.ts +102 -0
- package/dist/core/runner/phase3-runner.d.ts.map +1 -0
- package/dist/core/runner/phase3-runner.js +471 -0
- package/dist/core/secrets/crypto.d.ts +76 -0
- package/dist/core/secrets/crypto.d.ts.map +1 -0
- package/dist/core/secrets/crypto.js +225 -0
- package/dist/core/secrets/manager.d.ts +77 -0
- package/dist/core/secrets/manager.d.ts.map +1 -0
- package/dist/core/secrets/manager.js +219 -0
- package/dist/core/security/redaction-patterns-extended.d.ts +28 -0
- package/dist/core/security/redaction-patterns-extended.d.ts.map +1 -0
- package/dist/core/security/redaction-patterns-extended.js +247 -0
- package/dist/core/security/redactor.d.ts +72 -0
- package/dist/core/security/redactor.d.ts.map +1 -0
- package/dist/core/security/redactor.js +279 -0
- package/dist/core/serve/diagnostics-collector.d.ts +33 -0
- package/dist/core/serve/diagnostics-collector.d.ts.map +1 -0
- package/dist/core/serve/diagnostics-collector.js +149 -0
- package/dist/core/serve/health-checker.d.ts +45 -0
- package/dist/core/serve/health-checker.d.ts.map +1 -0
- package/dist/core/serve/health-checker.js +219 -0
- package/dist/core/serve/index.d.ts +9 -0
- package/dist/core/serve/index.d.ts.map +1 -0
- package/dist/core/serve/index.js +8 -0
- package/dist/core/serve/metrics-collector.d.ts +25 -0
- package/dist/core/serve/metrics-collector.d.ts.map +1 -0
- package/dist/core/serve/metrics-collector.js +322 -0
- package/dist/core/serve/process-manager.d.ts +37 -0
- package/dist/core/serve/process-manager.d.ts.map +1 -0
- package/dist/core/serve/process-manager.js +213 -0
- package/dist/core/serve/server.d.ts +37 -0
- package/dist/core/serve/server.d.ts.map +1 -0
- package/dist/core/serve/server.js +191 -0
- package/dist/core/types/pack-v1.d.ts +162 -0
- package/dist/core/types/pack-v1.d.ts.map +1 -0
- package/dist/core/types/pack-v1.js +5 -0
- package/dist/core/types/trust-score.d.ts +70 -0
- package/dist/core/types/trust-score.d.ts.map +1 -0
- package/dist/core/types/trust-score.js +191 -0
- package/dist/core/vault/cas.d.ts +87 -0
- package/dist/core/vault/cas.d.ts.map +1 -0
- package/dist/core/vault/cas.js +255 -0
- package/dist/core/vault/index.d.ts +205 -0
- package/dist/core/vault/index.d.ts.map +1 -0
- package/dist/core/vault/index.js +631 -0
- package/package.json +12 -6
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QA360 Playwright UI Adapter (Socle OOTB)
|
|
3
|
+
* UI smoke tests + accessibility via axe-core
|
|
4
|
+
*/
|
|
5
|
+
import { chromium } from '@playwright/test';
|
|
6
|
+
import { SecurityRedactor } from '../security/redactor.js';
|
|
7
|
+
export class PlaywrightUiAdapter {
|
|
8
|
+
browser;
|
|
9
|
+
context;
|
|
10
|
+
page;
|
|
11
|
+
redactor;
|
|
12
|
+
constructor() {
|
|
13
|
+
this.redactor = SecurityRedactor.forLogs();
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Execute UI smoke tests with accessibility
|
|
17
|
+
*/
|
|
18
|
+
async runSmokeTests(config) {
|
|
19
|
+
try {
|
|
20
|
+
await this.setupBrowser();
|
|
21
|
+
const results = [];
|
|
22
|
+
const pages = config.target.pages || [config.target.baseUrl];
|
|
23
|
+
console.log(`🖥️ Running UI smoke tests (${pages.length} pages)`);
|
|
24
|
+
// Optional login first
|
|
25
|
+
if (config.login) {
|
|
26
|
+
await this.performLogin(config.login);
|
|
27
|
+
}
|
|
28
|
+
for (const pageUrl of pages) {
|
|
29
|
+
const testResult = await this.testPage(pageUrl, config);
|
|
30
|
+
results.push(testResult);
|
|
31
|
+
if (testResult.success) {
|
|
32
|
+
const a11yInfo = testResult.accessibility ?
|
|
33
|
+
` | A11y: ${testResult.accessibility.score}% (${testResult.accessibility.violations.length} issues)` : '';
|
|
34
|
+
console.log(` ✅ ${pageUrl} -> ${testResult.loadTime}ms${a11yInfo}`);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
console.log(` ❌ ${pageUrl} -> ${testResult.error}`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
const summary = this.calculateSummary(results);
|
|
41
|
+
const junit = this.generateJUnit(results);
|
|
42
|
+
return {
|
|
43
|
+
success: summary.failed === 0,
|
|
44
|
+
results,
|
|
45
|
+
summary,
|
|
46
|
+
junit
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
finally {
|
|
50
|
+
await this.cleanup();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Test single page with accessibility
|
|
55
|
+
*/
|
|
56
|
+
async testPage(pageUrl, config) {
|
|
57
|
+
try {
|
|
58
|
+
const startTime = Date.now();
|
|
59
|
+
// Navigate to page
|
|
60
|
+
const response = await this.page.goto(pageUrl, {
|
|
61
|
+
timeout: config.timeout || 30000,
|
|
62
|
+
waitUntil: 'networkidle'
|
|
63
|
+
});
|
|
64
|
+
const loadTime = Date.now() - startTime;
|
|
65
|
+
if (!response || !response.ok()) {
|
|
66
|
+
return {
|
|
67
|
+
page: pageUrl,
|
|
68
|
+
success: false,
|
|
69
|
+
loadTime,
|
|
70
|
+
error: `HTTP ${response?.status() || 'unknown'}: Failed to load page`
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
// Take screenshot
|
|
74
|
+
const screenshot = await this.takeScreenshot(pageUrl);
|
|
75
|
+
// Get DOM snapshot
|
|
76
|
+
const domSnapshot = await this.getDomSnapshot();
|
|
77
|
+
// Run accessibility tests
|
|
78
|
+
const accessibility = await this.runAccessibilityTests(config.budgets);
|
|
79
|
+
// Check if accessibility meets budget
|
|
80
|
+
const a11yPassed = !config.budgets?.a11y_min ||
|
|
81
|
+
(accessibility?.score !== undefined && accessibility.score >= config.budgets.a11y_min);
|
|
82
|
+
return {
|
|
83
|
+
page: pageUrl,
|
|
84
|
+
success: a11yPassed,
|
|
85
|
+
loadTime,
|
|
86
|
+
screenshot,
|
|
87
|
+
accessibility,
|
|
88
|
+
domSnapshot,
|
|
89
|
+
error: a11yPassed ? undefined :
|
|
90
|
+
`Accessibility score ${accessibility?.score || 0}% below budget ${config.budgets?.a11y_min}%`
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
return {
|
|
95
|
+
page: pageUrl,
|
|
96
|
+
success: false,
|
|
97
|
+
loadTime: 0,
|
|
98
|
+
error: this.redactor.redact(error instanceof Error ? error.message : 'Unknown error')
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Perform login if configured
|
|
104
|
+
*/
|
|
105
|
+
async performLogin(login) {
|
|
106
|
+
if (!login || !login.username || !login.password) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
console.log(` 🔐 Performing login...`);
|
|
110
|
+
const loginUrl = login.url || this.page.url();
|
|
111
|
+
await this.page.goto(loginUrl);
|
|
112
|
+
// Fill login form
|
|
113
|
+
const usernameSelector = login.usernameSelector ||
|
|
114
|
+
'input[name="username"], input[name="email"], input[type="email"], #username, #email';
|
|
115
|
+
const passwordSelector = login.passwordSelector ||
|
|
116
|
+
'input[name="password"], input[type="password"], #password';
|
|
117
|
+
const submitSelector = login.submitSelector ||
|
|
118
|
+
'button[type="submit"], input[type="submit"], button:has-text("Login"), button:has-text("Sign in")';
|
|
119
|
+
await this.page.fill(usernameSelector, login.username);
|
|
120
|
+
await this.page.fill(passwordSelector, login.password);
|
|
121
|
+
await this.page.click(submitSelector);
|
|
122
|
+
// Wait for navigation or login completion
|
|
123
|
+
try {
|
|
124
|
+
await this.page.waitForLoadState('networkidle', { timeout: 10000 });
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
// Continue even if navigation doesn't complete
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Run accessibility tests using axe-core
|
|
132
|
+
*/
|
|
133
|
+
async runAccessibilityTests(budgets) {
|
|
134
|
+
try {
|
|
135
|
+
// Inject axe-core
|
|
136
|
+
await this.page.addScriptTag({
|
|
137
|
+
url: 'https://unpkg.com/axe-core@4.8.2/axe.min.js'
|
|
138
|
+
});
|
|
139
|
+
// Run axe analysis
|
|
140
|
+
const axeResults = await this.page.evaluate(() => {
|
|
141
|
+
return new Promise((resolve) => {
|
|
142
|
+
// @ts-ignore - axe is injected
|
|
143
|
+
if (typeof axe !== 'undefined') {
|
|
144
|
+
// @ts-ignore
|
|
145
|
+
axe.run((err, results) => {
|
|
146
|
+
if (err) {
|
|
147
|
+
resolve({ violations: [], passes: [], incomplete: [], inapplicable: [] });
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
resolve(results);
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
resolve({ violations: [], passes: [], incomplete: [], inapplicable: [] });
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
// Process violations
|
|
160
|
+
const violations = axeResults.violations?.map((violation) => ({
|
|
161
|
+
id: violation.id,
|
|
162
|
+
impact: violation.impact || 'minor',
|
|
163
|
+
description: violation.description || violation.help || 'Accessibility issue',
|
|
164
|
+
nodes: violation.nodes?.length || 0
|
|
165
|
+
})) || [];
|
|
166
|
+
// Calculate score (simple scoring: 100 - weighted violations)
|
|
167
|
+
const criticalCount = violations.filter((v) => v.impact === 'critical').length;
|
|
168
|
+
const seriousCount = violations.filter((v) => v.impact === 'serious').length;
|
|
169
|
+
const moderateCount = violations.filter((v) => v.impact === 'moderate').length;
|
|
170
|
+
const minorCount = violations.filter((v) => v.impact === 'minor').length;
|
|
171
|
+
const score = Math.max(0, 100 - (criticalCount * 25 +
|
|
172
|
+
seriousCount * 10 +
|
|
173
|
+
moderateCount * 5 +
|
|
174
|
+
minorCount * 1));
|
|
175
|
+
return {
|
|
176
|
+
score: Math.round(score),
|
|
177
|
+
violations
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
catch (error) {
|
|
181
|
+
console.log(` ⚠️ Accessibility test failed: ${error}`);
|
|
182
|
+
return {
|
|
183
|
+
score: 0,
|
|
184
|
+
violations: [{
|
|
185
|
+
id: 'axe-error',
|
|
186
|
+
impact: 'critical',
|
|
187
|
+
description: 'Failed to run accessibility analysis',
|
|
188
|
+
nodes: 0
|
|
189
|
+
}]
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Get DOM snapshot for debugging
|
|
195
|
+
*/
|
|
196
|
+
async getDomSnapshot() {
|
|
197
|
+
try {
|
|
198
|
+
const snapshot = await this.page.evaluate(() => {
|
|
199
|
+
return {
|
|
200
|
+
title: document.title,
|
|
201
|
+
url: window.location.href,
|
|
202
|
+
elements: {
|
|
203
|
+
buttons: document.querySelectorAll('button, input[type="button"], input[type="submit"]').length,
|
|
204
|
+
links: document.querySelectorAll('a[href]').length,
|
|
205
|
+
forms: document.querySelectorAll('form').length,
|
|
206
|
+
inputs: document.querySelectorAll('input, textarea, select').length
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
});
|
|
210
|
+
return snapshot;
|
|
211
|
+
}
|
|
212
|
+
catch {
|
|
213
|
+
return {
|
|
214
|
+
title: 'Unknown',
|
|
215
|
+
url: this.page.url(),
|
|
216
|
+
elements: { buttons: 0, links: 0, forms: 0, inputs: 0 }
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Take screenshot for debugging
|
|
222
|
+
*/
|
|
223
|
+
async takeScreenshot(pageUrl) {
|
|
224
|
+
try {
|
|
225
|
+
const screenshot = await this.page.screenshot({
|
|
226
|
+
type: 'png',
|
|
227
|
+
fullPage: false // Just viewport for performance
|
|
228
|
+
});
|
|
229
|
+
// Return base64 data URL for embedding
|
|
230
|
+
return `data:image/png;base64,${screenshot.toString('base64')}`;
|
|
231
|
+
}
|
|
232
|
+
catch {
|
|
233
|
+
return '';
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Calculate test summary
|
|
238
|
+
*/
|
|
239
|
+
calculateSummary(results) {
|
|
240
|
+
const total = results.length;
|
|
241
|
+
const passed = results.filter(r => r.success).length;
|
|
242
|
+
const failed = total - passed;
|
|
243
|
+
const avgLoadTime = total > 0 ?
|
|
244
|
+
Math.round(results.reduce((sum, r) => sum + r.loadTime, 0) / total) : 0;
|
|
245
|
+
const a11yScores = results
|
|
246
|
+
.map(r => r.accessibility?.score)
|
|
247
|
+
.filter((score) => typeof score === 'number');
|
|
248
|
+
const avgA11yScore = a11yScores.length > 0 ?
|
|
249
|
+
Math.round(a11yScores.reduce((sum, score) => sum + score, 0) / a11yScores.length) : 0;
|
|
250
|
+
return { total, passed, failed, avgLoadTime, avgA11yScore };
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Generate JUnit XML fragment
|
|
254
|
+
*/
|
|
255
|
+
generateJUnit(results) {
|
|
256
|
+
const summary = this.calculateSummary(results);
|
|
257
|
+
const timestamp = new Date().toISOString();
|
|
258
|
+
let junit = `<?xml version="1.0" encoding="UTF-8"?>
|
|
259
|
+
<testsuite name="UI Smoke Tests" tests="${summary.total}" failures="${summary.failed}" time="${summary.avgLoadTime / 1000}" timestamp="${timestamp}">
|
|
260
|
+
`;
|
|
261
|
+
for (const result of results) {
|
|
262
|
+
const testName = `UI Test: ${result.page}`;
|
|
263
|
+
const time = result.loadTime / 1000;
|
|
264
|
+
junit += ` <testcase name="${this.escapeXml(testName)}" time="${time}">
|
|
265
|
+
`;
|
|
266
|
+
if (!result.success) {
|
|
267
|
+
junit += ` <failure message="${this.escapeXml(result.error || 'Test failed')}">${this.escapeXml(JSON.stringify(result, null, 2))}</failure>
|
|
268
|
+
`;
|
|
269
|
+
}
|
|
270
|
+
junit += ` </testcase>
|
|
271
|
+
`;
|
|
272
|
+
}
|
|
273
|
+
junit += `</testsuite>`;
|
|
274
|
+
return junit;
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Escape XML special characters
|
|
278
|
+
*/
|
|
279
|
+
escapeXml(str) {
|
|
280
|
+
return str
|
|
281
|
+
.replace(/&/g, '&')
|
|
282
|
+
.replace(/</g, '<')
|
|
283
|
+
.replace(/>/g, '>')
|
|
284
|
+
.replace(/"/g, '"')
|
|
285
|
+
.replace(/'/g, ''');
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Setup browser context
|
|
289
|
+
*/
|
|
290
|
+
async setupBrowser() {
|
|
291
|
+
this.browser = await chromium.launch({
|
|
292
|
+
headless: true,
|
|
293
|
+
args: ['--no-sandbox', '--disable-dev-shm-usage']
|
|
294
|
+
});
|
|
295
|
+
this.context = await this.browser.newContext({
|
|
296
|
+
viewport: { width: 1280, height: 720 },
|
|
297
|
+
userAgent: 'QA360-UI-Smoke/1.0'
|
|
298
|
+
});
|
|
299
|
+
this.page = await this.context.newPage();
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Cleanup browser resources
|
|
303
|
+
*/
|
|
304
|
+
async cleanup() {
|
|
305
|
+
if (this.page) {
|
|
306
|
+
await this.page.close();
|
|
307
|
+
}
|
|
308
|
+
if (this.context) {
|
|
309
|
+
await this.context.close();
|
|
310
|
+
}
|
|
311
|
+
if (this.browser) {
|
|
312
|
+
await this.browser.close();
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Validate UI target configuration
|
|
317
|
+
*/
|
|
318
|
+
static validateConfig(target) {
|
|
319
|
+
const errors = [];
|
|
320
|
+
if (!target.baseUrl) {
|
|
321
|
+
errors.push('UI target requires baseUrl');
|
|
322
|
+
}
|
|
323
|
+
else {
|
|
324
|
+
try {
|
|
325
|
+
new URL(target.baseUrl);
|
|
326
|
+
}
|
|
327
|
+
catch {
|
|
328
|
+
errors.push('UI target baseUrl must be a valid URL');
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
if (target.pages) {
|
|
332
|
+
for (const page of target.pages) {
|
|
333
|
+
try {
|
|
334
|
+
new URL(page, target.baseUrl);
|
|
335
|
+
}
|
|
336
|
+
catch {
|
|
337
|
+
errors.push(`Invalid page URL: ${page}`);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
return {
|
|
342
|
+
valid: errors.length === 0,
|
|
343
|
+
errors
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QA360 Semgrep SAST Adapter (Socle OOTB)
|
|
3
|
+
* Static Application Security Testing with configurable severity thresholds
|
|
4
|
+
*/
|
|
5
|
+
import { PackSecurity } from '../types/pack-v1.js';
|
|
6
|
+
export interface SemgrepTestConfig {
|
|
7
|
+
workingDir: string;
|
|
8
|
+
security?: PackSecurity;
|
|
9
|
+
rules?: string[];
|
|
10
|
+
paths?: string[];
|
|
11
|
+
timeout?: number;
|
|
12
|
+
configFile?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface SemgrepFinding {
|
|
15
|
+
ruleId: string;
|
|
16
|
+
severity: 'INFO' | 'WARNING' | 'ERROR';
|
|
17
|
+
message: string;
|
|
18
|
+
file: string;
|
|
19
|
+
line: number;
|
|
20
|
+
column: number;
|
|
21
|
+
code?: string;
|
|
22
|
+
fix?: string;
|
|
23
|
+
}
|
|
24
|
+
export interface SemgrepTestResult {
|
|
25
|
+
success: boolean;
|
|
26
|
+
findings: SemgrepFinding[];
|
|
27
|
+
summary: {
|
|
28
|
+
total: number;
|
|
29
|
+
critical: number;
|
|
30
|
+
high: number;
|
|
31
|
+
medium: number;
|
|
32
|
+
low: number;
|
|
33
|
+
info: number;
|
|
34
|
+
};
|
|
35
|
+
thresholds: {
|
|
36
|
+
sast_max_high: {
|
|
37
|
+
passed: boolean;
|
|
38
|
+
actual: number;
|
|
39
|
+
budget: number;
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
error?: string;
|
|
43
|
+
rawOutput?: string;
|
|
44
|
+
junit?: string;
|
|
45
|
+
}
|
|
46
|
+
export declare class SemgrepSastAdapter {
|
|
47
|
+
private redactor;
|
|
48
|
+
constructor();
|
|
49
|
+
/**
|
|
50
|
+
* Execute Semgrep SAST scan
|
|
51
|
+
*/
|
|
52
|
+
runSastScan(config: SemgrepTestConfig): Promise<SemgrepTestResult>;
|
|
53
|
+
/**
|
|
54
|
+
* Execute Semgrep command
|
|
55
|
+
*/
|
|
56
|
+
private executeSemgrep;
|
|
57
|
+
/**
|
|
58
|
+
* Parse Semgrep JSON results
|
|
59
|
+
*/
|
|
60
|
+
private parseSemgrepResults;
|
|
61
|
+
/**
|
|
62
|
+
* Map Semgrep severity to standard levels
|
|
63
|
+
*/
|
|
64
|
+
private mapSeverity;
|
|
65
|
+
/**
|
|
66
|
+
* Calculate findings summary
|
|
67
|
+
*/
|
|
68
|
+
private calculateSummary;
|
|
69
|
+
/**
|
|
70
|
+
* Check security thresholds
|
|
71
|
+
*/
|
|
72
|
+
private checkThresholds;
|
|
73
|
+
/**
|
|
74
|
+
* Generate JUnit XML
|
|
75
|
+
*/
|
|
76
|
+
private generateJUnit;
|
|
77
|
+
/**
|
|
78
|
+
* Get default summary structure
|
|
79
|
+
*/
|
|
80
|
+
private getDefaultSummary;
|
|
81
|
+
/**
|
|
82
|
+
* Get default thresholds
|
|
83
|
+
*/
|
|
84
|
+
private getDefaultThresholds;
|
|
85
|
+
/**
|
|
86
|
+
* Check if Semgrep is available
|
|
87
|
+
*/
|
|
88
|
+
static isAvailable(): Promise<{
|
|
89
|
+
available: boolean;
|
|
90
|
+
error?: string;
|
|
91
|
+
}>;
|
|
92
|
+
/**
|
|
93
|
+
* Validate SAST configuration
|
|
94
|
+
*/
|
|
95
|
+
static validateConfig(config: SemgrepTestConfig): {
|
|
96
|
+
valid: boolean;
|
|
97
|
+
errors: string[];
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=semgrep-sast.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semgrep-sast.d.ts","sourceRoot":"","sources":["../../../src/core/adapters/semgrep-sast.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGnD,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,OAAO,EAAE;QACP,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,UAAU,EAAE;QACV,aAAa,EAAE;YACb,MAAM,EAAE,OAAO,CAAC;YAChB,MAAM,EAAE,MAAM,CAAC;YACf,MAAM,EAAE,MAAM,CAAC;SAChB,CAAC;KACH,CAAC;IACF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAmB;;IAMnC;;OAEG;IACG,WAAW,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAgCxE;;OAEG;YACW,cAAc;IAiF5B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IA4D3B;;OAEG;IACH,OAAO,CAAC,WAAW;IAOnB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IA2BxB;;OAEG;IACH,OAAO,CAAC,eAAe;IAYvB;;OAEG;IACH,OAAO,CAAC,aAAa;IA2BrB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAWzB;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAU5B;;OAEG;WACU,WAAW,IAAI,OAAO,CAAC;QAAE,SAAS,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAoB3E;;OAEG;IACH,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,iBAAiB,GAAG;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE;CA4BvF"}
|