api-tests-coverage 1.0.15 → 1.0.17

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 (139) hide show
  1. package/dist/dashboard/dist/assets/_basePickBy-C2jmWITn.js +1 -0
  2. package/dist/dashboard/dist/assets/_baseUniq-DE6cyzJb.js +1 -0
  3. package/dist/dashboard/dist/assets/arc-B-Q4nGPT.js +1 -0
  4. package/dist/dashboard/dist/assets/architectureDiagram-VXUJARFQ-C_5dqWCI.js +36 -0
  5. package/dist/dashboard/dist/assets/blockDiagram-VD42YOAC-DbGIO6Kt.js +122 -0
  6. package/dist/dashboard/dist/assets/c4Diagram-YG6GDRKO-CAFpcejP.js +10 -0
  7. package/dist/dashboard/dist/assets/channel-Di9el3wE.js +1 -0
  8. package/dist/dashboard/dist/assets/chunk-4BX2VUAB-DY1boKsq.js +1 -0
  9. package/dist/dashboard/dist/assets/chunk-55IACEB6-BSL35gyW.js +1 -0
  10. package/dist/dashboard/dist/assets/chunk-B4BG7PRW-eTDXrKrv.js +165 -0
  11. package/dist/dashboard/dist/assets/chunk-DI55MBZ5-M-8I3jEy.js +220 -0
  12. package/dist/dashboard/dist/assets/chunk-FMBD7UC4-bSA0XiS0.js +15 -0
  13. package/dist/dashboard/dist/assets/chunk-QN33PNHL-BrOIYUBs.js +1 -0
  14. package/dist/dashboard/dist/assets/chunk-QZHKN3VN-CliaQGD4.js +1 -0
  15. package/dist/dashboard/dist/assets/chunk-TZMSLE5B-CyhcxGB1.js +1 -0
  16. package/dist/dashboard/dist/assets/classDiagram-2ON5EDUG-BkGN4Cpz.js +1 -0
  17. package/dist/dashboard/dist/assets/classDiagram-v2-WZHVMYZB-BkGN4Cpz.js +1 -0
  18. package/dist/dashboard/dist/assets/clone-Cvq8JuOb.js +1 -0
  19. package/dist/dashboard/dist/assets/cose-bilkent-S5V4N54A-BUkL7Wtq.js +1 -0
  20. package/dist/dashboard/dist/assets/dagre-6UL2VRFP-B8oEROJc.js +4 -0
  21. package/dist/dashboard/dist/assets/diagram-PSM6KHXK-5uki9Dw8.js +24 -0
  22. package/dist/dashboard/dist/assets/diagram-QEK2KX5R-BRNhmby2.js +43 -0
  23. package/dist/dashboard/dist/assets/diagram-S2PKOQOG-D-ku_X8U.js +24 -0
  24. package/dist/dashboard/dist/assets/erDiagram-Q2GNP2WA-DGl6gPe2.js +60 -0
  25. package/dist/dashboard/dist/assets/flowDiagram-NV44I4VS-Co89qYBD.js +162 -0
  26. package/dist/dashboard/dist/assets/ganttDiagram-JELNMOA3-2r3WpWQC.js +267 -0
  27. package/dist/dashboard/dist/assets/gitGraphDiagram-V2S2FVAM-CuJ5l3TK.js +65 -0
  28. package/dist/dashboard/dist/assets/graph-ZtgwAPQj.js +1 -0
  29. package/dist/dashboard/dist/assets/index-D3sRJga7.js +777 -0
  30. package/dist/dashboard/dist/assets/infoDiagram-HS3SLOUP-ujnMqVz3.js +2 -0
  31. package/dist/dashboard/dist/assets/journeyDiagram-XKPGCS4Q-DQzfeBIo.js +139 -0
  32. package/dist/dashboard/dist/assets/kanban-definition-3W4ZIXB7-ueIaoeks.js +89 -0
  33. package/dist/dashboard/dist/assets/layout-B1fTYUMj.js +1 -0
  34. package/dist/dashboard/dist/assets/mindmap-definition-VGOIOE7T-B7wYeLe1.js +68 -0
  35. package/dist/dashboard/dist/assets/pieDiagram-ADFJNKIX-Bf8vKEOf.js +30 -0
  36. package/dist/dashboard/dist/assets/quadrantDiagram-AYHSOK5B-CM8qiFLR.js +7 -0
  37. package/dist/dashboard/dist/assets/requirementDiagram-UZGBJVZJ-DPTtP4Ve.js +64 -0
  38. package/dist/dashboard/dist/assets/sankeyDiagram-TZEHDZUN-DEVTdH0h.js +10 -0
  39. package/dist/dashboard/dist/assets/sequenceDiagram-WL72ISMW-Bjr5wgXg.js +145 -0
  40. package/dist/dashboard/dist/assets/stateDiagram-FKZM4ZOC-DDrhZYly.js +1 -0
  41. package/dist/dashboard/dist/assets/stateDiagram-v2-4FDKWEC3-Im6pH8C-.js +1 -0
  42. package/dist/dashboard/dist/assets/timeline-definition-IT6M3QCI-DAT3r9va.js +61 -0
  43. package/dist/dashboard/dist/assets/treemap-GDKQZRPO-BlA8rg0m.js +162 -0
  44. package/dist/dashboard/dist/assets/xychartDiagram-PRI3JC2R-7aSkQtVu.js +7 -0
  45. package/dist/src/ast/astTypes.d.ts +86 -0
  46. package/dist/src/ast/astTypes.d.ts.map +1 -1
  47. package/dist/src/discovery/fileClassifier.d.ts.map +1 -1
  48. package/dist/src/discovery/fileClassifier.js +15 -16
  49. package/dist/src/discovery/frameworkDetector.d.ts +28 -0
  50. package/dist/src/discovery/frameworkDetector.d.ts.map +1 -0
  51. package/dist/src/discovery/frameworkDetector.js +189 -0
  52. package/dist/src/discovery/projectDiscovery.d.ts +5 -1
  53. package/dist/src/discovery/projectDiscovery.d.ts.map +1 -1
  54. package/dist/src/discovery/projectDiscovery.js +8 -1
  55. package/dist/src/inference/routeInference.d.ts.map +1 -1
  56. package/dist/src/inference/routeInference.js +224 -1
  57. package/dist/src/languages/java/graphqlSchemaParser.d.ts +65 -0
  58. package/dist/src/languages/java/graphqlSchemaParser.d.ts.map +1 -0
  59. package/dist/src/languages/java/graphqlSchemaParser.js +164 -0
  60. package/dist/src/languages/java/mybatisXmlParser.d.ts +52 -0
  61. package/dist/src/languages/java/mybatisXmlParser.d.ts.map +1 -0
  62. package/dist/src/languages/java/mybatisXmlParser.js +107 -0
  63. package/dist/src/languages/java/semanticBuilder.d.ts.map +1 -1
  64. package/dist/src/languages/java/semanticBuilder.js +69 -12
  65. package/dist/src/languages/javascript/angularDetector.d.ts +74 -0
  66. package/dist/src/languages/javascript/angularDetector.d.ts.map +1 -0
  67. package/dist/src/languages/javascript/angularDetector.js +227 -0
  68. package/dist/src/languages/javascript/assertionResolver.js +6 -4
  69. package/dist/src/languages/javascript/hapiDetector.d.ts +40 -0
  70. package/dist/src/languages/javascript/hapiDetector.d.ts.map +1 -0
  71. package/dist/src/languages/javascript/hapiDetector.js +174 -0
  72. package/dist/src/languages/javascript/mongooseDetector.d.ts +65 -0
  73. package/dist/src/languages/javascript/mongooseDetector.d.ts.map +1 -0
  74. package/dist/src/languages/javascript/mongooseDetector.js +237 -0
  75. package/dist/src/languages/javascript/vueDetector.d.ts +42 -0
  76. package/dist/src/languages/javascript/vueDetector.d.ts.map +1 -0
  77. package/dist/src/languages/javascript/vueDetector.js +109 -0
  78. package/dist/src/languages/python/index.d.ts +6 -2
  79. package/dist/src/languages/python/index.d.ts.map +1 -1
  80. package/dist/src/languages/python/index.js +200 -5
  81. package/dist/src/languages/python/testPatternDetector.d.ts +70 -0
  82. package/dist/src/languages/python/testPatternDetector.d.ts.map +1 -0
  83. package/dist/src/languages/python/testPatternDetector.js +201 -0
  84. package/dist/src/pipeline/confidence.d.ts +6 -1
  85. package/dist/src/pipeline/confidence.d.ts.map +1 -1
  86. package/dist/src/pipeline/confidence.js +8 -3
  87. package/dist/src/pipeline/graph.d.ts.map +1 -1
  88. package/dist/src/pipeline/graph.js +16 -4
  89. package/dist/src/pipeline/stages/ast/astStage.d.ts.map +1 -1
  90. package/dist/src/pipeline/stages/ast/astStage.js +51 -1
  91. package/dist/src/pipeline/stages/ast/baseUrlComposer.d.ts +44 -0
  92. package/dist/src/pipeline/stages/ast/baseUrlComposer.d.ts.map +1 -0
  93. package/dist/src/pipeline/stages/ast/baseUrlComposer.js +97 -0
  94. package/dist/src/pipeline/stages/ast/crossFileResolutionPass.d.ts +54 -0
  95. package/dist/src/pipeline/stages/ast/crossFileResolutionPass.d.ts.map +1 -0
  96. package/dist/src/pipeline/stages/ast/crossFileResolutionPass.js +88 -0
  97. package/dist/src/pipeline/stages/ast/crossFileResolver.d.ts.map +1 -1
  98. package/dist/src/pipeline/stages/ast/crossFileResolver.js +39 -1
  99. package/dist/src/pipeline/stages/ast/graphBuilder.d.ts.map +1 -1
  100. package/dist/src/pipeline/stages/ast/graphBuilder.js +81 -0
  101. package/dist/src/pipeline/stages/ast/optionalAuthUnifier.d.ts +41 -0
  102. package/dist/src/pipeline/stages/ast/optionalAuthUnifier.d.ts.map +1 -0
  103. package/dist/src/pipeline/stages/ast/optionalAuthUnifier.js +101 -0
  104. package/dist/src/pipeline/stages/ast/resolvers/angularInjectionResolver.d.ts +18 -0
  105. package/dist/src/pipeline/stages/ast/resolvers/angularInjectionResolver.d.ts.map +1 -0
  106. package/dist/src/pipeline/stages/ast/resolvers/angularInjectionResolver.js +96 -0
  107. package/dist/src/pipeline/stages/ast/resolvers/dddLayerResolver.d.ts +46 -0
  108. package/dist/src/pipeline/stages/ast/resolvers/dddLayerResolver.d.ts.map +1 -0
  109. package/dist/src/pipeline/stages/ast/resolvers/dddLayerResolver.js +314 -0
  110. package/dist/src/pipeline/stages/ast/resolvers/expressRouterResolver.d.ts +17 -0
  111. package/dist/src/pipeline/stages/ast/resolvers/expressRouterResolver.d.ts.map +1 -0
  112. package/dist/src/pipeline/stages/ast/resolvers/expressRouterResolver.js +65 -0
  113. package/dist/src/pipeline/stages/ast/resolvers/flaskBlueprintResolver.d.ts +17 -0
  114. package/dist/src/pipeline/stages/ast/resolvers/flaskBlueprintResolver.d.ts.map +1 -0
  115. package/dist/src/pipeline/stages/ast/resolvers/flaskBlueprintResolver.js +114 -0
  116. package/dist/src/pipeline/stages/ast/resolvers/mybatisResolver.d.ts +27 -0
  117. package/dist/src/pipeline/stages/ast/resolvers/mybatisResolver.d.ts.map +1 -0
  118. package/dist/src/pipeline/stages/ast/resolvers/mybatisResolver.js +130 -0
  119. package/dist/src/pipeline/stages/ast/resolvers/vuexActionResolver.d.ts +17 -0
  120. package/dist/src/pipeline/stages/ast/resolvers/vuexActionResolver.d.ts.map +1 -0
  121. package/dist/src/pipeline/stages/ast/resolvers/vuexActionResolver.js +80 -0
  122. package/dist/src/pipeline/stages/ast/rulesEnforcer.d.ts +24 -0
  123. package/dist/src/pipeline/stages/ast/rulesEnforcer.d.ts.map +1 -0
  124. package/dist/src/pipeline/stages/ast/rulesEnforcer.js +411 -0
  125. package/dist/src/pipeline/stages/ast/types.d.ts +114 -1
  126. package/dist/src/pipeline/stages/ast/types.d.ts.map +1 -1
  127. package/dist/src/pipeline/stages/merge/conflictDetector.d.ts +2 -0
  128. package/dist/src/pipeline/stages/merge/conflictDetector.d.ts.map +1 -1
  129. package/dist/src/pipeline/stages/merge/conflictDetector.js +54 -2
  130. package/dist/src/pipeline/stages/merge/coverageMappingBuilder.d.ts.map +1 -1
  131. package/dist/src/pipeline/stages/merge/coverageMappingBuilder.js +67 -3
  132. package/dist/src/pipeline/stages/tia/mockBoundaryDetector.d.ts.map +1 -1
  133. package/dist/src/pipeline/stages/tia/mockBoundaryDetector.js +8 -1
  134. package/dist/src/pipeline/stages/tia/parameterizedTestExpander.js +8 -4
  135. package/dist/src/pipeline/stages/tia/testLayerClassifier.d.ts.map +1 -1
  136. package/dist/src/pipeline/stages/tia/testLayerClassifier.js +41 -10
  137. package/dist/src/pipeline/types.d.ts +1 -1
  138. package/dist/src/pipeline/types.d.ts.map +1 -1
  139. package/package.json +3 -3
