vskill 0.5.2 → 0.5.4

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 (205) hide show
  1. package/dist/agents/agents-registry.test.d.ts +1 -0
  2. package/dist/agents/agents-registry.test.js +248 -0
  3. package/dist/agents/agents-registry.test.js.map +1 -0
  4. package/dist/api/client.test.d.ts +1 -0
  5. package/dist/api/client.test.js +428 -0
  6. package/dist/api/client.test.js.map +1 -0
  7. package/dist/audit/audit-integration.test.d.ts +1 -0
  8. package/dist/audit/audit-integration.test.js +92 -0
  9. package/dist/audit/audit-integration.test.js.map +1 -0
  10. package/dist/audit/audit-llm.test.d.ts +1 -0
  11. package/dist/audit/audit-llm.test.js +110 -0
  12. package/dist/audit/audit-llm.test.js.map +1 -0
  13. package/dist/audit/audit-patterns.test.d.ts +1 -0
  14. package/dist/audit/audit-patterns.test.js +91 -0
  15. package/dist/audit/audit-patterns.test.js.map +1 -0
  16. package/dist/audit/audit-scanner.test.d.ts +1 -0
  17. package/dist/audit/audit-scanner.test.js +112 -0
  18. package/dist/audit/audit-scanner.test.js.map +1 -0
  19. package/dist/audit/audit-types.test.d.ts +1 -0
  20. package/dist/audit/audit-types.test.js +140 -0
  21. package/dist/audit/audit-types.test.js.map +1 -0
  22. package/dist/audit/config.test.d.ts +1 -0
  23. package/dist/audit/config.test.js +44 -0
  24. package/dist/audit/config.test.js.map +1 -0
  25. package/dist/audit/file-discovery.test.d.ts +1 -0
  26. package/dist/audit/file-discovery.test.js +120 -0
  27. package/dist/audit/file-discovery.test.js.map +1 -0
  28. package/dist/audit/fix-suggestions.test.d.ts +1 -0
  29. package/dist/audit/fix-suggestions.test.js +35 -0
  30. package/dist/audit/fix-suggestions.test.js.map +1 -0
  31. package/dist/audit/formatters/json-formatter.test.d.ts +1 -0
  32. package/dist/audit/formatters/json-formatter.test.js +49 -0
  33. package/dist/audit/formatters/json-formatter.test.js.map +1 -0
  34. package/dist/audit/formatters/report-formatter.test.d.ts +1 -0
  35. package/dist/audit/formatters/report-formatter.test.js +51 -0
  36. package/dist/audit/formatters/report-formatter.test.js.map +1 -0
  37. package/dist/audit/formatters/sarif-formatter.test.d.ts +1 -0
  38. package/dist/audit/formatters/sarif-formatter.test.js +71 -0
  39. package/dist/audit/formatters/sarif-formatter.test.js.map +1 -0
  40. package/dist/audit/formatters/terminal-formatter.test.d.ts +1 -0
  41. package/dist/audit/formatters/terminal-formatter.test.js +51 -0
  42. package/dist/audit/formatters/terminal-formatter.test.js.map +1 -0
  43. package/dist/blocklist/blocklist-e2e.test.d.ts +1 -0
  44. package/dist/blocklist/blocklist-e2e.test.js +346 -0
  45. package/dist/blocklist/blocklist-e2e.test.js.map +1 -0
  46. package/dist/blocklist/blocklist.test.d.ts +1 -0
  47. package/dist/blocklist/blocklist.test.js +259 -0
  48. package/dist/blocklist/blocklist.test.js.map +1 -0
  49. package/dist/commands/__tests__/eval-router.test.d.ts +1 -0
  50. package/dist/commands/__tests__/eval-router.test.js +60 -0
  51. package/dist/commands/__tests__/eval-router.test.js.map +1 -0
  52. package/dist/commands/__tests__/eval-serve.test.d.ts +1 -0
  53. package/dist/commands/__tests__/eval-serve.test.js +23 -0
  54. package/dist/commands/__tests__/eval-serve.test.js.map +1 -0
  55. package/dist/commands/add-blocklist-e2e.test.d.ts +1 -0
  56. package/dist/commands/add-blocklist-e2e.test.js +397 -0
  57. package/dist/commands/add-blocklist-e2e.test.js.map +1 -0
  58. package/dist/commands/add-wizard.test.d.ts +1 -0
  59. package/dist/commands/add-wizard.test.js +392 -0
  60. package/dist/commands/add-wizard.test.js.map +1 -0
  61. package/dist/commands/add.test.d.ts +1 -0
  62. package/dist/commands/add.test.js +2365 -0
  63. package/dist/commands/add.test.js.map +1 -0
  64. package/dist/commands/audit.test.d.ts +1 -0
  65. package/dist/commands/audit.test.js +79 -0
  66. package/dist/commands/audit.test.js.map +1 -0
  67. package/dist/commands/blocklist.test.d.ts +1 -0
  68. package/dist/commands/blocklist.test.js +158 -0
  69. package/dist/commands/blocklist.test.js.map +1 -0
  70. package/dist/commands/eval/__tests__/coverage.test.d.ts +1 -0
  71. package/dist/commands/eval/__tests__/coverage.test.js +122 -0
  72. package/dist/commands/eval/__tests__/coverage.test.js.map +1 -0
  73. package/dist/commands/eval/__tests__/generate-all.test.d.ts +1 -0
  74. package/dist/commands/eval/__tests__/generate-all.test.js +133 -0
  75. package/dist/commands/eval/__tests__/generate-all.test.js.map +1 -0
  76. package/dist/commands/eval/__tests__/init.test.d.ts +1 -0
  77. package/dist/commands/eval/__tests__/init.test.js +116 -0
  78. package/dist/commands/eval/__tests__/init.test.js.map +1 -0
  79. package/dist/commands/eval/__tests__/run.test.d.ts +1 -0
  80. package/dist/commands/eval/__tests__/run.test.js +186 -0
  81. package/dist/commands/eval/__tests__/run.test.js.map +1 -0
  82. package/dist/commands/find.test.d.ts +1 -0
  83. package/dist/commands/find.test.js +481 -0
  84. package/dist/commands/find.test.js.map +1 -0
  85. package/dist/commands/marketplace.test.d.ts +1 -0
  86. package/dist/commands/marketplace.test.js +129 -0
  87. package/dist/commands/marketplace.test.js.map +1 -0
  88. package/dist/commands/remove.test.d.ts +1 -0
  89. package/dist/commands/remove.test.js +164 -0
  90. package/dist/commands/remove.test.js.map +1 -0
  91. package/dist/commands/should-skip.test.d.ts +1 -0
  92. package/dist/commands/should-skip.test.js +56 -0
  93. package/dist/commands/should-skip.test.js.map +1 -0
  94. package/dist/commands/submit.test.d.ts +1 -0
  95. package/dist/commands/submit.test.js +83 -0
  96. package/dist/commands/submit.test.js.map +1 -0
  97. package/dist/commands/update.test.d.ts +1 -0
  98. package/dist/commands/update.test.js +250 -0
  99. package/dist/commands/update.test.js.map +1 -0
  100. package/dist/discovery/github-tree.test.d.ts +1 -0
  101. package/dist/discovery/github-tree.test.js +372 -0
  102. package/dist/discovery/github-tree.test.js.map +1 -0
  103. package/dist/eval/__tests__/activation-tester.test.d.ts +1 -0
  104. package/dist/eval/__tests__/activation-tester.test.js +203 -0
  105. package/dist/eval/__tests__/activation-tester.test.js.map +1 -0
  106. package/dist/eval/__tests__/benchmark-history.test.d.ts +1 -0
  107. package/dist/eval/__tests__/benchmark-history.test.js +422 -0
  108. package/dist/eval/__tests__/benchmark-history.test.js.map +1 -0
  109. package/dist/eval/__tests__/benchmark.test.d.ts +1 -0
  110. package/dist/eval/__tests__/benchmark.test.js +94 -0
  111. package/dist/eval/__tests__/benchmark.test.js.map +1 -0
  112. package/dist/eval/__tests__/comparator.test.d.ts +1 -0
  113. package/dist/eval/__tests__/comparator.test.js +282 -0
  114. package/dist/eval/__tests__/comparator.test.js.map +1 -0
  115. package/dist/eval/__tests__/judge.test.d.ts +1 -0
  116. package/dist/eval/__tests__/judge.test.js +122 -0
  117. package/dist/eval/__tests__/judge.test.js.map +1 -0
  118. package/dist/eval/__tests__/llm.test.d.ts +1 -0
  119. package/dist/eval/__tests__/llm.test.js +543 -0
  120. package/dist/eval/__tests__/llm.test.js.map +1 -0
  121. package/dist/eval/__tests__/mcp-detector.test.d.ts +1 -0
  122. package/dist/eval/__tests__/mcp-detector.test.js +180 -0
  123. package/dist/eval/__tests__/mcp-detector.test.js.map +1 -0
  124. package/dist/eval/__tests__/prompt-builder.test.d.ts +1 -0
  125. package/dist/eval/__tests__/prompt-builder.test.js +142 -0
  126. package/dist/eval/__tests__/prompt-builder.test.js.map +1 -0
  127. package/dist/eval/__tests__/schema.test.d.ts +1 -0
  128. package/dist/eval/__tests__/schema.test.js +247 -0
  129. package/dist/eval/__tests__/schema.test.js.map +1 -0
  130. package/dist/eval/__tests__/skill-scanner.test.d.ts +1 -0
  131. package/dist/eval/__tests__/skill-scanner.test.js +228 -0
  132. package/dist/eval/__tests__/skill-scanner.test.js.map +1 -0
  133. package/dist/eval/__tests__/verdict.test.d.ts +1 -0
  134. package/dist/eval/__tests__/verdict.test.js +47 -0
  135. package/dist/eval/__tests__/verdict.test.js.map +1 -0
  136. package/dist/eval-server/__tests__/benchmark-runner.test.d.ts +1 -0
  137. package/dist/eval-server/__tests__/benchmark-runner.test.js +301 -0
  138. package/dist/eval-server/__tests__/benchmark-runner.test.js.map +1 -0
  139. package/dist/eval-server/__tests__/comparison-sse-events.test.d.ts +1 -0
  140. package/dist/eval-server/__tests__/comparison-sse-events.test.js +278 -0
  141. package/dist/eval-server/__tests__/comparison-sse-events.test.js.map +1 -0
  142. package/dist/eval-server/__tests__/sse-helpers.test.d.ts +1 -0
  143. package/dist/eval-server/__tests__/sse-helpers.test.js +128 -0
  144. package/dist/eval-server/__tests__/sse-helpers.test.js.map +1 -0
  145. package/dist/installer/canonical.test.d.ts +1 -0
  146. package/dist/installer/canonical.test.js +264 -0
  147. package/dist/installer/canonical.test.js.map +1 -0
  148. package/dist/lockfile/lockfile.test.d.ts +1 -0
  149. package/dist/lockfile/lockfile.test.js +204 -0
  150. package/dist/lockfile/lockfile.test.js.map +1 -0
  151. package/dist/lockfile/project-root.test.d.ts +1 -0
  152. package/dist/lockfile/project-root.test.js +49 -0
  153. package/dist/lockfile/project-root.test.js.map +1 -0
  154. package/dist/marketplace/marketplace.test.d.ts +1 -0
  155. package/dist/marketplace/marketplace.test.js +312 -0
  156. package/dist/marketplace/marketplace.test.js.map +1 -0
  157. package/dist/resolvers/source-resolver.test.d.ts +1 -0
  158. package/dist/resolvers/source-resolver.test.js +104 -0
  159. package/dist/resolvers/source-resolver.test.js.map +1 -0
  160. package/dist/resolvers/url-resolver.test.d.ts +1 -0
  161. package/dist/resolvers/url-resolver.test.js +49 -0
  162. package/dist/resolvers/url-resolver.test.js.map +1 -0
  163. package/dist/scanner/dci-integration.test.d.ts +1 -0
  164. package/dist/scanner/dci-integration.test.js +83 -0
  165. package/dist/scanner/dci-integration.test.js.map +1 -0
  166. package/dist/scanner/patterns.test.d.ts +1 -0
  167. package/dist/scanner/patterns.test.js +832 -0
  168. package/dist/scanner/patterns.test.js.map +1 -0
  169. package/dist/scanner/tier1.test.d.ts +1 -0
  170. package/dist/scanner/tier1.test.js +305 -0
  171. package/dist/scanner/tier1.test.js.map +1 -0
  172. package/dist/security/platform-security.test.d.ts +1 -0
  173. package/dist/security/platform-security.test.js +92 -0
  174. package/dist/security/platform-security.test.js.map +1 -0
  175. package/dist/settings/settings.test.d.ts +1 -0
  176. package/dist/settings/settings.test.js +103 -0
  177. package/dist/settings/settings.test.js.map +1 -0
  178. package/dist/updater/source-fetcher.test.d.ts +1 -0
  179. package/dist/updater/source-fetcher.test.js +192 -0
  180. package/dist/updater/source-fetcher.test.js.map +1 -0
  181. package/dist/utils/__tests__/paths.test.d.ts +1 -0
  182. package/dist/utils/__tests__/paths.test.js +22 -0
  183. package/dist/utils/__tests__/paths.test.js.map +1 -0
  184. package/dist/utils/__tests__/resolve-binary.integration.test.d.ts +1 -0
  185. package/dist/utils/__tests__/resolve-binary.integration.test.js +138 -0
  186. package/dist/utils/__tests__/resolve-binary.integration.test.js.map +1 -0
  187. package/dist/utils/__tests__/resolve-binary.test.d.ts +1 -0
  188. package/dist/utils/__tests__/resolve-binary.test.js +175 -0
  189. package/dist/utils/__tests__/resolve-binary.test.js.map +1 -0
  190. package/dist/utils/__tests__/validation.test.d.ts +1 -0
  191. package/dist/utils/__tests__/validation.test.js +107 -0
  192. package/dist/utils/__tests__/validation.test.js.map +1 -0
  193. package/dist/utils/agent-filter.test.d.ts +1 -0
  194. package/dist/utils/agent-filter.test.js +75 -0
  195. package/dist/utils/agent-filter.test.js.map +1 -0
  196. package/dist/utils/output.test.d.ts +1 -0
  197. package/dist/utils/output.test.js +28 -0
  198. package/dist/utils/output.test.js.map +1 -0
  199. package/dist/utils/project-root.test.d.ts +1 -0
  200. package/dist/utils/project-root.test.js +74 -0
  201. package/dist/utils/project-root.test.js.map +1 -0
  202. package/dist/utils/prompts.test.d.ts +1 -0
  203. package/dist/utils/prompts.test.js +285 -0
  204. package/dist/utils/prompts.test.js.map +1 -0
  205. package/package.json +1 -1
