vaspera 2.9.0 → 2.10.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 (166) hide show
  1. package/CHANGELOG.md +122 -7
  2. package/README.md +58 -1
  3. package/dist/__tests__/autofix/branch-manager.test.d.ts +2 -0
  4. package/dist/__tests__/autofix/branch-manager.test.d.ts.map +1 -0
  5. package/dist/__tests__/autofix/branch-manager.test.js +60 -0
  6. package/dist/__tests__/autofix/branch-manager.test.js.map +1 -0
  7. package/dist/__tests__/autofix/commit-generator.test.d.ts +2 -0
  8. package/dist/__tests__/autofix/commit-generator.test.d.ts.map +1 -0
  9. package/dist/__tests__/autofix/commit-generator.test.js +147 -0
  10. package/dist/__tests__/autofix/commit-generator.test.js.map +1 -0
  11. package/dist/__tests__/autofix/constitution.test.d.ts +9 -0
  12. package/dist/__tests__/autofix/constitution.test.d.ts.map +1 -0
  13. package/dist/__tests__/autofix/constitution.test.js +421 -0
  14. package/dist/__tests__/autofix/constitution.test.js.map +1 -0
  15. package/dist/__tests__/autofix/pr-generator.test.d.ts +2 -0
  16. package/dist/__tests__/autofix/pr-generator.test.d.ts.map +1 -0
  17. package/dist/__tests__/autofix/pr-generator.test.js +152 -0
  18. package/dist/__tests__/autofix/pr-generator.test.js.map +1 -0
  19. package/dist/__tests__/property-test-helpers.d.ts +87 -0
  20. package/dist/__tests__/property-test-helpers.d.ts.map +1 -0
  21. package/dist/__tests__/property-test-helpers.js +136 -0
  22. package/dist/__tests__/property-test-helpers.js.map +1 -0
  23. package/dist/__tests__/scanners/dast/index.test.d.ts +2 -0
  24. package/dist/__tests__/scanners/dast/index.test.d.ts.map +1 -0
  25. package/dist/__tests__/scanners/dast/index.test.js +183 -0
  26. package/dist/__tests__/scanners/dast/index.test.js.map +1 -0
  27. package/dist/__tests__/scanners/dast/nuclei.test.d.ts +2 -0
  28. package/dist/__tests__/scanners/dast/nuclei.test.d.ts.map +1 -0
  29. package/dist/__tests__/scanners/dast/nuclei.test.js +166 -0
  30. package/dist/__tests__/scanners/dast/nuclei.test.js.map +1 -0
  31. package/dist/__tests__/scanners/dast/zap.test.d.ts +2 -0
  32. package/dist/__tests__/scanners/dast/zap.test.d.ts.map +1 -0
  33. package/dist/__tests__/scanners/dast/zap.test.js +158 -0
  34. package/dist/__tests__/scanners/dast/zap.test.js.map +1 -0
  35. package/dist/__tests__/scanners/fp-feedback.test.d.ts +2 -0
  36. package/dist/__tests__/scanners/fp-feedback.test.d.ts.map +1 -0
  37. package/dist/__tests__/scanners/fp-feedback.test.js +202 -0
  38. package/dist/__tests__/scanners/fp-feedback.test.js.map +1 -0
  39. package/dist/__tests__/scanners/fp-filter.property.test.d.ts +9 -0
  40. package/dist/__tests__/scanners/fp-filter.property.test.d.ts.map +1 -0
  41. package/dist/__tests__/scanners/fp-filter.property.test.js +253 -0
  42. package/dist/__tests__/scanners/fp-filter.property.test.js.map +1 -0
  43. package/dist/__tests__/scanners/fp-filter.test.d.ts +2 -0
  44. package/dist/__tests__/scanners/fp-filter.test.d.ts.map +1 -0
  45. package/dist/__tests__/scanners/fp-filter.test.js +234 -0
  46. package/dist/__tests__/scanners/fp-filter.test.js.map +1 -0
  47. package/dist/__tests__/scanners/fp-tracker.test.d.ts +2 -0
  48. package/dist/__tests__/scanners/fp-tracker.test.d.ts.map +1 -0
  49. package/dist/__tests__/scanners/fp-tracker.test.js +262 -0
  50. package/dist/__tests__/scanners/fp-tracker.test.js.map +1 -0
  51. package/dist/__tests__/scanners/logic/endpoint-analyzer.property.test.d.ts +10 -0
  52. package/dist/__tests__/scanners/logic/endpoint-analyzer.property.test.d.ts.map +1 -0
  53. package/dist/__tests__/scanners/logic/endpoint-analyzer.property.test.js +238 -0
  54. package/dist/__tests__/scanners/logic/endpoint-analyzer.property.test.js.map +1 -0
  55. package/dist/__tests__/scanners/logic/endpoint-analyzer.test.d.ts +2 -0
  56. package/dist/__tests__/scanners/logic/endpoint-analyzer.test.d.ts.map +1 -0
  57. package/dist/__tests__/scanners/logic/endpoint-analyzer.test.js +55 -0
  58. package/dist/__tests__/scanners/logic/endpoint-analyzer.test.js.map +1 -0
  59. package/dist/__tests__/scanners/logic/index.test.d.ts +2 -0
  60. package/dist/__tests__/scanners/logic/index.test.d.ts.map +1 -0
  61. package/dist/__tests__/scanners/logic/index.test.js +165 -0
  62. package/dist/__tests__/scanners/logic/index.test.js.map +1 -0
  63. package/dist/__tests__/scanners/logic/types.test.d.ts +2 -0
  64. package/dist/__tests__/scanners/logic/types.test.d.ts.map +1 -0
  65. package/dist/__tests__/scanners/logic/types.test.js +85 -0
  66. package/dist/__tests__/scanners/logic/types.test.js.map +1 -0
  67. package/dist/action/pr-comment.test.js +4 -0
  68. package/dist/action/pr-comment.test.js.map +1 -1
  69. package/dist/action/sarif-upload.test.js +4 -0
  70. package/dist/action/sarif-upload.test.js.map +1 -1
  71. package/dist/autofix/branch-manager.d.ts +115 -0
  72. package/dist/autofix/branch-manager.d.ts.map +1 -0
  73. package/dist/autofix/branch-manager.js +308 -0
  74. package/dist/autofix/branch-manager.js.map +1 -0
  75. package/dist/autofix/commit-generator.d.ts +55 -0
  76. package/dist/autofix/commit-generator.d.ts.map +1 -0
  77. package/dist/autofix/commit-generator.js +277 -0
  78. package/dist/autofix/commit-generator.js.map +1 -0
  79. package/dist/autofix/constitution.d.ts +77 -0
  80. package/dist/autofix/constitution.d.ts.map +1 -0
  81. package/dist/autofix/constitution.js +261 -0
  82. package/dist/autofix/constitution.js.map +1 -0
  83. package/dist/autofix/constitution.schema.d.ts +441 -0
  84. package/dist/autofix/constitution.schema.d.ts.map +1 -0
  85. package/dist/autofix/constitution.schema.js +144 -0
  86. package/dist/autofix/constitution.schema.js.map +1 -0
  87. package/dist/autofix/index.d.ts +13 -0
  88. package/dist/autofix/index.d.ts.map +1 -0
  89. package/dist/autofix/index.js +15 -0
  90. package/dist/autofix/index.js.map +1 -0
  91. package/dist/autofix/pr-generator.d.ts +57 -0
  92. package/dist/autofix/pr-generator.d.ts.map +1 -0
  93. package/dist/autofix/pr-generator.js +597 -0
  94. package/dist/autofix/pr-generator.js.map +1 -0
  95. package/dist/autofix/types.d.ts +151 -0
  96. package/dist/autofix/types.d.ts.map +1 -0
  97. package/dist/autofix/types.js +22 -0
  98. package/dist/autofix/types.js.map +1 -0
  99. package/dist/eval/fixtures.d.ts +20 -0
  100. package/dist/eval/fixtures.d.ts.map +1 -1
  101. package/dist/eval/fixtures.js +430 -0
  102. package/dist/eval/fixtures.js.map +1 -1
  103. package/dist/index.d.ts.map +1 -1
  104. package/dist/index.js +84 -1
  105. package/dist/index.js.map +1 -1
  106. package/dist/scanners/cache.d.ts.map +1 -1
  107. package/dist/scanners/cache.js +4 -0
  108. package/dist/scanners/cache.js.map +1 -1
  109. package/dist/scanners/dast/index.d.ts +39 -0
  110. package/dist/scanners/dast/index.d.ts.map +1 -0
  111. package/dist/scanners/dast/index.js +259 -0
  112. package/dist/scanners/dast/index.js.map +1 -0
  113. package/dist/scanners/dast/nuclei.d.ts +26 -0
  114. package/dist/scanners/dast/nuclei.d.ts.map +1 -0
  115. package/dist/scanners/dast/nuclei.js +354 -0
  116. package/dist/scanners/dast/nuclei.js.map +1 -0
  117. package/dist/scanners/dast/types.d.ts +306 -0
  118. package/dist/scanners/dast/types.d.ts.map +1 -0
  119. package/dist/scanners/dast/types.js +52 -0
  120. package/dist/scanners/dast/types.js.map +1 -0
  121. package/dist/scanners/dast/zap.d.ts +26 -0
  122. package/dist/scanners/dast/zap.d.ts.map +1 -0
  123. package/dist/scanners/dast/zap.js +453 -0
  124. package/dist/scanners/dast/zap.js.map +1 -0
  125. package/dist/scanners/fp-feedback.d.ts +140 -0
  126. package/dist/scanners/fp-feedback.d.ts.map +1 -0
  127. package/dist/scanners/fp-feedback.js +292 -0
  128. package/dist/scanners/fp-feedback.js.map +1 -0
  129. package/dist/scanners/fp-filter.d.ts +94 -0
  130. package/dist/scanners/fp-filter.d.ts.map +1 -0
  131. package/dist/scanners/fp-filter.js +397 -0
  132. package/dist/scanners/fp-filter.js.map +1 -0
  133. package/dist/scanners/fp-tracker.d.ts +125 -0
  134. package/dist/scanners/fp-tracker.d.ts.map +1 -0
  135. package/dist/scanners/fp-tracker.js +330 -0
  136. package/dist/scanners/fp-tracker.js.map +1 -0
  137. package/dist/scanners/index.d.ts.map +1 -1
  138. package/dist/scanners/index.js +56 -0
  139. package/dist/scanners/index.js.map +1 -1
  140. package/dist/scanners/index.test.js +6 -6
  141. package/dist/scanners/index.test.js.map +1 -1
  142. package/dist/scanners/logic/auth-flow-analyzer.d.ts +18 -0
  143. package/dist/scanners/logic/auth-flow-analyzer.d.ts.map +1 -0
  144. package/dist/scanners/logic/auth-flow-analyzer.js +384 -0
  145. package/dist/scanners/logic/auth-flow-analyzer.js.map +1 -0
  146. package/dist/scanners/logic/endpoint-analyzer.d.ts +29 -0
  147. package/dist/scanners/logic/endpoint-analyzer.d.ts.map +1 -0
  148. package/dist/scanners/logic/endpoint-analyzer.js +528 -0
  149. package/dist/scanners/logic/endpoint-analyzer.js.map +1 -0
  150. package/dist/scanners/logic/index.d.ts +41 -0
  151. package/dist/scanners/logic/index.d.ts.map +1 -0
  152. package/dist/scanners/logic/index.js +268 -0
  153. package/dist/scanners/logic/index.js.map +1 -0
  154. package/dist/scanners/logic/types.d.ts +254 -0
  155. package/dist/scanners/logic/types.d.ts.map +1 -0
  156. package/dist/scanners/logic/types.js +142 -0
  157. package/dist/scanners/logic/types.js.map +1 -0
  158. package/dist/scanners/types.d.ts +1 -1
  159. package/dist/scanners/types.d.ts.map +1 -1
  160. package/dist/scanners/types.js +4 -0
  161. package/dist/scanners/types.js.map +1 -1
  162. package/dist/telemetry/usage.d.ts +1 -1
  163. package/dist/telemetry/usage.d.ts.map +1 -1
  164. package/dist/telemetry/usage.js +14 -6
  165. package/dist/telemetry/usage.js.map +1 -1
  166. package/package.json +6 -8