@@ -0,0 +1,411 @@
1
+ "use strict";
2
+ /**
3
+ * Structure-agnostic rules enforcer (Feature 27, Sub-PR 9)
4
+ *
5
+ * Validates the 10 behavioral rules (SA01-SA10) after all resolution completes.
6
+ * Emits diagnostics for violations.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.enforceStructureAgnosticRules = enforceStructureAgnosticRules;
10
+ /**
11
+ * Run all SA rules against the resolved symbol table.
12
+ */
13
+ function enforceStructureAgnosticRules(symbolTable, projectRoot) {
14
+ const violations = [];
15
+ let rulesChecked = 0;
16
+ let rulesPassed = 0;
17
+ const checks = [
18
+ { id: 'SA01', fn: () => checkRuleSA01(symbolTable, projectRoot) },
19
+ { id: 'SA02', fn: () => checkRuleSA02(symbolTable) },
20
+ { id: 'SA03', fn: () => checkRuleSA03(symbolTable) },
21
+ { id: 'SA04', fn: () => checkRuleSA04(symbolTable) },
22
+ { id: 'SA05', fn: () => checkRuleSA05(symbolTable) },
23
+ { id: 'SA06', fn: () => checkRuleSA06(symbolTable) },
24
+ { id: 'SA07', fn: () => checkRuleSA07(symbolTable) },
25
+ { id: 'SA08', fn: () => checkRuleSA08(symbolTable) },
26
+ { id: 'SA09', fn: () => checkRuleSA09(symbolTable) },
27
+ { id: 'SA10', fn: () => checkRuleSA10(symbolTable) },
28
+ ];
29
+ for (const check of checks) {
30
+ rulesChecked++;
31
+ const ruleViolations = check.fn();
32
+ violations.push(...ruleViolations);
33
+ if (ruleViolations.length === 0)
34
+ rulesPassed++;
35
+ }
36
+ return { violations, rulesChecked, rulesPassed };
37
+ }
38
+ /**
39
+ * RULE-SA01: No endpoint nodes should be classified based on directory name alone.
40
+ * Checks that route registrations have content-based evidence, not just path-based.
41
+ */
42
+ function checkRuleSA01(symbolTable, projectRoot) {
43
+ const violations = [];
44
+ // Check route registrations for directory-only evidence
45
+ for (const [filePath, model] of symbolTable.models) {
46
+ if (!model.routeRegistrations)
47
+ continue;
48
+ for (const reg of model.routeRegistrations) {
49
+ // A route with no registrar (no decorator, no app.route, no router.METHOD)
50
+ // that was classified solely from its directory path is a violation
51
+ if (!reg.registrarName && !reg.methods && !reg.security) {
52
+ violations.push({
53
+ ruleId: 'SA01',
54
+ severity: 'error',
55
+ message: `Route '${reg.path}' in ${filePath} appears to lack content-based evidence`,
56
+ filePath,
57
+ line: reg.line,
58
+ });
59
+ }
60
+ }
61
+ }
62
+ return violations;
63
+ }
64
+ /**
65
+ * RULE-SA02: All endpoint nodes must have fully resolved URLs.
66
+ * Checks for router mounts with empty or partial prefixes.
67
+ */
68
+ function checkRuleSA02(symbolTable) {
69
+ const violations = [];
70
+ for (const [filePath, mounts] of symbolTable.routerMounts) {
71
+ for (const mount of mounts) {
72
+ if (!mount.prefix || mount.prefix === '/') {
73
+ // Empty or root prefix is only a warning if there's a target module
74
+ if (mount.targetModulePath) {
75
+ violations.push({
76
+ ruleId: 'SA02',
77
+ severity: 'warning',
78
+ message: `Router mount in ${filePath} has empty prefix for target '${mount.targetModulePath}'`,
79
+ filePath,
80
+ line: mount.line,
81
+ });
82
+ }
83
+ }
84
+ }
85
+ }
86
+ return violations;
87
+ }
88
+ /**
89
+ * RULE-SA03: Service/repository nodes must be detected without requiring framework annotations.
90
+ * Checks that interface implementations exist in the symbol table for projects that have
91
+ * classes following DDD patterns (Repository, Store, Gateway naming or method patterns).
92
+ */
93
+ function checkRuleSA03(symbolTable) {
94
+ const violations = [];
95
+ // Find classes that look like repositories by naming convention
96
+ const repoLikeClasses = [];
97
+ for (const [className, classDecl] of symbolTable.classes) {
98
+ if (/(?:Repository|Repo|Store|Gateway)$/i.test(className)) {
99
+ repoLikeClasses.push(className);
100
+ }
101
+ }
102
+ // If there are repository-like classes, check that at least some have interface implementations resolved
103
+ if (repoLikeClasses.length > 0) {
104
+ let hasAnyImpl = false;
105
+ for (const [, impls] of symbolTable.interfaceImplementations) {
106
+ if (impls.length > 0) {
107
+ hasAnyImpl = true;
108
+ break;
109
+ }
110
+ }
111
+ if (!hasAnyImpl && repoLikeClasses.length >= 2) {
112
+ violations.push({
113
+ ruleId: 'SA03',
114
+ severity: 'warning',
115
+ message: `Found ${repoLikeClasses.length} repository-like class(es) but no interface→implementation mappings resolved`,
116
+ });
117
+ }
118
+ }
119
+ return violations;
120
+ }
121
+ /**
122
+ * RULE-SA04: Optional auth must be distinguished from public.
123
+ * Checks that models with route registrations having security classifications
124
+ * properly distinguish between required, optional, and public.
125
+ */
126
+ function checkRuleSA04(symbolTable) {
127
+ const violations = [];
128
+ for (const [filePath, model] of symbolTable.models) {
129
+ if (!model.routeRegistrations)
130
+ continue;
131
+ for (const reg of model.routeRegistrations) {
132
+ if (reg.security) {
133
+ // Validate that optional and required are mutually exclusive
134
+ if (reg.security.required && reg.security.optional) {
135
+ violations.push({
136
+ ruleId: 'SA04',
137
+ severity: 'error',
138
+ message: `Route '${reg.path}' in ${filePath} has both required=true and optional=true`,
139
+ filePath,
140
+ line: reg.line,
141
+ });
142
+ }
143
+ }
144
+ }
145
+ }
146
+ return violations;
147
+ }
148
+ /**
149
+ * RULE-SA05: @Mapper interfaces must be linked to their XML mapper files.
150
+ * Checks that all interface implementations with MyBatis naming have corresponding XML bindings.
151
+ */
152
+ function checkRuleSA05(symbolTable) {
153
+ const violations = [];
154
+ // Find @Mapper-like classes (by naming convention or annotations)
155
+ for (const [className, classDecl] of symbolTable.classes) {
156
+ if (!className.endsWith('Mapper'))
157
+ continue;
158
+ // Check if this mapper has a corresponding interface implementation (XML binding)
159
+ let hasBinding = false;
160
+ for (const [, impls] of symbolTable.interfaceImplementations) {
161
+ if (impls.some((impl) => impl.interfaceName === className || impl.implName.includes(className))) {
162
+ hasBinding = true;
163
+ break;
164
+ }
165
+ }
166
+ // Check if there are any models with MyBatis-related content
167
+ const model = symbolTable.models.get(classDecl.filePath);
168
+ if (model && !hasBinding) {
169
+ // Only warn if the project appears to use MyBatis (has XML-linked implementations)
170
+ let projectUsesMyBatis = false;
171
+ for (const [, impls] of symbolTable.interfaceImplementations) {
172
+ if (impls.some((impl) => impl.implName.includes('XmlMapper'))) {
173
+ projectUsesMyBatis = true;
174
+ break;
175
+ }
176
+ }
177
+ if (projectUsesMyBatis) {
178
+ violations.push({
179
+ ruleId: 'SA05',
180
+ severity: 'warning',
181
+ message: `@Mapper interface '${className}' in ${classDecl.filePath} has no linked XML mapper`,
182
+ filePath: classDecl.filePath,
183
+ line: classDecl.line,
184
+ });
185
+ }
186
+ }
187
+ }
188
+ return violations;
189
+ }
190
+ /**
191
+ * RULE-SA06: .graphqls schema files must be parsed as first-class endpoint definitions.
192
+ * Checks that GraphQL schemas produce endpoint nodes when present.
193
+ */
194
+ function checkRuleSA06(symbolTable) {
195
+ const violations = [];
196
+ // Check if there are any .graphqls or .graphql files in the models that lack route registrations
197
+ for (const [filePath, model] of symbolTable.models) {
198
+ if (!filePath.endsWith('.graphqls') && !filePath.endsWith('.graphql'))
199
+ continue;
200
+ // GraphQL schema files should produce route registrations
201
+ if (!model.routeRegistrations || model.routeRegistrations.length === 0) {
202
+ violations.push({
203
+ ruleId: 'SA06',
204
+ severity: 'warning',
205
+ message: `GraphQL schema file '${filePath}' was not parsed into endpoint definitions`,
206
+ filePath,
207
+ });
208
+ }
209
+ }
210
+ return violations;
211
+ }
212
+ /**
213
+ * RULE-SA07: Angular HttpClient calls in @Injectable services must be followed through injection.
214
+ * Checks that services with HTTP calls have injection chains linking them to consumers.
215
+ */
216
+ function checkRuleSA07(symbolTable) {
217
+ var _a, _b;
218
+ const violations = [];
219
+ // Find services with HTTP calls that have no injection chain consumers
220
+ for (const [className, classDecl] of symbolTable.classes) {
221
+ const model = symbolTable.models.get(classDecl.filePath);
222
+ if (!model)
223
+ continue;
224
+ // Check if this class has methods with HTTP calls
225
+ let hasHttpCalls = false;
226
+ for (const [, func] of model.functions) {
227
+ if (func.bodyHttpCalls.length > 0) {
228
+ hasHttpCalls = true;
229
+ break;
230
+ }
231
+ }
232
+ if (!hasHttpCalls)
233
+ continue;
234
+ // Content-based check: is this an Angular @Injectable service?
235
+ // (RULE-SA01 compliant — no filename convention used)
236
+ const hasInjectableMarker = ((_b = (_a = model.decoratorStacks) === null || _a === void 0 ? void 0 : _a.some((ds) => ds.decorators.some((d) => d.name === 'Injectable' || d.name.includes('Injectable')))) !== null && _b !== void 0 ? _b : false) ||
237
+ Array.from(model.functions.values()).some((f) => { var _a; return (_a = f.annotations) === null || _a === void 0 ? void 0 : _a.some((a) => a === 'Injectable' || a === '@Injectable'); });
238
+ if (!hasInjectableMarker)
239
+ continue;
240
+ // Check if any injection chains reference this service
241
+ let hasConsumer = false;
242
+ for (const [, chains] of symbolTable.injectionChains) {
243
+ if (chains.some((c) => c.serviceClass === className)) {
244
+ hasConsumer = true;
245
+ break;
246
+ }
247
+ }
248
+ if (!hasConsumer) {
249
+ violations.push({
250
+ ruleId: 'SA07',
251
+ severity: 'info',
252
+ message: `Angular service '${className}' in ${classDecl.filePath} has HTTP calls but no resolved injection consumers`,
253
+ filePath: classDecl.filePath,
254
+ line: classDecl.line,
255
+ });
256
+ }
257
+ }
258
+ return violations;
259
+ }
260
+ /**
261
+ * RULE-SA08: Vuex dispatch calls must be linked to store action definitions.
262
+ * Checks that dispatch calls have corresponding injection chain entries.
263
+ */
264
+ function checkRuleSA08(symbolTable) {
265
+ const violations = [];
266
+ // Find models with dispatch calls that have no injection chain linking
267
+ for (const [filePath, model] of symbolTable.models) {
268
+ let hasDispatch = false;
269
+ for (const [, func] of model.functions) {
270
+ if (func.calledFunctions.some((f) => f.includes('dispatch'))) {
271
+ hasDispatch = true;
272
+ break;
273
+ }
274
+ }
275
+ if (!hasDispatch)
276
+ continue;
277
+ // Check if there's an injection chain linking this file to a store
278
+ const chains = symbolTable.injectionChains.get(filePath);
279
+ if (!chains || chains.length === 0) {
280
+ // Only warn if the project has Vuex store files (files with both actions and HTTP calls)
281
+ let hasStoreFiles = false;
282
+ for (const [otherFile, otherModel] of symbolTable.models) {
283
+ if (otherFile === filePath)
284
+ continue;
285
+ for (const [, func] of otherModel.functions) {
286
+ if (func.bodyHttpCalls.length > 0) {
287
+ hasStoreFiles = true;
288
+ break;
289
+ }
290
+ }
291
+ if (hasStoreFiles)
292
+ break;
293
+ }
294
+ if (hasStoreFiles) {
295
+ violations.push({
296
+ ruleId: 'SA08',
297
+ severity: 'info',
298
+ message: `File '${filePath}' dispatches Vuex actions but no dispatch→action links were resolved`,
299
+ filePath,
300
+ });
301
+ }
302
+ }
303
+ }
304
+ return violations;
305
+ }
306
+ /**
307
+ * RULE-SA09: Functional Angular guards (CanActivateFn) must be detected.
308
+ * Checks that guard files are recognized and linked to routes.
309
+ */
310
+ function checkRuleSA09(symbolTable) {
311
+ var _a, _b;
312
+ const violations = [];
313
+ // Find files with Angular guard-related content (content-based, not filename-based)
314
+ for (const [filePath, model] of symbolTable.models) {
315
+ // Content-based check: does this file have guard-related types or implementations?
316
+ // (RULE-SA01 compliant — no filename convention used)
317
+ let hasGuardContent = false;
318
+ // Check function annotations for guard type markers (CanActivateFn, etc.)
319
+ const guardTypeAnnotations = [
320
+ 'CanActivateFn',
321
+ 'CanActivateChildFn',
322
+ 'CanDeactivateFn',
323
+ 'ResolveFn',
324
+ 'CanMatchFn',
325
+ ];
326
+ for (const [, func] of model.functions) {
327
+ if ((_a = func.annotations) === null || _a === void 0 ? void 0 : _a.some((a) => guardTypeAnnotations.includes(a))) {
328
+ hasGuardContent = true;
329
+ break;
330
+ }
331
+ }
332
+ // Check if any class in this file implements guard interfaces
333
+ if (!hasGuardContent) {
334
+ const guardInterfaces = [
335
+ 'CanActivate',
336
+ 'CanActivateChild',
337
+ 'CanDeactivate',
338
+ 'Resolve',
339
+ 'CanMatch',
340
+ ];
341
+ for (const [, classDecl] of symbolTable.classes) {
342
+ if (classDecl.filePath === filePath &&
343
+ ((_b = classDecl.implementsInterfaces) === null || _b === void 0 ? void 0 : _b.some((i) => guardInterfaces.includes(i)))) {
344
+ hasGuardContent = true;
345
+ break;
346
+ }
347
+ }
348
+ }
349
+ // Check function names for guard-related patterns as content heuristic
350
+ if (!hasGuardContent) {
351
+ for (const [funcName] of model.functions) {
352
+ if (/guard|canActivate|canDeactivate|canMatch/i.test(funcName)) {
353
+ hasGuardContent = true;
354
+ break;
355
+ }
356
+ }
357
+ }
358
+ if (!hasGuardContent)
359
+ continue;
360
+ // Check if this guard has any route registrations or middleware entries
361
+ let isLinked = false;
362
+ for (const [, middleware] of symbolTable.middlewareInheritance) {
363
+ if (middleware.some((m) => m.sourceFile === filePath || m.name.includes('guard'))) {
364
+ isLinked = true;
365
+ break;
366
+ }
367
+ }
368
+ if (!isLinked) {
369
+ // Check if there's at least a function export that looks like a guard
370
+ let hasGuardFunction = false;
371
+ for (const [funcName] of model.functions) {
372
+ if (/guard|canActivate|canDeactivate|canMatch/i.test(funcName)) {
373
+ hasGuardFunction = true;
374
+ break;
375
+ }
376
+ }
377
+ if (hasGuardFunction) {
378
+ violations.push({
379
+ ruleId: 'SA09',
380
+ severity: 'info',
381
+ message: `Angular guard in '${filePath}' has guard functions but is not linked to any route`,
382
+ filePath,
383
+ });
384
+ }
385
+ }
386
+ }
387
+ return violations;
388
+ }
389
+ /**
390
+ * RULE-SA10: webtest/TestApp must be detected as API test evidence.
391
+ * Checks that files using webtest patterns have their HTTP calls extracted.
392
+ */
393
+ function checkRuleSA10(symbolTable) {
394
+ const violations = [];
395
+ for (const [filePath, model] of symbolTable.models) {
396
+ // Check if this model has webtest-detected calls (via the __webtest_calls__ synthetic function)
397
+ const webtestFunc = model.functions.get('__webtest_calls__');
398
+ if (!webtestFunc)
399
+ continue;
400
+ // Verify the webtest calls actually produced HTTP call entries
401
+ if (webtestFunc.bodyHttpCalls.length === 0) {
402
+ violations.push({
403
+ ruleId: 'SA10',
404
+ severity: 'warning',
405
+ message: `File '${filePath}' has webtest detection but produced no HTTP call entries`,
406
+ filePath,
407
+ });
408
+ }
409
+ }
410
+ return violations;
411
+ }
@@ -1,8 +1,9 @@
1
1
  /**
2
2
  * AST stage types — cross-file analysis, import resolution, and abstract layer traversal.
3
3
  */
