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 @@
1
+ export {};
@@ -0,0 +1,8 @@
1
+ // Clean application — no security issues
2
+ import { createServer } from "node:http";
3
+ const server = createServer((req, res) => {
4
+ res.writeHead(200, { "Content-Type": "application/json" });
5
+ res.end(JSON.stringify({ status: "ok" }));
6
+ });
7
+ server.listen(3000);
8
+ //# sourceMappingURL=app.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../../../../src/audit/__fixtures__/clean-project/app.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAEzC,MAAM,MAAM,GAAG,YAAY,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;IACvC,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;IAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AAC5C,CAAC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function add(a: number, b: number): number;
2
+ export declare function greet(name: string): string;
@@ -0,0 +1,8 @@
1
+ // Clean utility module
2
+ export function add(a, b) {
3
+ return a + b;
4
+ }
5
+ export function greet(name) {
6
+ return `Hello, ${name}!`;
7
+ }
8
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../../src/audit/__fixtures__/clean-project/utils.ts"],"names":[],"mappings":"AAAA,uBAAuB;AACvB,MAAM,UAAU,GAAG,CAAC,CAAS,EAAE,CAAS;IACtC,OAAO,CAAC,GAAG,CAAC,CAAC;AACf,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,IAAY;IAChC,OAAO,UAAU,IAAI,GAAG,CAAC;AAC3B,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function deploy(branch: string): void;
@@ -0,0 +1,6 @@
1
+ // Risky module — one vulnerability
2
+ import { exec } from "node:child_process";
3
+ export function deploy(branch) {
4
+ exec(`git push origin ${branch}`);
5
+ }
6
+ //# sourceMappingURL=risky.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"risky.js","sourceRoot":"","sources":["../../../../src/audit/__fixtures__/mixed-project/risky.ts"],"names":[],"mappings":"AAAA,mCAAmC;AACnC,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAE1C,MAAM,UAAU,MAAM,CAAC,MAAc;IACnC,IAAI,CAAC,mBAAmB,MAAM,EAAE,CAAC,CAAC;AACpC,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function parseId(raw: string): number;
@@ -0,0 +1,5 @@
1
+ // Safe module — no issues
2
+ export function parseId(raw) {
3
+ return parseInt(raw, 10);
4
+ }
5
+ //# sourceMappingURL=safe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"safe.js","sourceRoot":"","sources":["../../../../src/audit/__fixtures__/mixed-project/safe.ts"],"names":[],"mappings":"AAAA,0BAA0B;AAC1B,MAAM,UAAU,OAAO,CAAC,GAAW;IACjC,OAAO,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;AAC3B,CAAC"}
@@ -0,0 +1,4 @@
1
+ export declare function runCommand(userInput: string): void;
2
+ export declare function evaluate(code: string): any;
3
+ export declare function renderHtml(el: HTMLElement, content: string): void;
4
+ export declare function getUser(db: any, userId: string): any;
@@ -0,0 +1,21 @@
1
+ // Vulnerable handler — multiple security issues
2
+ import { exec } from "node:child_process";
3
+ // CI-001: Command injection via exec
4
+ export function runCommand(userInput) {
5
+ exec(`ls ${userInput}`);
6
+ }
7
+ // CE-001: Code execution via eval
8
+ export function evaluate(code) {
9
+ return eval(code);
10
+ }
11
+ // XSS-001: innerHTML assignment
12
+ export function renderHtml(el, content) {
13
+ el.innerHTML = content;
14
+ }
15
+ // HS-001: Hardcoded API key
16
+ const API_KEY = "sk-1234567890abcdef1234567890abcdef";
17
+ // SQLI-001: SQL injection via concatenation
18
+ export function getUser(db, userId) {
19
+ return db.query("SELECT * FROM users WHERE id = '" + userId + "'");
20
+ }
21
+ //# sourceMappingURL=handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler.js","sourceRoot":"","sources":["../../../../src/audit/__fixtures__/vulnerable-project/handler.ts"],"names":[],"mappings":"AAAA,gDAAgD;AAChD,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAE1C,qCAAqC;AACrC,MAAM,UAAU,UAAU,CAAC,SAAiB;IAC1C,IAAI,CAAC,MAAM,SAAS,EAAE,CAAC,CAAC;AAC1B,CAAC;AAED,kCAAkC;AAClC,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC;AACpB,CAAC;AAED,gCAAgC;AAChC,MAAM,UAAU,UAAU,CAAC,EAAe,EAAE,OAAe;IACzD,EAAE,CAAC,SAAS,GAAG,OAAO,CAAC;AACzB,CAAC;AAED,4BAA4B;AAC5B,MAAM,OAAO,GAAG,qCAAqC,CAAC;AAEtD,4CAA4C;AAC5C,MAAM,UAAU,OAAO,CAAC,EAAO,EAAE,MAAc;IAC7C,OAAO,EAAE,CAAC,KAAK,CAAC,kCAAkC,GAAG,MAAM,GAAG,GAAG,CAAC,CAAC;AACrE,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,92 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { join } from "node:path";
3
+ import { discoverAuditFiles } from "./file-discovery.js";
4
+ import { runAuditScan } from "./audit-scanner.js";
5
+ import { createDefaultAuditConfig } from "./audit-types.js";
6
+ import { formatJson } from "./formatters/json-formatter.js";
7
+ import { formatSarif } from "./formatters/sarif-formatter.js";
8
+ import { attachFixSuggestions } from "./fix-suggestions.js";
9
+ import { loadAuditConfig } from "./config.js";
10
+ const FIXTURES = join(import.meta.dirname, "__fixtures__");
11
+ describe("audit integration", () => {
12
+ it("TC-054: clean project produces PASS verdict", async () => {
13
+ const config = createDefaultAuditConfig();
14
+ const files = await discoverAuditFiles(join(FIXTURES, "clean-project"), config);
15
+ const result = runAuditScan(files, config);
16
+ expect(result.findings).toHaveLength(0);
17
+ expect(result.summary.verdict).toBe("PASS");
18
+ expect(result.summary.score).toBe(100);
19
+ expect(result.filesScanned).toBe(2);
20
+ });
21
+ it("TC-055: vulnerable project detects all planted vulnerabilities", async () => {
22
+ const config = createDefaultAuditConfig();
23
+ const files = await discoverAuditFiles(join(FIXTURES, "vulnerable-project"), config);
24
+ const result = runAuditScan(files, config);
25
+ expect(result.findings.length).toBeGreaterThanOrEqual(5);
26
+ const ruleIds = result.findings.map((f) => f.ruleId);
27
+ // exec() detection
28
+ expect(ruleIds.some((id) => id.startsWith("CI-"))).toBe(true);
29
+ // eval() detection
30
+ expect(ruleIds.some((id) => id.startsWith("CE-"))).toBe(true);
31
+ // innerHTML detection
32
+ expect(ruleIds.some((id) => id.startsWith("XSS-"))).toBe(true);
33
+ // Hardcoded secret detection
34
+ expect(ruleIds.some((id) => id.startsWith("HS-"))).toBe(true);
35
+ // SQL injection detection
36
+ expect(ruleIds.some((id) => id.startsWith("SQLI-"))).toBe(true);
37
+ });
38
+ it("TC-056: JSON output is valid and complete", async () => {
39
+ const config = createDefaultAuditConfig();
40
+ const files = await discoverAuditFiles(join(FIXTURES, "mixed-project"), config);
41
+ const result = runAuditScan(files, config);
42
+ const json = formatJson(result);
43
+ const parsed = JSON.parse(json);
44
+ expect(parsed.findings).toBeDefined();
45
+ expect(parsed.summary).toBeDefined();
46
+ expect(parsed.summary.critical).toBeDefined();
47
+ expect(parsed.summary.high).toBeDefined();
48
+ expect(parsed.summary.medium).toBeDefined();
49
+ expect(parsed.summary.low).toBeDefined();
50
+ expect(parsed.summary.info).toBeDefined();
51
+ expect(parsed.summary.score).toBeGreaterThanOrEqual(0);
52
+ expect(parsed.summary.verdict).toBeDefined();
53
+ expect(parsed.filesScanned).toBe(2);
54
+ });
55
+ it("TC-057: SARIF output has correct structure", async () => {
56
+ const config = createDefaultAuditConfig();
57
+ const files = await discoverAuditFiles(join(FIXTURES, "vulnerable-project"), config);
58
+ const result = runAuditScan(files, config);
59
+ const sarif = formatSarif(result);
60
+ const parsed = JSON.parse(sarif);
61
+ expect(parsed.version).toBe("2.1.0");
62
+ expect(parsed.$schema).toContain("sarif");
63
+ expect(parsed.runs).toHaveLength(1);
64
+ expect(parsed.runs[0].tool.driver.name).toBe("vskill-audit");
65
+ expect(parsed.runs[0].results.length).toBeGreaterThanOrEqual(5);
66
+ // Each result has correct location structure
67
+ for (const r of parsed.runs[0].results) {
68
+ expect(r.ruleId).toBeDefined();
69
+ expect(r.message.text).toBeDefined();
70
+ expect(r.locations[0].physicalLocation.artifactLocation.uri).toBeDefined();
71
+ expect(r.locations[0].physicalLocation.region.startLine).toBeGreaterThan(0);
72
+ }
73
+ });
74
+ it("fix suggestions are attached when fix=true", async () => {
75
+ const config = createDefaultAuditConfig();
76
+ config.fix = true;
77
+ const files = await discoverAuditFiles(join(FIXTURES, "vulnerable-project"), config);
78
+ const result = runAuditScan(files, config);
79
+ const withFixes = attachFixSuggestions(result.findings, true);
80
+ // Every finding should have a suggestedFix
81
+ for (const f of withFixes) {
82
+ expect(f.suggestedFix).toBeDefined();
83
+ expect(f.suggestedFix.length).toBeGreaterThan(0);
84
+ }
85
+ });
86
+ it("config loading works end-to-end", async () => {
87
+ const config = await loadAuditConfig(join(FIXTURES, "clean-project"), {});
88
+ expect(config.maxFiles).toBe(500);
89
+ expect(config.excludePaths).toEqual([]);
90
+ });
91
+ });
92
+ //# sourceMappingURL=audit-integration.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-integration.test.js","sourceRoot":"","sources":["../../src/audit/audit-integration.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * LLM-based security analysis engine.
3
+ *
4
+ * Performs deeper analysis on Tier 1 flagged files using an LLM
5
+ * (via subprocess). Traces data flows and identifies complex
6
+ * vulnerabilities that regex patterns alone cannot detect.
7
+ */
8
+ import type { AuditConfig, AuditFile, AuditFinding } from "./audit-types.js";
9
+ /**
10
+ * Build a security analysis prompt for the LLM.
11
+ */
12
+ export declare function buildLlmPrompt(file: AuditFile, tier1Findings: AuditFinding[]): string;
13
+ /**
14
+ * Parse the LLM's JSON response into AuditFinding objects.
15
+ */
16
+ export declare function parseLlmResponse(response: string, filePath: string): AuditFinding[];
17
+ /**
18
+ * Run LLM analysis on flagged files.
19
+ *
20
+ * @param files - Files that had Tier 1 findings
21
+ * @param tier1Findings - All Tier 1 findings (to provide context)
22
+ * @param config - Audit configuration
23
+ * @returns Additional findings from LLM analysis
24
+ */
25
+ export declare function runLlmAnalysis(files: AuditFile[], tier1Findings: AuditFinding[], config: AuditConfig): Promise<AuditFinding[]>;
@@ -0,0 +1,139 @@
1
+ /**
2
+ * LLM-based security analysis engine.
3
+ *
4
+ * Performs deeper analysis on Tier 1 flagged files using an LLM
5
+ * (via subprocess). Traces data flows and identifies complex
6
+ * vulnerabilities that regex patterns alone cannot detect.
7
+ */
8
+ import { execFile } from "node:child_process";
9
+ import { promisify } from "node:util";
10
+ const execFileAsync = promisify(execFile);
11
+ /**
12
+ * Build a security analysis prompt for the LLM.
13
+ */
14
+ export function buildLlmPrompt(file, tier1Findings) {
15
+ const findingSummaries = tier1Findings
16
+ .map((f) => ` - [${f.ruleId}] ${f.severity} (${f.category}): ${f.message} (line ${f.line})`)
17
+ .join("\n");
18
+ return `Analyze this file for security vulnerabilities. Focus on data flow from user input to dangerous sinks.
19
+
20
+ File: ${file.path}
21
+ Tier 1 findings:
22
+ ${findingSummaries}
23
+
24
+ Source code:
25
+ \`\`\`
26
+ ${file.content}
27
+ \`\`\`
28
+
29
+ Respond with JSON only:
30
+ {
31
+ "findings": [{
32
+ "ruleId": "LLM-XXX-NNN",
33
+ "severity": "critical|high|medium|low|info",
34
+ "confidence": "high|medium|low",
35
+ "category": "category-name",
36
+ "message": "description",
37
+ "line": <number>,
38
+ "dataFlow": {
39
+ "steps": [{"file": "path", "line": <number>, "description": "what happens", "code": "snippet"}]
40
+ },
41
+ "suggestedFix": "how to fix"
42
+ }]
43
+ }`;
44
+ }
45
+ /**
46
+ * Parse the LLM's JSON response into AuditFinding objects.
47
+ */
48
+ export function parseLlmResponse(response, filePath) {
49
+ try {
50
+ // Extract JSON from response (may contain markdown wrapping)
51
+ const jsonMatch = response.match(/\{[\s\S]*\}/);
52
+ if (!jsonMatch)
53
+ return [];
54
+ const data = JSON.parse(jsonMatch[0]);
55
+ if (!data.findings || !Array.isArray(data.findings))
56
+ return [];
57
+ let counter = 0;
58
+ return data.findings.map((f) => {
59
+ counter++;
60
+ const finding = {
61
+ id: `LLM-${String(counter).padStart(3, "0")}`,
62
+ ruleId: f.ruleId || "LLM-UNKNOWN",
63
+ severity: f.severity || "medium",
64
+ confidence: f.confidence || "medium",
65
+ category: f.category || "unknown",
66
+ message: f.message || "",
67
+ filePath,
68
+ line: f.line || 1,
69
+ snippet: "",
70
+ source: "llm",
71
+ };
72
+ // Parse data flow if present
73
+ if (f.dataFlow && typeof f.dataFlow === "object") {
74
+ const df = f.dataFlow;
75
+ if (Array.isArray(df.steps)) {
76
+ finding.dataFlow = {
77
+ steps: df.steps.map((s) => ({
78
+ file: s.file || filePath,
79
+ line: s.line || 1,
80
+ description: s.description || "",
81
+ code: s.code || "",
82
+ })),
83
+ };
84
+ }
85
+ }
86
+ // Parse suggested fix
87
+ if (f.suggestedFix && typeof f.suggestedFix === "string") {
88
+ finding.suggestedFix = f.suggestedFix;
89
+ }
90
+ return finding;
91
+ });
92
+ }
93
+ catch {
94
+ return [];
95
+ }
96
+ }
97
+ /**
98
+ * Run LLM analysis on flagged files.
99
+ *
100
+ * @param files - Files that had Tier 1 findings
101
+ * @param tier1Findings - All Tier 1 findings (to provide context)
102
+ * @param config - Audit configuration
103
+ * @returns Additional findings from LLM analysis
104
+ */
105
+ export async function runLlmAnalysis(files, tier1Findings, config) {
106
+ if (config.tier1Only || files.length === 0)
107
+ return [];
108
+ // Group Tier 1 findings by file
109
+ const findingsByFile = new Map();
110
+ for (const f of tier1Findings) {
111
+ const group = findingsByFile.get(f.filePath) || [];
112
+ group.push(f);
113
+ findingsByFile.set(f.filePath, group);
114
+ }
115
+ const allLlmFindings = [];
116
+ // Process files with concurrency limit
117
+ const concurrency = config.llmConcurrency;
118
+ for (let i = 0; i < files.length; i += concurrency) {
119
+ const batch = files.slice(i, i + concurrency);
120
+ const promises = batch.map(async (file) => {
121
+ const fileFindings = findingsByFile.get(file.path) || [];
122
+ const prompt = buildLlmPrompt(file, fileFindings);
123
+ try {
124
+ const { stdout } = await execFileAsync(config.llmProvider || "claude", ["--print", prompt], { timeout: config.llmTimeout });
125
+ return parseLlmResponse(stdout, file.path);
126
+ }
127
+ catch {
128
+ // Graceful fallback: LLM unavailable or timed out
129
+ return [];
130
+ }
131
+ });
132
+ const results = await Promise.all(promises);
133
+ for (const findings of results) {
134
+ allLlmFindings.push(...findings);
135
+ }
136
+ }
137
+ return allLlmFindings;
138
+ }
139
+ //# sourceMappingURL=audit-llm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-llm.js","sourceRoot":"","sources":["../../src/audit/audit-llm.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -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":"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"}
@@ -0,0 +1,31 @@
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 type { PatternCheck } from "../scanner/types.js";
9
+ /**
10
+ * Extended pattern with safe-context awareness and confidence.
11
+ */
12
+ export interface AuditPatternCheck extends PatternCheck {
13
+ /** Pattern ID (unique across all patterns) */
14
+ id: string;
15
+ /** Human-readable name */
16
+ name: string;
17
+ /** Regexes that suppress the finding when they match the line */
18
+ safeContexts?: RegExp[];
19
+ /** Default confidence for this pattern */
20
+ confidence: "high" | "medium" | "low";
21
+ }
22
+ /**
23
+ * Project-specific security patterns (beyond the existing 37 skill patterns).
24
+ */
25
+ export declare const PROJECT_PATTERNS: AuditPatternCheck[];
26
+ /**
27
+ * Combined audit patterns: original SCAN_PATTERNS + project-specific patterns.
28
+ *
29
+ * The SCAN_PATTERNS are adapted to AuditPatternCheck interface (id from ScanPattern.id).
30
+ */
31
+ export declare const AUDIT_PATTERNS: AuditPatternCheck[];