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
@@ -6,7 +6,7 @@ import { Command } from 'commander';
6
6
  import { existsSync, createWriteStream } from 'fs';
7
7
  import { join } from 'path';
8
8
  import chalk from 'chalk';
9
- import { EvidenceVault } from 'qa360-core';
9
+ import { EvidenceVault } from '../core/index.js';
10
10
  export class QA360History {
11
11
  vault;
12
12
  constructor() { }
@@ -7,7 +7,7 @@ import { join } from 'path';
7
7
  import chalk from 'chalk';
8
8
  import ora from 'ora';
9
9
  import * as yaml from 'js-yaml';
10
- import { PackValidator, PackMigrator } from 'qa360-core';
10
+ import { PackValidator, PackMigrator } from '../core/index.js';
11
11
  export class QA360Pack {
12
12
  qa360Dir = join(process.cwd(), '.qa360');
13
13
  packPath = join(this.qa360Dir, 'pack.yml');
@@ -6,7 +6,7 @@
6
6
  * qa360 run --output ./results
7
7
  * qa360 run --verbose
8
8
  */
9
- import { type Phase3RunResult, type PackConfigV1 } from 'qa360-core';
9
+ import { type Phase3RunResult, type PackConfigV1 } from '../core/index.js';
10
10
  /**
11
11
  * CLI options for run command
12
12
  */
@@ -1 +1 @@
1
- {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/commands/run.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,OAAO,EAAgB,KAAK,eAAe,EAAkC,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAEnH;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;GAEG;AACH,wBAAsB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAwBtE;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CA0BrD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CA8B5D;AAED;;GAEG;AACH,wBAAsB,UAAU,CAC9B,OAAO,CAAC,EAAE,MAAM,EAChB,OAAO,GAAE,UAAe,GACvB,OAAO,CAAC,IAAI,CAAC,CAiDf;AAGD,eAAe,UAAU,CAAC"}
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/commands/run.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,OAAO,EAAgB,KAAK,eAAe,EAAkC,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEzH;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;GAEG;AACH,wBAAsB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAwBtE;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CA0BrD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CA8B5D;AAED;;GAEG;AACH,wBAAsB,UAAU,CAC9B,OAAO,CAAC,EAAE,MAAM,EAChB,OAAO,GAAE,UAAe,GACvB,OAAO,CAAC,IAAI,CAAC,CAiDf;AAGD,eAAe,UAAU,CAAC"}
@@ -10,7 +10,7 @@ import { existsSync, readFileSync } from 'fs';
10
10
  import { join, resolve } from 'path';
11
11
  import chalk from 'chalk';
12
12
  import { load } from 'js-yaml';
13
- import { Phase3Runner, PackValidator } from 'qa360-core';
13
+ import { Phase3Runner, PackValidator } from '../core/index.js';
14
14
  /**
15
15
  * Load and validate pack configuration
16
16
  */
@@ -5,7 +5,7 @@
5
5
  import chalk from 'chalk';
6
6
  import ora from 'ora';
7
7
  import inquirer from 'inquirer';
8
- import { SecretsManager, SecretsCrypto } from 'qa360-core';
8
+ import { SecretsManager, SecretsCrypto } from '../core/index.js';
9
9
  export class QA360Secrets {
10
10
  manager;
11
11
  constructor() {
@@ -3,7 +3,7 @@
3
3
  * Démarre le serveur d'observabilité
4
4
  */
5
5
  import { Command } from 'commander';
6
- import { QA360Server } from 'qa360-core';
6
+ import { QA360Server } from '../core/index.js';
7
7
  export function createServeCommand() {
8
8
  return new Command('serve')
9
9
  .description('Start QA360 observability server')
@@ -14,7 +14,7 @@ import { readFileSync, existsSync, readdirSync, statSync } from 'fs';
14
14
  import { join, resolve, basename } from 'path';
15
15
  import chalk from 'chalk';
16
16
  // Import from core
17
- import { verifyProofFile, verifyPhase3Proof, VerificationCode, } from 'qa360-core';
17
+ import { verifyProofFile, verifyPhase3Proof, VerificationCode, } from '../core/index.js';
18
18
  /**
19
19
  * Format verification result for human-readable output
20
20
  */
@@ -0,0 +1,115 @@
1
+ /**
2
+ * QA360 Gitleaks Secrets Adapter (Sécurité Réelle)
3
+ * Scan for hardcoded secrets in source code
4
+ */
5
+ import { PackSecurity } from '../types/pack-v1.js';
6
+ export interface GitleaksConfig {
7
+ workingDir: string;
8
+ security?: PackSecurity;
9
+ timeout?: number;
10
+ excludePaths?: string[];
11
+ configFile?: string;
12
+ verbose?: boolean;
13
+ }
14
+ export interface GitleaksFinding {
15
+ Description: string;
16
+ StartLine: number;
17
+ EndLine: number;
18
+ StartColumn: number;
19
+ EndColumn: number;
20
+ Match: string;
21
+ Secret: string;
22
+ File: string;
23
+ SymlinkFile: string;
24
+ Commit: string;
25
+ Entropy: number;
26
+ Author: string;
27
+ Email: string;
28
+ Date: string;
29
+ Message: string;
30
+ Tags: string[];
31
+ RuleID: string;
32
+ Fingerprint: string;
33
+ }
34
+ export interface GitleaksScanResult {
35
+ success: boolean;
36
+ findings: GitleaksFinding[];
37
+ summary: {
38
+ total: number;
39
+ by_rule: Record<string, number>;
40
+ by_file: Record<string, number>;
41
+ high_entropy: number;
42
+ };
43
+ budgetCheck: {
44
+ findings_passed: boolean;
45
+ };
46
+ scannedPath: string;
47
+ error?: string;
48
+ rawOutput?: string;
49
+ junit?: string;
50
+ errorCode?: string;
51
+ }
52
+ export declare class GitleaksSecretsAdapter {
53
+ private redactor;
54
+ private workingDir;
55
+ constructor(workingDir?: string);
56
+ /**
57
+ * Execute Gitleaks secrets scan
58
+ */
59
+ runSecretsScan(config: GitleaksConfig): Promise<GitleaksScanResult>;
60
+ /**
61
+ * Prepare gitleaks configuration
62
+ */
63
+ private prepareConfig;
64
+ /**
65
+ * Generate TOML config from object
66
+ */
67
+ private generateTomlConfig;
68
+ /**
69
+ * Execute gitleaks scanner
70
+ */
71
+ private executeGitleaks;
72
+ /**
73
+ * Parse gitleaks results
74
+ */
75
+ private parseGitleaksResults;
76
+ /**
77
+ * Fallback mock scan when gitleaks not available
78
+ */
79
+ private fallbackMockScan;
80
+ /**
81
+ * Calculate findings summary
82
+ */
83
+ private calculateSummary;
84
+ /**
85
+ * Generate budget check based on security config
86
+ */
87
+ private generateBudgetCheck;
88
+ /**
89
+ * Get empty summary structure
90
+ */
91
+ private getEmptySummary;
92
+ /**
93
+ * Get default budget check structure
94
+ */
95
+ private getDefaultBudgetCheck;
96
+ /**
97
+ * Generate JUnit XML report
98
+ */
99
+ private generateJUnit;
100
+ /**
101
+ * Validate gitleaks scan configuration
102
+ */
103
+ static validateConfig(config: GitleaksConfig): {
104
+ valid: boolean;
105
+ errors: string[];
106
+ };
107
+ /**
108
+ * Check if Gitleaks is available
109
+ */
110
+ static isAvailable(): Promise<{
111
+ available: boolean;
112
+ error?: string;
113
+ }>;
114
+ }
115
+ //# sourceMappingURL=gitleaks-secrets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gitleaks-secrets.d.ts","sourceRoot":"","sources":["../../../src/core/adapters/gitleaks-secrets.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGnD,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,OAAO,EAAE;QACP,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAChC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAChC,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,WAAW,EAAE;QACX,eAAe,EAAE,OAAO,CAAC;KAC1B,CAAC;IACF,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,sBAAsB;IACjC,OAAO,CAAC,QAAQ,CAAmB;IACnC,OAAO,CAAC,UAAU,CAAS;gBAEf,UAAU,GAAE,MAAsB;IAK9C;;OAEG;IACG,cAAc,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAkCzE;;OAEG;YACW,aAAa;IA+D3B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAmD1B;;OAEG;YACW,eAAe;IA+E7B;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAgD5B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAexB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IA0BxB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAQ3B;;OAEG;IACH,OAAO,CAAC,eAAe;IASvB;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAM7B;;OAEG;IACH,OAAO,CAAC,aAAa;IAyBrB;;OAEG;IACH,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,cAAc,GAAG;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE;IAqBnF;;OAEG;WACU,WAAW,IAAI,OAAO,CAAC;QAAE,SAAS,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CA2B5E"}
@@ -0,0 +1,410 @@
1
+ /**
2
+ * QA360 Gitleaks Secrets Adapter (Sécurité Réelle)
3
+ * Scan for hardcoded secrets in source code
4
+ */
5
+ import { spawn } from 'child_process';
6
+ import { existsSync, writeFileSync, unlinkSync } from 'fs';
7
+ import { join } from 'path';
8
+ import { SecurityRedactor } from '../security/redactor.js';
9
+ export class GitleaksSecretsAdapter {
10
+ redactor;
11
+ workingDir;
12
+ constructor(workingDir = process.cwd()) {
13
+ this.redactor = SecurityRedactor.forLogs();
14
+ this.workingDir = workingDir;
15
+ }
16
+ /**
17
+ * Execute Gitleaks secrets scan
18
+ */
19
+ async runSecretsScan(config) {
20
+ try {
21
+ console.log('🔍 Running Gitleaks secrets scan');
22
+ // Generate gitleaks config if needed
23
+ const configPath = await this.prepareConfig(config);
24
+ // Execute gitleaks
25
+ const result = await this.executeGitleaks(configPath, config);
26
+ // Cleanup temp config
27
+ if (configPath && configPath.includes('gitleaks-temp')) {
28
+ try {
29
+ unlinkSync(configPath);
30
+ }
31
+ catch {
32
+ // Ignore cleanup errors
33
+ }
34
+ }
35
+ return result;
36
+ }
37
+ catch (error) {
38
+ return {
39
+ success: false,
40
+ findings: [],
41
+ summary: this.getEmptySummary(),
42
+ budgetCheck: this.getDefaultBudgetCheck(),
43
+ scannedPath: config.workingDir,
44
+ error: this.redactor.redact(error instanceof Error ? error.message : 'Unknown error'),
45
+ errorCode: 'GL099'
46
+ };
47
+ }
48
+ }
49
+ /**
50
+ * Prepare gitleaks configuration
51
+ */
52
+ async prepareConfig(config) {
53
+ if (config.configFile && existsSync(config.configFile)) {
54
+ return config.configFile;
55
+ }
56
+ // Generate default config with QA360 exclusions
57
+ const gitleaksConfig = {
58
+ title: 'QA360 Gitleaks Config',
59
+ extend: {
60
+ useDefault: true
61
+ },
62
+ allowlist: {
63
+ description: 'QA360 allowlist',
64
+ paths: [
65
+ '.qa360/**',
66
+ 'node_modules/**',
67
+ 'dist/**',
68
+ 'build/**',
69
+ 'coverage/**',
70
+ '**/*.min.js',
71
+ '**/*.map',
72
+ ...(config.excludePaths || [])
73
+ ],
74
+ regexes: [
75
+ 'example',
76
+ 'test.*key',
77
+ 'dummy.*secret',
78
+ 'placeholder',
79
+ 'YOUR_.*_HERE'
80
+ ]
81
+ },
82
+ rules: [
83
+ {
84
+ id: 'generic-api-key',
85
+ description: 'Generic API Key',
86
+ regex: '(?i)\\b[a-z0-9]{32,}\\b',
87
+ entropy: 3.5,
88
+ keywords: ['api', 'key', 'token']
89
+ },
90
+ {
91
+ id: 'jwt-token',
92
+ description: 'JWT Token',
93
+ regex: 'eyJ[A-Za-z0-9_/+-]*\\.eyJ[A-Za-z0-9_/+-]*\\.[A-Za-z0-9_/+-]*',
94
+ keywords: ['jwt', 'token']
95
+ },
96
+ {
97
+ id: 'private-key',
98
+ description: 'Private Key',
99
+ regex: '-----BEGIN [A-Z]+ PRIVATE KEY-----',
100
+ keywords: ['private', 'key']
101
+ }
102
+ ]
103
+ };
104
+ const configPath = join(config.workingDir, 'gitleaks-temp.toml');
105
+ // Convert to TOML format (simplified)
106
+ const tomlConfig = this.generateTomlConfig(gitleaksConfig);
107
+ writeFileSync(configPath, tomlConfig);
108
+ return configPath;
109
+ }
110
+ /**
111
+ * Generate TOML config from object
112
+ */
113
+ generateTomlConfig(config) {
114
+ let toml = `title = "${config.title}"\n\n`;
115
+ if (config.extend?.useDefault) {
116
+ toml += '[extend]\nuseDefault = true\n\n';
117
+ }
118
+ if (config.allowlist) {
119
+ toml += '[allowlist]\n';
120
+ toml += `description = "${config.allowlist.description}"\n`;
121
+ if (config.allowlist.paths) {
122
+ toml += 'paths = [\n';
123
+ for (const path of config.allowlist.paths) {
124
+ toml += ` "${path}",\n`;
125
+ }
126
+ toml += ']\n';
127
+ }
128
+ if (config.allowlist.regexes) {
129
+ toml += 'regexes = [\n';
130
+ for (const regex of config.allowlist.regexes) {
131
+ toml += ` "${regex}",\n`;
132
+ }
133
+ toml += ']\n\n';
134
+ }
135
+ }
136
+ if (config.rules) {
137
+ for (const rule of config.rules) {
138
+ toml += `[[rules]]\n`;
139
+ toml += `id = "${rule.id}"\n`;
140
+ toml += `description = "${rule.description}"\n`;
141
+ toml += `regex = '''${rule.regex}'''\n`;
142
+ if (rule.entropy) {
143
+ toml += `entropy = ${rule.entropy}\n`;
144
+ }
145
+ if (rule.keywords) {
146
+ toml += 'keywords = [\n';
147
+ for (const keyword of rule.keywords) {
148
+ toml += ` "${keyword}",\n`;
149
+ }
150
+ toml += ']\n';
151
+ }
152
+ toml += '\n';
153
+ }
154
+ }
155
+ return toml;
156
+ }
157
+ /**
158
+ * Execute gitleaks scanner
159
+ */
160
+ async executeGitleaks(configPath, config) {
161
+ return new Promise((resolve) => {
162
+ let output = '';
163
+ let error = '';
164
+ const args = [
165
+ 'detect',
166
+ '--source', config.workingDir,
167
+ '--report-format', 'json',
168
+ '--no-git'
169
+ ];
170
+ if (configPath) {
171
+ args.push('--config', configPath);
172
+ }
173
+ if (config.verbose) {
174
+ args.push('--verbose');
175
+ }
176
+ const child = spawn('gitleaks', args, {
177
+ cwd: config.workingDir,
178
+ stdio: ['ignore', 'pipe', 'pipe']
179
+ });
180
+ const timeout = setTimeout(() => {
181
+ child.kill('SIGKILL');
182
+ resolve({
183
+ success: false,
184
+ findings: [],
185
+ summary: this.getEmptySummary(),
186
+ budgetCheck: this.getDefaultBudgetCheck(),
187
+ scannedPath: config.workingDir,
188
+ error: `Gitleaks scan timed out after ${config.timeout || 120000}ms`,
189
+ errorCode: 'GL001'
190
+ });
191
+ }, config.timeout || 120000);
192
+ if (child.stdout) {
193
+ child.stdout.on('data', (data) => {
194
+ output += data.toString();
195
+ });
196
+ }
197
+ if (child.stderr) {
198
+ child.stderr.on('data', (data) => {
199
+ error += data.toString();
200
+ });
201
+ }
202
+ child.on('close', (code) => {
203
+ clearTimeout(timeout);
204
+ if (code === 0 || code === 1) { // 0 = no secrets, 1 = secrets found
205
+ const result = this.parseGitleaksResults(output, config);
206
+ resolve(result);
207
+ }
208
+ else {
209
+ resolve({
210
+ success: false,
211
+ findings: [],
212
+ summary: this.getEmptySummary(),
213
+ budgetCheck: this.getDefaultBudgetCheck(),
214
+ scannedPath: config.workingDir,
215
+ error: this.redactor.redact(error || `Gitleaks exited with code ${code}`),
216
+ rawOutput: this.redactor.redact(output),
217
+ errorCode: 'GL002'
218
+ });
219
+ }
220
+ });
221
+ child.on('error', (err) => {
222
+ clearTimeout(timeout);
223
+ // Fallback to mock scan
224
+ resolve(this.fallbackMockScan(config));
225
+ });
226
+ });
227
+ }
228
+ /**
229
+ * Parse gitleaks results
230
+ */
231
+ parseGitleaksResults(output, config) {
232
+ try {
233
+ let findings = [];
234
+ if (output.trim()) {
235
+ const data = JSON.parse(output);
236
+ findings = Array.isArray(data) ? data : [data];
237
+ }
238
+ // Redact sensitive information from findings
239
+ const redactedFindings = findings.map(finding => ({
240
+ ...finding,
241
+ Secret: this.redactor.redact(finding.Secret || ''),
242
+ Match: this.redactor.redact(finding.Match || ''),
243
+ Email: this.redactor.redact(finding.Email || ''),
244
+ Author: this.redactor.redact(finding.Author || '')
245
+ }));
246
+ const summary = this.calculateSummary(redactedFindings);
247
+ const budgetCheck = this.generateBudgetCheck(summary, config);
248
+ const success = budgetCheck.findings_passed;
249
+ const junit = this.generateJUnit(summary, success, config);
250
+ return {
251
+ success,
252
+ findings: redactedFindings,
253
+ summary,
254
+ budgetCheck,
255
+ scannedPath: config.workingDir,
256
+ rawOutput: this.redactor.redact(output),
257
+ junit
258
+ };
259
+ }
260
+ catch (error) {
261
+ return {
262
+ success: false,
263
+ findings: [],
264
+ summary: this.getEmptySummary(),
265
+ budgetCheck: this.getDefaultBudgetCheck(),
266
+ scannedPath: config.workingDir,
267
+ error: `Failed to parse Gitleaks results: ${error}`,
268
+ rawOutput: this.redactor.redact(output),
269
+ errorCode: 'GL003'
270
+ };
271
+ }
272
+ }
273
+ /**
274
+ * Fallback mock scan when gitleaks not available
275
+ */
276
+ fallbackMockScan(config) {
277
+ console.log('⚠️ Gitleaks not found, using mock scan (install gitleaks for real scanning)');
278
+ return {
279
+ success: true,
280
+ findings: [],
281
+ summary: this.getEmptySummary(),
282
+ budgetCheck: this.getDefaultBudgetCheck(),
283
+ scannedPath: config.workingDir,
284
+ error: 'Gitleaks not available - install from https://github.com/gitleaks/gitleaks',
285
+ junit: this.generateJUnit(this.getEmptySummary(), true, config),
286
+ errorCode: 'GL004'
287
+ };
288
+ }
289
+ /**
290
+ * Calculate findings summary
291
+ */
292
+ calculateSummary(findings) {
293
+ const summary = {
294
+ total: findings.length,
295
+ by_rule: {},
296
+ by_file: {},
297
+ high_entropy: 0
298
+ };
299
+ for (const finding of findings) {
300
+ // Count by rule
301
+ const ruleId = finding.RuleID || 'unknown';
302
+ summary.by_rule[ruleId] = (summary.by_rule[ruleId] || 0) + 1;
303
+ // Count by file
304
+ const file = finding.File || 'unknown';
305
+ summary.by_file[file] = (summary.by_file[file] || 0) + 1;
306
+ // Count high entropy findings
307
+ if (finding.Entropy && finding.Entropy > 4.0) {
308
+ summary.high_entropy++;
309
+ }
310
+ }
311
+ return summary;
312
+ }
313
+ /**
314
+ * Generate budget check based on security config
315
+ */
316
+ generateBudgetCheck(summary, config) {
317
+ const secrets = config.security?.secrets;
318
+ return {
319
+ findings_passed: !secrets?.max_findings || summary.total <= secrets.max_findings
320
+ };
321
+ }
322
+ /**
323
+ * Get empty summary structure
324
+ */
325
+ getEmptySummary() {
326
+ return {
327
+ total: 0,
328
+ by_rule: {},
329
+ by_file: {},
330
+ high_entropy: 0
331
+ };
332
+ }
333
+ /**
334
+ * Get default budget check structure
335
+ */
336
+ getDefaultBudgetCheck() {
337
+ return {
338
+ findings_passed: true
339
+ };
340
+ }
341
+ /**
342
+ * Generate JUnit XML report
343
+ */
344
+ generateJUnit(summary, success, config) {
345
+ const timestamp = new Date().toISOString();
346
+ const duration = '0.1';
347
+ let junit = `<?xml version="1.0" encoding="UTF-8"?>
348
+ <testsuite name="Gitleaks Secrets Scan" tests="1" failures="${success ? 0 : 1}" time="${duration}" timestamp="${timestamp}">
349
+ <testcase name="Secret Detection: ${config.workingDir}" time="${duration}">
350
+ `;
351
+ if (!success) {
352
+ junit += ` <failure message="Secrets found in source code">
353
+ Total findings: ${summary.total}
354
+ High entropy: ${summary.high_entropy}
355
+ Files affected: ${Object.keys(summary.by_file).length}
356
+ Rules triggered: ${Object.keys(summary.by_rule).length}
357
+ </failure>
358
+ `;
359
+ }
360
+ junit += ` </testcase>
361
+ </testsuite>`;
362
+ return junit;
363
+ }
364
+ /**
365
+ * Validate gitleaks scan configuration
366
+ */
367
+ static validateConfig(config) {
368
+ const errors = [];
369
+ if (!config.workingDir) {
370
+ errors.push('Working directory is required');
371
+ }
372
+ if (!existsSync(config.workingDir)) {
373
+ errors.push(`Working directory does not exist: ${config.workingDir}`);
374
+ }
375
+ if (config.configFile && !existsSync(config.configFile)) {
376
+ errors.push(`Config file does not exist: ${config.configFile}`);
377
+ }
378
+ return {
379
+ valid: errors.length === 0,
380
+ errors
381
+ };
382
+ }
383
+ /**
384
+ * Check if Gitleaks is available
385
+ */
386
+ static async isAvailable() {
387
+ return new Promise((resolve) => {
388
+ const child = spawn('gitleaks', ['version'], { stdio: 'pipe' });
389
+ child.on('close', (code) => {
390
+ resolve({
391
+ available: code === 0,
392
+ error: code !== 0 ? 'gitleaks not found. Install from https://github.com/gitleaks/gitleaks' : undefined
393
+ });
394
+ });
395
+ child.on('error', () => {
396
+ resolve({
397
+ available: false,
398
+ error: 'gitleaks not found. Install from https://github.com/gitleaks/gitleaks'
399
+ });
400
+ });
401
+ setTimeout(() => {
402
+ child.kill();
403
+ resolve({
404
+ available: false,
405
+ error: 'gitleaks check timed out'
406
+ });
407
+ }, 5000);
408
+ });
409
+ }
410
+ }
@@ -0,0 +1,86 @@
1
+ /**
2
+ * QA360 k6 Performance Adapter (Socle OOTB)
3
+ * Short performance tests with P95 calculation
4
+ */
5
+ import { PackBudgets } from '../types/pack-v1.js';
6
+ export interface K6TestConfig {
7
+ baseUrl: string;
8
+ budgets?: PackBudgets;
9
+ duration?: string;
10
+ vus?: number;
11
+ timeout?: number;
12
+ scenarios?: Record<string, any>;
13
+ }
14
+ export interface K6TestResult {
15
+ success: boolean;
16
+ metrics: {
17
+ http_req_duration_p95: number;
18
+ http_req_duration_avg: number;
19
+ http_req_failed_rate: number;
20
+ http_reqs_total: number;
21
+ vus_max: number;
22
+ iterations: number;
23
+ };
24
+ thresholds: {
25
+ [key: string]: {
26
+ passed: boolean;
27
+ value: number;
28
+ threshold: string;
29
+ };
30
+ };
31
+ error?: string;
32
+ rawOutput?: string;
33
+ junit?: string;
34
+ }
35
+ export declare class K6PerfAdapter {
36
+ private redactor;
37
+ private workingDir;
38
+ constructor(workingDir?: string);
39
+ /**
40
+ * Execute k6 performance test
41
+ */
42
+ runPerfTest(config: K6TestConfig): Promise<K6TestResult>;
43
+ /**
44
+ * Generate k6 test script
45
+ */
46
+ private generateK6Script;
47
+ /**
48
+ * Execute k6 command
49
+ */
50
+ private executeK6;
51
+ /**
52
+ * Parse k6 results from output
53
+ */
54
+ private parseK6Results;
55
+ /**
56
+ * Parse metrics from text output
57
+ */
58
+ private parseTextMetrics;
59
+ /**
60
+ * Parse thresholds from text output
61
+ */
62
+ private parseTextThresholds;
63
+ /**
64
+ * Generate JUnit XML
65
+ */
66
+ private generateJUnit;
67
+ /**
68
+ * Get default metrics structure
69
+ */
70
+ private getDefaultMetrics;
71
+ /**
72
+ * Check if k6 is available
73
+ */
74
+ static isAvailable(): Promise<{
75
+ available: boolean;
76
+ error?: string;
77
+ }>;
78
+ /**
79
+ * Validate performance test configuration
80
+ */
81
+ static validateConfig(config: K6TestConfig): {
82
+ valid: boolean;
83
+ errors: string[];
84
+ };
85
+ }
86
+ //# sourceMappingURL=k6-perf.d.ts.map