api-tests-coverage 1.0.12 → 1.0.14

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 (150) hide show
  1. package/dist/dashboard/dist/assets/_basePickBy-CErN2e4K.js +1 -0
  2. package/dist/dashboard/dist/assets/_baseUniq-DzHorfx6.js +1 -0
  3. package/dist/dashboard/dist/assets/arc-g03p1JXB.js +1 -0
  4. package/dist/dashboard/dist/assets/architectureDiagram-VXUJARFQ-CLCqS7Lv.js +36 -0
  5. package/dist/dashboard/dist/assets/blockDiagram-VD42YOAC-V4vxrfzX.js +122 -0
  6. package/dist/dashboard/dist/assets/c4Diagram-YG6GDRKO-Bs4R4b6P.js +10 -0
  7. package/dist/dashboard/dist/assets/channel-BSnIwwuG.js +1 -0
  8. package/dist/dashboard/dist/assets/chunk-4BX2VUAB-oleArqPu.js +1 -0
  9. package/dist/dashboard/dist/assets/chunk-55IACEB6-BIFhHB94.js +1 -0
  10. package/dist/dashboard/dist/assets/chunk-B4BG7PRW-BChq1Wly.js +165 -0
  11. package/dist/dashboard/dist/assets/chunk-DI55MBZ5-D7eiRvhB.js +220 -0
  12. package/dist/dashboard/dist/assets/chunk-FMBD7UC4-BgEzYy_c.js +15 -0
  13. package/dist/dashboard/dist/assets/chunk-QN33PNHL-BNX7uRa_.js +1 -0
  14. package/dist/dashboard/dist/assets/chunk-QZHKN3VN-mq-zucvn.js +1 -0
  15. package/dist/dashboard/dist/assets/chunk-TZMSLE5B-DGTVcqTS.js +1 -0
  16. package/dist/dashboard/dist/assets/classDiagram-2ON5EDUG-Be0F7AG8.js +1 -0
  17. package/dist/dashboard/dist/assets/classDiagram-v2-WZHVMYZB-Be0F7AG8.js +1 -0
  18. package/dist/dashboard/dist/assets/clone-B5PF81Z3.js +1 -0
  19. package/dist/dashboard/dist/assets/cose-bilkent-S5V4N54A-xVw-THr_.js +1 -0
  20. package/dist/dashboard/dist/assets/dagre-6UL2VRFP-Bjadb8g_.js +4 -0
  21. package/dist/dashboard/dist/assets/diagram-PSM6KHXK-BPFtplp4.js +24 -0
  22. package/dist/dashboard/dist/assets/diagram-QEK2KX5R-CYxueP7U.js +43 -0
  23. package/dist/dashboard/dist/assets/diagram-S2PKOQOG-CRUXUQeh.js +24 -0
  24. package/dist/dashboard/dist/assets/erDiagram-Q2GNP2WA-DvI8ycM6.js +60 -0
  25. package/dist/dashboard/dist/assets/flowDiagram-NV44I4VS-BAHshMEg.js +162 -0
  26. package/dist/dashboard/dist/assets/ganttDiagram-JELNMOA3-BS4JnN-M.js +267 -0
  27. package/dist/dashboard/dist/assets/gitGraphDiagram-V2S2FVAM-Uz3nRdju.js +65 -0
  28. package/dist/dashboard/dist/assets/graph-Cwn7jgQS.js +1 -0
  29. package/dist/dashboard/dist/assets/index-D3_88Gr5.js +777 -0
  30. package/dist/dashboard/dist/assets/index-D_begBP0.css +1 -0
  31. package/dist/dashboard/dist/assets/infoDiagram-HS3SLOUP-HLwGZBHJ.js +2 -0
  32. package/dist/dashboard/dist/assets/journeyDiagram-XKPGCS4Q-CFgbI9OH.js +139 -0
  33. package/dist/dashboard/dist/assets/kanban-definition-3W4ZIXB7-D3u5Ov-5.js +89 -0
  34. package/dist/dashboard/dist/assets/layout-DgtRACDS.js +1 -0
  35. package/dist/dashboard/dist/assets/mindmap-definition-VGOIOE7T-BJ5xCmsL.js +68 -0
  36. package/dist/dashboard/dist/assets/pieDiagram-ADFJNKIX-BIOVbZG_.js +30 -0
  37. package/dist/dashboard/dist/assets/quadrantDiagram-AYHSOK5B-Crgu5WqK.js +7 -0
  38. package/dist/dashboard/dist/assets/requirementDiagram-UZGBJVZJ-ClNSNeYe.js +64 -0
  39. package/dist/dashboard/dist/assets/sankeyDiagram-TZEHDZUN-VcdyPlVE.js +10 -0
  40. package/dist/dashboard/dist/assets/sequenceDiagram-WL72ISMW-97qjzqIO.js +145 -0
  41. package/dist/dashboard/dist/assets/stateDiagram-FKZM4ZOC-BWqoDymf.js +1 -0
  42. package/dist/dashboard/dist/assets/stateDiagram-v2-4FDKWEC3-K_qkvHaB.js +1 -0
  43. package/dist/dashboard/dist/assets/timeline-definition-IT6M3QCI-DR6HNny6.js +61 -0
  44. package/dist/dashboard/dist/assets/treemap-GDKQZRPO-MpQr6tee.js +162 -0
  45. package/dist/dashboard/dist/assets/xychartDiagram-PRI3JC2R-bS40I4IT.js +7 -0
  46. package/dist/dashboard/dist/index.html +2 -2
  47. package/dist/src/ast/astAnalysisOrchestrator.d.ts +28 -0
  48. package/dist/src/ast/astAnalysisOrchestrator.d.ts.map +1 -1
  49. package/dist/src/ast/astAnalysisOrchestrator.js +97 -27
  50. package/dist/src/languages/javascript/httpInteractionExtractor.js +10 -4
  51. package/dist/src/pipeline/confidence.d.ts +70 -0
  52. package/dist/src/pipeline/confidence.d.ts.map +1 -0
  53. package/dist/src/pipeline/confidence.js +198 -0
  54. package/dist/src/pipeline/graph.d.ts +58 -0
  55. package/dist/src/pipeline/graph.d.ts.map +1 -0
  56. package/dist/src/pipeline/graph.js +199 -0
  57. package/dist/src/pipeline/index.d.ts +24 -0
  58. package/dist/src/pipeline/index.d.ts.map +1 -0
  59. package/dist/src/pipeline/index.js +41 -0
  60. package/dist/src/pipeline/orchestrator.d.ts +42 -0
  61. package/dist/src/pipeline/orchestrator.d.ts.map +1 -0
  62. package/dist/src/pipeline/orchestrator.js +115 -0
  63. package/dist/src/pipeline/stageInterface.d.ts +45 -0
  64. package/dist/src/pipeline/stageInterface.d.ts.map +1 -0
  65. package/dist/src/pipeline/stageInterface.js +17 -0
  66. package/dist/src/pipeline/stages/ast/abstractLayerTraversal.d.ts +38 -0
  67. package/dist/src/pipeline/stages/ast/abstractLayerTraversal.d.ts.map +1 -0
  68. package/dist/src/pipeline/stages/ast/abstractLayerTraversal.js +203 -0
  69. package/dist/src/pipeline/stages/ast/astStage.d.ts +19 -0
  70. package/dist/src/pipeline/stages/ast/astStage.d.ts.map +1 -0
  71. package/dist/src/pipeline/stages/ast/astStage.js +238 -0
  72. package/dist/src/pipeline/stages/ast/crossFileResolver.d.ts +23 -0
  73. package/dist/src/pipeline/stages/ast/crossFileResolver.d.ts.map +1 -0
  74. package/dist/src/pipeline/stages/ast/crossFileResolver.js +183 -0
  75. package/dist/src/pipeline/stages/ast/graphBuilder.d.ts +15 -0
  76. package/dist/src/pipeline/stages/ast/graphBuilder.d.ts.map +1 -0
  77. package/dist/src/pipeline/stages/ast/graphBuilder.js +268 -0
  78. package/dist/src/pipeline/stages/ast/importResolver.d.ts +22 -0
  79. package/dist/src/pipeline/stages/ast/importResolver.d.ts.map +1 -0
  80. package/dist/src/pipeline/stages/ast/importResolver.js +186 -0
  81. package/dist/src/pipeline/stages/ast/types.d.ts +85 -0
  82. package/dist/src/pipeline/stages/ast/types.d.ts.map +1 -0
  83. package/dist/src/pipeline/stages/ast/types.js +5 -0
  84. package/dist/src/pipeline/stages/dast/conflictEmitter.d.ts +25 -0
  85. package/dist/src/pipeline/stages/dast/conflictEmitter.d.ts.map +1 -0
  86. package/dist/src/pipeline/stages/dast/conflictEmitter.js +90 -0
  87. package/dist/src/pipeline/stages/dast/dastStage.d.ts +17 -0
  88. package/dist/src/pipeline/stages/dast/dastStage.d.ts.map +1 -0
  89. package/dist/src/pipeline/stages/dast/dastStage.js +203 -0
  90. package/dist/src/pipeline/stages/dast/types.d.ts +49 -0
  91. package/dist/src/pipeline/stages/dast/types.d.ts.map +1 -0
  92. package/dist/src/pipeline/stages/dast/types.js +9 -0
  93. package/dist/src/pipeline/stages/iast/iastStage.d.ts +17 -0
  94. package/dist/src/pipeline/stages/iast/iastStage.d.ts.map +1 -0
  95. package/dist/src/pipeline/stages/iast/iastStage.js +191 -0
  96. package/dist/src/pipeline/stages/iast/types.d.ts +48 -0
  97. package/dist/src/pipeline/stages/iast/types.d.ts.map +1 -0
  98. package/dist/src/pipeline/stages/iast/types.js +8 -0
  99. package/dist/src/pipeline/stages/merge/conflictDetector.d.ts +17 -0
  100. package/dist/src/pipeline/stages/merge/conflictDetector.d.ts.map +1 -0
  101. package/dist/src/pipeline/stages/merge/conflictDetector.js +60 -0
  102. package/dist/src/pipeline/stages/merge/coverageMappingBuilder.d.ts +15 -0
  103. package/dist/src/pipeline/stages/merge/coverageMappingBuilder.d.ts.map +1 -0
  104. package/dist/src/pipeline/stages/merge/coverageMappingBuilder.js +141 -0
  105. package/dist/src/pipeline/stages/merge/mergeRules.d.ts +39 -0
  106. package/dist/src/pipeline/stages/merge/mergeRules.d.ts.map +1 -0
  107. package/dist/src/pipeline/stages/merge/mergeRules.js +90 -0
  108. package/dist/src/pipeline/stages/merge/mergeStage.d.ts +20 -0
  109. package/dist/src/pipeline/stages/merge/mergeStage.d.ts.map +1 -0
  110. package/dist/src/pipeline/stages/merge/mergeStage.js +145 -0
  111. package/dist/src/pipeline/stages/merge/summaryComputer.d.ts +11 -0
  112. package/dist/src/pipeline/stages/merge/summaryComputer.d.ts.map +1 -0
  113. package/dist/src/pipeline/stages/merge/summaryComputer.js +46 -0
  114. package/dist/src/pipeline/stages/sca/ciDetector.d.ts +15 -0
  115. package/dist/src/pipeline/stages/sca/ciDetector.d.ts.map +1 -0
  116. package/dist/src/pipeline/stages/sca/ciDetector.js +87 -0
  117. package/dist/src/pipeline/stages/sca/dependencyClassification.d.ts +31 -0
  118. package/dist/src/pipeline/stages/sca/dependencyClassification.d.ts.map +1 -0
  119. package/dist/src/pipeline/stages/sca/dependencyClassification.js +296 -0
  120. package/dist/src/pipeline/stages/sca/dependencyDetector.d.ts +25 -0
  121. package/dist/src/pipeline/stages/sca/dependencyDetector.d.ts.map +1 -0
  122. package/dist/src/pipeline/stages/sca/dependencyDetector.js +416 -0
  123. package/dist/src/pipeline/stages/sca/scaStage.d.ts +21 -0
  124. package/dist/src/pipeline/stages/sca/scaStage.d.ts.map +1 -0
  125. package/dist/src/pipeline/stages/sca/scaStage.js +208 -0
  126. package/dist/src/pipeline/stages/sca/types.d.ts +61 -0
  127. package/dist/src/pipeline/stages/sca/types.d.ts.map +1 -0
  128. package/dist/src/pipeline/stages/sca/types.js +9 -0
  129. package/dist/src/pipeline/stages/tia/mockBoundaryDetector.d.ts +19 -0
  130. package/dist/src/pipeline/stages/tia/mockBoundaryDetector.d.ts.map +1 -0
  131. package/dist/src/pipeline/stages/tia/mockBoundaryDetector.js +118 -0
  132. package/dist/src/pipeline/stages/tia/parameterizedTestExpander.d.ts +20 -0
  133. package/dist/src/pipeline/stages/tia/parameterizedTestExpander.d.ts.map +1 -0
  134. package/dist/src/pipeline/stages/tia/parameterizedTestExpander.js +238 -0
  135. package/dist/src/pipeline/stages/tia/testEndpointMapper.d.ts +22 -0
  136. package/dist/src/pipeline/stages/tia/testEndpointMapper.d.ts.map +1 -0
  137. package/dist/src/pipeline/stages/tia/testEndpointMapper.js +134 -0
  138. package/dist/src/pipeline/stages/tia/testLayerClassifier.d.ts +16 -0
  139. package/dist/src/pipeline/stages/tia/testLayerClassifier.d.ts.map +1 -0
  140. package/dist/src/pipeline/stages/tia/testLayerClassifier.js +191 -0
  141. package/dist/src/pipeline/stages/tia/tiaStage.d.ts +20 -0
  142. package/dist/src/pipeline/stages/tia/tiaStage.d.ts.map +1 -0
  143. package/dist/src/pipeline/stages/tia/tiaStage.js +215 -0
  144. package/dist/src/pipeline/stages/tia/types.d.ts +52 -0
  145. package/dist/src/pipeline/stages/tia/types.d.ts.map +1 -0
  146. package/dist/src/pipeline/stages/tia/types.js +5 -0
  147. package/dist/src/pipeline/types.d.ts +128 -0
  148. package/dist/src/pipeline/types.d.ts.map +1 -0
  149. package/dist/src/pipeline/types.js +9 -0
  150. package/package.json +1 -1