4
- import type { SemanticModel, SemanticHttpCall, SemanticAssertion } from '../../../ast/astTypes';
4
+ import type { SemanticModel, SemanticHttpCall, SemanticAssertion, SecurityClassification } from '../../../ast/astTypes';
5
5
  import type { AssertionSource } from '../../types';
6
+ import type { DetectedApiFramework } from '../../../discovery/frameworkDetector';
6
7
  /**
7
8
  * An import declaration extracted from a source file.
8
9
  */
@@ -29,6 +30,62 @@ export interface ClassDeclaration {
29
30
  filePath: string;
30
31
  line?: number;
31
32
  }
33
+ /**
34
+ * A router mount point: app.use('/prefix', router) or register_blueprint(bp, url_prefix=...)
35
+ */
36
+ export interface RouterMount {
37
+ /** URL prefix being mounted */
38
+ prefix: string;
39
+ /** Path to the target module/file being mounted */
40
+ targetModulePath: string;
41
+ /** Middleware applied at this mount point */
42
+ middleware: MiddlewareEntry[];
43
+ sourceFile: string;
44
+ line?: number;
45
+ }
46
+ /**
47
+ * An Angular/Vue/React injection chain: component → service → HTTP call
48
+ */
49
+ export interface InjectionChain {
50
+ /** File containing the consumer (component) */
51
+ consumerFile: string;
52
+ /** Class name of the consumer */
53
+ consumerClass: string;
54
+ /** Class name of the injected service */
55
+ serviceClass: string;
56
+ /** File containing the service */
57
+ serviceFile: string;
58
+ /** How injection was detected */
59
+ injectionStyle: 'constructor' | 'inject-fn' | 'decorator' | 'property';
60
+ }
61
+ /**
62
+ * A middleware entry in a chain (auth, validation, error handling)
63
+ */
64
+ export interface MiddlewareEntry {
65
+ /** Middleware name or identifier */
66
+ name: string;
67
+ /** Classified type */
68
+ type: 'auth-required' | 'auth-optional' | 'validation' | 'error-handler' | 'custom';
69
+ /** Whether this applies to an entire router or a single route */
70
+ appliedTo: 'router' | 'route';
71
+ /** Security classification if this is an auth middleware */
72
+ security?: SecurityClassification;
73
+ sourceFile: string;
74
+ line?: number;
75
+ }
76
+ /**
77
+ * A domain interface → infrastructure implementation mapping (DDD)
78
+ */
79
+ export interface InterfaceImpl {
80
+ /** Fully qualified interface name */
81
+ interfaceName: string;
82
+ /** File containing the interface */
83
+ interfaceFile: string;
84
+ /** Fully qualified implementation class name */
85
+ implName: string;
86
+ /** File containing the implementation */
87
+ implFile: string;
88
+ }
32
89
  /**
33
90
  * Multi-file symbol table aggregating all parsed file models.
34
91
  */
