qa360 1.0.4 → 1.1.1

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 (108) hide show
  1. package/dist/commands/history.js +1 -1
  2. package/dist/commands/pack.js +1 -1
  3. package/dist/commands/run.d.ts +1 -1
  4. package/dist/commands/run.d.ts.map +1 -1
  5. package/dist/commands/run.js +1 -1
  6. package/dist/commands/secrets.js +1 -1
  7. package/dist/commands/serve.js +1 -1
  8. package/dist/commands/verify.js +1 -1
  9. package/dist/core/adapters/gitleaks-secrets.d.ts +115 -0
  10. package/dist/core/adapters/gitleaks-secrets.d.ts.map +1 -0
  11. package/dist/core/adapters/gitleaks-secrets.js +410 -0
  12. package/dist/core/adapters/k6-perf.d.ts +86 -0
  13. package/dist/core/adapters/k6-perf.d.ts.map +1 -0
  14. package/dist/core/adapters/k6-perf.js +398 -0
  15. package/dist/core/adapters/osv-deps.d.ts +124 -0
  16. package/dist/core/adapters/osv-deps.d.ts.map +1 -0
  17. package/dist/core/adapters/osv-deps.js +372 -0
  18. package/dist/core/adapters/playwright-api.d.ts +82 -0
  19. package/dist/core/adapters/playwright-api.d.ts.map +1 -0
  20. package/dist/core/adapters/playwright-api.js +252 -0
  21. package/dist/core/adapters/playwright-ui.d.ts +115 -0
  22. package/dist/core/adapters/playwright-ui.d.ts.map +1 -0
  23. package/dist/core/adapters/playwright-ui.js +346 -0
  24. package/dist/core/adapters/semgrep-sast.d.ts +100 -0
  25. package/dist/core/adapters/semgrep-sast.d.ts.map +1 -0
  26. package/dist/core/adapters/semgrep-sast.js +322 -0
  27. package/dist/core/adapters/zap-dast.d.ts +134 -0
  28. package/dist/core/adapters/zap-dast.d.ts.map +1 -0
  29. package/dist/core/adapters/zap-dast.js +424 -0
  30. package/dist/core/hooks/compose.d.ts +62 -0
  31. package/dist/core/hooks/compose.d.ts.map +1 -0
  32. package/dist/core/hooks/compose.js +225 -0
  33. package/dist/core/hooks/runner.d.ts +69 -0
  34. package/dist/core/hooks/runner.d.ts.map +1 -0
  35. package/dist/core/hooks/runner.js +303 -0
  36. package/dist/core/index.d.ts +74 -0
  37. package/dist/core/index.d.ts.map +1 -0
  38. package/dist/core/index.js +39 -0
  39. package/dist/core/pack/migrator.d.ts +52 -0
  40. package/dist/core/pack/migrator.d.ts.map +1 -0
  41. package/dist/core/pack/migrator.js +304 -0
  42. package/dist/core/pack/validator.d.ts +43 -0
  43. package/dist/core/pack/validator.d.ts.map +1 -0
  44. package/dist/core/pack/validator.js +292 -0
  45. package/dist/core/proof/bundle.d.ts +138 -0
  46. package/dist/core/proof/bundle.d.ts.map +1 -0
  47. package/dist/core/proof/bundle.js +160 -0
  48. package/dist/core/proof/canonicalize.d.ts +48 -0
  49. package/dist/core/proof/canonicalize.d.ts.map +1 -0
  50. package/dist/core/proof/canonicalize.js +105 -0
  51. package/dist/core/proof/index.d.ts +14 -0
  52. package/dist/core/proof/index.d.ts.map +1 -0
  53. package/dist/core/proof/index.js +18 -0
  54. package/dist/core/proof/schema.d.ts +218 -0
  55. package/dist/core/proof/schema.d.ts.map +1 -0
  56. package/dist/core/proof/schema.js +263 -0
  57. package/dist/core/proof/signer.d.ts +112 -0
  58. package/dist/core/proof/signer.d.ts.map +1 -0
  59. package/dist/core/proof/signer.js +226 -0
  60. package/dist/core/proof/verifier.d.ts +98 -0
  61. package/dist/core/proof/verifier.d.ts.map +1 -0
  62. package/dist/core/proof/verifier.js +302 -0
  63. package/dist/core/runner/phase3-runner.d.ts +102 -0
  64. package/dist/core/runner/phase3-runner.d.ts.map +1 -0
  65. package/dist/core/runner/phase3-runner.js +471 -0
  66. package/dist/core/secrets/crypto.d.ts +76 -0
  67. package/dist/core/secrets/crypto.d.ts.map +1 -0
  68. package/dist/core/secrets/crypto.js +225 -0
  69. package/dist/core/secrets/manager.d.ts +77 -0
  70. package/dist/core/secrets/manager.d.ts.map +1 -0
  71. package/dist/core/secrets/manager.js +219 -0
  72. package/dist/core/security/redaction-patterns-extended.d.ts +28 -0
  73. package/dist/core/security/redaction-patterns-extended.d.ts.map +1 -0
  74. package/dist/core/security/redaction-patterns-extended.js +247 -0
  75. package/dist/core/security/redactor.d.ts +72 -0
  76. package/dist/core/security/redactor.d.ts.map +1 -0
  77. package/dist/core/security/redactor.js +279 -0
  78. package/dist/core/serve/diagnostics-collector.d.ts +33 -0
  79. package/dist/core/serve/diagnostics-collector.d.ts.map +1 -0
  80. package/dist/core/serve/diagnostics-collector.js +149 -0
  81. package/dist/core/serve/health-checker.d.ts +45 -0
  82. package/dist/core/serve/health-checker.d.ts.map +1 -0
  83. package/dist/core/serve/health-checker.js +219 -0
  84. package/dist/core/serve/index.d.ts +9 -0
  85. package/dist/core/serve/index.d.ts.map +1 -0
  86. package/dist/core/serve/index.js +8 -0
  87. package/dist/core/serve/metrics-collector.d.ts +25 -0
  88. package/dist/core/serve/metrics-collector.d.ts.map +1 -0
  89. package/dist/core/serve/metrics-collector.js +322 -0
  90. package/dist/core/serve/process-manager.d.ts +37 -0
  91. package/dist/core/serve/process-manager.d.ts.map +1 -0
  92. package/dist/core/serve/process-manager.js +213 -0
  93. package/dist/core/serve/server.d.ts +37 -0
  94. package/dist/core/serve/server.d.ts.map +1 -0
  95. package/dist/core/serve/server.js +191 -0
  96. package/dist/core/types/pack-v1.d.ts +162 -0
  97. package/dist/core/types/pack-v1.d.ts.map +1 -0
  98. package/dist/core/types/pack-v1.js +5 -0
  99. package/dist/core/types/trust-score.d.ts +70 -0
  100. package/dist/core/types/trust-score.d.ts.map +1 -0
  101. package/dist/core/types/trust-score.js +191 -0
  102. package/dist/core/vault/cas.d.ts +87 -0
  103. package/dist/core/vault/cas.d.ts.map +1 -0
  104. package/dist/core/vault/cas.js +255 -0
  105. package/dist/core/vault/index.d.ts +205 -0
  106. package/dist/core/vault/index.d.ts.map +1 -0
  107. package/dist/core/vault/index.js +631 -0
  108. package/package.json +13 -6
