@quantracode/vibecheck 0.0.1 → 0.0.2

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 (208) hide show
  1. package/README.md +6 -6
  2. package/dist/index.d.ts +0 -2
  3. package/dist/index.js +7902 -8
  4. package/package.json +13 -7
  5. package/dist/__tests__/cli.test.d.ts +0 -2
  6. package/dist/__tests__/cli.test.d.ts.map +0 -1
  7. package/dist/__tests__/cli.test.js +0 -243
  8. package/dist/__tests__/fixtures/safe-app/app/api/users/route.js +0 -36
  9. package/dist/__tests__/fixtures/vulnerable-app/app/api/users/route.js +0 -28
  10. package/dist/__tests__/fixtures/vulnerable-app/lib/config.d.ts +0 -4
  11. package/dist/__tests__/fixtures/vulnerable-app/lib/config.d.ts.map +0 -1
  12. package/dist/__tests__/fixtures/vulnerable-app/lib/config.js +0 -6
  13. package/dist/__tests__/scanners/env-config.test.d.ts +0 -2
  14. package/dist/__tests__/scanners/env-config.test.d.ts.map +0 -1
  15. package/dist/__tests__/scanners/env-config.test.js +0 -142
  16. package/dist/__tests__/scanners/nextjs-middleware.test.d.ts +0 -2
  17. package/dist/__tests__/scanners/nextjs-middleware.test.d.ts.map +0 -1
  18. package/dist/__tests__/scanners/nextjs-middleware.test.js +0 -193
  19. package/dist/__tests__/scanners/scanner-packs.test.d.ts +0 -2
  20. package/dist/__tests__/scanners/scanner-packs.test.d.ts.map +0 -1
  21. package/dist/__tests__/scanners/scanner-packs.test.js +0 -126
  22. package/dist/__tests__/scanners/unused-security-imports.test.d.ts +0 -2
  23. package/dist/__tests__/scanners/unused-security-imports.test.d.ts.map +0 -1
  24. package/dist/__tests__/scanners/unused-security-imports.test.js +0 -145
  25. package/dist/commands/demo-artifact.d.ts +0 -7
  26. package/dist/commands/demo-artifact.d.ts.map +0 -1
  27. package/dist/commands/demo-artifact.js +0 -322
  28. package/dist/commands/evaluate.d.ts +0 -30
  29. package/dist/commands/evaluate.d.ts.map +0 -1
  30. package/dist/commands/evaluate.js +0 -258
  31. package/dist/commands/explain.d.ts +0 -12
  32. package/dist/commands/explain.d.ts.map +0 -1
  33. package/dist/commands/explain.js +0 -214
  34. package/dist/commands/index.d.ts +0 -7
  35. package/dist/commands/index.d.ts.map +0 -1
  36. package/dist/commands/index.js +0 -6
  37. package/dist/commands/intent.d.ts +0 -21
  38. package/dist/commands/intent.d.ts.map +0 -1
  39. package/dist/commands/intent.js +0 -192
  40. package/dist/commands/scan.d.ts +0 -44
  41. package/dist/commands/scan.d.ts.map +0 -1
  42. package/dist/commands/scan.js +0 -497
  43. package/dist/commands/waivers.d.ts +0 -30
  44. package/dist/commands/waivers.d.ts.map +0 -1
  45. package/dist/commands/waivers.js +0 -249
  46. package/dist/index.d.ts.map +0 -1
  47. package/dist/phase3/index.d.ts +0 -11
  48. package/dist/phase3/index.d.ts.map +0 -1
  49. package/dist/phase3/index.js +0 -12
  50. package/dist/phase3/intent-miner.d.ts +0 -32
  51. package/dist/phase3/intent-miner.d.ts.map +0 -1
  52. package/dist/phase3/intent-miner.js +0 -323
  53. package/dist/phase3/proof-trace-builder.d.ts +0 -42
  54. package/dist/phase3/proof-trace-builder.d.ts.map +0 -1
  55. package/dist/phase3/proof-trace-builder.js +0 -441
  56. package/dist/phase3/scanners/auth-by-ui-server-gap.d.ts +0 -15
  57. package/dist/phase3/scanners/auth-by-ui-server-gap.d.ts.map +0 -1
  58. package/dist/phase3/scanners/auth-by-ui-server-gap.js +0 -237
  59. package/dist/phase3/scanners/comment-claim-unproven.d.ts +0 -14
  60. package/dist/phase3/scanners/comment-claim-unproven.d.ts.map +0 -1
  61. package/dist/phase3/scanners/comment-claim-unproven.js +0 -161
  62. package/dist/phase3/scanners/index.d.ts +0 -31
  63. package/dist/phase3/scanners/index.d.ts.map +0 -1
  64. package/dist/phase3/scanners/index.js +0 -40
  65. package/dist/phase3/scanners/middleware-assumed-not-matching.d.ts +0 -14
  66. package/dist/phase3/scanners/middleware-assumed-not-matching.d.ts.map +0 -1
  67. package/dist/phase3/scanners/middleware-assumed-not-matching.js +0 -172
  68. package/dist/phase3/scanners/validation-claimed-missing.d.ts +0 -15
  69. package/dist/phase3/scanners/validation-claimed-missing.d.ts.map +0 -1
  70. package/dist/phase3/scanners/validation-claimed-missing.js +0 -204
  71. package/dist/scanners/abuse/compute-abuse.d.ts +0 -20
  72. package/dist/scanners/abuse/compute-abuse.d.ts.map +0 -1
  73. package/dist/scanners/abuse/compute-abuse.js +0 -509
  74. package/dist/scanners/abuse/index.d.ts +0 -12
  75. package/dist/scanners/abuse/index.d.ts.map +0 -1
  76. package/dist/scanners/abuse/index.js +0 -15
  77. package/dist/scanners/auth/index.d.ts +0 -5
  78. package/dist/scanners/auth/index.d.ts.map +0 -1
  79. package/dist/scanners/auth/index.js +0 -10
  80. package/dist/scanners/auth/middleware-gap.d.ts +0 -22
  81. package/dist/scanners/auth/middleware-gap.d.ts.map +0 -1
  82. package/dist/scanners/auth/middleware-gap.js +0 -203
  83. package/dist/scanners/auth/unprotected-api-route.d.ts +0 -12
  84. package/dist/scanners/auth/unprotected-api-route.d.ts.map +0 -1
  85. package/dist/scanners/auth/unprotected-api-route.js +0 -126
  86. package/dist/scanners/config/index.d.ts +0 -5
  87. package/dist/scanners/config/index.d.ts.map +0 -1
  88. package/dist/scanners/config/index.js +0 -10
  89. package/dist/scanners/config/insecure-defaults.d.ts +0 -12
  90. package/dist/scanners/config/insecure-defaults.d.ts.map +0 -1
  91. package/dist/scanners/config/insecure-defaults.js +0 -77
  92. package/dist/scanners/config/undocumented-env.d.ts +0 -24
  93. package/dist/scanners/config/undocumented-env.d.ts.map +0 -1
  94. package/dist/scanners/config/undocumented-env.js +0 -159
  95. package/dist/scanners/crypto/index.d.ts +0 -6
  96. package/dist/scanners/crypto/index.d.ts.map +0 -1
  97. package/dist/scanners/crypto/index.js +0 -11
  98. package/dist/scanners/crypto/jwt-decode-unverified.d.ts +0 -14
  99. package/dist/scanners/crypto/jwt-decode-unverified.d.ts.map +0 -1
  100. package/dist/scanners/crypto/jwt-decode-unverified.js +0 -87
  101. package/dist/scanners/crypto/math-random-tokens.d.ts +0 -13
  102. package/dist/scanners/crypto/math-random-tokens.d.ts.map +0 -1
  103. package/dist/scanners/crypto/math-random-tokens.js +0 -80
  104. package/dist/scanners/crypto/weak-hashing.d.ts +0 -11
  105. package/dist/scanners/crypto/weak-hashing.d.ts.map +0 -1
  106. package/dist/scanners/crypto/weak-hashing.js +0 -95
  107. package/dist/scanners/env-config.d.ts +0 -24
  108. package/dist/scanners/env-config.d.ts.map +0 -1
  109. package/dist/scanners/env-config.js +0 -164
  110. package/dist/scanners/hallucinations/index.d.ts +0 -4
  111. package/dist/scanners/hallucinations/index.d.ts.map +0 -1
  112. package/dist/scanners/hallucinations/index.js +0 -8
  113. package/dist/scanners/hallucinations/unused-security-imports.d.ts +0 -36
  114. package/dist/scanners/hallucinations/unused-security-imports.d.ts.map +0 -1
  115. package/dist/scanners/hallucinations/unused-security-imports.js +0 -309
  116. package/dist/scanners/helpers/ast-helpers.d.ts +0 -6
  117. package/dist/scanners/helpers/ast-helpers.d.ts.map +0 -1
  118. package/dist/scanners/helpers/ast-helpers.js +0 -945
  119. package/dist/scanners/helpers/context-builder.d.ts +0 -17
  120. package/dist/scanners/helpers/context-builder.d.ts.map +0 -1
  121. package/dist/scanners/helpers/context-builder.js +0 -148
  122. package/dist/scanners/helpers/index.d.ts +0 -3
  123. package/dist/scanners/helpers/index.d.ts.map +0 -1
  124. package/dist/scanners/helpers/index.js +0 -2
  125. package/dist/scanners/index.d.ts +0 -30
  126. package/dist/scanners/index.d.ts.map +0 -1
  127. package/dist/scanners/index.js +0 -102
  128. package/dist/scanners/middleware/index.d.ts +0 -4
  129. package/dist/scanners/middleware/index.d.ts.map +0 -1
  130. package/dist/scanners/middleware/index.js +0 -7
  131. package/dist/scanners/middleware/missing-rate-limit.d.ts +0 -13
  132. package/dist/scanners/middleware/missing-rate-limit.d.ts.map +0 -1
  133. package/dist/scanners/middleware/missing-rate-limit.js +0 -140
  134. package/dist/scanners/network/cors-misconfiguration.d.ts +0 -14
  135. package/dist/scanners/network/cors-misconfiguration.d.ts.map +0 -1
  136. package/dist/scanners/network/cors-misconfiguration.js +0 -89
  137. package/dist/scanners/network/index.d.ts +0 -7
  138. package/dist/scanners/network/index.d.ts.map +0 -1
  139. package/dist/scanners/network/index.js +0 -18
  140. package/dist/scanners/network/missing-timeout.d.ts +0 -15
  141. package/dist/scanners/network/missing-timeout.d.ts.map +0 -1
  142. package/dist/scanners/network/missing-timeout.js +0 -93
  143. package/dist/scanners/network/open-redirect.d.ts +0 -15
  144. package/dist/scanners/network/open-redirect.d.ts.map +0 -1
  145. package/dist/scanners/network/open-redirect.js +0 -88
  146. package/dist/scanners/network/ssrf-prone-fetch.d.ts +0 -12
  147. package/dist/scanners/network/ssrf-prone-fetch.d.ts.map +0 -1
  148. package/dist/scanners/network/ssrf-prone-fetch.js +0 -90
  149. package/dist/scanners/nextjs-middleware.d.ts +0 -26
  150. package/dist/scanners/nextjs-middleware.d.ts.map +0 -1
  151. package/dist/scanners/nextjs-middleware.js +0 -246
  152. package/dist/scanners/privacy/debug-flags.d.ts +0 -13
  153. package/dist/scanners/privacy/debug-flags.d.ts.map +0 -1
  154. package/dist/scanners/privacy/debug-flags.js +0 -124
  155. package/dist/scanners/privacy/index.d.ts +0 -6
  156. package/dist/scanners/privacy/index.d.ts.map +0 -1
  157. package/dist/scanners/privacy/index.js +0 -11
  158. package/dist/scanners/privacy/over-broad-response.d.ts +0 -15
  159. package/dist/scanners/privacy/over-broad-response.d.ts.map +0 -1
  160. package/dist/scanners/privacy/over-broad-response.js +0 -109
  161. package/dist/scanners/privacy/sensitive-logging.d.ts +0 -11
  162. package/dist/scanners/privacy/sensitive-logging.d.ts.map +0 -1
  163. package/dist/scanners/privacy/sensitive-logging.js +0 -78
  164. package/dist/scanners/types.d.ts +0 -456
  165. package/dist/scanners/types.d.ts.map +0 -1
  166. package/dist/scanners/types.js +0 -16
  167. package/dist/scanners/unused-security-imports.d.ts +0 -34
  168. package/dist/scanners/unused-security-imports.d.ts.map +0 -1
  169. package/dist/scanners/unused-security-imports.js +0 -206
  170. package/dist/scanners/uploads/index.d.ts +0 -5
  171. package/dist/scanners/uploads/index.d.ts.map +0 -1
  172. package/dist/scanners/uploads/index.js +0 -9
  173. package/dist/scanners/uploads/missing-constraints.d.ts +0 -15
  174. package/dist/scanners/uploads/missing-constraints.d.ts.map +0 -1
  175. package/dist/scanners/uploads/missing-constraints.js +0 -109
  176. package/dist/scanners/uploads/public-path.d.ts +0 -11
  177. package/dist/scanners/uploads/public-path.d.ts.map +0 -1
  178. package/dist/scanners/uploads/public-path.js +0 -87
  179. package/dist/scanners/validation/client-side-only.d.ts +0 -14
  180. package/dist/scanners/validation/client-side-only.d.ts.map +0 -1
  181. package/dist/scanners/validation/client-side-only.js +0 -140
  182. package/dist/scanners/validation/ignored-validation.d.ts +0 -12
  183. package/dist/scanners/validation/ignored-validation.d.ts.map +0 -1
  184. package/dist/scanners/validation/ignored-validation.js +0 -119
  185. package/dist/scanners/validation/index.d.ts +0 -5
  186. package/dist/scanners/validation/index.d.ts.map +0 -1
  187. package/dist/scanners/validation/index.js +0 -9
  188. package/dist/utils/exclude-patterns.d.ts +0 -35
  189. package/dist/utils/exclude-patterns.d.ts.map +0 -1
  190. package/dist/utils/exclude-patterns.js +0 -78
  191. package/dist/utils/file-utils.d.ts +0 -37
  192. package/dist/utils/file-utils.d.ts.map +0 -1
  193. package/dist/utils/file-utils.js +0 -77
  194. package/dist/utils/fingerprint.d.ts +0 -25
  195. package/dist/utils/fingerprint.d.ts.map +0 -1
  196. package/dist/utils/fingerprint.js +0 -28
  197. package/dist/utils/git-info.d.ts +0 -14
  198. package/dist/utils/git-info.d.ts.map +0 -1
  199. package/dist/utils/git-info.js +0 -55
  200. package/dist/utils/index.d.ts +0 -4
  201. package/dist/utils/index.d.ts.map +0 -1
  202. package/dist/utils/index.js +0 -3
  203. package/dist/utils/progress.d.ts +0 -42
  204. package/dist/utils/progress.d.ts.map +0 -1
  205. package/dist/utils/progress.js +0 -165
  206. package/dist/utils/sarif-formatter.d.ts +0 -92
  207. package/dist/utils/sarif-formatter.d.ts.map +0 -1
  208. package/dist/utils/sarif-formatter.js +0 -172
