vskill 0.1.2 → 0.1.3

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 (123) hide show
  1. package/dist/audit/__fixtures__/clean-project/app.d.ts +1 -0
  2. package/dist/audit/__fixtures__/clean-project/app.js +8 -0
  3. package/dist/audit/__fixtures__/clean-project/app.js.map +1 -0
  4. package/dist/audit/__fixtures__/clean-project/utils.d.ts +2 -0
  5. package/dist/audit/__fixtures__/clean-project/utils.js +8 -0
  6. package/dist/audit/__fixtures__/clean-project/utils.js.map +1 -0
  7. package/dist/audit/__fixtures__/mixed-project/risky.d.ts +1 -0
  8. package/dist/audit/__fixtures__/mixed-project/risky.js +6 -0
  9. package/dist/audit/__fixtures__/mixed-project/risky.js.map +1 -0
  10. package/dist/audit/__fixtures__/mixed-project/safe.d.ts +1 -0
  11. package/dist/audit/__fixtures__/mixed-project/safe.js +5 -0
  12. package/dist/audit/__fixtures__/mixed-project/safe.js.map +1 -0
  13. package/dist/audit/__fixtures__/vulnerable-project/handler.d.ts +4 -0
  14. package/dist/audit/__fixtures__/vulnerable-project/handler.js +21 -0
  15. package/dist/audit/__fixtures__/vulnerable-project/handler.js.map +1 -0
  16. package/dist/audit/audit-integration.test.d.ts +1 -0
  17. package/dist/audit/audit-integration.test.js +92 -0
  18. package/dist/audit/audit-integration.test.js.map +1 -0
  19. package/dist/audit/audit-llm.d.ts +25 -0
  20. package/dist/audit/audit-llm.js +139 -0
  21. package/dist/audit/audit-llm.js.map +1 -0
  22. package/dist/audit/audit-llm.test.d.ts +1 -0
  23. package/dist/audit/audit-llm.test.js +110 -0
  24. package/dist/audit/audit-llm.test.js.map +1 -0
  25. package/dist/audit/audit-patterns.d.ts +31 -0
  26. package/dist/audit/audit-patterns.js +239 -0
  27. package/dist/audit/audit-patterns.js.map +1 -0
  28. package/dist/audit/audit-patterns.test.d.ts +1 -0
  29. package/dist/audit/audit-patterns.test.js +91 -0
  30. package/dist/audit/audit-patterns.test.js.map +1 -0
  31. package/dist/audit/audit-scanner.d.ts +16 -0
  32. package/dist/audit/audit-scanner.js +151 -0
  33. package/dist/audit/audit-scanner.js.map +1 -0
  34. package/dist/audit/audit-scanner.test.d.ts +1 -0
  35. package/dist/audit/audit-scanner.test.js +112 -0
  36. package/dist/audit/audit-scanner.test.js.map +1 -0
  37. package/dist/audit/audit-types.d.ts +98 -0
  38. package/dist/audit/audit-types.js +19 -0
  39. package/dist/audit/audit-types.js.map +1 -0
  40. package/dist/audit/audit-types.test.d.ts +1 -0
  41. package/dist/audit/audit-types.test.js +140 -0
  42. package/dist/audit/audit-types.test.js.map +1 -0
  43. package/dist/audit/config.d.ts +13 -0
  44. package/dist/audit/config.js +90 -0
  45. package/dist/audit/config.js.map +1 -0
  46. package/dist/audit/config.test.d.ts +1 -0
  47. package/dist/audit/config.test.js +44 -0
  48. package/dist/audit/config.test.js.map +1 -0
  49. package/dist/audit/file-discovery.d.ts +15 -0
  50. package/dist/audit/file-discovery.js +153 -0
  51. package/dist/audit/file-discovery.js.map +1 -0
  52. package/dist/audit/file-discovery.test.d.ts +1 -0
  53. package/dist/audit/file-discovery.test.js +120 -0
  54. package/dist/audit/file-discovery.test.js.map +1 -0
  55. package/dist/audit/fix-suggestions.d.ts +13 -0
  56. package/dist/audit/fix-suggestions.js +84 -0
  57. package/dist/audit/fix-suggestions.js.map +1 -0
  58. package/dist/audit/fix-suggestions.test.d.ts +1 -0
  59. package/dist/audit/fix-suggestions.test.js +35 -0
  60. package/dist/audit/fix-suggestions.test.js.map +1 -0
  61. package/dist/audit/formatters/json-formatter.d.ts +8 -0
  62. package/dist/audit/formatters/json-formatter.js +10 -0
  63. package/dist/audit/formatters/json-formatter.js.map +1 -0
  64. package/dist/audit/formatters/json-formatter.test.d.ts +1 -0
  65. package/dist/audit/formatters/json-formatter.test.js +49 -0
  66. package/dist/audit/formatters/json-formatter.test.js.map +1 -0
  67. package/dist/audit/formatters/report-formatter.d.ts +8 -0
  68. package/dist/audit/formatters/report-formatter.js +97 -0
  69. package/dist/audit/formatters/report-formatter.js.map +1 -0
  70. package/dist/audit/formatters/report-formatter.test.d.ts +1 -0
  71. package/dist/audit/formatters/report-formatter.test.js +51 -0
  72. package/dist/audit/formatters/report-formatter.test.js.map +1 -0
  73. package/dist/audit/formatters/sarif-formatter.d.ts +11 -0
  74. package/dist/audit/formatters/sarif-formatter.js +87 -0
  75. package/dist/audit/formatters/sarif-formatter.js.map +1 -0
  76. package/dist/audit/formatters/sarif-formatter.test.d.ts +1 -0
  77. package/dist/audit/formatters/sarif-formatter.test.js +71 -0
  78. package/dist/audit/formatters/sarif-formatter.test.js.map +1 -0
  79. package/dist/audit/formatters/terminal-formatter.d.ts +9 -0
  80. package/dist/audit/formatters/terminal-formatter.js +61 -0
  81. package/dist/audit/formatters/terminal-formatter.js.map +1 -0
  82. package/dist/audit/formatters/terminal-formatter.test.d.ts +1 -0
  83. package/dist/audit/formatters/terminal-formatter.test.js +51 -0
  84. package/dist/audit/formatters/terminal-formatter.test.js.map +1 -0
  85. package/dist/audit/index.d.ts +2 -0
  86. package/dist/audit/index.js +2 -0
  87. package/dist/audit/index.js.map +1 -0
  88. package/dist/blocklist/blocklist-e2e.test.d.ts +1 -0
  89. package/dist/blocklist/blocklist-e2e.test.js +346 -0
  90. package/dist/blocklist/blocklist-e2e.test.js.map +1 -0
  91. package/dist/commands/add-blocklist-e2e.test.d.ts +1 -0
  92. package/dist/commands/add-blocklist-e2e.test.js +390 -0
  93. package/dist/commands/add-blocklist-e2e.test.js.map +1 -0
  94. package/dist/commands/add.js +184 -7
  95. package/dist/commands/add.js.map +1 -1
  96. package/dist/commands/add.test.js +159 -19
  97. package/dist/commands/add.test.js.map +1 -1
  98. package/dist/commands/audit.d.ts +23 -0
  99. package/dist/commands/audit.js +100 -0
  100. package/dist/commands/audit.js.map +1 -0
  101. package/dist/commands/audit.test.d.ts +1 -0
  102. package/dist/commands/audit.test.js +79 -0
  103. package/dist/commands/audit.test.js.map +1 -0
  104. package/dist/discovery/github-tree.d.ts +15 -0
  105. package/dist/discovery/github-tree.js +54 -0
  106. package/dist/discovery/github-tree.js.map +1 -0
  107. package/dist/discovery/github-tree.test.d.ts +1 -0
  108. package/dist/discovery/github-tree.test.js +143 -0
  109. package/dist/discovery/github-tree.test.js.map +1 -0
  110. package/dist/index.js +24 -0
  111. package/dist/index.js.map +1 -1
  112. package/dist/lockfile/index.d.ts +1 -0
  113. package/dist/lockfile/index.js +1 -0
  114. package/dist/lockfile/index.js.map +1 -1
  115. package/dist/lockfile/lockfile.js +2 -1
  116. package/dist/lockfile/lockfile.js.map +1 -1
  117. package/dist/lockfile/project-root.d.ts +11 -0
  118. package/dist/lockfile/project-root.js +29 -0
  119. package/dist/lockfile/project-root.js.map +1 -0
  120. package/dist/lockfile/project-root.test.d.ts +1 -0
  121. package/dist/lockfile/project-root.test.js +49 -0
  122. package/dist/lockfile/project-root.test.js.map +1 -0
  123. package/package.json +1 -1