@@ -0,0 +1,110 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { buildLlmPrompt, parseLlmResponse, runLlmAnalysis } from "./audit-llm.js";
3
+ import { createDefaultAuditConfig } from "./audit-types.js";
4
+ describe("audit-llm", () => {
5
+ describe("buildLlmPrompt", () => {
6
+ it("TC-040: builds correct prompt with file content and Tier 1 findings", () => {
7
+ const file = {
8
+ path: "src/handler.ts",
9
+ content: 'const msg = req.body.message;\nexec(`echo ${msg}`);',
10
+ sizeBytes: 50,
11
+ };
12
+ const findings = [
13
+ {
14
+ id: "AF-001", ruleId: "CI-001", severity: "critical", confidence: "high",
15
+ category: "command-injection", message: "exec() call detected",
16
+ filePath: "src/handler.ts", line: 2, snippet: "exec(`echo ${msg}`);",
17
+ source: "tier1",
18
+ },
19
+ ];
20
+ const prompt = buildLlmPrompt(file, findings);
21
+ expect(prompt).toContain("src/handler.ts");
22
+ expect(prompt).toContain("exec(`echo ${msg}`)");
23
+ expect(prompt).toContain("CI-001");
24
+ expect(prompt).toContain("command-injection");
25
+ });
26
+ });
27
+ describe("parseLlmResponse", () => {
28
+ it("TC-041: parses valid LLM JSON response", () => {
29
+ const response = JSON.stringify({
30
+ findings: [
31
+ {
32
+ ruleId: "LLM-CI-001",
33
+ severity: "critical",
34
+ confidence: "high",
35
+ category: "command-injection",
36
+ message: "Command injection via webhook payload",
37
+ line: 2,
38
+ dataFlow: {
39
+ steps: [
40
+ { file: "src/handler.ts", line: 1, description: "User input", code: "const msg = req.body.message;" },
41
+ { file: "src/handler.ts", line: 2, description: "Shell exec", code: "exec(`echo ${msg}`);" },
42
+ ],
43
+ },
44
+ suggestedFix: "Use execFile with array args instead of exec with template",
45
+ },
46
+ ],
47
+ });
48
+ const parsed = parseLlmResponse(response, "src/handler.ts");
49
+ expect(parsed).toHaveLength(1);
50
+ expect(parsed[0].ruleId).toBe("LLM-CI-001");
51
+ expect(parsed[0].source).toBe("llm");
52
+ expect(parsed[0].filePath).toBe("src/handler.ts");
53
+ });
54
+ it("TC-042: returns empty array on invalid JSON", () => {
55
+ const parsed = parseLlmResponse("not json at all", "src/file.ts");
56
+ expect(parsed).toHaveLength(0);
57
+ });
58
+ it("TC-045: data flow trace is parsed from LLM response", () => {
59
+ const response = JSON.stringify({
60
+ findings: [{
61
+ ruleId: "LLM-SSRF-001",
62
+ severity: "high",
63
+ confidence: "high",
64
+ category: "ssrf",
65
+ message: "SSRF via user URL",
66
+ line: 10,
67
+ dataFlow: {
68
+ steps: [
69
+ { file: "src/api.ts", line: 5, description: "Input received", code: "const url = req.query.url;" },
70
+ { file: "src/api.ts", line: 10, description: "Fetch called", code: "fetch(url);" },
71
+ ],
72
+ },
73
+ }],
74
+ });
75
+ const parsed = parseLlmResponse(response, "src/api.ts");
76
+ expect(parsed[0].dataFlow).toBeDefined();
77
+ expect(parsed[0].dataFlow.steps).toHaveLength(2);
78
+ expect(parsed[0].dataFlow.steps[0].file).toBe("src/api.ts");
79
+ expect(parsed[0].dataFlow.steps[1].line).toBe(10);
80
+ });
81
+ it("TC-046: missing data flow is handled gracefully", () => {
82
+ const response = JSON.stringify({
83
+ findings: [{
84
+ ruleId: "LLM-XSS-001",
85
+ severity: "high",
86
+ confidence: "medium",
87
+ category: "xss",
88
+ message: "Potential XSS",
89
+ line: 5,
90
+ }],
91
+ });
92
+ const parsed = parseLlmResponse(response, "src/page.ts");
93
+ expect(parsed[0].dataFlow).toBeUndefined();
94
+ });
95
+ });
96
+ describe("runLlmAnalysis", () => {
97
+ it("TC-043: skips LLM when tier1Only is true", async () => {
98
+ const config = createDefaultAuditConfig();
99
+ config.tier1Only = true;
100
+ const result = await runLlmAnalysis([], [], config);
101
+ expect(result).toHaveLength(0);
102
+ });
103
+ it("TC-044: returns empty when no flagged files", async () => {
104
+ const config = createDefaultAuditConfig();
105
+ const result = await runLlmAnalysis([], [], config);
106
+ expect(result).toHaveLength(0);
107
+ });
108
+ });
109
+ });
110
+ //# sourceMappingURL=audit-llm.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-llm.test.js","sourceRoot":"","sources":["../../src/audit/audit-llm.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAkB,MAAM,QAAQ,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAClF,OAAO,EAAE,wBAAwB,EAAqC,MAAM,kBAAkB,CAAC;AAE/F,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;IACzB,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;QAC9B,EAAE,CAAC,qEAAqE,EAAE,GAAG,EAAE;YAC7E,MAAM,IAAI,GAAc;gBACtB,IAAI,EAAE,gBAAgB;gBACtB,OAAO,EAAE,qDAAqD;gBAC9D,SAAS,EAAE,EAAE;aACd,CAAC;YACF,MAAM,QAAQ,GAAmB;gBAC/B;oBACE,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM;oBACxE,QAAQ,EAAE,mBAAmB,EAAE,OAAO,EAAE,sBAAsB;oBAC9D,QAAQ,EAAE,gBAAgB,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,sBAAsB;oBACpE,MAAM,EAAE,OAAO;iBAChB;aACF,CAAC;YAEF,MAAM,MAAM,GAAG,cAAc,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;YAE9C,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;YAC3C,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,qBAAqB,CAAC,CAAC;YAChD,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;YACnC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC;QAChD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;QAChC,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;YAChD,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC;gBAC9B,QAAQ,EAAE;oBACR;wBACE,MAAM,EAAE,YAAY;wBACpB,QAAQ,EAAE,UAAU;wBACpB,UAAU,EAAE,MAAM;wBAClB,QAAQ,EAAE,mBAAmB;wBAC7B,OAAO,EAAE,uCAAuC;wBAChD,IAAI,EAAE,CAAC;wBACP,QAAQ,EAAE;4BACR,KAAK,EAAE;gCACL,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,CAAC,EAAE,WAAW,EAAE,YAAY,EAAE,IAAI,EAAE,+BAA+B,EAAE;gCACrG,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,CAAC,EAAE,WAAW,EAAE,YAAY,EAAE,IAAI,EAAE,sBAAsB,EAAE;6BAC7F;yBACF;wBACD,YAAY,EAAE,4DAA4D;qBAC3E;iBACF;aACF,CAAC,CAAC;YAEH,MAAM,MAAM,GAAG,gBAAgB,CAAC,QAAQ,EAAE,gBAAgB,CAAC,CAAC;YAE5D,MAAM,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YAC/B,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YAC5C,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACrC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;QACpD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;YACrD,MAAM,MAAM,GAAG,gBAAgB,CAAC,iBAAiB,EAAE,aAAa,CAAC,CAAC;YAClE,MAAM,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACjC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;YAC7D,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC;gBAC9B,QAAQ,EAAE,CAAC;wBACT,MAAM,EAAE,cAAc;wBACtB,QAAQ,EAAE,MAAM;wBAChB,UAAU,EAAE,MAAM;wBAClB,QAAQ,EAAE,MAAM;wBAChB,OAAO,EAAE,mBAAmB;wBAC5B,IAAI,EAAE,EAAE;wBACR,QAAQ,EAAE;4BACR,KAAK,EAAE;gCACL,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,EAAE,WAAW,EAAE,gBAAgB,EAAE,IAAI,EAAE,4BAA4B,EAAE;gCAClG,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,EAAE,EAAE,WAAW,EAAE,cAAc,EAAE,IAAI,EAAE,aAAa,EAAE;6BACnF;yBACF;qBACF,CAAC;aACH,CAAC,CAAC;YAEH,MAAM,MAAM,GAAG,gBAAgB,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;YAExD,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;YACzC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAS,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YAClD,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YAC7D,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACrD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;YACzD,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC;gBAC9B,QAAQ,EAAE,CAAC;wBACT,MAAM,EAAE,aAAa;wBACrB,QAAQ,EAAE,MAAM;wBAChB,UAAU,EAAE,QAAQ;wBACpB,QAAQ,EAAE,KAAK;wBACf,OAAO,EAAE,eAAe;wBACxB,IAAI,EAAE,CAAC;qBACR,CAAC;aACH,CAAC,CAAC;YAEH,MAAM,MAAM,GAAG,gBAAgB,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;YAEzD,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,aAAa,EAAE,CAAC;QAC7C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;QAC9B,EAAE,CAAC,0CAA0C,EAAE,KAAK,IAAI,EAAE;YACxD,MAAM,MAAM,GAAG,wBAAwB,EAAE,CAAC;YAC1C,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC;YAExB,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC;YAEpD,MAAM,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACjC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;YAC3D,MAAM,MAAM,GAAG,wBAAwB,EAAE,CAAC;YAC1C,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC;YACpD,MAAM,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACjC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,91 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { AUDIT_PATTERNS, PROJECT_PATTERNS } from "./audit-patterns.js";
3
+ import { SCAN_PATTERNS } from "../scanner/patterns.js";
4
+ describe("audit-patterns", () => {
5
+ it("TC-009: AUDIT_PATTERNS includes all 37 original SCAN_PATTERNS", () => {
6
+ const auditIds = new Set(AUDIT_PATTERNS.map((p) => p.id));
7
+ for (const original of SCAN_PATTERNS) {
8
+ expect(auditIds.has(original.id)).toBe(true);
9
+ }
10
+ });
11
+ it("TC-010: AUDIT_PATTERNS adds at least 15 new project-specific patterns", () => {
12
+ const originalIds = new Set(SCAN_PATTERNS.map((p) => p.id));
13
+ const newPatterns = AUDIT_PATTERNS.filter((p) => !originalIds.has(p.id));
14
+ expect(newPatterns.length).toBeGreaterThanOrEqual(15);
15
+ });
16
+ it("TC-011: SQL injection pattern detects string concatenation in queries", () => {
17
+ const sqliPatterns = PROJECT_PATTERNS.filter((p) => p.category === "sql-injection");
18
+ expect(sqliPatterns.length).toBeGreaterThan(0);
19
+ const testLine = `"SELECT * FROM users WHERE id = '" + userId + "'"`;
20
+ const matched = sqliPatterns.some((p) => {
21
+ const regex = new RegExp(p.pattern.source, p.pattern.flags);
22
+ return regex.test(testLine);
23
+ });
24
+ expect(matched).toBe(true);
25
+ });
26
+ it("TC-012: SSRF pattern detects URL construction from variables", () => {
27
+ const ssrfPatterns = PROJECT_PATTERNS.filter((p) => p.category === "ssrf");
28
+ expect(ssrfPatterns.length).toBeGreaterThan(0);
29
+ const testLine = `fetch(userProvidedUrl)`;
30
+ const matched = ssrfPatterns.some((p) => {
31
+ const regex = new RegExp(p.pattern.source, p.pattern.flags);
32
+ return regex.test(testLine);
33
+ });
34
+ expect(matched).toBe(true);
35
+ });
36
+ it("TC-013: Hardcoded secret pattern detects API key assignments", () => {
37
+ const secretPatterns = PROJECT_PATTERNS.filter((p) => p.category === "hardcoded-secrets");
38
+ expect(secretPatterns.length).toBeGreaterThan(0);
39
+ const testLine = `const API_KEY = "sk-1234567890abcdef"`;
40
+ const matched = secretPatterns.some((p) => {
41
+ const regex = new RegExp(p.pattern.source, p.pattern.flags);
42
+ return regex.test(testLine);
43
+ });
44
+ expect(matched).toBe(true);
45
+ });
46
+ it("TC-014: XSS pattern detects innerHTML assignment", () => {
47
+ const xssPatterns = PROJECT_PATTERNS.filter((p) => p.category === "xss");
48
+ expect(xssPatterns.length).toBeGreaterThan(0);
49
+ const testLine = `element.innerHTML = userInput`;
50
+ const matched = xssPatterns.some((p) => {
51
+ const regex = new RegExp(p.pattern.source, p.pattern.flags);
52
+ return regex.test(testLine);
53
+ });
54
+ expect(matched).toBe(true);
55
+ });
56
+ it("TC-015: safe contexts suppress false positives", () => {
57
+ const patternsWithSafe = PROJECT_PATTERNS.filter((p) => p.safeContexts && p.safeContexts.length > 0);
58
+ expect(patternsWithSafe.length).toBeGreaterThan(0);
59
+ // For each pattern with safeContexts, at least one safe context regex exists
60
+ for (const pattern of patternsWithSafe) {
61
+ expect(pattern.safeContexts.length).toBeGreaterThan(0);
62
+ expect(pattern.safeContexts[0]).toBeInstanceOf(RegExp);
63
+ }
64
+ });
65
+ it("TC-016: all pattern IDs are unique across combined set", () => {
66
+ const ids = AUDIT_PATTERNS.map((p) => p.id);
67
+ const uniqueIds = new Set(ids);
68
+ expect(uniqueIds.size).toBe(ids.length);
69
+ });
70
+ it("detects open redirect pattern", () => {
71
+ const redirectPatterns = PROJECT_PATTERNS.filter((p) => p.category === "open-redirect");
72
+ expect(redirectPatterns.length).toBeGreaterThan(0);
73
+ const testLine = `res.redirect(req.query.url)`;
74
+ const matched = redirectPatterns.some((p) => {
75
+ const regex = new RegExp(p.pattern.source, p.pattern.flags);
76
+ return regex.test(testLine);
77
+ });
78
+ expect(matched).toBe(true);
79
+ });
80
+ it("detects insecure deserialization", () => {
81
+ const deserPatterns = PROJECT_PATTERNS.filter((p) => p.category === "insecure-deserialization");
82
+ expect(deserPatterns.length).toBeGreaterThan(0);
83
+ const testLine = `yaml.load(userInput)`;
84
+ const matched = deserPatterns.some((p) => {
85
+ const regex = new RegExp(p.pattern.source, p.pattern.flags);
86
+ return regex.test(testLine);
87
+ });
88
+ expect(matched).toBe(true);
89
+ });
90
+ });
91
+ //# sourceMappingURL=audit-patterns.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-patterns.test.js","sourceRoot":"","sources":["../../src/audit/audit-patterns.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,112 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { runAuditScan } from "./audit-scanner.js";
3
+ import { createDefaultAuditConfig } from "./audit-types.js";
4
+ function makeFile(path, content) {
5
+ return { path, content, sizeBytes: Buffer.byteLength(content) };
6
+ }
7
+ describe("audit-scanner", () => {
8
+ it("TC-017: returns empty findings for clean files", () => {
9
+ const files = [
10
+ makeFile("src/clean.ts", "const x = 1;\nconst y = 2;\nexport { x, y };"),
11
+ makeFile("src/utils.ts", "export function add(a: number, b: number) { return a + b; }"),
12
+ ];
13
+ const config = createDefaultAuditConfig();
14
+ const result = runAuditScan(files, config);
15
+ expect(result.findings).toHaveLength(0);
16
+ expect(result.summary.verdict).toBe("PASS");
17
+ expect(result.summary.total).toBe(0);
18
+ expect(result.summary.score).toBe(100);
19
+ });
20
+ it("TC-018: detects findings across multiple files", () => {
21
+ const files = [
22
+ makeFile("src/cmd.ts", 'exec("rm -rf /");'),
23
+ makeFile("src/xss.ts", 'element.innerHTML = userInput;'),
24
+ makeFile("src/sql.ts", '`SELECT * FROM users WHERE id = ${userId}`'),
25
+ ];
26
+ const config = createDefaultAuditConfig();
27
+ const result = runAuditScan(files, config);
28
+ expect(result.findings.length).toBeGreaterThanOrEqual(3);
29
+ const filePaths = new Set(result.findings.map((f) => f.filePath));
30
+ expect(filePaths.has("src/cmd.ts")).toBe(true);
31
+ expect(filePaths.has("src/xss.ts")).toBe(true);
32
+ expect(filePaths.has("src/sql.ts")).toBe(true);
33
+ });
34
+ it("TC-019: findings are sorted by severity then file path", () => {
35
+ const files = [
36
+ makeFile("z-file.ts", "element.innerHTML = x;"), // high
37
+ makeFile("a-file.ts", 'eval("code");'), // critical
38
+ ];
39
+ const config = createDefaultAuditConfig();
40
+ const result = runAuditScan(files, config);
41
+ // Critical should come before high
42
+ const severities = result.findings.map((f) => f.severity);
43
+ const criticalIndex = severities.indexOf("critical");
44
+ const highIndex = severities.indexOf("high");
45
+ if (criticalIndex !== -1 && highIndex !== -1) {
46
+ expect(criticalIndex).toBeLessThan(highIndex);
47
+ }
48
+ });
49
+ it("TC-020: summary statistics are accurate", () => {
50
+ const files = [
51
+ makeFile("src/a.ts", 'eval("x");'), // critical (CE-001)
52
+ makeFile("src/b.ts", "element.innerHTML = y;"), // high (XSS-001)
53
+ ];
54
+ const config = createDefaultAuditConfig();
55
+ const result = runAuditScan(files, config);
56
+ expect(result.summary.total).toBe(result.findings.length);
57
+ expect(result.summary.critical + result.summary.high + result.summary.medium +
58
+ result.summary.low + result.summary.info).toBe(result.summary.total);
59
+ });
60
+ it("TC-021: score and verdict are calculated correctly", () => {
61
+ // Clean project -> score 100, PASS
62
+ const cleanFiles = [
63
+ makeFile("src/clean.ts", "const x = 1;"),
64
+ ];
65
+ const config = createDefaultAuditConfig();
66
+ const cleanResult = runAuditScan(cleanFiles, config);
67
+ expect(cleanResult.summary.score).toBe(100);
68
+ expect(cleanResult.summary.verdict).toBe("PASS");
69
+ // Many critical findings -> score < 50, FAIL
70
+ const badFiles = [
71
+ makeFile("src/bad.ts", [
72
+ 'eval("a");',
73
+ 'eval("b");',
74
+ 'eval("c");',
75
+ 'eval("d");',
76
+ 'eval("e");',
77
+ ].join("\n")),
78
+ ];
79
+ const badResult = runAuditScan(badFiles, config);
80
+ expect(badResult.summary.score).toBeLessThan(50);
81
+ expect(badResult.summary.verdict).toBe("FAIL");
82
+ });
83
+ it("TC-022: duration is tracked", () => {
84
+ const files = [makeFile("src/a.ts", "const x = 1;")];
85
+ const config = createDefaultAuditConfig();
86
+ const result = runAuditScan(files, config);
87
+ expect(result.durationMs).toBeGreaterThanOrEqual(0);
88
+ expect(typeof result.durationMs).toBe("number");
89
+ });
90
+ it("populates filesScanned and filesWithFindings", () => {
91
+ const files = [
92
+ makeFile("src/clean.ts", "const x = 1;"),
93
+ makeFile("src/bad.ts", 'eval("x");'),
94
+ makeFile("src/also-clean.ts", "const y = 2;"),
95
+ ];
96
+ const config = createDefaultAuditConfig();
97
+ const result = runAuditScan(files, config);
98
+ expect(result.filesScanned).toBe(3);
99
+ expect(result.filesWithFindings).toBe(1);
100
+ });
101
+ it("applies safeContexts to suppress false positives", () => {
102
+ // innerHTML in a line with DOMPurify should be suppressed
103
+ const files = [
104
+ makeFile("src/safe.ts", "element.innerHTML = DOMPurify.sanitize(input);"),
105
+ ];
106
+ const config = createDefaultAuditConfig();
107
+ const result = runAuditScan(files, config);
108
+ const xssFindings = result.findings.filter((f) => f.ruleId === "XSS-001");
109
+ expect(xssFindings).toHaveLength(0);
110
+ });
111
+ });
112
+ //# sourceMappingURL=audit-scanner.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-scanner.test.js","sourceRoot":"","sources":["../../src/audit/audit-scanner.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,140 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { createDefaultAuditConfig, } from "./audit-types.js";
3
+ describe("audit-types", () => {
4
+ describe("AuditFinding", () => {
5
+ it("TC-001: is correctly importable and all fields are typed", () => {
6
+ const finding = {
7
+ id: "AF-001",
8
+ ruleId: "CI-001",
9
+ severity: "critical",
10
+ confidence: "high",
11
+ category: "command-injection",
12
+ message: "exec() call detected",
13
+ filePath: "src/index.ts",
14
+ line: 42,
15
+ snippet: " exec(command);",
16
+ source: "tier1",
17
+ };
18
+ expect(finding.id).toBe("AF-001");
19
+ expect(finding.ruleId).toBe("CI-001");
20
+ expect(finding.severity).toBe("critical");
21
+ expect(finding.confidence).toBe("high");
22
+ expect(finding.category).toBe("command-injection");
23
+ expect(finding.message).toBe("exec() call detected");
24
+ expect(finding.filePath).toBe("src/index.ts");
25
+ expect(finding.line).toBe(42);
26
+ expect(finding.snippet).toBe(" exec(command);");
27
+ expect(finding.source).toBe("tier1");
28
+ });
29
+ it("supports optional fields: column, endLine, dataFlow, suggestedFix", () => {
30
+ const finding = {
31
+ id: "AF-002",
32
+ ruleId: "SSRF-001",
33
+ severity: "high",
34
+ confidence: "medium",
35
+ category: "ssrf",
36
+ message: "SSRF via user-controlled URL",
37
+ filePath: "src/api.ts",
38
+ line: 10,
39
+ column: 5,
40
+ endLine: 12,
41
+ snippet: " fetch(url);",
42
+ source: "llm",
43
+ dataFlow: {
44
+ steps: [
45
+ {
46
+ file: "src/api.ts",
47
+ line: 5,
48
+ description: "User input received",
49
+ code: "const url = req.query.url;",
50
+ },
51
+ ],
52
+ },
53
+ suggestedFix: "Validate URL against an allowlist",
54
+ };
55
+ expect(finding.column).toBe(5);
56
+ expect(finding.endLine).toBe(12);
57
+ expect(finding.dataFlow?.steps).toHaveLength(1);
58
+ expect(finding.suggestedFix).toBe("Validate URL against an allowlist");
59
+ });
60
+ });
61
+ describe("AuditConfig", () => {
62
+ it("TC-002: default values are correct", () => {
63
+ const config = createDefaultAuditConfig();
64
+ expect(config.excludePaths).toEqual([]);
65
+ expect(config.severityThreshold).toBe("low");
66
+ expect(config.maxFiles).toBe(500);
67
+ expect(config.maxFileSize).toBe(100 * 1024);
68
+ expect(config.tier1Only).toBe(false);
69
+ expect(config.llmProvider).toBeNull();
70
+ expect(config.llmTimeout).toBe(30_000);
71
+ expect(config.llmConcurrency).toBe(5);
72
+ expect(config.customPatterns).toEqual([]);
73
+ expect(config.fix).toBe(false);
74
+ });
75
+ });
76
+ describe("AuditResult", () => {
77
+ it("contains all required fields for a complete result", () => {
78
+ const result = {
79
+ rootPath: "/project",
80
+ startedAt: "2026-02-20T18:00:00Z",
81
+ completedAt: "2026-02-20T18:00:05Z",
82
+ durationMs: 5000,
83
+ filesScanned: 100,
84
+ filesWithFindings: 3,
85
+ findings: [],
86
+ summary: {
87
+ critical: 0,
88
+ high: 0,
89
+ medium: 0,
90
+ low: 0,
91
+ info: 0,
92
+ total: 0,
93
+ score: 100,
94
+ verdict: "PASS",
95
+ },
96
+ config: createDefaultAuditConfig(),
97
+ };
98
+ expect(result.rootPath).toBe("/project");
99
+ expect(result.filesScanned).toBe(100);
100
+ expect(result.summary.verdict).toBe("PASS");
101
+ expect(result.summary.score).toBe(100);
102
+ });
103
+ });
104
+ describe("DataFlowTrace", () => {
105
+ it("has steps with file, line, description, code", () => {
106
+ const trace = {
107
+ steps: [
108
+ {
109
+ file: "src/handler.ts",
110
+ line: 10,
111
+ description: "User input received from webhook",
112
+ code: 'const msg = req.body.message;',
113
+ },
114
+ {
115
+ file: "src/handler.ts",
116
+ line: 15,
117
+ description: "Passed to shell execution",
118
+ code: 'exec(`echo ${msg}`);',
119
+ },
120
+ ],
121
+ };
122
+ expect(trace.steps).toHaveLength(2);
123
+ expect(trace.steps[0].file).toBe("src/handler.ts");
124
+ expect(trace.steps[1].line).toBe(15);
125
+ });
126
+ });
127
+ describe("AuditFile", () => {
128
+ it("represents a discovered file with path, content, sizeBytes", () => {
129
+ const file = {
130
+ path: "src/index.ts",
131
+ content: "console.log('hello');",
132
+ sizeBytes: 21,
133
+ };
134
+ expect(file.path).toBe("src/index.ts");
135
+ expect(file.content).toBe("console.log('hello');");
136
+ expect(file.sizeBytes).toBe(21);
137
+ });
138
+ });
139
+ });
140
+ //# sourceMappingURL=audit-types.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-types.test.js","sourceRoot":"","sources":["../../src/audit/audit-types.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,44 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
+ import { mkdtemp, writeFile, rm } from "node:fs/promises";
3
+ import { join } from "node:path";
4
+ import { tmpdir } from "node:os";
5
+ import { loadAuditConfig } from "./config.js";
6
+ describe("config", () => {
7
+ let tmpDir;
8
+ beforeEach(async () => {
9
+ tmpDir = await mkdtemp(join(tmpdir(), "vskill-config-"));
10
+ });
11
+ afterEach(async () => {
12
+ await rm(tmpDir, { recursive: true, force: true });
13
+ });
14
+ it("TC-050: returns defaults when no config file exists", async () => {
15
+ const config = await loadAuditConfig(tmpDir, {});
16
+ expect(config.excludePaths).toEqual([]);
17
+ expect(config.maxFiles).toBe(500);
18
+ expect(config.severityThreshold).toBe("low");
19
+ expect(config.tier1Only).toBe(false);
20
+ expect(config.fix).toBe(false);
21
+ });
22
+ it("TC-051: loads and merges .vskill-audit.json", async () => {
23
+ await writeFile(join(tmpDir, ".vskill-audit.json"), JSON.stringify({ excludePaths: ["vendor/"], maxFiles: 200 }));
24
+ const config = await loadAuditConfig(tmpDir, {});
25
+ expect(config.excludePaths).toEqual(["vendor/"]);
26
+ expect(config.maxFiles).toBe(200);
27
+ // Other fields remain defaults
28
+ expect(config.severityThreshold).toBe("low");
29
+ });
30
+ it("TC-052: CLI flags override config file values", async () => {
31
+ await writeFile(join(tmpDir, ".vskill-audit.json"), JSON.stringify({ maxFiles: 100 }));
32
+ const config = await loadAuditConfig(tmpDir, { maxFiles: "50" });
33
+ expect(config.maxFiles).toBe(50);
34
+ });
35
+ it("TC-053: invalid severity value throws error", async () => {
36
+ await expect(loadAuditConfig(tmpDir, { severity: "invalid" })).rejects.toThrow();
37
+ });
38
+ it("loads .vskillrc as fallback", async () => {
39
+ await writeFile(join(tmpDir, ".vskillrc"), JSON.stringify({ tier1Only: true }));
40
+ const config = await loadAuditConfig(tmpDir, {});
41
+ expect(config.tier1Only).toBe(true);
42
+ });
43
+ });
44
+ //# sourceMappingURL=config.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.test.js","sourceRoot":"","sources":["../../src/audit/config.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};