@@ -44,6 +101,52 @@ export interface CrossFileSymbolTable {
44
101
  classes: Map<string, ClassDeclaration>;
45
102
  /** Import graph: filePath → array of resolved import file paths */
46
103
  importGraph: Map<string, string[]>;
104
+ /** Router/blueprint mounts: sourceFile → mounts (Feature 27) */
105
+ routerMounts: Map<string, RouterMount[]>;
106
+ /** Injection chains: consumerFile → chains (Feature 27) */
107
+ injectionChains: Map<string, InjectionChain[]>;
108
+ /** Interface → implementations: interfaceName → implNames (Feature 27) */
109
+ interfaceImplementations: Map<string, InterfaceImpl[]>;
110
+ /** Middleware applied to routers: routerFile → middleware (Feature 27) */
111
+ middlewareInheritance: Map<string, MiddlewareEntry[]>;
112
+ }
113
+ /**
114
+ * Context threaded through all cross-file resolvers.
115
+ */
116
+ export interface CrossFileResolutionContext {
117
+ /** The cross-file symbol table to enrich */
118
+ symbolTable: CrossFileSymbolTable;
119
+ /** Project root directory */
120
+ projectRoot: string;
121
+ /** Detected API frameworks */
122
+ apiFrameworks: DetectedApiFramework[];
123
+ /** All source file paths */
124
+ allSourceFiles: string[];
125
+ }
126
+ /**
127
+ * Result from a single cross-file resolver.
128
+ */
129
+ export interface CrossFileResolutionResult {
130
+ /** Number of new entries added to the symbol table */
131
+ entriesAdded: number;
132
+ /** Diagnostic messages from resolution */
133
+ diagnostics: string[];
134
+ /** Unresolved references that could not be completed */
135
+ unresolvedRefs: Array<{
136
+ ref: string;
137
+ reason: string;
138
+ }>;
139
+ }
140
+ /**
141
+ * Interface that each framework-specific cross-file resolver must implement.
142
+ */
143
+ export interface CrossFileResolver {
144
+ /** Human-readable resolver name */
145
+ name: string;
146
+ /** Returns true if this resolver should run given the detected frameworks */
147
+ appliesTo(frameworks: DetectedApiFramework[]): boolean;
148
+ /** Perform cross-file resolution, mutating the symbol table */
149
+ resolve(ctx: CrossFileResolutionContext): CrossFileResolutionResult;
47
150
  }