@@ -0,0 +1,262 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
+ import { mkdir, rm } from "fs/promises";
3
+ import { join } from "path";
4
+ import { tmpdir } from "os";
5
+ import { loadTrackingData, saveTrackingData, markFalsePositive, markTruePositive, adjustFindingConfidence, generateFPReport, } from "../../scanners/fp-tracker.js";
6
+ describe("fp-tracker", () => {
7
+ let testDir;
8
+ beforeEach(async () => {
9
+ testDir = join(tmpdir(), `fp-tracker-test-${Date.now()}`);
10
+ await mkdir(testDir, { recursive: true });
11
+ });
12
+ afterEach(async () => {
13
+ try {
14
+ await rm(testDir, { recursive: true, force: true });
15
+ }
16
+ catch {
17
+ // Ignore cleanup errors
18
+ }
19
+ });
20
+ describe("loadTrackingData", () => {
21
+ it("returns default data for new project", async () => {
22
+ const data = await loadTrackingData(testDir);
23
+ expect(data.version).toBe("1.0.0");
24
+ expect(data.projectPath).toBe(testDir);
25
+ expect(Object.keys(data.scanners)).toHaveLength(0);
26
+ expect(data.globalStats.totalFindings).toBe(0);
27
+ });
28
+ it("loads existing data", async () => {
29
+ // First save some data
30
+ const initialData = await loadTrackingData(testDir);
31
+ initialData.globalStats.totalFindings = 10;
32
+ await saveTrackingData(testDir, initialData);
33
+ // Then load it
34
+ const loadedData = await loadTrackingData(testDir);
35
+ expect(loadedData.globalStats.totalFindings).toBe(10);
36
+ });
37
+ });
38
+ describe("markFalsePositive", () => {
39
+ it("returns undefined for non-existent scanner", async () => {
40
+ const result = await markFalsePositive(testDir, "semgrep", "some-rule");
41
+ expect(result).toBeUndefined();
42
+ });
43
+ it("updates FP metrics correctly", async () => {
44
+ // First create a scanner and rule entry
45
+ const data = await loadTrackingData(testDir);
46
+ data.scanners["semgrep"] = {
47
+ scanner: "semgrep",
48
+ totalRules: 1,
49
+ totalFindings: 5,
50
+ overallFPRate: 0,
51
+ overallTPRate: 1,
52
+ ruleMetrics: new Map([
53
+ [
54
+ "test-rule",
55
+ {
56
+ scanner: "semgrep",
57
+ ruleId: "test-rule",
58
+ totalReported: 5,
59
+ confirmedTP: 2,
60
+ confirmedFP: 0,
61
+ pendingReview: 3,
62
+ fpRate: 0,
63
+ tpRate: 1,
64
+ adjustmentFactor: 1,
65
+ lastUpdated: new Date().toISOString(),
66
+ severityDistribution: {},
67
+ },
68
+ ],
69
+ ]),
70
+ };
71
+ await saveTrackingData(testDir, data);
72
+ // Mark as FP
73
+ const result = await markFalsePositive(testDir, "semgrep", "test-rule");
74
+ expect(result).toBeDefined();
75
+ expect(result.confirmedFP).toBe(1);
76
+ expect(result.pendingReview).toBe(2);
77
+ expect(result.fpRate).toBeGreaterThan(0);
78
+ });
79
+ });
80
+ describe("markTruePositive", () => {
81
+ it("updates TP metrics correctly", async () => {
82
+ // First create a scanner and rule entry
83
+ const data = await loadTrackingData(testDir);
84
+ data.scanners["semgrep"] = {
85
+ scanner: "semgrep",
86
+ totalRules: 1,
87
+ totalFindings: 5,
88
+ overallFPRate: 0,
89
+ overallTPRate: 1,
90
+ ruleMetrics: new Map([
91
+ [
92
+ "test-rule",
93
+ {
94
+ scanner: "semgrep",
95
+ ruleId: "test-rule",
96
+ totalReported: 5,
97
+ confirmedTP: 0,
98
+ confirmedFP: 2,
99
+ pendingReview: 3,
100
+ fpRate: 1,
101
+ tpRate: 0,
102
+ adjustmentFactor: 0.1,
103
+ lastUpdated: new Date().toISOString(),
104
+ severityDistribution: {},
105
+ },
106
+ ],
107
+ ]),
108
+ };
109
+ await saveTrackingData(testDir, data);
110
+ // Mark as TP
111
+ const result = await markTruePositive(testDir, "semgrep", "test-rule");
112
+ expect(result).toBeDefined();
113
+ expect(result.confirmedTP).toBe(1);
114
+ expect(result.pendingReview).toBe(2);
115
+ expect(result.tpRate).toBeGreaterThan(0);
116
+ });
117
+ });
118
+ describe("adjustFindingConfidence", () => {
119
+ it("returns original confidence when no metrics", () => {
120
+ const finding = {
121
+ scanner: "semgrep",
122
+ ruleId: "test",
123
+ file: "test.ts",
124
+ line: 1,
125
+ message: "Test",
126
+ severity: "high",
127
+ confidence: 100,
128
+ };
129
+ const result = adjustFindingConfidence(finding, undefined);
130
+ expect(result).toBe(100);
131
+ });
132
+ it("reduces confidence for high FP rate rules", () => {
133
+ const finding = {
134
+ scanner: "semgrep",
135
+ ruleId: "test",
136
+ file: "test.ts",
137
+ line: 1,
138
+ message: "Test",
139
+ severity: "high",
140
+ confidence: 100,
141
+ };
142
+ const metrics = {
143
+ scanner: "semgrep",
144
+ ruleId: "test",
145
+ totalReported: 10,
146
+ confirmedTP: 2,
147
+ confirmedFP: 8,
148
+ pendingReview: 0,
149
+ fpRate: 0.8,
150
+ tpRate: 0.2,
151
+ adjustmentFactor: 0.28, // 1 - (0.8 * 0.9) = 0.28
152
+ lastUpdated: new Date().toISOString(),
153
+ severityDistribution: {},
154
+ };
155
+ const result = adjustFindingConfidence(finding, metrics);
156
+ expect(result).toBeLessThan(100);
157
+ expect(result).toBe(28);
158
+ });
159
+ it("maintains confidence for low FP rate rules", () => {
160
+ const finding = {
161
+ scanner: "semgrep",
162
+ ruleId: "test",
163
+ file: "test.ts",
164
+ line: 1,
165
+ message: "Test",
166
+ severity: "high",
167
+ confidence: 100,
168
+ };
169
+ const metrics = {
170
+ scanner: "semgrep",
171
+ ruleId: "test",
172
+ totalReported: 10,
173
+ confirmedTP: 9,
174
+ confirmedFP: 1,
175
+ pendingReview: 0,
176
+ fpRate: 0.1,
177
+ tpRate: 0.9,
178
+ adjustmentFactor: 0.91, // 1 - (0.1 * 0.9) = 0.91
179
+ lastUpdated: new Date().toISOString(),
180
+ severityDistribution: {},
181
+ };
182
+ const result = adjustFindingConfidence(finding, metrics);
183
+ expect(result).toBeGreaterThan(90);
184
+ });
185
+ it("clamps confidence to valid range", () => {
186
+ const finding = {
187
+ scanner: "semgrep",
188
+ ruleId: "test",
189
+ file: "test.ts",
190
+ line: 1,
191
+ message: "Test",
192
+ severity: "high",
193
+ confidence: 100,
194
+ };
195
+ const metrics = {
196
+ scanner: "semgrep",
197
+ ruleId: "test",
198
+ totalReported: 10,
199
+ confirmedTP: 0,
200
+ confirmedFP: 10,
201
+ pendingReview: 0,
202
+ fpRate: 1.0,
203
+ tpRate: 0,
204
+ adjustmentFactor: 0.1, // Minimum
205
+ lastUpdated: new Date().toISOString(),
206
+ severityDistribution: {},
207
+ };
208
+ const result = adjustFindingConfidence(finding, metrics);
209
+ expect(result).toBeGreaterThanOrEqual(1);
210
+ expect(result).toBeLessThanOrEqual(100);
211
+ });
212
+ });
213
+ describe("generateFPReport", () => {
214
+ it("generates empty report for new project", async () => {
215
+ const report = await generateFPReport(testDir);
216
+ expect(report.summary.totalScanners).toBe(0);
217
+ expect(report.summary.totalRules).toBe(0);
218
+ expect(report.highFPRules).toHaveLength(0);
219
+ });
220
+ it("includes recommendations for high FP rates", async () => {
221
+ // Create data with high FP rate
222
+ const data = await loadTrackingData(testDir);
223
+ data.scanners["semgrep"] = {
224
+ scanner: "semgrep",
225
+ totalRules: 1,
226
+ totalFindings: 20,
227
+ overallFPRate: 0.8,
228
+ overallTPRate: 0.2,
229
+ ruleMetrics: new Map([
230
+ [
231
+ "high-fp-rule",
232
+ {
233
+ scanner: "semgrep",
234
+ ruleId: "high-fp-rule",
235
+ totalReported: 20,
236
+ confirmedTP: 4,
237
+ confirmedFP: 16,
238
+ pendingReview: 0,
239
+ fpRate: 0.8,
240
+ tpRate: 0.2,
241
+ adjustmentFactor: 0.28,
242
+ lastUpdated: new Date().toISOString(),
243
+ severityDistribution: {},
244
+ },
245
+ ],
246
+ ]),
247
+ };
248
+ data.globalStats = {
249
+ totalFindings: 20,
250
+ totalTP: 4,
251
+ totalFP: 16,
252
+ totalPending: 0,
253
+ overallAccuracy: 0.2,
254
+ };
255
+ await saveTrackingData(testDir, data);
256
+ const report = await generateFPReport(testDir, { minSampleSize: 5 });
257
+ expect(report.highFPRules.length).toBeGreaterThan(0);
258
+ expect(report.recommendations.length).toBeGreaterThan(0);
259
+ });
260
+ });
261
+ });
262
+ //# sourceMappingURL=fp-tracker.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fp-tracker.test.js","sourceRoot":"","sources":["../../../src/__tests__/scanners/fp-tracker.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Property-Based Tests for Endpoint Analyzer
3
+ *
4
+ * Tests invariants of extractPathParams and inferResourceType
5
+ * using fast-check property-based testing.
6
+ *
7
+ * @module __tests__/scanners/logic/endpoint-analyzer.property
8
+ */
9
+ export {};
10
+ //# sourceMappingURL=endpoint-analyzer.property.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"endpoint-analyzer.property.test.d.ts","sourceRoot":"","sources":["../../../../src/__tests__/scanners/logic/endpoint-analyzer.property.test.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
@@ -0,0 +1,238 @@
1
+ /**
2
+ * Property-Based Tests for Endpoint Analyzer
3
+ *
4
+ * Tests invariants of extractPathParams and inferResourceType
5
+ * using fast-check property-based testing.
6
+ *
7
+ * @module __tests__/scanners/logic/endpoint-analyzer.property
8
+ */
9
+ import { describe, it } from "vitest";
10
+ import * as fc from "fast-check";
11
+ import { extractPathParams, inferResourceType, } from "../../../scanners/logic/endpoint-analyzer.js";
12
+ import { arbitraries, expressPath, nextjsPath, flaskPath, springPath, uniqueParamNames, PARAM_DELIMITERS, containsAny, } from "../../property-test-helpers.js";
13
+ describe("extractPathParams - Property Tests", () => {
14
+ describe("Invariants", () => {
15
+ it("always returns an array", () => {
16
+ fc.assert(fc.property(fc.string(), (path) => {
17
+ const result = extractPathParams(path);
18
+ return Array.isArray(result);
19
+ }));
20
+ });
21
+ it("never returns params containing delimiter characters", () => {
22
+ fc.assert(fc.property(fc.string(), (path) => {
23
+ const result = extractPathParams(path);
24
+ return result.every((param) => !containsAny(param, PARAM_DELIMITERS));
25
+ }));
26
+ });
27
+ it("is idempotent - same input always produces same output", () => {
28
+ fc.assert(fc.property(fc.string(), (path) => {
29
+ const r1 = extractPathParams(path);
30
+ const r2 = extractPathParams(path);
31
+ return JSON.stringify(r1) === JSON.stringify(r2);
32
+ }));
33
+ });
34
+ it("returns empty array for paths without parameter syntax", () => {
35
+ fc.assert(fc.property(fc.array(arbitraries.pathSegment, { minLength: 1, maxLength: 5 }), (segments) => {
36
+ // Build a path with no parameter syntax
37
+ const path = "/" + segments.join("/");
38
+ const result = extractPathParams(path);
39
+ return result.length === 0;
40
+ }));
41
+ });
42
+ });
43
+ describe("Express-style :param", () => {
44
+ it("extracts all colon-prefixed params", () => {
45
+ fc.assert(fc.property(uniqueParamNames, (paramNames) => {
46
+ if (paramNames.length === 0)
47
+ return true;
48
+ const path = expressPath(paramNames);
49
+ const result = extractPathParams(path);
50
+ return paramNames.every((p) => result.includes(p));
51
+ }));
52
+ });
53
+ it("extracts correct number of params", () => {
54
+ fc.assert(fc.property(uniqueParamNames, (paramNames) => {
55
+ if (paramNames.length === 0)
56
+ return true;
57
+ const path = expressPath(paramNames);
58
+ const result = extractPathParams(path);
59
+ return result.length === paramNames.length;
60
+ }));
61
+ });
62
+ });
63
+ describe("Next.js-style [param]", () => {
64
+ it("extracts all bracket params", () => {
65
+ fc.assert(fc.property(uniqueParamNames, (paramNames) => {
66
+ if (paramNames.length === 0)
67
+ return true;
68
+ const path = nextjsPath(paramNames);
69
+ const result = extractPathParams(path);
70
+ return paramNames.every((p) => result.includes(p));
71
+ }));
72
+ });
73
+ it("extracts correct number of params", () => {
74
+ fc.assert(fc.property(uniqueParamNames, (paramNames) => {
75
+ if (paramNames.length === 0)
76
+ return true;
77
+ const path = nextjsPath(paramNames);
78
+ const result = extractPathParams(path);
79
+ return result.length === paramNames.length;
80
+ }));
81
+ });
82
+ });
83
+ describe("Flask-style <param>", () => {
84
+ it("extracts all angle bracket params", () => {
85
+ fc.assert(fc.property(uniqueParamNames, (paramNames) => {
86
+ if (paramNames.length === 0)
87
+ return true;
88
+ const path = flaskPath(paramNames, false);
89
+ const result = extractPathParams(path);
90
+ return paramNames.every((p) => result.includes(p));
91
+ }));
92
+ });
93
+ it("extracts params ignoring type hints", () => {
94
+ fc.assert(fc.property(uniqueParamNames, (paramNames) => {
95
+ if (paramNames.length === 0)
96
+ return true;
97
+ const path = flaskPath(paramNames, true);
98
+ const result = extractPathParams(path);
99
+ return paramNames.every((p) => result.includes(p));
100
+ }));
101
+ });
102
+ });
103
+ describe("Spring-style {param}", () => {
104
+ it("extracts all curly brace params", () => {
105
+ fc.assert(fc.property(uniqueParamNames, (paramNames) => {
106
+ if (paramNames.length === 0)
107
+ return true;
108
+ const path = springPath(paramNames);
109
+ const result = extractPathParams(path);
110
+ return paramNames.every((p) => result.includes(p));
111
+ }));
112
+ });
113
+ it("extracts correct number of params", () => {
114
+ fc.assert(fc.property(uniqueParamNames, (paramNames) => {
115
+ if (paramNames.length === 0)
116
+ return true;
117
+ const path = springPath(paramNames);
118
+ const result = extractPathParams(path);
119
+ return result.length === paramNames.length;
120
+ }));
121
+ });
122
+ });
123
+ describe("Cross-framework consistency", () => {
124
+ it("all framework styles extract same param names", () => {
125
+ fc.assert(fc.property(uniqueParamNames, (paramNames) => {
126
+ if (paramNames.length === 0)
127
+ return true;
128
+ const expressResult = new Set(extractPathParams(expressPath(paramNames)));
129
+ const nextjsResult = new Set(extractPathParams(nextjsPath(paramNames)));
130
+ const flaskResult = new Set(extractPathParams(flaskPath(paramNames)));
131
+ const springResult = new Set(extractPathParams(springPath(paramNames)));
132
+ // All should extract the same set of param names
133
+ const expected = new Set(paramNames);
134
+ const setsEqual = (a, b) => a.size === b.size && [...a].every((x) => b.has(x));
135
+ return (setsEqual(expressResult, expected) &&
136
+ setsEqual(nextjsResult, expected) &&
137
+ setsEqual(flaskResult, expected) &&
138
+ setsEqual(springResult, expected));
139
+ }));
140
+ });
141
+ });
142
+ });
143
+ describe("inferResourceType - Property Tests", () => {
144
+ describe("Singularization properties", () => {
145
+ it("output is never longer than the resource segment", () => {
146
+ fc.assert(fc.property(arbitraries.pluralNoun, (plural) => {
147
+ const path = `/api/${plural}`;
148
+ const result = inferResourceType(path);
149
+ if (!result)
150
+ return true;
151
+ return result.length <= plural.length;
152
+ }));
153
+ });
154
+ it("returns undefined for empty or root paths", () => {
155
+ fc.assert(fc.property(fc.constantFrom("", "/", "//"), (path) => {
156
+ const result = inferResourceType(path);
157
+ return result === undefined;
158
+ }));
159
+ });
160
+ it("result does not end with 's' for regular plurals (with exceptions)", () => {
161
+ // Words like "users", "orders", "products" should become "user", "order", "product"
162
+ const regularPlurals = fc.constantFrom("users", "orders", "products", "items", "files", "posts");
163
+ fc.assert(fc.property(regularPlurals, (plural) => {
164
+ const path = `/api/${plural}`;
165
+ const result = inferResourceType(path);
166
+ if (!result)
167
+ return true;
168
+ // Regular plurals (ending in just 's') should be singularized
169
+ return !result.endsWith("s") || result.endsWith("ss");
170
+ }));
171
+ });
172
+ it("'-ies' endings become '-y'", () => {
173
+ const iesPlurals = fc.constantFrom("categories", "companies", "stories", "entries", "policies");
174
+ fc.assert(fc.property(iesPlurals, (plural) => {
175
+ const path = `/api/${plural}`;
176
+ const result = inferResourceType(path);
177
+ if (!result)
178
+ return true;
179
+ return result.endsWith("y");
180
+ }));
181
+ });
182
+ it("handles '-ses' endings correctly", () => {
183
+ const sesPlurals = fc.constantFrom("addresses", "statuses", "databases");
184
+ fc.assert(fc.property(sesPlurals, (plural) => {
185
+ const path = `/api/${plural}`;
186
+ const result = inferResourceType(path);
187
+ if (!result)
188
+ return true;
189
+ // "addresses" -> "address", "statuses" -> "status"
190
+ return !result.endsWith("es") || result === plural;
191
+ }));
192
+ });
193
+ it("handles '-xes', '-ches', '-shes' endings", () => {
194
+ const esPlurals = fc.constantFrom("boxes", "matches", "bushes", "taxes");
195
+ fc.assert(fc.property(esPlurals, (plural) => {
196
+ const path = `/api/${plural}`;
197
+ const result = inferResourceType(path);
198
+ if (!result)
199
+ return true;
200
+ // These should drop "es" but keep the base
201
+ return result.length < plural.length;
202
+ }));
203
+ });
204
+ it("is idempotent after one application", () => {
205
+ fc.assert(fc.property(arbitraries.pluralNoun, (plural) => {
206
+ const path1 = `/api/${plural}`;
207
+ const result1 = inferResourceType(path1);
208
+ if (!result1)
209
+ return true;
210
+ // Applying again (pluralizing then singularizing) should be stable
211
+ const path2 = `/api/${result1}s`;
212
+ const result2 = inferResourceType(path2);
213
+ // The second singularization should match the first
214
+ // (This tests stability, not exact equality since re-pluralizing changes the input)
215
+ return result2 !== undefined;
216
+ }));
217
+ });
218
+ });
219
+ describe("API path handling", () => {
220
+ it("extracts resource from standard API paths", () => {
221
+ fc.assert(fc.property(arbitraries.apiPrefix, arbitraries.pluralNoun, (prefix, resource) => {
222
+ const path = `${prefix}/${resource}`;
223
+ const result = inferResourceType(path);
224
+ // Should return something for valid paths
225
+ return result !== undefined || path === "/" || path === "";
226
+ }));
227
+ });
228
+ it("ignores numeric ID segments", () => {
229
+ fc.assert(fc.property(arbitraries.pluralNoun, fc.nat({ max: 9999 }), (resource, id) => {
230
+ const path = `/api/${resource}/${id}`;
231
+ const result = inferResourceType(path);
232
+ // Should extract the resource, not the ID
233
+ return result !== undefined && !/^\d+$/.test(result);
234
+ }));
235
+ });
236
+ });
237
+ });
238
+ //# sourceMappingURL=endpoint-analyzer.property.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"endpoint-analyzer.property.test.js","sourceRoot":"","sources":["../../../../src/__tests__/scanners/logic/endpoint-analyzer.property.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=endpoint-analyzer.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"endpoint-analyzer.test.d.ts","sourceRoot":"","sources":["../../../../src/__tests__/scanners/logic/endpoint-analyzer.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,55 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { extractPathParams, inferResourceType, } from "../../../scanners/logic/endpoint-analyzer.js";
3
+ describe("endpoint-analyzer", () => {
4
+ describe("extractPathParams", () => {
5
+ it("extracts Express-style colon params", () => {
6
+ const params = extractPathParams("/api/users/:id/posts/:postId");
7
+ expect(params).toContain("id");
8
+ expect(params).toContain("postId");
9
+ });
10
+ it("extracts Next.js-style bracket params", () => {
11
+ const params = extractPathParams("/api/users/[id]/posts/[postId]");
12
+ expect(params).toContain("id");
13
+ expect(params).toContain("postId");
14
+ });
15
+ it("extracts Flask/Django-style angle bracket params", () => {
16
+ const params = extractPathParams("/api/users/<id>/posts/<post_id:int>");
17
+ expect(params).toContain("id");
18
+ expect(params).toContain("post_id");
19
+ });
20
+ it("extracts Spring-style curly brace params", () => {
21
+ const params = extractPathParams("/api/users/{id}/posts/{postId}");
22
+ expect(params).toContain("id");
23
+ expect(params).toContain("postId");
24
+ });
25
+ it("returns empty array for paths without params", () => {
26
+ const params = extractPathParams("/api/users/all");
27
+ expect(params).toHaveLength(0);
28
+ });
29
+ it("handles mixed parameter styles", () => {
30
+ const params = extractPathParams("/api/:userId/[orderId]");
31
+ expect(params).toContain("userId");
32
+ expect(params).toContain("orderId");
33
+ });
34
+ });
35
+ describe("inferResourceType", () => {
36
+ it("infers resource from API path", () => {
37
+ expect(inferResourceType("/api/users")).toBe("user");
38
+ expect(inferResourceType("/api/v1/orders")).toBe("order");
39
+ expect(inferResourceType("/api/products/123")).toBe("product");
40
+ });
41
+ it("handles pluralized resources correctly", () => {
42
+ expect(inferResourceType("/api/categories")).toBe("category");
43
+ expect(inferResourceType("/api/companies")).toBe("company");
44
+ expect(inferResourceType("/api/addresses")).toBe("address");
45
+ });
46
+ it("extracts first resource segment from nested paths", () => {
47
+ // The function extracts the first resource segment after /api/v*
48
+ expect(inferResourceType("/api/v2/admin/users")).toBe("admin");
49
+ });
50
+ it("returns undefined for root paths", () => {
51
+ expect(inferResourceType("/")).toBeUndefined();
52
+ });
53
+ });
54
+ });
55
+ //# sourceMappingURL=endpoint-analyzer.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"endpoint-analyzer.test.js","sourceRoot":"","sources":["../../../../src/__tests__/scanners/logic/endpoint-analyzer.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../../../../src/__tests__/scanners/logic/index.test.ts"],"names":[],"mappings":""}