@@ -1,193 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { parseMatcherConfig, matcherCoversApi, scanNextjsMiddleware, } from "../../scanners/nextjs-middleware.js";
3
- import path from "node:path";
4
- import fs from "node:fs";
5
- import os from "node:os";
6
- describe("parseMatcherConfig", () => {
7
- it("parses single string matcher", () => {
8
- const content = `
9
- export const config = {
10
- matcher: '/dashboard/:path*'
11
- };
12
- `;
13
- const matchers = parseMatcherConfig(content);
14
- expect(matchers).toEqual(["/dashboard/:path*"]);
15
- });
16
- it("parses array matcher", () => {
17
- const content = `
18
- export const config = {
19
- matcher: ['/dashboard/:path*', '/admin/:path*']
20
- };
21
- `;
22
- const matchers = parseMatcherConfig(content);
23
- expect(matchers).toEqual(["/dashboard/:path*", "/admin/:path*"]);
24
- });
25
- it("returns null when no config export", () => {
26
- const content = `
27
- export function middleware(request) {
28
- return NextResponse.next();
29
- }
30
- `;
31
- const matchers = parseMatcherConfig(content);
32
- expect(matchers).toBeNull();
33
- });
34
- it("parses complex negation pattern", () => {
35
- const content = `
36
- export const config = {
37
- matcher: '/((?!_next/static|_next/image|favicon.ico).*)'
38
- };
39
- `;
40
- const matchers = parseMatcherConfig(content);
41
- expect(matchers).toEqual(["/((?!_next/static|_next/image|favicon.ico).*)"]);
42
- });
43
- });
44
- describe("matcherCoversApi", () => {
45
- it("returns true for direct /api match", () => {
46
- expect(matcherCoversApi(["/api"])).toBe(true);
47
- expect(matcherCoversApi(["/api/:path*"])).toBe(true);
48
- });
49
- it("returns true for patterns starting with /api", () => {
50
- expect(matcherCoversApi(["/api/users/:path*"])).toBe(true);
51
- });
52
- it("returns true for catch-all patterns", () => {
53
- expect(matcherCoversApi(["/:path*"])).toBe(true);
54
- });
55
- it("returns true for negation patterns not excluding api", () => {
56
- expect(matcherCoversApi(["/((?!_next/static|_next/image|favicon.ico).*)"])).toBe(true);
57
- });
58
- it("returns false for dashboard-only patterns", () => {
59
- expect(matcherCoversApi(["/dashboard/:path*"])).toBe(false);
60
- });
61
- it("returns false for unrelated patterns", () => {
62
- expect(matcherCoversApi(["/admin", "/profile"])).toBe(false);
63
- });
64
- });
65
- describe("scanNextjsMiddleware", () => {
66
- function createNextProject(tmpDir, options = {}) {
67
- // Create package.json
68
- const pkg = {
69
- name: "test-app",
70
- dependencies: {
71
- next: "14.0.0",
72
- ...(options.hasNextAuth && { "next-auth": "4.0.0" }),
73
- },
74
- };
75
- fs.writeFileSync(path.join(tmpDir, "package.json"), JSON.stringify(pkg));
76
- // Create middleware if specified
77
- if (options.hasMiddleware && options.middlewareContent) {
78
- fs.writeFileSync(path.join(tmpDir, "middleware.ts"), options.middlewareContent);
79
- }
80
- // Create API routes if specified
81
- if (options.hasApiRoutes) {
82
- const apiDir = path.join(tmpDir, "app", "api", "users");
83
- fs.mkdirSync(apiDir, { recursive: true });
84
- fs.writeFileSync(path.join(apiDir, "route.ts"), `export async function GET() { return Response.json({}); }`);
85
- }
86
- }
87
- it("returns no findings for non-Next.js project", async () => {
88
- const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "vibecheck-test-"));
89
- try {
90
- fs.writeFileSync(path.join(tmpDir, "package.json"), JSON.stringify({ name: "test" }));
91
- const context = {
92
- targetDir: tmpDir,
93
- sourceFiles: [],
94
- };
95
- const findings = await scanNextjsMiddleware(context);
96
- expect(findings).toHaveLength(0);
97
- }
98
- finally {
99
- fs.rmSync(tmpDir, { recursive: true });
100
- }
101
- });
102
- it("returns no findings when no API routes exist", async () => {
103
- const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "vibecheck-test-"));
104
- try {
105
- createNextProject(tmpDir, { hasApiRoutes: false });
106
- const context = {
107
- targetDir: tmpDir,
108
- sourceFiles: [],
109
- };
110
- const findings = await scanNextjsMiddleware(context);
111
- expect(findings).toHaveLength(0);
112
- }
113
- finally {
114
- fs.rmSync(tmpDir, { recursive: true });
115
- }
116
- });
117
- it("finds missing middleware with next-auth", async () => {
118
- const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "vibecheck-test-"));
119
- try {
120
- createNextProject(tmpDir, {
121
- hasNextAuth: true,
122
- hasApiRoutes: true,
123
- });
124
- const context = {
125
- targetDir: tmpDir,
126
- sourceFiles: [],
127
- };
128
- const findings = await scanNextjsMiddleware(context);
129
- expect(findings).toHaveLength(1);
130
- expect(findings[0].ruleId).toBe("VC-AUTH-INFO-001");
131
- expect(findings[0].severity).toBe("medium");
132
- }
133
- finally {
134
- fs.rmSync(tmpDir, { recursive: true });
135
- }
136
- });
137
- it("finds middleware not covering API routes", async () => {
138
- const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "vibecheck-test-"));
139
- try {
140
- createNextProject(tmpDir, {
141
- hasMiddleware: true,
142
- middlewareContent: `
143
- export function middleware(request) {
144
- return NextResponse.next();
145
- }
146
-
147
- export const config = {
148
- matcher: '/dashboard/:path*'
149
- };
150
- `,
151
- hasApiRoutes: true,
152
- });
153
- const context = {
154
- targetDir: tmpDir,
155
- sourceFiles: [],
156
- };
157
- const findings = await scanNextjsMiddleware(context);
158
- expect(findings).toHaveLength(1);
159
- expect(findings[0].ruleId).toBe("VC-MW-001");
160
- expect(findings[0].severity).toBe("high");
161
- }
162
- finally {
163
- fs.rmSync(tmpDir, { recursive: true });
164
- }
165
- });
166
- it("returns no findings when middleware covers API", async () => {
167
- const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "vibecheck-test-"));
168
- try {
169
- createNextProject(tmpDir, {
170
- hasMiddleware: true,
171
- middlewareContent: `
172
- export function middleware(request) {
173
- return NextResponse.next();
174
- }
175
-
176
- export const config = {
177
- matcher: ['/dashboard/:path*', '/api/:path*']
178
- };
179
- `,
180
- hasApiRoutes: true,
181
- });
182
- const context = {
183
- targetDir: tmpDir,
184
- sourceFiles: [],
185
- };
186
- const findings = await scanNextjsMiddleware(context);
187
- expect(findings).toHaveLength(0);
188
- }
189
- finally {
190
- fs.rmSync(tmpDir, { recursive: true });
191
- }
192
- });
193
- });
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=scanner-packs.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"scanner-packs.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/scanners/scanner-packs.test.ts"],"names":[],"mappings":""}
@@ -1,126 +0,0 @@
1
- import { describe, it, expect, beforeAll } from "vitest";
2
- import path from "node:path";
3
- import { buildScanContext } from "../../scanners/index.js";
4
- import { scanUnprotectedApiRoutes } from "../../scanners/auth/unprotected-api-route.js";
5
- import { parseMatcherConfig, matcherCoversApi } from "../../scanners/auth/middleware-gap.js";
6
- import { scanInsecureDefaults } from "../../scanners/config/insecure-defaults.js";
7
- import { findSecurityImports, checkIdentifierUsage, } from "../../scanners/hallucinations/unused-security-imports.js";
8
- const FIXTURES_DIR = path.resolve(__dirname, "../fixtures");
9
- const VULNERABLE_APP = path.join(FIXTURES_DIR, "vulnerable-app");
10
- const SAFE_APP = path.join(FIXTURES_DIR, "safe-app");
11
- describe("Scanner Packs", () => {
12
- let vulnerableContext;
13
- let safeContext;
14
- beforeAll(async () => {
15
- vulnerableContext = await buildScanContext(VULNERABLE_APP);
16
- safeContext = await buildScanContext(SAFE_APP);
17
- });
18
- describe("Auth Pack", () => {
19
- describe("VC-AUTH-001: Unprotected API Routes", () => {
20
- it("should detect unprotected POST handler with database writes", async () => {
21
- const findings = await scanUnprotectedApiRoutes(vulnerableContext);
22
- const postFinding = findings.find((f) => f.ruleId === "VC-AUTH-001" && f.title.includes("POST"));
23
- expect(postFinding).toBeDefined();
24
- expect(postFinding?.severity).toBe("high");
25
- expect(postFinding?.category).toBe("auth");
26
- });
27
- it("should detect unprotected DELETE handler as critical", async () => {
28
- const findings = await scanUnprotectedApiRoutes(vulnerableContext);
29
- const deleteFinding = findings.find((f) => f.ruleId === "VC-AUTH-001" && f.title.includes("DELETE"));
30
- expect(deleteFinding).toBeDefined();
31
- expect(deleteFinding?.severity).toBe("critical");
32
- });
33
- it("should not flag protected routes", async () => {
34
- const findings = await scanUnprotectedApiRoutes(safeContext);
35
- expect(findings).toHaveLength(0);
36
- });
37
- });
38
- describe("Middleware Gap Detection", () => {
39
- it("should parse single string matcher", () => {
40
- const content = `export const config = { matcher: '/api/:path*' }`;
41
- const matchers = parseMatcherConfig(content);
42
- expect(matchers).toEqual(["/api/:path*"]);
43
- });
44
- it("should parse array matcher", () => {
45
- const content = `export const config = { matcher: ['/api/:path*', '/admin/:path*'] }`;
46
- const matchers = parseMatcherConfig(content);
47
- expect(matchers).toEqual(["/api/:path*", "/admin/:path*"]);
48
- });
49
- it("should detect when matcher covers api", () => {
50
- expect(matcherCoversApi(["/api/:path*"])).toBe(true);
51
- expect(matcherCoversApi(["/api/users"])).toBe(true);
52
- expect(matcherCoversApi(["/:path*"])).toBe(true);
53
- });
54
- it("should detect when matcher does not cover api", () => {
55
- expect(matcherCoversApi(["/dashboard/:path*"])).toBe(false);
56
- expect(matcherCoversApi(["/admin/:path*"])).toBe(false);
57
- });
58
- });
59
- });
60
- describe("Config Pack", () => {
61
- describe("VC-CONFIG-002: Insecure Defaults", () => {
62
- it("should detect insecure default for JWT_SECRET", async () => {
63
- const findings = await scanInsecureDefaults(vulnerableContext);
64
- const jwtFinding = findings.find((f) => f.ruleId === "VC-CONFIG-002" && f.title.includes("JWT_SECRET"));
65
- expect(jwtFinding).toBeDefined();
66
- expect(jwtFinding?.severity).toBe("critical");
67
- });
68
- it("should detect insecure default for SESSION_SECRET", async () => {
69
- const findings = await scanInsecureDefaults(vulnerableContext);
70
- const sessionFinding = findings.find((f) => f.ruleId === "VC-CONFIG-002" && f.title.includes("SESSION_SECRET"));
71
- expect(sessionFinding).toBeDefined();
72
- expect(sessionFinding?.severity).toBe("critical");
73
- });
74
- });
75
- });
76
- describe("Hallucinations Pack", () => {
77
- describe("findSecurityImports", () => {
78
- it("should find default imports", () => {
79
- const content = `import helmet from "helmet";`;
80
- const imports = findSecurityImports(content, ["helmet"]);
81
- expect(imports).toHaveLength(1);
82
- expect(imports[0].library).toBe("helmet");
83
- expect(imports[0].importedNames).toEqual(["helmet"]);
84
- expect(imports[0].isDefaultImport).toBe(true);
85
- });
86
- it("should find named imports", () => {
87
- const content = `import { z, ZodError } from "zod";`;
88
- const imports = findSecurityImports(content, ["zod"]);
89
- expect(imports).toHaveLength(1);
90
- expect(imports[0].library).toBe("zod");
91
- expect(imports[0].importedNames).toContain("z");
92
- expect(imports[0].importedNames).toContain("ZodError");
93
- });
94
- it("should find namespace imports", () => {
95
- const content = `import * as yup from "yup";`;
96
- const imports = findSecurityImports(content, ["yup"]);
97
- expect(imports).toHaveLength(1);
98
- expect(imports[0].library).toBe("yup");
99
- expect(imports[0].isNamespaceImport).toBe(true);
100
- });
101
- });
102
- describe("checkIdentifierUsage", () => {
103
- it("should detect used identifiers", () => {
104
- const content = `import helmet from "helmet";
105
-
106
- app.use(helmet());`;
107
- const usage = checkIdentifierUsage(content, 1, ["helmet"], false);
108
- expect(usage[0].used).toBe(true);
109
- });
110
- it("should detect unused identifiers", () => {
111
- const content = `import helmet from "helmet";
112
-
113
- app.use(cors());`;
114
- const usage = checkIdentifierUsage(content, 1, ["helmet"], false);
115
- expect(usage[0].used).toBe(false);
116
- });
117
- it("should detect namespace usage", () => {
118
- const content = `import * as yup from "yup";
119
-
120
- const schema = yup.object();`;
121
- const usage = checkIdentifierUsage(content, 1, ["yup"], true);
122
- expect(usage[0].used).toBe(true);
123
- });
124
- });
125
- });
126
- });
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=unused-security-imports.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"unused-security-imports.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/scanners/unused-security-imports.test.ts"],"names":[],"mappings":""}
@@ -1,145 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { findSecurityImports, checkIdentifierUsage, scanUnusedSecurityImports, } from "../../scanners/unused-security-imports.js";
3
- import path from "node:path";
4
- import fs from "node:fs";
5
- import os from "node:os";
6
- describe("findSecurityImports", () => {
7
- it("finds default imports", () => {
8
- const content = `import zod from "zod";`;
9
- const imports = findSecurityImports(content, ["zod"]);
10
- expect(imports).toHaveLength(1);
11
- expect(imports[0].library).toBe("zod");
12
- expect(imports[0].importedNames).toContain("zod");
13
- expect(imports[0].isDefaultImport).toBe(true);
14
- });
15
- it("finds named imports", () => {
16
- const content = `import { z, ZodError } from "zod";`;
17
- const imports = findSecurityImports(content, ["zod"]);
18
- expect(imports).toHaveLength(1);
19
- expect(imports[0].importedNames).toContain("z");
20
- expect(imports[0].importedNames).toContain("ZodError");
21
- });
22
- it("finds namespace imports", () => {
23
- const content = `import * as yup from "yup";`;
24
- const imports = findSecurityImports(content, ["yup"]);
25
- expect(imports).toHaveLength(1);
26
- expect(imports[0].isNamespaceImport).toBe(true);
27
- expect(imports[0].importedNames).toContain("yup");
28
- });
29
- it("finds helmet import", () => {
30
- const content = `import helmet from "helmet";`;
31
- const imports = findSecurityImports(content, ["helmet"]);
32
- expect(imports).toHaveLength(1);
33
- expect(imports[0].library).toBe("helmet");
34
- });
35
- it("returns correct line numbers", () => {
36
- const content = `// line 1
37
- // line 2
38
- import { z } from "zod";
39
- `;
40
- const imports = findSecurityImports(content, ["zod"]);
41
- expect(imports[0].line).toBe(3);
42
- });
43
- it("ignores non-security imports", () => {
44
- const content = `
45
- import express from "express";
46
- import { z } from "zod";
47
- `;
48
- const imports = findSecurityImports(content, ["zod", "helmet"]);
49
- expect(imports).toHaveLength(1);
50
- expect(imports[0].library).toBe("zod");
51
- });
52
- });
53
- describe("checkIdentifierUsage", () => {
54
- it("detects used identifiers", () => {
55
- const content = `
56
- import { z } from "zod";
57
- const schema = z.string();
58
- `;
59
- const result = checkIdentifierUsage(content, 2, ["z"], false);
60
- expect(result[0].used).toBe(true);
61
- });
62
- it("detects unused identifiers", () => {
63
- const content = `
64
- import { z, ZodError } from "zod";
65
- const schema = z.string();
66
- `;
67
- const result = checkIdentifierUsage(content, 2, ["z", "ZodError"], false);
68
- expect(result.find((r) => r.identifier === "z")?.used).toBe(true);
69
- expect(result.find((r) => r.identifier === "ZodError")?.used).toBe(false);
70
- });
71
- it("handles namespace imports", () => {
72
- const content = `
73
- import * as yup from "yup";
74
- const schema = yup.string();
75
- `;
76
- const result = checkIdentifierUsage(content, 2, ["yup"], true);
77
- expect(result[0].used).toBe(true);
78
- });
79
- it("detects unused namespace imports", () => {
80
- const content = `
81
- import * as yup from "yup";
82
- // not used
83
- `;
84
- const result = checkIdentifierUsage(content, 2, ["yup"], true);
85
- expect(result[0].used).toBe(false);
86
- });
87
- });
88
- describe("scanUnusedSecurityImports", () => {
89
- it("finds unused zod import", async () => {
90
- const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "vibecheck-test-"));
91
- fs.writeFileSync(path.join(tmpDir, "app.ts"), `import { z } from "zod";
92
- // import is never used below
93
- const x = 1;
94
- `);
95
- try {
96
- const context = {
97
- targetDir: tmpDir,
98
- sourceFiles: ["app.ts"],
99
- };
100
- const findings = await scanUnusedSecurityImports(context);
101
- expect(findings).toHaveLength(1);
102
- expect(findings[0].ruleId).toBe("VC-HALL-001");
103
- expect(findings[0].category).toBe("validation");
104
- }
105
- finally {
106
- fs.rmSync(tmpDir, { recursive: true });
107
- }
108
- });
109
- it("does not flag used imports", async () => {
110
- const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "vibecheck-test-"));
111
- fs.writeFileSync(path.join(tmpDir, "app.ts"), `import { z } from "zod";
112
- const schema = z.string();
113
- `);
114
- try {
115
- const context = {
116
- targetDir: tmpDir,
117
- sourceFiles: ["app.ts"],
118
- };
119
- const findings = await scanUnusedSecurityImports(context);
120
- expect(findings).toHaveLength(0);
121
- }
122
- finally {
123
- fs.rmSync(tmpDir, { recursive: true });
124
- }
125
- });
126
- it("finds unused helmet import", async () => {
127
- const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "vibecheck-test-"));
128
- fs.writeFileSync(path.join(tmpDir, "server.ts"), `import helmet from "helmet";
129
- // import is never used below
130
- const app = express();
131
- `);
132
- try {
133
- const context = {
134
- targetDir: tmpDir,
135
- sourceFiles: ["server.ts"],
136
- };
137
- const findings = await scanUnusedSecurityImports(context);
138
- expect(findings).toHaveLength(1);
139
- expect(findings[0].category).toBe("middleware");
140
- }
141
- finally {
142
- fs.rmSync(tmpDir, { recursive: true });
143
- }
144
- });
145
- });
@@ -1,7 +0,0 @@
1
- import { Command } from "commander";
2
- export interface DemoArtifactOptions {
3
- out?: string;
4
- }
5
- export declare function executeDemoArtifact(options: DemoArtifactOptions): void;
6
- export declare function registerDemoArtifactCommand(program: Command): void;
7
- //# sourceMappingURL=demo-artifact.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"demo-artifact.d.ts","sourceRoot":"","sources":["../../src/commands/demo-artifact.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AASpC,MAAM,WAAW,mBAAmB;IAClC,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AA4SD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,mBAAmB,GAAG,IAAI,CA6BtE;AAED,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAQlE"}