@@ -0,0 +1,239 @@
1
+ /**
2
+ * Extended audit patterns for project-level security scanning.
3
+ *
4
+ * Imports the existing 37 SCAN_PATTERNS from the scanner module
5
+ * and extends them with project-audit-specific patterns for
6
+ * SQL injection, SSRF, XSS, hardcoded secrets, etc.
7
+ */
8
+ import { SCAN_PATTERNS } from "../scanner/patterns.js";
9
+ /**
10
+ * Project-specific security patterns (beyond the existing 37 skill patterns).
11
+ */
12
+ export const PROJECT_PATTERNS = [
13
+ // --- SQL Injection ---
14
+ {
15
+ id: "SQLI-001",
16
+ name: "SQL string concatenation",
17
+ severity: "critical",
18
+ category: "sql-injection",
19
+ message: "SQL query built with string concatenation — use parameterized queries",
20
+ pattern: /(?:SELECT|INSERT|UPDATE|DELETE|DROP|CREATE|ALTER)\s+.*(?:\+\s*\w|\$\{)/gi,
21
+ confidence: "high",
22
+ safeContexts: [/\/\/.*SQL/i, /\*.*SQL/i],
23
+ },
24
+ {
25
+ id: "SQLI-002",
26
+ name: "Raw SQL template literal",
27
+ severity: "high",
28
+ category: "sql-injection",
29
+ message: "SQL query in template literal with interpolation",
30
+ pattern: /`\s*(?:SELECT|INSERT|UPDATE|DELETE)\s+[^`]*\$\{/gi,
31
+ confidence: "high",
32
+ },
33
+ {
34
+ id: "SQLI-003",
35
+ name: "Unparameterized query method",
36
+ severity: "high",
37
+ category: "sql-injection",
38
+ message: "Database query with string interpolation instead of parameters",
39
+ pattern: /\.(?:query|execute|raw)\s*\(\s*(?:`[^`]*\$\{|['"][^'"]*['"]\s*\+)/gi,
40
+ confidence: "medium",
41
+ },
42
+ // --- SSRF ---
43
+ {
44
+ id: "SSRF-001",
45
+ name: "Fetch with variable URL",
46
+ severity: "high",
47
+ category: "ssrf",
48
+ message: "HTTP request with user-controlled URL — validate against allowlist",
49
+ pattern: /(?:fetch|axios\.get|axios\.post|got|request|http\.get|https\.get)\s*\(\s*(?:[a-zA-Z_]\w*(?:\.\w+)*)\s*[,)]/g,
50
+ confidence: "medium",
51
+ safeContexts: [/const\s+\w+\s*=\s*['"]https?:\/\//, /\.env\./],
52
+ },
53
+ {
54
+ id: "SSRF-002",
55
+ name: "URL from request parameters",
56
+ severity: "critical",
57
+ category: "ssrf",
58
+ message: "URL constructed from request input — potential SSRF",
59
+ pattern: /(?:req\.(?:query|params|body)\.\w+|request\.(?:query|params|body)\.\w+).*(?:fetch|axios|got|request|http|https)/g,
60
+ confidence: "high",
61
+ },
62
+ // --- Broken Access Control ---
63
+ {
64
+ id: "BAC-001",
65
+ name: "Missing auth middleware",
66
+ severity: "medium",
67
+ category: "broken-access-control",
68
+ message: "Route handler without visible authentication middleware",
69
+ pattern: /(?:app|router)\.(?:get|post|put|patch|delete)\s*\(\s*['"][^'"]*['"]\s*,\s*(?:async\s+)?\(?(?:req|ctx)/g,
70
+ confidence: "low",
71
+ safeContexts: [/auth/, /protect/, /guard/, /middleware/, /public/, /health/],
72
+ },
73
+ {
74
+ id: "BAC-002",
75
+ name: "Direct ID access without ownership check",
76
+ severity: "medium",
77
+ category: "broken-access-control",
78
+ message: "Resource accessed by ID from request without ownership verification",
79
+ pattern: /(?:findById|findOne|findUnique)\s*\(\s*(?:req\.(?:params|query|body)\.\w+|ctx\.params\.\w+)/g,
80
+ confidence: "low",
81
+ safeContexts: [/userId/, /session\.user/, /currentUser/],
82
+ },
83
+ // --- Hardcoded Secrets ---
84
+ {
85
+ id: "HS-001",
86
+ name: "API key assignment",
87
+ severity: "critical",
88
+ category: "hardcoded-secrets",
89
+ message: "Hardcoded API key or secret in source code",
90
+ pattern: /(?:api[_-]?key|apiKey|secret[_-]?key|secretKey|access[_-]?token|accessToken)\s*[:=]\s*['"][a-zA-Z0-9_\-]{16,}['"]/gi,
91
+ confidence: "high",
92
+ safeContexts: [/process\.env/, /\.env/, /example/, /placeholder/, /test/i, /mock/i],
93
+ },
94
+ {
95
+ id: "HS-002",
96
+ name: "Private key in source",
97
+ severity: "critical",
98
+ category: "hardcoded-secrets",
99
+ message: "Private key embedded in source code",
100
+ pattern: /-----BEGIN\s+(?:RSA\s+)?PRIVATE\s+KEY-----/g,
101
+ confidence: "high",
102
+ },
103
+ {
104
+ id: "HS-003",
105
+ name: "Password assignment",
106
+ severity: "high",
107
+ category: "hardcoded-secrets",
108
+ message: "Hardcoded password in source code",
109
+ pattern: /(?:password|passwd|pwd)\s*[:=]\s*['"][^'"]{4,}['"]/gi,
110
+ confidence: "medium",
111
+ safeContexts: [/process\.env/, /\.env/, /hash/, /bcrypt/, /argon/, /test/i, /mock/i, /example/i],
112
+ },
113
+ {
114
+ id: "HS-004",
115
+ name: "AWS/cloud credential pattern",
116
+ severity: "critical",
117
+ category: "hardcoded-secrets",
118
+ message: "Cloud provider credential pattern detected",
119
+ pattern: /(?:AKIA[0-9A-Z]{16}|sk-[a-zA-Z0-9]{20,}|ghp_[a-zA-Z0-9]{36}|gho_[a-zA-Z0-9]{36})/g,
120
+ confidence: "high",
121
+ },
122
+ // --- XSS ---
123
+ {
124
+ id: "XSS-001",
125
+ name: "innerHTML assignment",
126
+ severity: "high",
127
+ category: "xss",
128
+ message: "Direct innerHTML assignment — use textContent or sanitize input",
129
+ pattern: /\.innerHTML\s*=\s*/g,
130
+ confidence: "high",
131
+ safeContexts: [/sanitize/, /DOMPurify/, /escape/],
132
+ },
133
+ {
134
+ id: "XSS-002",
135
+ name: "dangerouslySetInnerHTML",
136
+ severity: "high",
137
+ category: "xss",
138
+ message: "React dangerouslySetInnerHTML — ensure content is sanitized",
139
+ pattern: /dangerouslySetInnerHTML\s*=\s*\{\s*\{/g,
140
+ confidence: "high",
141
+ safeContexts: [/sanitize/, /DOMPurify/],
142
+ },
143
+ {
144
+ id: "XSS-003",
145
+ name: "document.write",
146
+ severity: "high",
147
+ category: "xss",
148
+ message: "document.write with dynamic content — potential XSS",
149
+ pattern: /document\.write(?:ln)?\s*\(/g,
150
+ confidence: "medium",
151
+ },
152
+ // --- Open Redirect ---
153
+ {
154
+ id: "OR-001",
155
+ name: "Redirect from user input",
156
+ severity: "medium",
157
+ category: "open-redirect",
158
+ message: "Redirect URL from user input — validate against allowlist",
159
+ pattern: /(?:res\.redirect|redirect|location\.href|window\.location)\s*(?:\(|\s*=)\s*(?:req\.(?:query|params|body)\.\w+)/g,
160
+ confidence: "high",
161
+ },
162
+ {
163
+ id: "OR-002",
164
+ name: "Location header from variable",
165
+ severity: "medium",
166
+ category: "open-redirect",
167
+ message: "Location header set from variable — potential open redirect",
168
+ pattern: /(?:setHeader|set)\s*\(\s*['"]Location['"]\s*,\s*(?:[a-zA-Z_]\w*)/gi,
169
+ confidence: "low",
170
+ safeContexts: [/allowlist/, /whitelist/, /valid/],
171
+ },
172
+ // --- Insecure Deserialization ---
173
+ {
174
+ id: "ID-001",
175
+ name: "YAML unsafe load",
176
+ severity: "high",
177
+ category: "insecure-deserialization",
178
+ message: "yaml.load without safe loader — use yaml.safeLoad or yaml.load with safe schema",
179
+ pattern: /yaml\.load\s*\(/g,
180
+ confidence: "medium",
181
+ safeContexts: [/safe/, /safeLoad/, /SAFE_SCHEMA/],
182
+ },
183
+ {
184
+ id: "ID-002",
185
+ name: "Pickle deserialization",
186
+ severity: "critical",
187
+ category: "insecure-deserialization",
188
+ message: "pickle.loads on untrusted data — use safe alternatives",
189
+ pattern: /pickle\.loads?\s*\(/g,
190
+ confidence: "high",
191
+ },
192
+ {
193
+ id: "ID-003",
194
+ name: "Unsafe JSON parse of request body",
195
+ severity: "low",
196
+ category: "insecure-deserialization",
197
+ message: "JSON.parse of raw request body — ensure schema validation",
198
+ pattern: /JSON\.parse\s*\(\s*(?:req\.body|request\.body|body)\s*\)/g,
199
+ confidence: "low",
200
+ safeContexts: [/zod/, /joi/, /yup/, /ajv/, /validate/],
201
+ },
202
+ // --- Weak Cryptography ---
203
+ {
204
+ id: "WC-001",
205
+ name: "MD5 usage",
206
+ severity: "medium",
207
+ category: "weak-cryptography",
208
+ message: "MD5 is cryptographically broken — use SHA-256 or better",
209
+ pattern: /(?:createHash|crypto\.subtle\.digest)\s*\(\s*['"]md5['"]/gi,
210
+ confidence: "high",
211
+ },
212
+ {
213
+ id: "WC-002",
214
+ name: "SHA-1 usage",
215
+ severity: "medium",
216
+ category: "weak-cryptography",
217
+ message: "SHA-1 is deprecated — use SHA-256 or better",
218
+ pattern: /(?:createHash|crypto\.subtle\.digest)\s*\(\s*['"]sha-?1['"]/gi,
219
+ confidence: "high",
220
+ },
221
+ ];
222
+ /**
223
+ * Combined audit patterns: original SCAN_PATTERNS + project-specific patterns.
224
+ *
225
+ * The SCAN_PATTERNS are adapted to AuditPatternCheck interface (id from ScanPattern.id).
226
+ */
227
+ export const AUDIT_PATTERNS = [
228
+ ...SCAN_PATTERNS.map((sp) => ({
229
+ id: sp.id,
230
+ name: sp.name,
231
+ severity: sp.severity,
232
+ category: sp.category,
233
+ message: sp.description,
234
+ pattern: sp.pattern,
235
+ confidence: "high",
236
+ })),
237
+ ...PROJECT_PATTERNS,
238
+ ];
239
+ //# sourceMappingURL=audit-patterns.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-patterns.js","sourceRoot":"","sources":["../../src/audit/audit-patterns.ts"],"names":[],"mappings":"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"}
@@ -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,16 @@
1
+ /**
2
+ * Core audit scanner — orchestrates Tier 1 pattern scanning across files.
3
+ *
4
+ * Runs extended audit patterns against each discovered file and produces
5
+ * an aggregated AuditResult with per-file findings, summary statistics,
6
+ * score, and verdict.
7
+ */
8
+ import type { AuditConfig, AuditFile, AuditResult } from "./audit-types.js";
9
+ /**
10
+ * Run the audit scan across all provided files.
11
+ *
12
+ * @param files - Discovered files to scan
13
+ * @param config - Audit configuration
14
+ * @returns Complete AuditResult with findings, summary, and metadata
15
+ */
16
+ export declare function runAuditScan(files: AuditFile[], config: AuditConfig): AuditResult;
@@ -0,0 +1,151 @@
1
+ /**
2
+ * Core audit scanner — orchestrates Tier 1 pattern scanning across files.
3
+ *
4
+ * Runs extended audit patterns against each discovered file and produces
5
+ * an aggregated AuditResult with per-file findings, summary statistics,
6
+ * score, and verdict.
7
+ */
8
+ import { AUDIT_PATTERNS } from "./audit-patterns.js";
9
+ /** Severity scoring weights (same as existing tier1.ts) */
10
+ const SEVERITY_DEDUCTIONS = {
11
+ critical: 25,
12
+ high: 15,
13
+ medium: 8,
14
+ low: 3,
15
+ info: 0,
16
+ };
17
+ const SEVERITY_ORDER = ["critical", "high", "medium", "low", "info"];
18
+ /**
19
+ * Scan a single file against all audit patterns.
20
+ */
21
+ function scanFile(file, patterns, findingCounter) {
22
+ const lines = file.content.split("\n");
23
+ const findings = [];
24
+ for (const pattern of patterns) {
25
+ const regex = new RegExp(pattern.pattern.source, pattern.pattern.flags);
26
+ for (let lineIdx = 0; lineIdx < lines.length; lineIdx++) {
27
+ const line = lines[lineIdx];
28
+ let match;
29
+ while ((match = regex.exec(line)) !== null) {
30
+ // Check safe contexts
31
+ if (pattern.safeContexts?.some((sc) => sc.test(line))) {
32
+ break;
33
+ }
34
+ // Build code snippet with 2 lines context
35
+ const snippetLines = [];
36
+ const startLine = Math.max(0, lineIdx - 2);
37
+ const endLine = Math.min(lines.length - 1, lineIdx + 2);
38
+ for (let i = startLine; i <= endLine; i++) {
39
+ const prefix = i === lineIdx ? ">" : " ";
40
+ snippetLines.push(`${prefix} ${i + 1} | ${lines[i]}`);
41
+ }
42
+ findingCounter.count++;
43
+ findings.push({
44
+ id: `AF-${String(findingCounter.count).padStart(3, "0")}`,
45
+ ruleId: pattern.id,
46
+ severity: pattern.severity,
47
+ confidence: pattern.confidence,
48
+ category: pattern.category,
49
+ message: pattern.message,
50
+ filePath: file.path,
51
+ line: lineIdx + 1,
52
+ column: match.index + 1,
53
+ snippet: snippetLines.join("\n"),
54
+ source: "tier1",
55
+ });
56
+ // Prevent infinite loop on zero-length matches
57
+ if (match[0].length === 0)
58
+ break;
59
+ }
60
+ }
61
+ }
62
+ return findings;
63
+ }
64
+ /**
65
+ * Run the audit scan across all provided files.
66
+ *
67
+ * @param files - Discovered files to scan
68
+ * @param config - Audit configuration
69
+ * @returns Complete AuditResult with findings, summary, and metadata
70
+ */
71
+ export function runAuditScan(files, config) {
72
+ const startedAt = new Date().toISOString();
73
+ const start = performance.now();
74
+ const allFindings = [];
75
+ const filesWithFindingsSet = new Set();
76
+ const findingCounter = { count: 0 };
77
+ for (const file of files) {
78
+ const fileFindings = scanFile(file, AUDIT_PATTERNS, findingCounter);
79
+ if (fileFindings.length > 0) {
80
+ filesWithFindingsSet.add(file.path);
81
+ allFindings.push(...fileFindings);
82
+ }
83
+ }
84
+ // Sort: severity (critical first), then file path
85
+ allFindings.sort((a, b) => {
86
+ const sevA = SEVERITY_ORDER.indexOf(a.severity);
87
+ const sevB = SEVERITY_ORDER.indexOf(b.severity);
88
+ if (sevA !== sevB)
89
+ return sevA - sevB;
90
+ return a.filePath.localeCompare(b.filePath);
91
+ });
92
+ // Compute summary
93
+ const summary = computeSummary(allFindings);
94
+ const durationMs = Math.round(performance.now() - start);
95
+ return {
96
+ rootPath: "",
97
+ startedAt,
98
+ completedAt: new Date().toISOString(),
99
+ durationMs,
100
+ filesScanned: files.length,
101
+ filesWithFindings: filesWithFindingsSet.size,
102
+ findings: allFindings,
103
+ summary,
104
+ config,
105
+ };
106
+ }
107
+ function computeSummary(findings) {
108
+ let critical = 0;
109
+ let high = 0;
110
+ let medium = 0;
111
+ let low = 0;
112
+ let info = 0;
113
+ for (const f of findings) {
114
+ switch (f.severity) {
115
+ case "critical":
116
+ critical++;
117
+ break;
118
+ case "high":
119
+ high++;
120
+ break;
121
+ case "medium":
122
+ medium++;
123
+ break;
124
+ case "low":
125
+ low++;
126
+ break;
127
+ case "info":
128
+ info++;
129
+ break;
130
+ }
131
+ }
132
+ let score = 100;
133
+ for (const f of findings) {
134
+ score -= SEVERITY_DEDUCTIONS[f.severity];
135
+ }
136
+ score = Math.max(0, Math.min(100, score));
137
+ let verdict;
138
+ if (score >= 80)
139
+ verdict = "PASS";
140
+ else if (score >= 50)
141
+ verdict = "CONCERNS";
142
+ else
143
+ verdict = "FAIL";
144
+ return {
145
+ critical, high, medium, low, info,
146
+ total: findings.length,
147
+ score,
148
+ verdict,
149
+ };
150
+ }
151
+ //# sourceMappingURL=audit-scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-scanner.js","sourceRoot":"","sources":["../../src/audit/audit-scanner.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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"}