@@ -0,0 +1,90 @@
1
+ "use strict";
2
+ /**
3
+ * DAST conflict emitter — detects conflicts between DAST probe results and
4
+ * AST-declared endpoints.
5
+ *
6
+ * Conflict rules from spec §7:
7
+ *
8
+ * | DAST Result | AST Declared | Conflict Type |
9
+ * |--------------------------|-----------------------|------------------------------------|
10
+ * | Not reachable | Endpoint exists | dast-unreachable |
11
+ * | Reachable, no auth check | @Secured present | security-annotation-not-enforced |
12
+ * | Returns 500 | No error handler | unhandled-server-error |
13
+ * | New endpoint found | Not in AST | undeclared-endpoint |
14
+ */
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.emitDastConflicts = emitDastConflicts;
17
+ /**
18
+ * Emit conflicts by comparing DAST results with the AST-declared graph.
19
+ *
20
+ * @param results - DAST probe results
21
+ * @param graph - Current coverage knowledge graph
22
+ * @returns Array of conflict nodes to be added to the graph
23
+ */
24
+ function emitDastConflicts(results, graph) {
25
+ var _a, _b;
26
+ const conflicts = [];
27
+ const astEndpointIds = new Set(graph.getNodesByType('endpoint').map((n) => n.id));
28
+ for (const result of results) {
29
+ const endpointPath = (_a = result.normalizedPath) !== null && _a !== void 0 ? _a : result.path;
30
+ const endpointId = `endpoint:${result.method.toUpperCase()}:${endpointPath}`;
31
+ const existsInAst = astEndpointIds.has(endpointId);
32
+ // Rule 1: DAST can't reach an AST-declared endpoint
33
+ if (!result.reachable && existsInAst) {
34
+ conflicts.push({
35
+ conflictId: `conflict:dast-unreachable:${endpointId}`,
36
+ nodeId: endpointId,
37
+ type: 'dast-unreachable',
38
+ stages: ['ast', 'dast'],
39
+ stageOutputs: { ast: 'endpoint-declared', dast: 'not-reachable' },
40
+ detail: `DAST could not reach ${result.method} ${result.path}, but AST declares it as an endpoint.`,
41
+ suggestedAction: 'Verify the endpoint is deployed and accessible in the test environment. Check for routing middleware that may block access.',
42
+ severity: 'warning',
43
+ });
44
+ }
45
+ // Rule 2: DAST reaches endpoint without auth, but AST shows security annotation
46
+ if (result.reachable && result.authBypass && existsInAst) {
47
+ const endpointNode = graph.getNode(endpointId);
48
+ const hasSecurityAnnotation = ((_b = endpointNode === null || endpointNode === void 0 ? void 0 : endpointNode.metadata) === null || _b === void 0 ? void 0 : _b.securityAnnotation) != null;
49
+ if (hasSecurityAnnotation || result.authRequired === false) {
50
+ conflicts.push({
51
+ conflictId: `conflict:security-not-enforced:${endpointId}`,
52
+ nodeId: endpointId,
53
+ type: 'security-annotation-not-enforced',
54
+ stages: ['ast', 'dast'],
55
+ stageOutputs: { ast: 'security-annotation-present', dast: 'auth-bypass-detected' },
56
+ detail: `DAST accessed ${result.method} ${result.path} without authentication, but security annotation is present in code.`,
57
+ suggestedAction: 'Review security configuration. Ensure authentication middleware is applied to this endpoint and annotations are enforced at runtime.',
58
+ severity: 'error',
59
+ });
60
+ }
61
+ }
62
+ // Rule 3: DAST gets 500 error, indicating unhandled server error
63
+ if (result.reachable && result.serverError && existsInAst) {
64
+ conflicts.push({
65
+ conflictId: `conflict:unhandled-error:${endpointId}`,
66
+ nodeId: endpointId,
67
+ type: 'unhandled-server-error',
68
+ stages: ['ast', 'dast'],
69
+ stageOutputs: { ast: 'endpoint-declared', dast: 'server-error-500' },
70
+ detail: `DAST received a 500 error from ${result.method} ${result.path}. This may indicate unhandled exceptions.`,
71
+ suggestedAction: 'Add error handling for this endpoint. Review exception handling middleware and ensure all error paths return appropriate status codes.',
72
+ severity: 'warning',
73
+ });
74
+ }
75
+ // Rule 4: DAST finds an endpoint not declared in AST
76
+ if (result.reachable && !existsInAst) {
77
+ conflicts.push({
78
+ conflictId: `conflict:undeclared-endpoint:${endpointId}`,
79
+ nodeId: endpointId,
80
+ type: 'undeclared-endpoint',
81
+ stages: ['dast'],
82
+ stageOutputs: { dast: 'endpoint-reachable' },
83
+ detail: `DAST discovered ${result.method} ${result.path} which is not declared in any AST-analyzed source file.`,
84
+ suggestedAction: 'Check if this endpoint is generated dynamically, comes from a third-party library, or is defined in code not included in the analysis scope.',
85
+ severity: 'info',
86
+ });
87
+ }
88
+ }
89
+ return conflicts;
90
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * DAST Stage — Stage 5 of the coverage pipeline (optional).
3
+ *
4
+ * Reads dast-results.json if present, processes probe results,
5
+ * emits conflicts, and records endpoint reachability confirmations.
6
+ *
7
+ * When this stage is skipped (no DAST data), the pipeline continues
8
+ * without DAST confirmation (confidence cannot reach 'verified').
9
+ */
10
+ import type { PipelineStage, PipelineContext } from '../../stageInterface';
11
+ import type { DastOutput } from './types';
12
+ export declare class DastStage implements PipelineStage<DastOutput> {
13
+ readonly name: "dast";
14
+ readonly optional = true;
15
+ execute(context: PipelineContext): Promise<DastOutput>;
16
+ }
17
+ //# sourceMappingURL=dastStage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dastStage.d.ts","sourceRoot":"","sources":["../../../../../src/pipeline/stages/dast/dastStage.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE3E,OAAO,KAAK,EAAE,UAAU,EAAmB,MAAM,SAAS,CAAC;AAG3D,qBAAa,SAAU,YAAW,aAAa,CAAC,UAAU,CAAC;IACzD,QAAQ,CAAC,IAAI,EAAG,MAAM,CAAU;IAChC,QAAQ,CAAC,QAAQ,QAAQ;IAEnB,OAAO,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,UAAU,CAAC;CAkK7D"}
@@ -0,0 +1,203 @@
1
+ "use strict";
2
+ /**
3
+ * DAST Stage — Stage 5 of the coverage pipeline (optional).
4
+ *
5
+ * Reads dast-results.json if present, processes probe results,
6
+ * emits conflicts, and records endpoint reachability confirmations.
7
+ *
8
+ * When this stage is skipped (no DAST data), the pipeline continues
9
+ * without DAST confirmation (confidence cannot reach 'verified').
10
+ */
11
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
12
+ if (k2 === undefined) k2 = k;
13
+ var desc = Object.getOwnPropertyDescriptor(m, k);
14
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
15
+ desc = { enumerable: true, get: function() { return m[k]; } };
16
+ }
17
+ Object.defineProperty(o, k2, desc);
18
+ }) : (function(o, m, k, k2) {
19
+ if (k2 === undefined) k2 = k;
20
+ o[k2] = m[k];
21
+ }));
22
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
23
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
24
+ }) : function(o, v) {
25
+ o["default"] = v;
26
+ });
27
+ var __importStar = (this && this.__importStar) || (function () {
28
+ var ownKeys = function(o) {
29
+ ownKeys = Object.getOwnPropertyNames || function (o) {
30
+ var ar = [];
31
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
32
+ return ar;
33
+ };
34
+ return ownKeys(o);
35
+ };
36
+ return function (mod) {
37
+ if (mod && mod.__esModule) return mod;
38
+ var result = {};
39
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
40
+ __setModuleDefault(result, mod);
41
+ return result;
42
+ };
43
+ })();
44
+ Object.defineProperty(exports, "__esModule", { value: true });
45
+ exports.DastStage = void 0;
46
+ const fs = __importStar(require("fs"));
47
+ const path = __importStar(require("path"));
48
+ const conflictEmitter_1 = require("./conflictEmitter");
49
+ class DastStage {
50
+ constructor() {
51
+ this.name = 'dast';
52
+ this.optional = true;
53
+ }
54
+ async execute(context) {
55
+ var _a, _b, _c;
56
+ const startTime = Date.now();
57
+ const filesScanned = [];
58
+ const filesSkipped = [];
59
+ const output = {
60
+ results: [],
61
+ confirmedEndpoints: [],
62
+ unreachableEndpoints: [],
63
+ conflictsEmitted: 0,
64
+ };
65
+ // Determine the DAST results file path
66
+ const resultsPath = (_a = context.config.dastResultsPath) !== null && _a !== void 0 ? _a : path.join(context.projectRoot, 'dast-results.json');
67
+ // Try to read the results file
68
+ if (!fs.existsSync(resultsPath)) {
69
+ context.diagnostics.set('dast', {
70
+ stageName: 'dast',
71
+ filesScanned,
72
+ filesSkipped: [{ file: resultsPath, reason: 'file-not-found' }],
73
+ durationMs: Date.now() - startTime,
74
+ metadata: { skipped: true, reason: 'no-dast-results-file' },
75
+ });
76
+ context.stageOutputs.set('dast', output);
77
+ return output;
78
+ }
79
+ filesScanned.push(resultsPath);
80
+ let resultsFile;
81
+ try {
82
+ const content = fs.readFileSync(resultsPath, 'utf-8');
83
+ resultsFile = JSON.parse(content);
84
+ }
85
+ catch (err) {
86
+ filesSkipped.push({
87
+ file: resultsPath,
88
+ reason: `parse-error: ${err instanceof Error ? err.message : String(err)}`,
89
+ });
90
+ context.diagnostics.set('dast', {
91
+ stageName: 'dast',
92
+ filesScanned,
93
+ filesSkipped,
94
+ durationMs: Date.now() - startTime,
95
+ metadata: { skipped: true, reason: 'parse-error' },
96
+ });
97
+ context.stageOutputs.set('dast', output);
98
+ return output;
99
+ }
100
+ if (!resultsFile.results || !Array.isArray(resultsFile.results)) {
101
+ filesSkipped.push({ file: resultsPath, reason: 'invalid-format: missing results array' });
102
+ context.diagnostics.set('dast', {
103
+ stageName: 'dast',
104
+ filesScanned,
105
+ filesSkipped,
106
+ durationMs: Date.now() - startTime,
107
+ metadata: { skipped: true, reason: 'invalid-format' },
108
+ });
109
+ context.stageOutputs.set('dast', output);
110
+ return output;
111
+ }
112
+ output.results = resultsFile.results;
113
+ // Categorize results
114
+ for (const result of resultsFile.results) {
115
+ const endpointPath = (_b = result.normalizedPath) !== null && _b !== void 0 ? _b : result.path;
116
+ const endpointId = `endpoint:${result.method.toUpperCase()}:${endpointPath}`;
117
+ if (result.reachable) {
118
+ if (!output.confirmedEndpoints.includes(endpointId)) {
119
+ output.confirmedEndpoints.push(endpointId);
120
+ }
121
+ }
122
+ else {
123
+ if (!output.unreachableEndpoints.includes(endpointId)) {
124
+ output.unreachableEndpoints.push(endpointId);
125
+ }
126
+ }
127
+ }
128
+ // Add DAST-discovered endpoints that don't exist in the graph (RULE-09: don't override types)
129
+ for (const result of resultsFile.results) {
130
+ if (!result.reachable)
131
+ continue;
132
+ const endpointPath = (_c = result.normalizedPath) !== null && _c !== void 0 ? _c : result.path;
133
+ const endpointId = `endpoint:${result.method.toUpperCase()}:${endpointPath}`;
134
+ if (!context.graph.hasNode(endpointId)) {
135
+ // New endpoint discovered by DAST — add it as a DAST-sourced node
136
+ const node = {
137
+ id: endpointId,
138
+ type: 'endpoint',
139
+ label: `${result.method.toUpperCase()} ${endpointPath}`,
140
+ sourceStage: 'dast',
141
+ metadata: {
142
+ method: result.method.toUpperCase(),
143
+ path: endpointPath,
144
+ statusCode: result.statusCode,
145
+ discoveredBy: 'dast',
146
+ },
147
+ };
148
+ context.graph.addNode(node);
149
+ }
150
+ }
151
+ // Emit conflicts (spec §7)
152
+ const conflicts = (0, conflictEmitter_1.emitDastConflicts)(resultsFile.results, context.graph);
153
+ output.conflictsEmitted = conflicts.length;
154
+ // Add conflict nodes to graph
155
+ for (const conflict of conflicts) {
156
+ const conflictNodeId = conflict.conflictId;
157
+ if (!context.graph.hasNode(conflictNodeId)) {
158
+ const node = {
159
+ id: conflictNodeId,
160
+ type: 'conflict',
161
+ label: `Conflict: ${conflict.type}`,
162
+ sourceStage: 'dast',
163
+ metadata: {
164
+ conflictType: conflict.type,
165
+ stages: conflict.stages,
166
+ detail: conflict.detail,
167
+ suggestedAction: conflict.suggestedAction,
168
+ severity: conflict.severity,
169
+ },
170
+ };
171
+ context.graph.addNode(node);
172
+ // Link conflict to the affected endpoint
173
+ if (context.graph.hasNode(conflict.nodeId)) {
174
+ context.graph.addEdge({
175
+ id: `${conflictNodeId}->conflicts-with->${conflict.nodeId}`,
176
+ type: 'conflicts-with',
177
+ sourceNodeId: conflictNodeId,
178
+ targetNodeId: conflict.nodeId,
179
+ sourceStage: 'dast',
180
+ metadata: { conflictType: conflict.type },
181
+ });
182
+ }
183
+ }
184
+ }
185
+ // Record diagnostics
186
+ const diagnostics = {
187
+ stageName: 'dast',
188
+ filesScanned,
189
+ filesSkipped,
190
+ durationMs: Date.now() - startTime,
191
+ metadata: {
192
+ totalResults: output.results.length,
193
+ confirmedEndpoints: output.confirmedEndpoints.length,
194
+ unreachableEndpoints: output.unreachableEndpoints.length,
195
+ conflictsEmitted: output.conflictsEmitted,
196
+ },
197
+ };
198
+ context.diagnostics.set('dast', diagnostics);
199
+ context.stageOutputs.set('dast', output);
200
+ return output;
201
+ }
202
+ }
203
+ exports.DastStage = DastStage;
@@ -0,0 +1,49 @@
1
+ /**
2
+ * DAST (Dynamic Application Security Testing) stage types.
3
+ *
4
+ * DAST results are produced by an external scanner (e.g. ZAP, Burp)
5
+ * and consumed by this stage to verify endpoint reachability and
6
+ * detect security annotation enforcement gaps.
7
+ */
8
+ /**
9
+ * A single DAST probe result.
10
+ */
11
+ export interface DastProbeResult {
12
+ /** HTTP method probed */
13
+ method: string;
14
+ /** URL path probed */
15
+ path: string;
16
+ /** Normalized path template */
17
+ normalizedPath?: string;
18
+ /** Whether the endpoint was reachable */
19
+ reachable: boolean;
20
+ /** HTTP status code returned */
21
+ statusCode?: number;
22
+ /** Whether authentication was required */
23
+ authRequired?: boolean;
24
+ /** Whether the probe detected an auth bypass */
25
+ authBypass?: boolean;
26
+ /** Whether the response indicated server error */
27
+ serverError?: boolean;
28
+ /** Additional metadata (e.g. response headers, scan tool info) */
29
+ metadata?: Record<string, unknown>;
30
+ }
31
+ /**
32
+ * Shape of the dast-results.json file.
33
+ */
34
+ export interface DastResultsFile {
35
+ results: DastProbeResult[];
36
+ generatedAt?: string;
37
+ scannerVersion?: string;
38
+ targetUrl?: string;
39
+ }
40
+ /**
41
+ * Output of the DAST stage.
42
+ */
43
+ export interface DastOutput {
44
+ results: DastProbeResult[];
45
+ confirmedEndpoints: string[];
46
+ unreachableEndpoints: string[];
47
+ conflictsEmitted: number;
48
+ }
49
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/pipeline/stages/dast/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,yBAAyB;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,sBAAsB;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,+BAA+B;IAC/B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,yCAAyC;IACzC,SAAS,EAAE,OAAO,CAAC;IACnB,gCAAgC;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0CAA0C;IAC1C,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,gDAAgD;IAChD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,kDAAkD;IAClD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,oBAAoB,EAAE,MAAM,EAAE,CAAC;IAC/B,gBAAgB,EAAE,MAAM,CAAC;CAC1B"}
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ /**
3
+ * DAST (Dynamic Application Security Testing) stage types.
4
+ *
5
+ * DAST results are produced by an external scanner (e.g. ZAP, Burp)
6
+ * and consumed by this stage to verify endpoint reachability and
7
+ * detect security annotation enforcement gaps.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,17 @@
1
+ /**
2
+ * IAST Stage — Stage 4 of the coverage pipeline (optional).
3
+ *
4
+ * Reads iast-events.json if present, creates runtime-event nodes in the graph,
5
+ * and upgrades confidence for confirmed endpoints.
6
+ *
7
+ * When this stage is skipped (no IAST data), the pipeline continues
8
+ * in static-only mode with confidence capped at medium.
9
+ */
10
+ import type { PipelineStage, PipelineContext } from '../../stageInterface';
11
+ import type { IastOutput } from './types';
12
+ export declare class IastStage implements PipelineStage<IastOutput> {
13
+ readonly name: "iast";
14
+ readonly optional = true;
15
+ execute(context: PipelineContext): Promise<IastOutput>;
16
+ }
17
+ //# sourceMappingURL=iastStage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"iastStage.d.ts","sourceRoot":"","sources":["../../../../../src/pipeline/stages/iast/iastStage.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE3E,OAAO,KAAK,EAAE,UAAU,EAA6B,MAAM,SAAS,CAAC;AAErE,qBAAa,SAAU,YAAW,aAAa,CAAC,UAAU,CAAC;IACzD,QAAQ,CAAC,IAAI,EAAG,MAAM,CAAU;IAChC,QAAQ,CAAC,QAAQ,QAAQ;IAEnB,OAAO,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,UAAU,CAAC;CAsJ7D"}
@@ -0,0 +1,191 @@
1
+ "use strict";
2
+ /**
3
+ * IAST Stage — Stage 4 of the coverage pipeline (optional).
4
+ *
5
+ * Reads iast-events.json if present, creates runtime-event nodes in the graph,
6
+ * and upgrades confidence for confirmed endpoints.
7
+ *
8
+ * When this stage is skipped (no IAST data), the pipeline continues
9
+ * in static-only mode with confidence capped at medium.
10
+ */
11
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
12
+ if (k2 === undefined) k2 = k;
13
+ var desc = Object.getOwnPropertyDescriptor(m, k);
14
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
15
+ desc = { enumerable: true, get: function() { return m[k]; } };
16
+ }
17
+ Object.defineProperty(o, k2, desc);
18
+ }) : (function(o, m, k, k2) {
19
+ if (k2 === undefined) k2 = k;
20
+ o[k2] = m[k];
21
+ }));
22
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
23
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
24
+ }) : function(o, v) {
25
+ o["default"] = v;
26
+ });
27
+ var __importStar = (this && this.__importStar) || (function () {
28
+ var ownKeys = function(o) {
29
+ ownKeys = Object.getOwnPropertyNames || function (o) {
30
+ var ar = [];
31
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
32
+ return ar;
33
+ };
34
+ return ownKeys(o);
35
+ };
36
+ return function (mod) {
37
+ if (mod && mod.__esModule) return mod;
38
+ var result = {};
39
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
40
+ __setModuleDefault(result, mod);
41
+ return result;
42
+ };
43
+ })();
44
+ Object.defineProperty(exports, "__esModule", { value: true });
45
+ exports.IastStage = void 0;
46
+ const fs = __importStar(require("fs"));
47
+ const path = __importStar(require("path"));
48
+ class IastStage {
49
+ constructor() {
50
+ this.name = 'iast';
51
+ this.optional = true;
52
+ }
53
+ async execute(context) {
54
+ var _a, _b, _c;
55
+ const startTime = Date.now();
56
+ const filesScanned = [];
57
+ const filesSkipped = [];
58
+ const output = {
59
+ events: [],
60
+ confirmedEndpoints: [],
61
+ runtimeEventNodesCreated: 0,
62
+ };
63
+ // Determine the IAST events file path
64
+ const eventsPath = (_a = context.config.iastEventsPath) !== null && _a !== void 0 ? _a : path.join(context.projectRoot, 'iast-events.json');
65
+ // Try to read the events file
66
+ if (!fs.existsSync(eventsPath)) {
67
+ // No IAST data — stage produces empty output (pipeline continues in static-only mode)
68
+ context.diagnostics.set('iast', {
69
+ stageName: 'iast',
70
+ filesScanned,
71
+ filesSkipped: [{ file: eventsPath, reason: 'file-not-found' }],
72
+ durationMs: Date.now() - startTime,
73
+ metadata: { skipped: true, reason: 'no-iast-events-file' },
74
+ });
75
+ context.stageOutputs.set('iast', output);
76
+ return output;
77
+ }
78
+ filesScanned.push(eventsPath);
79
+ let eventsFile;
80
+ try {
81
+ const content = fs.readFileSync(eventsPath, 'utf-8');
82
+ eventsFile = JSON.parse(content);
83
+ }
84
+ catch (err) {
85
+ filesSkipped.push({
86
+ file: eventsPath,
87
+ reason: `parse-error: ${err instanceof Error ? err.message : String(err)}`,
88
+ });
89
+ context.diagnostics.set('iast', {
90
+ stageName: 'iast',
91
+ filesScanned,
92
+ filesSkipped,
93
+ durationMs: Date.now() - startTime,
94
+ metadata: { skipped: true, reason: 'parse-error' },
95
+ });
96
+ context.stageOutputs.set('iast', output);
97
+ return output;
98
+ }
99
+ if (!eventsFile.events || !Array.isArray(eventsFile.events)) {
100
+ filesSkipped.push({ file: eventsPath, reason: 'invalid-format: missing events array' });
101
+ context.diagnostics.set('iast', {
102
+ stageName: 'iast',
103
+ filesScanned,
104
+ filesSkipped,
105
+ durationMs: Date.now() - startTime,
106
+ metadata: { skipped: true, reason: 'invalid-format' },
107
+ });
108
+ context.stageOutputs.set('iast', output);
109
+ return output;
110
+ }
111
+ output.events = eventsFile.events;
112
+ // Process each event: create runtime-event nodes and link to endpoints
113
+ for (const event of eventsFile.events) {
114
+ if (!event.method || !event.path)
115
+ continue;
116
+ const endpointPath = (_b = event.normalizedPath) !== null && _b !== void 0 ? _b : event.path;
117
+ const endpointId = `endpoint:${event.method.toUpperCase()}:${endpointPath}`;
118
+ const nodeId = `runtime-event:iast:${(_c = event.eventId) !== null && _c !== void 0 ? _c : `${event.method}:${event.path}`}`;
119
+ // Create runtime-event node
120
+ if (!context.graph.hasNode(nodeId)) {
121
+ const node = {
122
+ id: nodeId,
123
+ type: 'runtime-event',
124
+ label: `IAST: ${event.method} ${event.path}`,
125
+ sourceStage: 'iast',
126
+ filePath: event.handlerFile,
127
+ metadata: {
128
+ method: event.method,
129
+ path: event.path,
130
+ normalizedPath: event.normalizedPath,
131
+ statusCode: event.statusCode,
132
+ testId: event.testId,
133
+ timestamp: event.timestamp,
134
+ },
135
+ };
136
+ context.graph.addNode(node);
137
+ output.runtimeEventNodesCreated++;
138
+ }
139
+ // Link to endpoint node if it exists
140
+ if (context.graph.hasNode(endpointId)) {
141
+ const edgeId = `${nodeId}->observed-by->${endpointId}`;
142
+ if (!context.graph.hasEdge(edgeId)) {
143
+ context.graph.addEdge({
144
+ id: edgeId,
145
+ type: 'observed-by',
146
+ sourceNodeId: nodeId,
147
+ targetNodeId: endpointId,
148
+ sourceStage: 'iast',
149
+ metadata: { statusCode: event.statusCode },
150
+ });
151
+ }
152
+ if (!output.confirmedEndpoints.includes(endpointId)) {
153
+ output.confirmedEndpoints.push(endpointId);
154
+ }
155
+ }
156
+ // Link to test file if known
157
+ if (event.testId) {
158
+ const testFileId = `file:${event.testId}`;
159
+ if (context.graph.hasNode(testFileId)) {
160
+ const edgeId = `${testFileId}->executes->${nodeId}`;
161
+ if (!context.graph.hasEdge(edgeId)) {
162
+ context.graph.addEdge({
163
+ id: edgeId,
164
+ type: 'executes',
165
+ sourceNodeId: testFileId,
166
+ targetNodeId: nodeId,
167
+ sourceStage: 'iast',
168
+ metadata: {},
169
+ });
170
+ }
171
+ }
172
+ }
173
+ }
174
+ // Record diagnostics
175
+ const diagnostics = {
176
+ stageName: 'iast',
177
+ filesScanned,
178
+ filesSkipped,
179
+ durationMs: Date.now() - startTime,
180
+ metadata: {
181
+ totalEvents: output.events.length,
182
+ confirmedEndpoints: output.confirmedEndpoints.length,
183
+ runtimeEventNodesCreated: output.runtimeEventNodesCreated,
184
+ },
185
+ };
186
+ context.diagnostics.set('iast', diagnostics);
187
+ context.stageOutputs.set('iast', output);
188
+ return output;
189
+ }
190
+ }
191
+ exports.IastStage = IastStage;
@@ -0,0 +1,48 @@
1
+ /**
2
+ * IAST (Interactive Application Security Testing) stage types.
3
+ *
4
+ * IAST events are produced by an external runtime agent and consumed
5
+ * by this stage to confirm code paths observed during test execution.
6
+ */
7
+ /**
8
+ * A single IAST event recording a runtime observation.
9
+ */
10
+ export interface IastEvent {
11
+ /** Unique event identifier */
12
+ eventId: string;
13
+ /** HTTP method observed */
14
+ method: string;
15
+ /** URL path observed */
16
+ path: string;
17
+ /** Normalized path template (e.g. /users/{id}) */
18
+ normalizedPath?: string;
19
+ /** Timestamp of the observation */
20
+ timestamp?: string;
21
+ /** Test that triggered this event (if known) */
22
+ testId?: string;
23
+ /** Source file of the handler (if known) */
24
+ handlerFile?: string;
25
+ /** Handler function name (if known) */
26
+ handlerFunction?: string;
27
+ /** HTTP status code observed */
28
+ statusCode?: number;
29
+ /** Additional metadata */
30
+ metadata?: Record<string, unknown>;
31
+ }
32
+ /**
33
+ * Shape of the iast-events.json file.
34
+ */
35
+ export interface IastEventsFile {
36
+ events: IastEvent[];
37
+ generatedAt?: string;
38
+ agentVersion?: string;
39
+ }
40
+ /**
41
+ * Output of the IAST stage.
42
+ */
43
+ export interface IastOutput {
44
+ events: IastEvent[];
45
+ confirmedEndpoints: string[];
46
+ runtimeEventNodesCreated: number;
47
+ }
48
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/pipeline/stages/iast/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,8BAA8B;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,2BAA2B;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,wBAAwB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,kDAAkD;IAClD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,mCAAmC;IACnC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gDAAgD;IAChD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uCAAuC;IACvC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gCAAgC;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0BAA0B;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,wBAAwB,EAAE,MAAM,CAAC;CAClC"}
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ /**
3
+ * IAST (Interactive Application Security Testing) stage types.
4
+ *
5
+ * IAST events are produced by an external runtime agent and consumed
6
+ * by this stage to confirm code paths observed during test execution.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Conflict detector — detects stage disagreements and structural conflicts
3
+ * in the knowledge graph after all stages have run.
4
+ *
5
+ * Detects:
6
+ * - Runtime-unconfirmed: AST+TIA say covered, but IAST/DAST disagree
7
+ * - Stage disagreement: Two stages assign different types to the same node
8
+ */
9
+ import type { ConflictNode } from '../../types';
10
+ import type { CoverageKnowledgeGraph } from '../../graph';
11
+ import type { IastOutput } from '../iast/types';
12
+ import type { DastOutput } from '../dast/types';
13
+ /**
14
+ * Detect conflicts across all stages.
15
+ */
16
+ export declare function detectConflicts(graph: CoverageKnowledgeGraph, iastOutput: IastOutput | undefined, dastOutput: DastOutput | undefined): ConflictNode[];
17
+ //# sourceMappingURL=conflictDetector.d.ts.map