vskill 0.1.2 → 0.1.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 (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 +56 -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,98 @@
1
+ /**
2
+ * Types and interfaces for the vskill audit module.
3
+ */
4
+ import type { PatternCheck, Severity, ScanVerdict } from "../scanner/types.js";
5
+ export type { Severity, ScanVerdict };
6
+ /** Confidence level for a finding */
7
+ export type Confidence = "high" | "medium" | "low";
8
+ /** Source of a finding */
9
+ export type FindingSource = "tier1" | "llm";
10
+ /** A file discovered for auditing */
11
+ export interface AuditFile {
12
+ /** Relative path within the audited directory */
13
+ path: string;
14
+ /** File content as a string */
15
+ content: string;
16
+ /** File size in bytes */
17
+ sizeBytes: number;
18
+ }
19
+ /** A single step in a data flow trace */
20
+ export interface DataFlowStep {
21
+ file: string;
22
+ line: number;
23
+ description: string;
24
+ code: string;
25
+ }
26
+ /** Data flow trace from LLM analysis */
27
+ export interface DataFlowTrace {
28
+ steps: DataFlowStep[];
29
+ }
30
+ /** A single audit finding */
31
+ export interface AuditFinding {
32
+ /** Unique finding ID (e.g., "AF-001") */
33
+ id: string;
34
+ /** Pattern/rule ID that triggered this finding */
35
+ ruleId: string;
36
+ /** Severity level */
37
+ severity: Severity;
38
+ /** Confidence level */
39
+ confidence: Confidence;
40
+ /** Category of the vulnerability */
41
+ category: string;
42
+ /** Human-readable description */
43
+ message: string;
44
+ /** Relative file path */
45
+ filePath: string;
46
+ /** Line number (1-indexed) */
47
+ line: number;
48
+ /** Column number (optional) */
49
+ column?: number;
50
+ /** End line number (optional, for multi-line findings) */
51
+ endLine?: number;
52
+ /** Code snippet with context */
53
+ snippet: string;
54
+ /** Source of the finding */
55
+ source: FindingSource;
56
+ /** Data flow trace (from LLM analysis) */
57
+ dataFlow?: DataFlowTrace;
58
+ /** Suggested remediation (when --fix is used) */
59
+ suggestedFix?: string;
60
+ }
61
+ /** Summary statistics for an audit */
62
+ export interface AuditSummary {
63
+ critical: number;
64
+ high: number;
65
+ medium: number;
66
+ low: number;
67
+ info: number;
68
+ total: number;
69
+ score: number;
70
+ verdict: ScanVerdict;
71
+ }
72
+ /** Configuration for an audit run */
73
+ export interface AuditConfig {
74
+ excludePaths: string[];
75
+ severityThreshold: Severity;
76
+ maxFiles: number;
77
+ maxFileSize: number;
78
+ tier1Only: boolean;
79
+ llmProvider: string | null;
80
+ llmTimeout: number;
81
+ llmConcurrency: number;
82
+ customPatterns: PatternCheck[];
83
+ fix: boolean;
84
+ }
85
+ /** Complete audit result */
86
+ export interface AuditResult {
87
+ rootPath: string;
88
+ startedAt: string;
89
+ completedAt: string;
90
+ durationMs: number;
91
+ filesScanned: number;
92
+ filesWithFindings: number;
93
+ findings: AuditFinding[];
94
+ summary: AuditSummary;
95
+ config: AuditConfig;
96
+ }
97
+ /** Create a default AuditConfig with sensible defaults */
98
+ export declare function createDefaultAuditConfig(): AuditConfig;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Types and interfaces for the vskill audit module.
3
+ */
4
+ /** Create a default AuditConfig with sensible defaults */
5
+ export function createDefaultAuditConfig() {
6
+ return {
7
+ excludePaths: [],
8
+ severityThreshold: "low",
9
+ maxFiles: 500,
10
+ maxFileSize: 100 * 1024,
11
+ tier1Only: false,
12
+ llmProvider: null,
13
+ llmTimeout: 30_000,
14
+ llmConcurrency: 5,
15
+ customPatterns: [],
16
+ fix: false,
17
+ };
18
+ }
19
+ //# sourceMappingURL=audit-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-types.js","sourceRoot":"","sources":["../../src/audit/audit-types.ts"],"names":[],"mappings":"AAAA;;GAEG;AA2GH,0DAA0D;AAC1D,MAAM,UAAU,wBAAwB;IACtC,OAAO;QACL,YAAY,EAAE,EAAE;QAChB,iBAAiB,EAAE,KAAK;QACxB,QAAQ,EAAE,GAAG;QACb,WAAW,EAAE,GAAG,GAAG,IAAI;QACvB,SAAS,EAAE,KAAK;QAChB,WAAW,EAAE,IAAI;QACjB,UAAU,EAAE,MAAM;QAClB,cAAc,EAAE,CAAC;QACjB,cAAc,EAAE,EAAE;QAClB,GAAG,EAAE,KAAK;KACX,CAAC;AACJ,CAAC"}
@@ -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":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EACL,wBAAwB,GAQzB,MAAM,kBAAkB,CAAC;AAE1B,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;QAC5B,EAAE,CAAC,0DAA0D,EAAE,GAAG,EAAE;YAClE,MAAM,OAAO,GAAiB;gBAC5B,EAAE,EAAE,QAAQ;gBACZ,MAAM,EAAE,QAAQ;gBAChB,QAAQ,EAAE,UAAU;gBACpB,UAAU,EAAE,MAAM;gBAClB,QAAQ,EAAE,mBAAmB;gBAC7B,OAAO,EAAE,sBAAsB;gBAC/B,QAAQ,EAAE,cAAc;gBACxB,IAAI,EAAE,EAAE;gBACR,OAAO,EAAE,kBAAkB;gBAC3B,MAAM,EAAE,OAAO;aAChB,CAAC;YAEF,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAClC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACtC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAC1C,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACxC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;YACnD,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;YACrD,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;YAC9C,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAC9B,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;YACjD,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACvC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,mEAAmE,EAAE,GAAG,EAAE;YAC3E,MAAM,OAAO,GAAiB;gBAC5B,EAAE,EAAE,QAAQ;gBACZ,MAAM,EAAE,UAAU;gBAClB,QAAQ,EAAE,MAAM;gBAChB,UAAU,EAAE,QAAQ;gBACpB,QAAQ,EAAE,MAAM;gBAChB,OAAO,EAAE,8BAA8B;gBACvC,QAAQ,EAAE,YAAY;gBACtB,IAAI,EAAE,EAAE;gBACR,MAAM,EAAE,CAAC;gBACT,OAAO,EAAE,EAAE;gBACX,OAAO,EAAE,eAAe;gBACxB,MAAM,EAAE,KAAK;gBACb,QAAQ,EAAE;oBACR,KAAK,EAAE;wBACL;4BACE,IAAI,EAAE,YAAY;4BAClB,IAAI,EAAE,CAAC;4BACP,WAAW,EAAE,qBAAqB;4BAClC,IAAI,EAAE,4BAA4B;yBACnC;qBACF;iBACF;gBACD,YAAY,EAAE,mCAAmC;aAClD,CAAC;YAEF,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC/B,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACjC,MAAM,CAAC,OAAO,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YAChD,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,mCAAmC,CAAC,CAAC;QACzE,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;QAC3B,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;YAC5C,MAAM,MAAM,GAAG,wBAAwB,EAAE,CAAC;YAE1C,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YACxC,MAAM,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC7C,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAClC,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC;YAC5C,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACrC,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,QAAQ,EAAE,CAAC;YACtC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACvC,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACtC,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YAC1C,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACjC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;QAC3B,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;YAC5D,MAAM,MAAM,GAAgB;gBAC1B,QAAQ,EAAE,UAAU;gBACpB,SAAS,EAAE,sBAAsB;gBACjC,WAAW,EAAE,sBAAsB;gBACnC,UAAU,EAAE,IAAI;gBAChB,YAAY,EAAE,GAAG;gBACjB,iBAAiB,EAAE,CAAC;gBACpB,QAAQ,EAAE,EAAE;gBACZ,OAAO,EAAE;oBACP,QAAQ,EAAE,CAAC;oBACX,IAAI,EAAE,CAAC;oBACP,MAAM,EAAE,CAAC;oBACT,GAAG,EAAE,CAAC;oBACN,IAAI,EAAE,CAAC;oBACP,KAAK,EAAE,CAAC;oBACR,KAAK,EAAE,GAAG;oBACV,OAAO,EAAE,MAAM;iBAChB;gBACD,MAAM,EAAE,wBAAwB,EAAE;aACnC,CAAC;YAEF,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YACzC,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACtC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAC5C,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;QAC7B,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;YACtD,MAAM,KAAK,GAAkB;gBAC3B,KAAK,EAAE;oBACL;wBACE,IAAI,EAAE,gBAAgB;wBACtB,IAAI,EAAE,EAAE;wBACR,WAAW,EAAE,kCAAkC;wBAC/C,IAAI,EAAE,+BAA+B;qBACtC;oBACD;wBACE,IAAI,EAAE,gBAAgB;wBACtB,IAAI,EAAE,EAAE;wBACR,WAAW,EAAE,2BAA2B;wBACxC,IAAI,EAAE,sBAAsB;qBAC7B;iBACF;aACF,CAAC;YAEF,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YACpC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;YACnD,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACvC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;QACzB,EAAE,CAAC,4DAA4D,EAAE,GAAG,EAAE;YACpE,MAAM,IAAI,GAAc;gBACtB,IAAI,EAAE,cAAc;gBACpB,OAAO,EAAE,uBAAuB;gBAChC,SAAS,EAAE,EAAE;aACd,CAAC;YAEF,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;YACvC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;YACnD,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAClC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Audit configuration loader.
3
+ *
4
+ * Loads config from .vskill-audit.json or .vskillrc, merges with defaults,
5
+ * then applies CLI flag overrides.
6
+ */
7
+ import { type AuditConfig } from "./audit-types.js";
8
+ /**
9
+ * Load audit configuration by merging defaults, config file, and CLI overrides.
10
+ *
11
+ * Priority: CLI flags > config file > defaults
12
+ */
13
+ export declare function loadAuditConfig(rootPath: string, cliOverrides: Record<string, string | undefined>): Promise<AuditConfig>;
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Audit configuration loader.
3
+ *
4
+ * Loads config from .vskill-audit.json or .vskillrc, merges with defaults,
5
+ * then applies CLI flag overrides.
6
+ */
7
+ import { readFile } from "node:fs/promises";
8
+ import { join } from "node:path";
9
+ import { createDefaultAuditConfig } from "./audit-types.js";
10
+ const VALID_SEVERITIES = ["critical", "high", "medium", "low", "info"];
11
+ const CONFIG_FILES = [".vskill-audit.json", ".vskillrc"];
12
+ /**
13
+ * Try to read and parse a JSON config file. Returns null if not found.
14
+ */
15
+ async function tryLoadJsonFile(filePath) {
16
+ try {
17
+ const raw = await readFile(filePath, "utf-8");
18
+ return JSON.parse(raw);
19
+ }
20
+ catch {
21
+ return null;
22
+ }
23
+ }
24
+ /**
25
+ * Load audit configuration by merging defaults, config file, and CLI overrides.
26
+ *
27
+ * Priority: CLI flags > config file > defaults
28
+ */
29
+ export async function loadAuditConfig(rootPath, cliOverrides) {
30
+ const config = createDefaultAuditConfig();
31
+ // Try config files in order
32
+ let fileConfig = null;
33
+ for (const name of CONFIG_FILES) {
34
+ fileConfig = await tryLoadJsonFile(join(rootPath, name));
35
+ if (fileConfig)
36
+ break;
37
+ }
38
+ // Merge file config into defaults
39
+ if (fileConfig) {
40
+ if (Array.isArray(fileConfig.excludePaths)) {
41
+ config.excludePaths = fileConfig.excludePaths;
42
+ }
43
+ if (typeof fileConfig.maxFiles === "number") {
44
+ config.maxFiles = fileConfig.maxFiles;
45
+ }
46
+ if (typeof fileConfig.maxFileSize === "number") {
47
+ config.maxFileSize = fileConfig.maxFileSize;
48
+ }
49
+ if (typeof fileConfig.severityThreshold === "string") {
50
+ config.severityThreshold = fileConfig.severityThreshold;
51
+ }
52
+ if (typeof fileConfig.tier1Only === "boolean") {
53
+ config.tier1Only = fileConfig.tier1Only;
54
+ }
55
+ if (typeof fileConfig.fix === "boolean") {
56
+ config.fix = fileConfig.fix;
57
+ }
58
+ if (typeof fileConfig.llmProvider === "string") {
59
+ config.llmProvider = fileConfig.llmProvider;
60
+ }
61
+ if (typeof fileConfig.llmTimeout === "number") {
62
+ config.llmTimeout = fileConfig.llmTimeout;
63
+ }
64
+ if (typeof fileConfig.llmConcurrency === "number") {
65
+ config.llmConcurrency = fileConfig.llmConcurrency;
66
+ }
67
+ }
68
+ // Apply CLI overrides
69
+ if (cliOverrides.maxFiles !== undefined) {
70
+ config.maxFiles = Number(cliOverrides.maxFiles);
71
+ }
72
+ if (cliOverrides.severity !== undefined) {
73
+ const sev = cliOverrides.severity;
74
+ if (!VALID_SEVERITIES.includes(sev)) {
75
+ throw new Error(`Invalid severity: "${cliOverrides.severity}". Valid values: ${VALID_SEVERITIES.join(", ")}`);
76
+ }
77
+ config.severityThreshold = sev;
78
+ }
79
+ if (cliOverrides.tier1Only !== undefined) {
80
+ config.tier1Only = cliOverrides.tier1Only === "true";
81
+ }
82
+ if (cliOverrides.fix !== undefined) {
83
+ config.fix = cliOverrides.fix === "true";
84
+ }
85
+ if (cliOverrides.exclude !== undefined) {
86
+ config.excludePaths = cliOverrides.exclude.split(",").map((p) => p.trim());
87
+ }
88
+ return config;
89
+ }
90
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/audit/config.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,15 @@
1
+ /**
2
+ * File discovery for local project auditing.
3
+ *
4
+ * Walks the filesystem to find scannable files, respecting
5
+ * configurable exclude patterns, max file limits, and binary detection.
6
+ */
7
+ import type { AuditConfig, AuditFile } from "./audit-types.js";
8
+ /**
9
+ * Discover files in a directory or single file for auditing.
10
+ *
11
+ * @param targetPath - Path to a directory or single file
12
+ * @param config - Audit configuration with exclude patterns and limits
13
+ * @returns Array of discovered AuditFile objects
14
+ */
15
+ export declare function discoverAuditFiles(targetPath: string, config: AuditConfig): Promise<AuditFile[]>;
@@ -0,0 +1,153 @@
1
+ /**
2
+ * File discovery for local project auditing.
3
+ *
4
+ * Walks the filesystem to find scannable files, respecting
5
+ * configurable exclude patterns, max file limits, and binary detection.
6
+ */
7
+ import { readdir, readFile, stat } from "node:fs/promises";
8
+ import { join, basename, extname, relative } from "node:path";
9
+ /** Extensions considered scannable for security auditing */
10
+ const SCANNABLE_EXTENSIONS = new Set([
11
+ ".md", ".json", ".yaml", ".yml", ".toml",
12
+ ".sh", ".bash", ".zsh", ".ps1", ".bat", ".cmd",
13
+ ".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs",
14
+ ".py", ".rb", ".lua", ".go", ".rs", ".java",
15
+ ".php", ".cs", ".c", ".cpp", ".h", ".hpp",
16
+ ".swift", ".kt", ".kts", ".scala",
17
+ ".sql", ".graphql", ".gql",
18
+ ".env", ".ini", ".cfg", ".conf",
19
+ ".xml", ".html", ".htm", ".vue", ".svelte",
20
+ ]);
21
+ /** Directories to always skip */
22
+ const SKIP_DIRS = new Set([
23
+ "node_modules", ".git", "dist", "build", "coverage",
24
+ ".next", ".nuxt", ".output", "__pycache__", ".pytest_cache",
25
+ "vendor", ".venv", "venv", ".tox",
26
+ ".idea", ".vscode",
27
+ "target", // Rust/Java
28
+ ]);
29
+ /**
30
+ * Check if a buffer contains binary content (null byte in first 8KB).
31
+ */
32
+ function isBinary(buffer) {
33
+ const checkLength = Math.min(buffer.length, 8192);
34
+ for (let i = 0; i < checkLength; i++) {
35
+ if (buffer[i] === 0)
36
+ return true;
37
+ }
38
+ return false;
39
+ }
40
+ /**
41
+ * Check if a file path is scannable based on its extension.
42
+ */
43
+ function isScannable(filePath) {
44
+ const name = basename(filePath);
45
+ const ext = extname(name).toLowerCase();
46
+ return ext !== "" && SCANNABLE_EXTENSIONS.has(ext);
47
+ }
48
+ /**
49
+ * Simple glob pattern matching for exclude paths.
50
+ * Supports ** (any path) and * (any segment).
51
+ */
52
+ function matchesExcludePattern(relativePath, patterns) {
53
+ for (const pattern of patterns) {
54
+ const regex = patternToRegex(pattern);
55
+ if (regex.test(relativePath))
56
+ return true;
57
+ }
58
+ return false;
59
+ }
60
+ function patternToRegex(pattern) {
61
+ // Normalize: **/X means "anywhere/X" including at root
62
+ let p = pattern;
63
+ // Handle leading **/ — matches zero or more directories
64
+ if (p.startsWith("**/")) {
65
+ p = p.slice(3);
66
+ const inner = globSegmentToRegex(p);
67
+ return new RegExp(`^(?:.*\\/)?${inner}$`);
68
+ }
69
+ return new RegExp(`^${globSegmentToRegex(p)}$`);
70
+ }
71
+ function globSegmentToRegex(pattern) {
72
+ return pattern
73
+ .replace(/[.+^${}()|[\]\\]/g, "\\$&")
74
+ .replace(/\*\*/g, "§§")
75
+ .replace(/\*/g, "[^/]*")
76
+ .replace(/§§/g, ".*");
77
+ }
78
+ /**
79
+ * Discover files in a directory or single file for auditing.
80
+ *
81
+ * @param targetPath - Path to a directory or single file
82
+ * @param config - Audit configuration with exclude patterns and limits
83
+ * @returns Array of discovered AuditFile objects
84
+ */
85
+ export async function discoverAuditFiles(targetPath, config) {
86
+ const targetStat = await stat(targetPath);
87
+ // Single file mode
88
+ if (targetStat.isFile()) {
89
+ const content = await readFile(targetPath, "utf-8");
90
+ return [
91
+ {
92
+ path: basename(targetPath),
93
+ content,
94
+ sizeBytes: targetStat.size,
95
+ },
96
+ ];
97
+ }
98
+ // Directory mode
99
+ const files = [];
100
+ async function walk(currentDir) {
101
+ if (files.length >= config.maxFiles)
102
+ return;
103
+ let entries;
104
+ try {
105
+ entries = await readdir(currentDir, { withFileTypes: true });
106
+ }
107
+ catch {
108
+ return;
109
+ }
110
+ for (const entry of entries) {
111
+ if (files.length >= config.maxFiles)
112
+ break;
113
+ const fullPath = join(currentDir, entry.name);
114
+ const relativePath = relative(targetPath, fullPath);
115
+ if (entry.isDirectory()) {
116
+ // Skip known non-useful directories
117
+ if (SKIP_DIRS.has(entry.name) || entry.name.startsWith("."))
118
+ continue;
119
+ // Check exclude patterns
120
+ if (matchesExcludePattern(relativePath, config.excludePaths))
121
+ continue;
122
+ await walk(fullPath);
123
+ }
124
+ else if (entry.isFile()) {
125
+ if (!isScannable(relativePath))
126
+ continue;
127
+ if (matchesExcludePattern(relativePath, config.excludePaths))
128
+ continue;
129
+ try {
130
+ const fileStat = await stat(fullPath);
131
+ // Skip files exceeding size limit
132
+ if (fileStat.size > config.maxFileSize)
133
+ continue;
134
+ const buffer = await readFile(fullPath);
135
+ if (isBinary(buffer))
136
+ continue;
137
+ const content = buffer.toString("utf-8");
138
+ files.push({
139
+ path: relativePath,
140
+ content,
141
+ sizeBytes: fileStat.size,
142
+ });
143
+ }
144
+ catch {
145
+ // Skip unreadable files
146
+ }
147
+ }
148
+ }
149
+ }
150
+ await walk(targetPath);
151
+ return files;
152
+ }
153
+ //# sourceMappingURL=file-discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-discovery.js","sourceRoot":"","sources":["../../src/audit/file-discovery.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};