@@ -0,0 +1 @@
1
+ {"version":3,"file":"k6-perf.d.ts","sourceRoot":"","sources":["../../../src/core/adapters/k6-perf.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAGlD,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE;QACP,qBAAqB,EAAE,MAAM,CAAC;QAC9B,qBAAqB,EAAE,MAAM,CAAC;QAC9B,oBAAoB,EAAE,MAAM,CAAC;QAC7B,eAAe,EAAE,MAAM,CAAC;QACxB,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,UAAU,EAAE;QACV,CAAC,GAAG,EAAE,MAAM,GAAG;YACb,MAAM,EAAE,OAAO,CAAC;YAChB,KAAK,EAAE,MAAM,CAAC;YACd,SAAS,EAAE,MAAM,CAAC;SACnB,CAAC;KACH,CAAC;IACF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAmB;IACnC,OAAO,CAAC,UAAU,CAAS;gBAEf,UAAU,GAAE,MAAsB;IAK9C;;OAEG;IACG,WAAW,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;IAuB9D;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAsGxB;;OAEG;YACW,SAAS;IAqEvB;;OAEG;IACH,OAAO,CAAC,cAAc;IA0EtB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAsBxB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAwB3B;;OAEG;IACH,OAAO,CAAC,aAAa;IA0BrB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAWzB;;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,YAAY,GAAG;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE;CA0BlF"}
@@ -0,0 +1,398 @@
1
+ /**
2
+ * QA360 k6 Performance Adapter (Socle OOTB)
3
+ * Short performance tests with P95 calculation
4
+ */
5
+ import { spawn } from 'child_process';
6
+ import { writeFileSync, unlinkSync, existsSync } from 'fs';
7
+ import { join } from 'path';
8
+ import { SecurityRedactor } from '../security/redactor.js';
9
+ export class K6PerfAdapter {
10
+ redactor;
11
+ workingDir;
12
+ constructor(workingDir = process.cwd()) {
13
+ this.redactor = SecurityRedactor.forLogs();
14
+ this.workingDir = workingDir;
15
+ }
16
+ /**
17
+ * Execute k6 performance test
18
+ */
19
+ async runPerfTest(config) {
20
+ const scriptPath = join(this.workingDir, 'k6-test-temp.js');
21
+ try {
22
+ // Generate k6 script
23
+ const script = this.generateK6Script(config);
24
+ writeFileSync(scriptPath, script);
25
+ console.log(`⚡ Running k6 performance test (${config.duration || '30s'}, ${config.vus || 5} VUs)`);
26
+ // Execute k6
27
+ const result = await this.executeK6(scriptPath, config);
28
+ return result;
29
+ }
30
+ finally {
31
+ // Cleanup temp script
32
+ if (existsSync(scriptPath)) {
33
+ unlinkSync(scriptPath);
34
+ }
35
+ }
36
+ }
37
+ /**
38
+ * Generate k6 test script
39
+ */
40
+ generateK6Script(config) {
41
+ const duration = config.duration || '30s';
42
+ const vus = config.vus || 5;
43
+ const p95Budget = config.budgets?.perf_p95_ms || 2000;
44
+ const scenarios = config.scenarios || {
45
+ load_test: {
46
+ executor: 'constant-vus',
47
+ vus: vus,
48
+ duration: duration
49
+ }
50
+ };
51
+ return `
52
+ import http from 'k6/http';
53
+ import { check, sleep } from 'k6';
54
+ import { Rate } from 'k6/metrics';
55
+
56
+ // Custom metrics
57
+ export let errorRate = new Rate('errors');
58
+
59
+ export let options = {
60
+ scenarios: ${JSON.stringify(scenarios, null, 2)},
61
+ thresholds: {
62
+ 'http_req_duration': ['p(95)<${p95Budget}'],
63
+ 'http_req_failed': ['rate<0.1'], // Less than 10% errors
64
+ 'errors': ['rate<0.1']
65
+ }
66
+ };
67
+
68
+ export default function() {
69
+ const baseUrl = '${config.baseUrl}';
70
+
71
+ // Main request
72
+ const response = http.get(baseUrl, {
73
+ headers: {
74
+ 'User-Agent': 'QA360-k6-Perf/1.0'
75
+ }
76
+ });
77
+
78
+ // Check response
79
+ const success = check(response, {
80
+ 'status is 200-299': (r) => r.status >= 200 && r.status < 300,
81
+ 'response time < ${p95Budget}ms': (r) => r.timings.duration < ${p95Budget}
82
+ });
83
+
84
+ errorRate.add(!success);
85
+
86
+ // Small delay between requests
87
+ sleep(0.1);
88
+ }
89
+
90
+ export function handleSummary(data) {
91
+ return {
92
+ 'stdout': textSummary(data, { indent: ' ', enableColors: false }),
93
+ '/tmp/k6-summary.json': JSON.stringify(data, null, 2)
94
+ };
95
+ }
96
+
97
+ function textSummary(data, options = {}) {
98
+ const indent = options.indent || '';
99
+ const colors = options.enableColors !== false;
100
+
101
+ let output = '';
102
+
103
+ // Test run info
104
+ output += indent + 'Test Run Summary\\n';
105
+ output += indent + '================\\n\\n';
106
+
107
+ // Scenarios
108
+ if (data.root_group && data.root_group.groups) {
109
+ for (const [name, group] of Object.entries(data.root_group.groups)) {
110
+ output += indent + \`Scenario: \${name}\\n\`;
111
+ }
112
+ }
113
+
114
+ // Metrics
115
+ output += indent + 'Metrics:\\n';
116
+ for (const [name, metric] of Object.entries(data.metrics)) {
117
+ if (metric.type === 'trend') {
118
+ output += indent + \` \${name}: avg=\${metric.values.avg.toFixed(2)}ms p95=\${metric.values['p(95)'].toFixed(2)}ms\\n\`;
119
+ } else if (metric.type === 'rate') {
120
+ output += indent + \` \${name}: \${(metric.values.rate * 100).toFixed(2)}%\\n\`;
121
+ } else if (metric.type === 'counter') {
122
+ output += indent + \` \${name}: \${metric.values.count}\\n\`;
123
+ }
124
+ }
125
+
126
+ // Thresholds
127
+ if (data.thresholds) {
128
+ output += indent + '\\nThresholds:\\n';
129
+ for (const [name, threshold] of Object.entries(data.thresholds)) {
130
+ const status = threshold.ok ? '✓' : '✗';
131
+ output += indent + \` \${status} \${name}\\n\`;
132
+ }
133
+ }
134
+
135
+ return output;
136
+ }
137
+ `;
138
+ }
139
+ /**
140
+ * Execute k6 command
141
+ */
142
+ async executeK6(scriptPath, config) {
143
+ return new Promise((resolve) => {
144
+ let output = '';
145
+ let error = '';
146
+ const args = [
147
+ 'run',
148
+ '--out', 'json=/tmp/k6-results.json',
149
+ '--summary-export', '/tmp/k6-summary.json',
150
+ scriptPath
151
+ ];
152
+ const child = spawn('k6', args, {
153
+ cwd: this.workingDir,
154
+ stdio: ['ignore', 'pipe', 'pipe']
155
+ });
156
+ const timeout = setTimeout(() => {
157
+ child.kill('SIGKILL');
158
+ resolve({
159
+ success: false,
160
+ metrics: this.getDefaultMetrics(),
161
+ thresholds: {},
162
+ error: `k6 test timed out after ${config.timeout || 120000}ms`
163
+ });
164
+ }, config.timeout || 120000);
165
+ if (child.stdout) {
166
+ child.stdout.on('data', (data) => {
167
+ output += data.toString();
168
+ });
169
+ }
170
+ if (child.stderr) {
171
+ child.stderr.on('data', (data) => {
172
+ error += data.toString();
173
+ });
174
+ }
175
+ child.on('close', (code) => {
176
+ clearTimeout(timeout);
177
+ if (code === 0) {
178
+ // Parse results
179
+ const result = this.parseK6Results(output, config);
180
+ resolve(result);
181
+ }
182
+ else {
183
+ resolve({
184
+ success: false,
185
+ metrics: this.getDefaultMetrics(),
186
+ thresholds: {},
187
+ error: this.redactor.redact(error || `k6 exited with code ${code}`),
188
+ rawOutput: this.redactor.redact(output)
189
+ });
190
+ }
191
+ });
192
+ child.on('error', (err) => {
193
+ clearTimeout(timeout);
194
+ resolve({
195
+ success: false,
196
+ metrics: this.getDefaultMetrics(),
197
+ thresholds: {},
198
+ error: `Failed to start k6: ${err.message}. Make sure k6 is installed.`
199
+ });
200
+ });
201
+ });
202
+ }
203
+ /**
204
+ * Parse k6 results from output
205
+ */
206
+ parseK6Results(output, config) {
207
+ try {
208
+ // Try to read JSON summary if available
209
+ const summaryPath = '/tmp/k6-summary.json';
210
+ let summaryData = null;
211
+ try {
212
+ if (existsSync(summaryPath)) {
213
+ const summaryContent = require('fs').readFileSync(summaryPath, 'utf8');
214
+ summaryData = JSON.parse(summaryContent);
215
+ unlinkSync(summaryPath); // Cleanup
216
+ }
217
+ }
218
+ catch {
219
+ // Continue with text parsing
220
+ }
221
+ let metrics = this.getDefaultMetrics();
222
+ let thresholds = {};
223
+ if (summaryData && summaryData.metrics) {
224
+ // Parse from JSON summary
225
+ const m = summaryData.metrics;
226
+ metrics = {
227
+ http_req_duration_p95: m.http_req_duration?.values?.['p(95)'] || 0,
228
+ http_req_duration_avg: m.http_req_duration?.values?.avg || 0,
229
+ http_req_failed_rate: (m.http_req_failed?.values?.rate || 0) * 100,
230
+ http_reqs_total: m.http_reqs?.values?.count || 0,
231
+ vus_max: m.vus_max?.values?.max || config.vus || 5,
232
+ iterations: m.iterations?.values?.count || 0
233
+ };
234
+ // Parse thresholds
235
+ if (summaryData.thresholds) {
236
+ for (const [name, threshold] of Object.entries(summaryData.thresholds)) {
237
+ thresholds[name] = {
238
+ passed: threshold.ok || false,
239
+ value: 0, // Would need more parsing
240
+ threshold: name
241
+ };
242
+ }
243
+ }
244
+ }
245
+ else {
246
+ // Fallback: parse from text output
247
+ metrics = this.parseTextMetrics(output);
248
+ thresholds = this.parseTextThresholds(output);
249
+ }
250
+ // Check if test passed based on budgets
251
+ const p95Budget = config.budgets?.perf_p95_ms || 2000;
252
+ const success = metrics.http_req_duration_p95 <= p95Budget &&
253
+ metrics.http_req_failed_rate < 10;
254
+ const junit = this.generateJUnit(metrics, success, config);
255
+ return {
256
+ success,
257
+ metrics,
258
+ thresholds,
259
+ rawOutput: this.redactor.redact(output),
260
+ junit
261
+ };
262
+ }
263
+ catch (error) {
264
+ return {
265
+ success: false,
266
+ metrics: this.getDefaultMetrics(),
267
+ thresholds: {},
268
+ error: `Failed to parse k6 results: ${error}`,
269
+ rawOutput: this.redactor.redact(output)
270
+ };
271
+ }
272
+ }
273
+ /**
274
+ * Parse metrics from text output
275
+ */
276
+ parseTextMetrics(output) {
277
+ const metrics = this.getDefaultMetrics();
278
+ // Parse common patterns from k6 output
279
+ const patterns = {
280
+ http_req_duration_p95: /http_req_duration.*p\(95\)=([0-9.]+)ms/,
281
+ http_req_duration_avg: /http_req_duration.*avg=([0-9.]+)ms/,
282
+ http_req_failed_rate: /http_req_failed[.\s]*:\s*([0-9.]+)%/,
283
+ http_reqs_total: /http_reqs[.\s]*:\s*([0-9]+)/,
284
+ iterations: /iterations[.\s]*:\s*([0-9]+)/
285
+ };
286
+ for (const [key, pattern] of Object.entries(patterns)) {
287
+ const match = output.match(pattern);
288
+ if (match) {
289
+ metrics[key] = parseFloat(match[1]);
290
+ }
291
+ }
292
+ return metrics;
293
+ }
294
+ /**
295
+ * Parse thresholds from text output
296
+ */
297
+ parseTextThresholds(output) {
298
+ const thresholds = {};
299
+ // Look for threshold results (✓ or ✗)
300
+ const thresholdLines = output.split('\n').filter(line => line.includes('✓') || line.includes('✗') || line.includes('PASS') || line.includes('FAIL'));
301
+ for (const line of thresholdLines) {
302
+ const passed = line.includes('✓') || line.includes('PASS');
303
+ const name = line.replace(/[✓✗]/g, '').trim();
304
+ if (name) {
305
+ thresholds[name] = {
306
+ passed,
307
+ value: 0,
308
+ threshold: name
309
+ };
310
+ }
311
+ }
312
+ return thresholds;
313
+ }
314
+ /**
315
+ * Generate JUnit XML
316
+ */
317
+ generateJUnit(metrics, success, config) {
318
+ const timestamp = new Date().toISOString();
319
+ const duration = (metrics.http_req_duration_avg / 1000).toFixed(3);
320
+ let junit = `<?xml version="1.0" encoding="UTF-8"?>
321
+ <testsuite name="k6 Performance Test" tests="1" failures="${success ? 0 : 1}" time="${duration}" timestamp="${timestamp}">
322
+ <testcase name="Performance Test: ${config.baseUrl}" time="${duration}">
323
+ `;
324
+ if (!success) {
325
+ const p95Budget = config.budgets?.perf_p95_ms || 2000;
326
+ junit += ` <failure message="Performance budget exceeded">
327
+ P95 response time: ${metrics.http_req_duration_p95}ms (budget: ${p95Budget}ms)
328
+ Average response time: ${metrics.http_req_duration_avg}ms
329
+ Failed requests: ${metrics.http_req_failed_rate}%
330
+ Total requests: ${metrics.http_reqs_total}
331
+ </failure>
332
+ `;
333
+ }
334
+ junit += ` </testcase>
335
+ </testsuite>`;
336
+ return junit;
337
+ }
338
+ /**
339
+ * Get default metrics structure
340
+ */
341
+ getDefaultMetrics() {
342
+ return {
343
+ http_req_duration_p95: 0,
344
+ http_req_duration_avg: 0,
345
+ http_req_failed_rate: 0,
346
+ http_reqs_total: 0,
347
+ vus_max: 0,
348
+ iterations: 0
349
+ };
350
+ }
351
+ /**
352
+ * Check if k6 is available
353
+ */
354
+ static async isAvailable() {
355
+ return new Promise((resolve) => {
356
+ const child = spawn('k6', ['version'], { stdio: 'pipe' });
357
+ child.on('close', (code) => {
358
+ resolve({
359
+ available: code === 0,
360
+ error: code !== 0 ? 'k6 not found. Install from https://k6.io/docs/get-started/installation/' : undefined
361
+ });
362
+ });
363
+ child.on('error', () => {
364
+ resolve({
365
+ available: false,
366
+ error: 'k6 not found. Install from https://k6.io/docs/get-started/installation/'
367
+ });
368
+ });
369
+ });
370
+ }
371
+ /**
372
+ * Validate performance test configuration
373
+ */
374
+ static validateConfig(config) {
375
+ const errors = [];
376
+ if (!config.baseUrl) {
377
+ errors.push('Performance test requires baseUrl');
378
+ }
379
+ else {
380
+ try {
381
+ new URL(config.baseUrl);
382
+ }
383
+ catch {
384
+ errors.push('Performance test baseUrl must be a valid URL');
385
+ }
386
+ }
387
+ if (config.vus !== undefined && (config.vus <= 0 || config.vus > 1000)) {
388
+ errors.push('VUs must be between 1 and 1000');
389
+ }
390
+ if (config.duration && !/^\d+[smh]$/.test(config.duration)) {
391
+ errors.push('Duration must be in format like "30s", "5m", "1h"');
392
+ }
393
+ return {
394
+ valid: errors.length === 0,
395
+ errors
396
+ };
397
+ }
398
+ }
@@ -0,0 +1,124 @@
1
+ /**
2
+ * QA360 OSV Dependencies Adapter (Sécurité Réelle)
3
+ * Scan vulnerabilities in package-lock.json / pnpm-lock.yaml
4
+ */
5
+ import { PackSecurity } from '../types/pack-v1.js';
6
+ export interface OsvScanConfig {
7
+ workingDir: string;
8
+ security?: PackSecurity;
9
+ timeout?: number;
10
+ lockFiles?: string[];
11
+ }
12
+ export interface OsvVulnerability {
13
+ id: string;
14
+ summary: string;
15
+ severity: 'CRITICAL' | 'HIGH' | 'MEDIUM' | 'LOW' | 'UNKNOWN';
16
+ package: {
17
+ name: string;
18
+ version: string;
19
+ ecosystem: string;
20
+ };
21
+ affected: Array<{
22
+ package: {
23
+ name: string;
24
+ ecosystem: string;
25
+ };
26
+ ranges: Array<{
27
+ type: string;
28
+ events: Array<{
29
+ introduced?: string;
30
+ fixed?: string;
31
+ }>;
32
+ }>;
33
+ }>;
34
+ references: Array<{
35
+ type: string;
36
+ url: string;
37
+ }>;
38
+ }
39
+ export interface OsvScanResult {
40
+ success: boolean;
41
+ vulnerabilities: OsvVulnerability[];
42
+ summary: {
43
+ total: number;
44
+ critical: number;
45
+ high: number;
46
+ medium: number;
47
+ low: number;
48
+ unknown: number;
49
+ };
50
+ budgetCheck: {
51
+ critical_passed: boolean;
52
+ high_passed: boolean;
53
+ medium_passed: boolean;
54
+ };
55
+ scannedFiles: string[];
56
+ error?: string;
57
+ rawOutput?: string;
58
+ junit?: string;
59
+ errorCode?: string;
60
+ }
61
+ export declare class OsvDepsAdapter {
62
+ private redactor;
63
+ private workingDir;
64
+ constructor(workingDir?: string);
65
+ /**
66
+ * Execute OSV dependency scan
67
+ */
68
+ runDependencyScan(config: OsvScanConfig): Promise<OsvScanResult>;
69
+ /**
70
+ * Find lock files in working directory
71
+ */
72
+ private findLockFiles;
73
+ /**
74
+ * Execute OSV scanner on lock files
75
+ */
76
+ private executeOsvScan;
77
+ /**
78
+ * Parse OSV scanner results
79
+ */
80
+ private parseOsvResults;
81
+ /**
82
+ * Fallback API-based scanning when osv-scanner not available
83
+ */
84
+ private fallbackApiScan;
85
+ /**
86
+ * Map severity from various formats to standard levels
87
+ */
88
+ private mapSeverity;
89
+ /**
90
+ * Calculate vulnerability summary
91
+ */
92
+ private calculateSummary;
93
+ /**
94
+ * Generate budget check based on security config
95
+ */
96
+ private generateBudgetCheck;
97
+ /**
98
+ * Get empty summary structure
99
+ */
100
+ private getEmptySummary;
101
+ /**
102
+ * Get default budget check structure
103
+ */
104
+ private getDefaultBudgetCheck;
105
+ /**
106
+ * Generate JUnit XML report
107
+ */
108
+ private generateJUnit;
109
+ /**
110
+ * Validate OSV scan configuration
111
+ */
112
+ static validateConfig(config: OsvScanConfig): {
113
+ valid: boolean;
114
+ errors: string[];
115
+ };
116
+ /**
117
+ * Check if OSV scanner is available
118
+ */
119
+ static isAvailable(): Promise<{
120
+ available: boolean;
121
+ error?: string;
122
+ }>;
123
+ }
124
+ //# sourceMappingURL=osv-deps.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"osv-deps.d.ts","sourceRoot":"","sources":["../../../src/core/adapters/osv-deps.ts"],"names":[],"mappings":"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"}