48
151
  /**
49
152
  * Result of abstract layer traversal (inheritance, helpers, fixtures).
@@ -81,5 +184,15 @@ export interface AstStageOutput {
81
184
  file: string;
82
185
  reason: string;
83
186
  }>;
187
+ /** Cross-file resolution diagnostics (Feature 27) */
188
+ crossFileResolutionDiagnostics?: Array<{
189
+ resolverName: string;
190
+ entriesAdded: number;
191
+ diagnostics: string[];
192
+ unresolvedRefs: Array<{
193
+ ref: string;
194
+ reason: string;
195
+ }>;
196
+ }>;
84
197
  }
85
198
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/pipeline/stages/ast/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,iBAAiB,EAAuC,MAAM,uBAAuB,CAAC;AACrI,OAAO,KAAK,EAAE,eAAe,EAAiB,MAAM,aAAa,CAAC;AAElE;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,gFAAgF;IAChF,MAAM,EAAE,MAAM,CAAC;IACf,kEAAkE;IAClE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kEAAkE;IAClE,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,uCAAuC;IACvC,SAAS,EAAE,OAAO,CAAC;IACnB,iCAAiC;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;IAChC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,oDAAoD;IACpD,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACnC,yDAAyD;IACzD,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAClE,2CAA2C;IAC3C,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IACvC,mEAAmE;IACnE,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,kEAAkE;IAClE,kBAAkB,EAAE,iBAAiB,EAAE,CAAC;IACxC,+CAA+C;IAC/C,iBAAiB,EAAE,gBAAgB,EAAE,CAAC;IACtC,oCAAoC;IACpC,eAAe,EAAE,eAAe,CAAC;IACjC,kCAAkC;IAClC,cAAc,EAAE,MAAM,CAAC;IACvB,4CAA4C;IAC5C,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,uDAAuD;IACvD,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,oDAAoD;IACpD,aAAa,EAAE,OAAO,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,iCAAiC;IACjC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACnC,8BAA8B;IAC9B,cAAc,EAAE,oBAAoB,CAAC;IACrC,sCAAsC;IACtC,gBAAgB,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAC/C,4CAA4C;IAC5C,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,wCAAwC;IACxC,YAAY,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACvD"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/pipeline/stages/ast/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,iBAAiB,EAAuC,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC7J,OAAO,KAAK,EAAE,eAAe,EAAiB,MAAM,aAAa,CAAC;AAClE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;AAEjF;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,gFAAgF;IAChF,MAAM,EAAE,MAAM,CAAC;IACf,kEAAkE;IAClE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kEAAkE;IAClE,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,uCAAuC;IACvC,SAAS,EAAE,OAAO,CAAC;IACnB,iCAAiC;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;IAChC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAID;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,+BAA+B;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,mDAAmD;IACnD,gBAAgB,EAAE,MAAM,CAAC;IACzB,6CAA6C;IAC7C,UAAU,EAAE,eAAe,EAAE,CAAC;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,+CAA+C;IAC/C,YAAY,EAAE,MAAM,CAAC;IACrB,iCAAiC;IACjC,aAAa,EAAE,MAAM,CAAC;IACtB,yCAAyC;IACzC,YAAY,EAAE,MAAM,CAAC;IACrB,kCAAkC;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,iCAAiC;IACjC,cAAc,EAAE,aAAa,GAAG,WAAW,GAAG,WAAW,GAAG,UAAU,CAAC;CACxE;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,oCAAoC;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,sBAAsB;IACtB,IAAI,EAAE,eAAe,GAAG,eAAe,GAAG,YAAY,GAAG,eAAe,GAAG,QAAQ,CAAC;IACpF,iEAAiE;IACjE,SAAS,EAAE,QAAQ,GAAG,OAAO,CAAC;IAC9B,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,sBAAsB,CAAC;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,qCAAqC;IACrC,aAAa,EAAE,MAAM,CAAC;IACtB,oCAAoC;IACpC,aAAa,EAAE,MAAM,CAAC;IACtB,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAC;IACjB,yCAAyC;IACzC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,oDAAoD;IACpD,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACnC,yDAAyD;IACzD,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAClE,2CAA2C;IAC3C,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IACvC,mEAAmE;IACnE,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACnC,gEAAgE;IAChE,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC;IACzC,2DAA2D;IAC3D,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC,CAAC;IAC/C,0EAA0E;IAC1E,wBAAwB,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC;IACvD,0EAA0E;IAC1E,qBAAqB,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,EAAE,CAAC,CAAC;CACvD;AAID;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACzC,4CAA4C;IAC5C,WAAW,EAAE,oBAAoB,CAAC;IAClC,6BAA6B;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,8BAA8B;IAC9B,aAAa,EAAE,oBAAoB,EAAE,CAAC;IACtC,4BAA4B;IAC5B,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,sDAAsD;IACtD,YAAY,EAAE,MAAM,CAAC;IACrB,0CAA0C;IAC1C,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,wDAAwD;IACxD,cAAc,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACxD;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,mCAAmC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,6EAA6E;IAC7E,SAAS,CAAC,UAAU,EAAE,oBAAoB,EAAE,GAAG,OAAO,CAAC;IACvD,+DAA+D;IAC/D,OAAO,CAAC,GAAG,EAAE,0BAA0B,GAAG,yBAAyB,CAAC;CACrE;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,kEAAkE;IAClE,kBAAkB,EAAE,iBAAiB,EAAE,CAAC;IACxC,+CAA+C;IAC/C,iBAAiB,EAAE,gBAAgB,EAAE,CAAC;IACtC,oCAAoC;IACpC,eAAe,EAAE,eAAe,CAAC;IACjC,kCAAkC;IAClC,cAAc,EAAE,MAAM,CAAC;IACvB,4CAA4C;IAC5C,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,uDAAuD;IACvD,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,oDAAoD;IACpD,aAAa,EAAE,OAAO,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,iCAAiC;IACjC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACnC,8BAA8B;IAC9B,cAAc,EAAE,oBAAoB,CAAC;IACrC,sCAAsC;IACtC,gBAAgB,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAC/C,4CAA4C;IAC5C,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,wCAAwC;IACxC,YAAY,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACtD,qDAAqD;IACrD,8BAA8B,CAAC,EAAE,KAAK,CAAC;QACrC,YAAY,EAAE,MAAM,CAAC;QACrB,YAAY,EAAE,MAAM,CAAC;QACrB,WAAW,EAAE,MAAM,EAAE,CAAC;QACtB,cAAc,EAAE,KAAK,CAAC;YAAE,GAAG,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;KACxD,CAAC,CAAC;CACJ"}
@@ -4,6 +4,8 @@
4
4
  *
