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.
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 +12 -6
@@ -0,0 +1,471 @@
1
+ /**
2
+ * QA360 Phase 3 Runner
3
+ * Orchestrates hooks, adapters, and proof generation
4
+ */
5
+ import { existsSync, writeFileSync, mkdirSync } from 'fs';
6
+ import { join } from 'path';
7
+ import { createHash } from 'crypto';
8
+ import chalk from 'chalk';
9
+ import { HooksRunner } from '../hooks/runner.js';
10
+ import { PlaywrightApiAdapter } from '../adapters/playwright-api.js';
11
+ import { PlaywrightUiAdapter } from '../adapters/playwright-ui.js';
12
+ import { K6PerfAdapter } from '../adapters/k6-perf.js';
13
+ import { SemgrepSastAdapter } from '../adapters/semgrep-sast.js';
14
+ import { SecurityRedactor } from '../security/redactor.js';
15
+ import { initializeKeys, sign } from '../proof/signer.js';
16
+ import { canonicalize } from '../proof/canonicalize.js';
17
+ import { EvidenceVault } from '../vault/index.js';
18
+ export class Phase3Runner {
19
+ workingDir;
20
+ pack;
21
+ outputDir;
22
+ redactor;
23
+ hooksRunner;
24
+ keyPair;
25
+ vault;
26
+ constructor(options) {
27
+ this.workingDir = options.workingDir;
28
+ this.pack = options.pack;
29
+ this.outputDir = options.outputDir || join(this.workingDir, '.qa360', 'runs');
30
+ this.redactor = SecurityRedactor.forLogs();
31
+ this.hooksRunner = new HooksRunner({
32
+ workingDir: this.workingDir,
33
+ hooks: this.pack.hooks || {},
34
+ execution: this.pack.execution,
35
+ redactor: this.redactor
36
+ });
37
+ }
38
+ /**
39
+ * Execute complete Phase 3 workflow
40
+ */
41
+ async run() {
42
+ const startTime = Date.now();
43
+ console.log(chalk.bold.blue(`\n🚀 QA360 Phase 3 Runner - ${this.pack.name}`));
44
+ console.log(chalk.gray(`Gates: ${this.pack.gates.join(', ')}`));
45
+ try {
46
+ // Ensure output directory exists
47
+ this.ensureOutputDir();
48
+ // Initialize cryptographic keys
49
+ console.log(chalk.blue('\n🔑 Initializing Ed25519 keys...'));
50
+ this.keyPair = await initializeKeys();
51
+ console.log(chalk.green(' ✅ Keys ready'));
52
+ // Initialize Evidence Vault
53
+ console.log(chalk.blue('\n🗄️ Initializing Evidence Vault...'));
54
+ const vaultDir = join(this.workingDir, '.qa360');
55
+ this.vault = await EvidenceVault.open(vaultDir);
56
+ console.log(chalk.green(' ✅ Vault ready'));
57
+ // Execute beforeAll hooks
58
+ console.log(chalk.blue('\n🔗 Phase 1: Setup Hooks'));
59
+ const beforeAllResults = await this.hooksRunner.executeHooks('beforeAll');
60
+ // Check if setup failed and should stop
61
+ const setupFailed = beforeAllResults.some(r => !r.success);
62
+ if (setupFailed && this.pack.execution?.on_failure === 'stop') {
63
+ throw new Error('Setup hooks failed, stopping execution');
64
+ }
65
+ // Execute gates
66
+ console.log(chalk.blue('\n🎯 Phase 2: Quality Gates'));
67
+ const gateResults = [];
68
+ for (const gate of this.pack.gates) {
69
+ const gateResult = await this.executeGate(gate);
70
+ gateResults.push(gateResult);
71
+ // Check if gate failed and should stop
72
+ if (!gateResult.success && this.pack.execution?.on_failure === 'stop') {
73
+ console.log(chalk.yellow(`🛑 Gate ${gate} failed, stopping execution`));
74
+ break;
75
+ }
76
+ }
77
+ // Execute afterAll hooks
78
+ console.log(chalk.blue('\n🔗 Phase 3: Cleanup Hooks'));
79
+ const afterAllResults = await this.hooksRunner.executeHooks('afterAll');
80
+ // Calculate results
81
+ const duration = Date.now() - startTime;
82
+ const summary = this.calculateSummary(gateResults);
83
+ const success = summary.failed === 0;
84
+ // Generate proof
85
+ console.log(chalk.blue('\n📋 Phase 4: Proof Generation'));
86
+ const proofPath = await this.generateProof({
87
+ success,
88
+ pack: this.pack,
89
+ duration,
90
+ gates: gateResults,
91
+ hooks: {
92
+ beforeAll: beforeAllResults,
93
+ beforeEach: [],
94
+ afterEach: [],
95
+ afterAll: afterAllResults
96
+ },
97
+ summary
98
+ });
99
+ // Save to Evidence Vault
100
+ console.log(chalk.blue('\n💾 Phase 5: Evidence Storage'));
101
+ const runId = proofPath.split('/').pop()?.replace('-proof.json', '') || 'unknown';
102
+ await this.saveToVault(runId, {
103
+ success,
104
+ pack: this.pack,
105
+ duration,
106
+ gates: gateResults,
107
+ hooks: {
108
+ beforeAll: beforeAllResults,
109
+ beforeEach: [],
110
+ afterEach: [],
111
+ afterAll: afterAllResults
112
+ },
113
+ summary,
114
+ proofPath
115
+ }, proofPath);
116
+ // Final summary
117
+ console.log(chalk.blue('\n📊 Execution Summary'));
118
+ console.log(` Duration: ${duration}ms`);
119
+ console.log(` Gates: ${summary.passed}/${summary.total} passed`);
120
+ console.log(` Trust Score: ${summary.trustScore}%`);
121
+ console.log(` Proof: ${proofPath}`);
122
+ if (success) {
123
+ console.log(chalk.green('\n✅ All quality gates passed!'));
124
+ }
125
+ else {
126
+ console.log(chalk.red(`\n❌ ${summary.failed} quality gate(s) failed`));
127
+ }
128
+ return {
129
+ success,
130
+ pack: this.pack,
131
+ duration,
132
+ gates: gateResults,
133
+ hooks: {
134
+ beforeAll: beforeAllResults,
135
+ beforeEach: [],
136
+ afterEach: [],
137
+ afterAll: afterAllResults
138
+ },
139
+ summary,
140
+ proofPath
141
+ };
142
+ }
143
+ catch (error) {
144
+ const duration = Date.now() - startTime;
145
+ // Ensure cleanup even on error
146
+ try {
147
+ await this.hooksRunner.executeHooks('afterAll');
148
+ }
149
+ catch {
150
+ // Ignore cleanup errors
151
+ }
152
+ return {
153
+ success: false,
154
+ pack: this.pack,
155
+ duration,
156
+ gates: [],
157
+ hooks: { beforeAll: [], beforeEach: [], afterEach: [], afterAll: [] },
158
+ summary: { total: 0, passed: 0, failed: 0, trustScore: 0 },
159
+ error: this.redactor.redact(error instanceof Error ? error.message : 'Unknown error')
160
+ };
161
+ }
162
+ }
163
+ /**
164
+ * Execute a single quality gate
165
+ */
166
+ async executeGate(gate) {
167
+ const startTime = Date.now();
168
+ console.log(chalk.cyan(`\n 🎯 Gate: ${gate}`));
169
+ try {
170
+ let result;
171
+ let adapter;
172
+ switch (gate) {
173
+ case 'api_smoke':
174
+ adapter = 'playwright-api';
175
+ result = await this.runApiSmokeGate();
176
+ break;
177
+ case 'ui':
178
+ adapter = 'playwright-ui';
179
+ result = await this.runUiGate();
180
+ break;
181
+ case 'a11y':
182
+ adapter = 'playwright-ui';
183
+ result = await this.runA11yGate();
184
+ break;
185
+ case 'perf':
186
+ adapter = 'k6';
187
+ result = await this.runPerfGate();
188
+ break;
189
+ case 'sast':
190
+ adapter = 'semgrep';
191
+ result = await this.runSastGate();
192
+ break;
193
+ case 'dast':
194
+ adapter = 'zap';
195
+ result = await this.runDastGate();
196
+ break;
197
+ default:
198
+ throw new Error(`Unknown gate: ${gate}`);
199
+ }
200
+ const duration = Date.now() - startTime;
201
+ if (result.success) {
202
+ console.log(chalk.green(` ✅ ${gate} passed (${duration}ms)`));
203
+ }
204
+ else {
205
+ console.log(chalk.red(` ❌ ${gate} failed (${duration}ms)`));
206
+ if (result.error) {
207
+ console.log(chalk.red(` 🔍 ${result.error}`));
208
+ }
209
+ }
210
+ return {
211
+ gate,
212
+ success: result.success,
213
+ duration,
214
+ adapter,
215
+ results: result,
216
+ junit: result.junit,
217
+ error: result.error
218
+ };
219
+ }
220
+ catch (error) {
221
+ const duration = Date.now() - startTime;
222
+ const errorMessage = this.redactor.redact(error instanceof Error ? error.message : 'Unknown error');
223
+ console.log(chalk.red(` 💥 ${gate} crashed (${duration}ms): ${errorMessage}`));
224
+ return {
225
+ gate,
226
+ success: false,
227
+ duration,
228
+ adapter: 'unknown',
229
+ results: null,
230
+ error: errorMessage
231
+ };
232
+ }
233
+ }
234
+ /**
235
+ * Run API smoke gate
236
+ */
237
+ async runApiSmokeGate() {
238
+ if (!this.pack.targets?.api) {
239
+ throw new Error('API smoke gate requires targets.api configuration');
240
+ }
241
+ const adapter = new PlaywrightApiAdapter();
242
+ return await adapter.runSmokeTests({
243
+ target: this.pack.targets.api,
244
+ budgets: this.pack.budgets,
245
+ timeout: this.pack.execution?.timeout || 10000,
246
+ retries: this.pack.execution?.max_retries || 1
247
+ });
248
+ }
249
+ /**
250
+ * Run UI gate (includes basic accessibility)
251
+ */
252
+ async runUiGate() {
253
+ if (!this.pack.targets?.web) {
254
+ throw new Error('UI gate requires targets.web configuration');
255
+ }
256
+ const adapter = new PlaywrightUiAdapter();
257
+ return await adapter.runSmokeTests({
258
+ target: this.pack.targets.web,
259
+ budgets: this.pack.budgets,
260
+ timeout: this.pack.execution?.timeout || 30000
261
+ });
262
+ }
263
+ /**
264
+ * Run A11y gate (focused accessibility testing)
265
+ */
266
+ async runA11yGate() {
267
+ // Same as UI gate but focused on accessibility
268
+ return await this.runUiGate();
269
+ }
270
+ /**
271
+ * Run performance gate
272
+ */
273
+ async runPerfGate() {
274
+ const baseUrl = this.pack.targets?.web?.baseUrl || this.pack.targets?.api?.baseUrl;
275
+ if (!baseUrl) {
276
+ throw new Error('Performance gate requires web or api target');
277
+ }
278
+ const adapter = new K6PerfAdapter(this.workingDir);
279
+ return await adapter.runPerfTest({
280
+ baseUrl,
281
+ budgets: this.pack.budgets,
282
+ duration: '30s',
283
+ vus: 5,
284
+ timeout: 120000
285
+ });
286
+ }
287
+ /**
288
+ * Run SAST gate
289
+ */
290
+ async runSastGate() {
291
+ const adapter = new SemgrepSastAdapter();
292
+ return await adapter.runSastScan({
293
+ workingDir: this.workingDir,
294
+ security: this.pack.security,
295
+ rules: ['auto'],
296
+ paths: ['src/', 'lib/', '.'],
297
+ timeout: 120000
298
+ });
299
+ }
300
+ /**
301
+ * Run DAST gate (mock implementation)
302
+ */
303
+ async runDastGate() {
304
+ // Mock DAST implementation for Phase 3
305
+ console.log(chalk.yellow(' ⚠️ DAST gate: Mock implementation (ZAP integration in Phase 4)'));
306
+ return {
307
+ success: true,
308
+ findings: [],
309
+ summary: { total: 0, high: 0, medium: 0, low: 0 },
310
+ junit: `<?xml version="1.0" encoding="UTF-8"?>
311
+ <testsuite name="DAST Mock" tests="1" failures="0" time="0">
312
+ <testcase name="Mock DAST Scan" time="0"></testcase>
313
+ </testsuite>`
314
+ };
315
+ }
316
+ /**
317
+ * Calculate execution summary
318
+ */
319
+ calculateSummary(gateResults) {
320
+ const total = gateResults.length;
321
+ const passed = gateResults.filter(g => g.success).length;
322
+ const failed = total - passed;
323
+ // Calculate trust score (weighted by gate importance)
324
+ const gateWeights = {
325
+ 'api_smoke': 20,
326
+ 'ui': 15,
327
+ 'perf': 15,
328
+ 'sast': 20,
329
+ 'dast': 20,
330
+ 'a11y': 10
331
+ };
332
+ let totalWeight = 0;
333
+ let passedWeight = 0;
334
+ for (const gate of gateResults) {
335
+ const weight = gateWeights[gate.gate] || 10;
336
+ totalWeight += weight;
337
+ if (gate.success) {
338
+ passedWeight += weight;
339
+ }
340
+ }
341
+ const trustScore = totalWeight > 0 ? Math.round((passedWeight / totalWeight) * 100) : 0;
342
+ return { total, passed, failed, trustScore };
343
+ }
344
+ /**
345
+ * Generate cryptographically signed proof document
346
+ */
347
+ async generateProof(result) {
348
+ const timestamp = new Date().toISOString();
349
+ const runId = `run-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
350
+ // Build proof payload (without signature)
351
+ const proofPayload = {
352
+ version: '3.0.0',
353
+ runId,
354
+ timestamp,
355
+ pack: {
356
+ name: result.pack.name,
357
+ version: result.pack.version,
358
+ gates: result.pack.gates
359
+ },
360
+ execution: {
361
+ duration: result.duration,
362
+ success: result.success,
363
+ trustScore: result.summary.trustScore
364
+ },
365
+ gates: result.gates.map(g => ({
366
+ gate: g.gate,
367
+ adapter: g.adapter,
368
+ success: g.success,
369
+ duration: g.duration,
370
+ error: g.error
371
+ })),
372
+ hooks: {
373
+ beforeAll: result.hooks.beforeAll.length,
374
+ afterAll: result.hooks.afterAll.length
375
+ }
376
+ };
377
+ // Canonicalize the payload for signing
378
+ const canonicalPayload = canonicalize(proofPayload);
379
+ // Sign with Ed25519
380
+ let signatureValue;
381
+ let algorithm;
382
+ let publicKeyB64;
383
+ if (this.keyPair) {
384
+ signatureValue = sign(canonicalPayload, this.keyPair.secretKey);
385
+ algorithm = 'ed25519';
386
+ publicKeyB64 = Buffer.from(this.keyPair.publicKey).toString('base64');
387
+ console.log(chalk.green(' 🔏 Proof signed with Ed25519'));
388
+ }
389
+ else {
390
+ signatureValue = `unsigned-${runId}`;
391
+ algorithm = 'none';
392
+ publicKeyB64 = '';
393
+ console.log(chalk.yellow(' ⚠️ Proof unsigned (no keys available)'));
394
+ }
395
+ // Build complete proof with signature
396
+ const proof = {
397
+ ...proofPayload,
398
+ signature: {
399
+ algorithm,
400
+ publicKey: publicKeyB64,
401
+ value: signatureValue,
402
+ timestamp
403
+ }
404
+ };
405
+ // Save proof
406
+ const proofPath = join(this.outputDir, `${runId}-proof.json`);
407
+ writeFileSync(proofPath, JSON.stringify(proof, null, 2));
408
+ return proofPath;
409
+ }
410
+ /**
411
+ * Save run results to Evidence Vault
412
+ */
413
+ async saveToVault(runId, result, proofPath) {
414
+ if (!this.vault) {
415
+ console.log(chalk.yellow(' ⚠️ Vault not initialized, skipping storage'));
416
+ return;
417
+ }
418
+ try {
419
+ // Begin run in vault (returns actual runId used)
420
+ const { runId: vaultRunId } = await this.vault.beginRun({
421
+ pack_path: 'test-pack.yaml',
422
+ pack_hash: this.hashPack(result.pack)
423
+ });
424
+ // Finish run with final status
425
+ await this.vault.finishRun(vaultRunId, {
426
+ status: result.success ? 'passed' : 'failed',
427
+ trust_score: result.summary.trustScore,
428
+ signature: this.keyPair ? 'ed25519-signed' : undefined
429
+ });
430
+ // Record gate executions
431
+ for (const gate of result.gates) {
432
+ await this.vault.recordGate(runId, {
433
+ name: gate.gate,
434
+ status: gate.success ? 'passed' : 'failed',
435
+ duration_ms: gate.duration,
436
+ metrics_json: JSON.stringify(gate.results?.summary || {})
437
+ });
438
+ // Record finding if gate has error
439
+ if (gate.error) {
440
+ await this.vault.recordFinding(runId, {
441
+ gate: gate.gate,
442
+ severity: 'high',
443
+ rule: 'gate-failure',
444
+ message: gate.error
445
+ });
446
+ }
447
+ }
448
+ console.log(chalk.green(' 💾 Run saved to Evidence Vault'));
449
+ }
450
+ catch (error) {
451
+ console.log(chalk.yellow(` ⚠️ Failed to save to vault: ${error}`));
452
+ }
453
+ }
454
+ /**
455
+ * Generate hash of pack configuration
456
+ */
457
+ hashPack(pack) {
458
+ return createHash('sha256')
459
+ .update(JSON.stringify(pack))
460
+ .digest('hex')
461
+ .substring(0, 16);
462
+ }
463
+ /**
464
+ * Ensure output directory exists
465
+ */
466
+ ensureOutputDir() {
467
+ if (!existsSync(this.outputDir)) {
468
+ mkdirSync(this.outputDir, { recursive: true });
469
+ }
470
+ }
471
+ }
@@ -0,0 +1,76 @@
1
+ /**
2
+ * QA360 Secrets Cryptography
3
+ * AES-256-GCM encryption with PBKDF2 key derivation
4
+ */
5
+ export interface EncryptedData {
6
+ data: string;
7
+ iv: string;
8
+ salt: string;
9
+ tag: string;
10
+ algorithm: 'aes-256-gcm';
11
+ iterations: number;
12
+ }
13
+ export interface SecretEntry {
14
+ name: string;
15
+ value: string;
16
+ createdAt: string;
17
+ updatedAt: string;
18
+ }
19
+ export interface SecretsStore {
20
+ version: string;
21
+ encrypted: EncryptedData;
22
+ checksum: string;
23
+ }
24
+ export declare class SecretsCrypto {
25
+ private static readonly ALGORITHM;
26
+ private static readonly KEY_LENGTH;
27
+ private static readonly IV_LENGTH;
28
+ private static readonly SALT_LENGTH;
29
+ private static readonly TAG_LENGTH;
30
+ private static readonly ITERATIONS;
31
+ /**
32
+ * Encrypt secrets with password-derived key
33
+ */
34
+ static encrypt(secrets: Record<string, SecretEntry>, password: string): SecretsStore;
35
+ /**
36
+ * Decrypt secrets with password
37
+ */
38
+ static decrypt(store: SecretsStore, password: string): Record<string, SecretEntry>;
39
+ /**
40
+ * Generate a secure random password
41
+ */
42
+ static generatePassword(length?: number): string;
43
+ /**
44
+ * Derive password from system keychain or environment
45
+ */
46
+ static deriveSystemPassword(): Promise<string>;
47
+ /**
48
+ * Get password from macOS Keychain
49
+ */
50
+ private static getMacOSKeychainPassword;
51
+ /**
52
+ * Get password from Linux keyring (using secret-tool)
53
+ */
54
+ private static getLinuxKeychainPassword;
55
+ /**
56
+ * Get password from Windows Credential Manager
57
+ */
58
+ private static getWindowsCredentialPassword;
59
+ /**
60
+ * Generate machine-specific password as fallback
61
+ */
62
+ private static generateMachinePassword;
63
+ /**
64
+ * Calculate checksum for integrity verification
65
+ */
66
+ private static calculateChecksum;
67
+ /**
68
+ * Redact secret value for logging
69
+ */
70
+ static redactSecret(value: string): string;
71
+ /**
72
+ * Check if a string looks like a secret
73
+ */
74
+ static looksLikeSecret(value: string): boolean;
75
+ }
76
+ //# sourceMappingURL=crypto.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../../../src/core/secrets/crypto.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,aAAa,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,aAAa,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAiB;IAClD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAM;IACxC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAM;IACvC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAM;IACzC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAM;IACxC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAU;IAE5C;;OAEG;IACH,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EAAE,QAAQ,EAAE,MAAM,GAAG,YAAY;IA6CpF;;OAEG;IACH,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC;IAqClF;;OAEG;IACH,MAAM,CAAC,gBAAgB,CAAC,MAAM,GAAE,MAAW,GAAG,MAAM;IAYpD;;OAEG;WACU,oBAAoB,IAAI,OAAO,CAAC,MAAM,CAAC;IAyBpD;;OAEG;mBACkB,wBAAwB;IAqB7C;;OAEG;mBACkB,wBAAwB;IAqB7C;;OAEG;mBACkB,4BAA4B;IAqBjD;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,uBAAuB;IAmBtC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,iBAAiB;IAKhC;;OAEG;IACH,MAAM,CAAC,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAO1C;;OAEG;IACH,MAAM,CAAC,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;CAW/C"}