5
5
  * Detects:
6
6
  * - Runtime-unconfirmed: AST+TIA say covered, but IAST/DAST disagree
7
+ * - DAST-unreachable: DAST probed an endpoint but could not reach it
8
+ * - Undeclared-endpoint: DAST discovered endpoints not found by static analysis
7
9
  * - Stage disagreement: Two stages assign different types to the same node
8
10
  */
9
11
  import type { ConflictNode } from '../../types';
@@ -1 +1 @@
1
- {"version":3,"file":"conflictDetector.d.ts","sourceRoot":"","sources":["../../../../../src/pipeline/stages/merge/conflictDetector.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,YAAY,EAA2B,MAAM,aAAa,CAAC;AACzE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD;;GAEG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,sBAAsB,EAC7B,UAAU,EAAE,UAAU,GAAG,SAAS,EAClC,UAAU,EAAE,UAAU,GAAG,SAAS,GACjC,YAAY,EAAE,CA0ChB"}
1
+ {"version":3,"file":"conflictDetector.d.ts","sourceRoot":"","sources":["../../../../../src/pipeline/stages/merge/conflictDetector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,YAAY,EAA2B,MAAM,aAAa,CAAC;AACzE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD;;GAEG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,sBAAsB,EAC7B,UAAU,EAAE,UAAU,GAAG,SAAS,EAClC,UAAU,EAAE,UAAU,GAAG,SAAS,GACjC,YAAY,EAAE,CAmGhB"}
@@ -5,6 +5,8 @@
5
5
  *
6
6
  * Detects:
7
7
  * - Runtime-unconfirmed: AST+TIA say covered, but IAST/DAST disagree
8
+ * - DAST-unreachable: DAST probed an endpoint but could not reach it
9
+ * - Undeclared-endpoint: DAST discovered endpoints not found by static analysis
8
10
  * - Stage disagreement: Two stages assign different types to the same node
9
11
  */
10
12
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -13,7 +15,7 @@ exports.detectConflicts = detectConflicts;
13
15
  * Detect conflicts across all stages.
14
16
  */
15
17
  function detectConflicts(graph, iastOutput, dastOutput) {
16
- var _a, _b, _c, _d, _e;
18
+ var _a, _b, _c, _d, _e, _f, _g;
17
19
  const conflicts = [];
18
20
  // 1. Runtime-unconfirmed: endpoints that AST found but neither IAST nor DAST confirmed
19
21
  const endpointNodes = graph.getNodesByType('endpoint');
@@ -46,7 +48,57 @@ function detectConflicts(graph, iastOutput, dastOutput) {
46
48
  }
47
49
  }
48
50
  }
49
- // 2. Stage disagreement: same node ID added by multiple stages with different types
51
+ // 2. DAST-unreachable: endpoints that DAST explicitly could not reach
52
+ if (dastOutput) {
53
+ for (const endpointId of dastUnreachable) {
54
+ const node = graph.getNode(endpointId);
55
+ const label = (_f = node === null || node === void 0 ? void 0 : node.label) !== null && _f !== void 0 ? _f : endpointId;
56
+ conflicts.push({
57
+ conflictId: `conflict:dast-unreachable:${endpointId}`,
58
+ nodeId: endpointId,
59
+ type: 'dast-unreachable',
60
+ stages: ['dast'],
61
+ stageOutputs: {
62
+ dast: 'unreachable',
63
+ },
64
+ detail: `${label} was probed by DAST but could not be reached.`,
65
+ suggestedAction: 'Verify the endpoint is deployed and accessible. Check authentication requirements and network configuration for the DAST scanner.',
66
+ severity: 'warning',
67
+ });
68
+ }
69
+ }
70
+ // 3. Undeclared-endpoint: DAST discovered endpoints not found by static analysis
71
+ if (dastOutput) {
72
+ const staticEndpointIds = new Set(endpointNodes
73
+ .filter((n) => n.sourceStage !== 'dast')
74
+ .map((n) => n.id));
75
+ for (const result of dastOutput.results) {
76
+ if (!result.reachable)
77
+ continue;
78
+ const endpointPath = (_g = result.normalizedPath) !== null && _g !== void 0 ? _g : result.path;
79
+ const endpointId = `endpoint:${result.method.toUpperCase()}:${endpointPath}`;
80
+ if (!staticEndpointIds.has(endpointId)) {
81
+ // Avoid duplicate conflicts for the same endpoint
82
+ const conflictId = `conflict:undeclared-endpoint:${endpointId}`;
83
+ if (conflicts.some((c) => c.conflictId === conflictId))
84
+ continue;
85
+ conflicts.push({
86
+ conflictId,
87
+ nodeId: endpointId,
88
+ type: 'undeclared-endpoint',
89
+ stages: ['dast'],
90
+ stageOutputs: {
91
+ dast: 'discovered',
92
+ ast: 'not-declared',
93
+ },
94
+ detail: `${result.method.toUpperCase()} ${endpointPath} was discovered by DAST but not found by static analysis.`,
95
+ suggestedAction: 'Review the endpoint source. It may be dynamically registered, generated by a framework, or missing from the scanned codebase.',
96
+ severity: 'warning',
97
+ });
98
+ }
99
+ }
100
+ }
101
+ // 4. Stage disagreement: same node ID added by multiple stages with different types
50
102
  // (This is handled by the graph merge(), which already returns ConflictNode[])
51
103
  return conflicts;
52
104
  }
@@ -1 +1 @@
1
- {"version":3,"file":"coverageMappingBuilder.d.ts","sourceRoot":"","sources":["../../../../../src/pipeline/stages/merge/coverageMappingBuilder.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EACV,eAAe,EAMhB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAIhD;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,sBAAsB,EAC7B,SAAS,EAAE,SAAS,GAAG,SAAS,EAChC,UAAU,EAAE,UAAU,GAAG,SAAS,EAClC,UAAU,EAAE,UAAU,GAAG,SAAS,EAClC,gBAAgB,EAAE,OAAO,GACxB,eAAe,EAAE,CAuJnB"}
1
+ {"version":3,"file":"coverageMappingBuilder.d.ts","sourceRoot":"","sources":["../../../../../src/pipeline/stages/merge/coverageMappingBuilder.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EACV,eAAe,EAOhB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAoBhD;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,sBAAsB,EAC7B,SAAS,EAAE,SAAS,GAAG,SAAS,EAChC,UAAU,EAAE,UAAU,GAAG,SAAS,EAClC,UAAU,EAAE,UAAU,GAAG,SAAS,EAClC,gBAAgB,EAAE,OAAO,GACxB,eAAe,EAAE,CAyNnB"}