vaspera 2.9.0 → 2.10.0

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 (166) hide show
  1. package/CHANGELOG.md +122 -7
  2. package/README.md +58 -1
  3. package/dist/__tests__/autofix/branch-manager.test.d.ts +2 -0
  4. package/dist/__tests__/autofix/branch-manager.test.d.ts.map +1 -0
  5. package/dist/__tests__/autofix/branch-manager.test.js +60 -0
  6. package/dist/__tests__/autofix/branch-manager.test.js.map +1 -0
  7. package/dist/__tests__/autofix/commit-generator.test.d.ts +2 -0
  8. package/dist/__tests__/autofix/commit-generator.test.d.ts.map +1 -0
  9. package/dist/__tests__/autofix/commit-generator.test.js +147 -0
  10. package/dist/__tests__/autofix/commit-generator.test.js.map +1 -0
  11. package/dist/__tests__/autofix/constitution.test.d.ts +9 -0
  12. package/dist/__tests__/autofix/constitution.test.d.ts.map +1 -0
  13. package/dist/__tests__/autofix/constitution.test.js +421 -0
  14. package/dist/__tests__/autofix/constitution.test.js.map +1 -0
  15. package/dist/__tests__/autofix/pr-generator.test.d.ts +2 -0
  16. package/dist/__tests__/autofix/pr-generator.test.d.ts.map +1 -0
  17. package/dist/__tests__/autofix/pr-generator.test.js +152 -0
  18. package/dist/__tests__/autofix/pr-generator.test.js.map +1 -0
  19. package/dist/__tests__/property-test-helpers.d.ts +87 -0
  20. package/dist/__tests__/property-test-helpers.d.ts.map +1 -0
  21. package/dist/__tests__/property-test-helpers.js +136 -0
  22. package/dist/__tests__/property-test-helpers.js.map +1 -0
  23. package/dist/__tests__/scanners/dast/index.test.d.ts +2 -0
  24. package/dist/__tests__/scanners/dast/index.test.d.ts.map +1 -0
  25. package/dist/__tests__/scanners/dast/index.test.js +183 -0
  26. package/dist/__tests__/scanners/dast/index.test.js.map +1 -0
  27. package/dist/__tests__/scanners/dast/nuclei.test.d.ts +2 -0
  28. package/dist/__tests__/scanners/dast/nuclei.test.d.ts.map +1 -0
  29. package/dist/__tests__/scanners/dast/nuclei.test.js +166 -0
  30. package/dist/__tests__/scanners/dast/nuclei.test.js.map +1 -0
  31. package/dist/__tests__/scanners/dast/zap.test.d.ts +2 -0
  32. package/dist/__tests__/scanners/dast/zap.test.d.ts.map +1 -0
  33. package/dist/__tests__/scanners/dast/zap.test.js +158 -0
  34. package/dist/__tests__/scanners/dast/zap.test.js.map +1 -0
  35. package/dist/__tests__/scanners/fp-feedback.test.d.ts +2 -0
  36. package/dist/__tests__/scanners/fp-feedback.test.d.ts.map +1 -0
  37. package/dist/__tests__/scanners/fp-feedback.test.js +202 -0
  38. package/dist/__tests__/scanners/fp-feedback.test.js.map +1 -0
  39. package/dist/__tests__/scanners/fp-filter.property.test.d.ts +9 -0
  40. package/dist/__tests__/scanners/fp-filter.property.test.d.ts.map +1 -0
  41. package/dist/__tests__/scanners/fp-filter.property.test.js +253 -0
  42. package/dist/__tests__/scanners/fp-filter.property.test.js.map +1 -0
  43. package/dist/__tests__/scanners/fp-filter.test.d.ts +2 -0
  44. package/dist/__tests__/scanners/fp-filter.test.d.ts.map +1 -0
  45. package/dist/__tests__/scanners/fp-filter.test.js +234 -0
  46. package/dist/__tests__/scanners/fp-filter.test.js.map +1 -0
  47. package/dist/__tests__/scanners/fp-tracker.test.d.ts +2 -0
  48. package/dist/__tests__/scanners/fp-tracker.test.d.ts.map +1 -0
  49. package/dist/__tests__/scanners/fp-tracker.test.js +262 -0
  50. package/dist/__tests__/scanners/fp-tracker.test.js.map +1 -0
  51. package/dist/__tests__/scanners/logic/endpoint-analyzer.property.test.d.ts +10 -0
  52. package/dist/__tests__/scanners/logic/endpoint-analyzer.property.test.d.ts.map +1 -0
  53. package/dist/__tests__/scanners/logic/endpoint-analyzer.property.test.js +238 -0
  54. package/dist/__tests__/scanners/logic/endpoint-analyzer.property.test.js.map +1 -0
  55. package/dist/__tests__/scanners/logic/endpoint-analyzer.test.d.ts +2 -0
  56. package/dist/__tests__/scanners/logic/endpoint-analyzer.test.d.ts.map +1 -0
  57. package/dist/__tests__/scanners/logic/endpoint-analyzer.test.js +55 -0
  58. package/dist/__tests__/scanners/logic/endpoint-analyzer.test.js.map +1 -0
  59. package/dist/__tests__/scanners/logic/index.test.d.ts +2 -0
  60. package/dist/__tests__/scanners/logic/index.test.d.ts.map +1 -0
  61. package/dist/__tests__/scanners/logic/index.test.js +165 -0
  62. package/dist/__tests__/scanners/logic/index.test.js.map +1 -0
  63. package/dist/__tests__/scanners/logic/types.test.d.ts +2 -0
  64. package/dist/__tests__/scanners/logic/types.test.d.ts.map +1 -0
  65. package/dist/__tests__/scanners/logic/types.test.js +85 -0
  66. package/dist/__tests__/scanners/logic/types.test.js.map +1 -0
  67. package/dist/action/pr-comment.test.js +4 -0
  68. package/dist/action/pr-comment.test.js.map +1 -1
  69. package/dist/action/sarif-upload.test.js +4 -0
  70. package/dist/action/sarif-upload.test.js.map +1 -1
  71. package/dist/autofix/branch-manager.d.ts +115 -0
  72. package/dist/autofix/branch-manager.d.ts.map +1 -0
  73. package/dist/autofix/branch-manager.js +308 -0
  74. package/dist/autofix/branch-manager.js.map +1 -0
  75. package/dist/autofix/commit-generator.d.ts +55 -0
  76. package/dist/autofix/commit-generator.d.ts.map +1 -0
  77. package/dist/autofix/commit-generator.js +277 -0
  78. package/dist/autofix/commit-generator.js.map +1 -0
  79. package/dist/autofix/constitution.d.ts +77 -0
  80. package/dist/autofix/constitution.d.ts.map +1 -0
  81. package/dist/autofix/constitution.js +261 -0
  82. package/dist/autofix/constitution.js.map +1 -0
  83. package/dist/autofix/constitution.schema.d.ts +441 -0
  84. package/dist/autofix/constitution.schema.d.ts.map +1 -0
  85. package/dist/autofix/constitution.schema.js +144 -0
  86. package/dist/autofix/constitution.schema.js.map +1 -0
  87. package/dist/autofix/index.d.ts +13 -0
  88. package/dist/autofix/index.d.ts.map +1 -0
  89. package/dist/autofix/index.js +15 -0
  90. package/dist/autofix/index.js.map +1 -0
  91. package/dist/autofix/pr-generator.d.ts +57 -0
  92. package/dist/autofix/pr-generator.d.ts.map +1 -0
  93. package/dist/autofix/pr-generator.js +597 -0
  94. package/dist/autofix/pr-generator.js.map +1 -0
  95. package/dist/autofix/types.d.ts +151 -0
  96. package/dist/autofix/types.d.ts.map +1 -0
  97. package/dist/autofix/types.js +22 -0
  98. package/dist/autofix/types.js.map +1 -0
  99. package/dist/eval/fixtures.d.ts +20 -0
  100. package/dist/eval/fixtures.d.ts.map +1 -1
  101. package/dist/eval/fixtures.js +430 -0
  102. package/dist/eval/fixtures.js.map +1 -1
  103. package/dist/index.d.ts.map +1 -1
  104. package/dist/index.js +84 -1
  105. package/dist/index.js.map +1 -1
  106. package/dist/scanners/cache.d.ts.map +1 -1
  107. package/dist/scanners/cache.js +4 -0
  108. package/dist/scanners/cache.js.map +1 -1
  109. package/dist/scanners/dast/index.d.ts +39 -0
  110. package/dist/scanners/dast/index.d.ts.map +1 -0
  111. package/dist/scanners/dast/index.js +259 -0
  112. package/dist/scanners/dast/index.js.map +1 -0
  113. package/dist/scanners/dast/nuclei.d.ts +26 -0
  114. package/dist/scanners/dast/nuclei.d.ts.map +1 -0
  115. package/dist/scanners/dast/nuclei.js +354 -0
  116. package/dist/scanners/dast/nuclei.js.map +1 -0
  117. package/dist/scanners/dast/types.d.ts +306 -0
  118. package/dist/scanners/dast/types.d.ts.map +1 -0
  119. package/dist/scanners/dast/types.js +52 -0
  120. package/dist/scanners/dast/types.js.map +1 -0
  121. package/dist/scanners/dast/zap.d.ts +26 -0
  122. package/dist/scanners/dast/zap.d.ts.map +1 -0
  123. package/dist/scanners/dast/zap.js +453 -0
  124. package/dist/scanners/dast/zap.js.map +1 -0
  125. package/dist/scanners/fp-feedback.d.ts +140 -0
  126. package/dist/scanners/fp-feedback.d.ts.map +1 -0
  127. package/dist/scanners/fp-feedback.js +292 -0
  128. package/dist/scanners/fp-feedback.js.map +1 -0
  129. package/dist/scanners/fp-filter.d.ts +94 -0
  130. package/dist/scanners/fp-filter.d.ts.map +1 -0
  131. package/dist/scanners/fp-filter.js +397 -0
  132. package/dist/scanners/fp-filter.js.map +1 -0
  133. package/dist/scanners/fp-tracker.d.ts +125 -0
  134. package/dist/scanners/fp-tracker.d.ts.map +1 -0
  135. package/dist/scanners/fp-tracker.js +330 -0
  136. package/dist/scanners/fp-tracker.js.map +1 -0
  137. package/dist/scanners/index.d.ts.map +1 -1
  138. package/dist/scanners/index.js +56 -0
  139. package/dist/scanners/index.js.map +1 -1
  140. package/dist/scanners/index.test.js +6 -6
  141. package/dist/scanners/index.test.js.map +1 -1
  142. package/dist/scanners/logic/auth-flow-analyzer.d.ts +18 -0
  143. package/dist/scanners/logic/auth-flow-analyzer.d.ts.map +1 -0
  144. package/dist/scanners/logic/auth-flow-analyzer.js +384 -0
  145. package/dist/scanners/logic/auth-flow-analyzer.js.map +1 -0
  146. package/dist/scanners/logic/endpoint-analyzer.d.ts +29 -0
  147. package/dist/scanners/logic/endpoint-analyzer.d.ts.map +1 -0
  148. package/dist/scanners/logic/endpoint-analyzer.js +528 -0
  149. package/dist/scanners/logic/endpoint-analyzer.js.map +1 -0
  150. package/dist/scanners/logic/index.d.ts +41 -0
  151. package/dist/scanners/logic/index.d.ts.map +1 -0
  152. package/dist/scanners/logic/index.js +268 -0
  153. package/dist/scanners/logic/index.js.map +1 -0
  154. package/dist/scanners/logic/types.d.ts +254 -0
  155. package/dist/scanners/logic/types.d.ts.map +1 -0
  156. package/dist/scanners/logic/types.js +142 -0
  157. package/dist/scanners/logic/types.js.map +1 -0
  158. package/dist/scanners/types.d.ts +1 -1
  159. package/dist/scanners/types.d.ts.map +1 -1
  160. package/dist/scanners/types.js +4 -0
  161. package/dist/scanners/types.js.map +1 -1
  162. package/dist/telemetry/usage.d.ts +1 -1
  163. package/dist/telemetry/usage.d.ts.map +1 -1
  164. package/dist/telemetry/usage.js +14 -6
  165. package/dist/telemetry/usage.js.map +1 -1
  166. package/package.json +6 -8
@@ -0,0 +1,308 @@
1
+ /**
2
+ * Branch Manager
3
+ *
4
+ * Handles git branch operations for autofix PRs.
5
+ * Uses cross-spawn with array args per CLAUDE.md guidelines.
6
+ *
7
+ * @module autofix/branch-manager
8
+ */
9
+ import spawn from "cross-spawn";
10
+ import { logger } from "../logger.js";
11
+ /**
12
+ * Execute a git command and return the result
13
+ */
14
+ export async function git(args, options = { cwd: process.cwd() }) {
15
+ return new Promise((resolve) => {
16
+ const child = spawn("git", args, {
17
+ cwd: options.cwd,
18
+ timeout: options.timeout ?? 30000,
19
+ });
20
+ let stdout = "";
21
+ let stderr = "";
22
+ child.stdout?.on("data", (data) => {
23
+ stdout += data.toString();
24
+ });
25
+ child.stderr?.on("data", (data) => {
26
+ stderr += data.toString();
27
+ });
28
+ child.on("close", (exitCode) => {
29
+ const success = exitCode === 0;
30
+ if (!success) {
31
+ logger.debug("git.command_failed", {
32
+ args: args.join(" "),
33
+ exitCode,
34
+ stderr: stderr.slice(0, 500),
35
+ });
36
+ }
37
+ resolve({
38
+ success,
39
+ stdout: stdout.trim(),
40
+ stderr: stderr.trim(),
41
+ exitCode: exitCode ?? undefined,
42
+ });
43
+ });
44
+ child.on("error", (error) => {
45
+ logger.error("git.spawn_error", {
46
+ args: args.join(" "),
47
+ error: String(error),
48
+ });
49
+ resolve({
50
+ success: false,
51
+ stdout,
52
+ stderr,
53
+ error: String(error),
54
+ });
55
+ });
56
+ });
57
+ }
58
+ /**
59
+ * Check if git is available
60
+ */
61
+ export async function isGitAvailable(cwd) {
62
+ const result = await git(["--version"], { cwd, timeout: 5000 });
63
+ return result.success;
64
+ }
65
+ /**
66
+ * Check if directory is a git repository
67
+ */
68
+ export async function isGitRepo(cwd) {
69
+ const result = await git(["rev-parse", "--is-inside-work-tree"], { cwd, timeout: 5000 });
70
+ return result.success && result.stdout === "true";
71
+ }
72
+ /**
73
+ * Get the current branch name
74
+ */
75
+ export async function getCurrentBranch(cwd) {
76
+ const result = await git(["rev-parse", "--abbrev-ref", "HEAD"], { cwd });
77
+ return result.success ? result.stdout : undefined;
78
+ }
79
+ /**
80
+ * Get the default branch name (main or master)
81
+ */
82
+ export async function getDefaultBranch(cwd) {
83
+ // Try to get from remote HEAD reference
84
+ const remoteResult = await git(["symbolic-ref", "refs/remotes/origin/HEAD", "--short"], { cwd });
85
+ if (remoteResult.success && remoteResult.stdout) {
86
+ // Returns something like "origin/main", extract just "main"
87
+ const parts = remoteResult.stdout.split("/");
88
+ return parts[parts.length - 1];
89
+ }
90
+ // Fallback: check if main exists
91
+ const mainResult = await git(["show-ref", "--verify", "--quiet", "refs/heads/main"], { cwd });
92
+ if (mainResult.success) {
93
+ return "main";
94
+ }
95
+ // Final fallback
96
+ return "master";
97
+ }
98
+ /**
99
+ * Check if a branch exists locally
100
+ */
101
+ export async function branchExists(cwd, branchName) {
102
+ const result = await git(["show-ref", "--verify", "--quiet", `refs/heads/${branchName}`], { cwd });
103
+ return result.success;
104
+ }
105
+ /**
106
+ * Check if a branch exists on remote
107
+ */
108
+ export async function remoteBranchExists(cwd, branchName, remote = "origin") {
109
+ const result = await git(["ls-remote", "--heads", remote, branchName], { cwd, timeout: 30000 });
110
+ return result.success && !!result.stdout?.includes(branchName);
111
+ }
112
+ /**
113
+ * Create a new branch from a base
114
+ */
115
+ export async function createBranch(cwd, branchName, baseBranch) {
116
+ logger.info("git.create_branch", { branchName, baseBranch });
117
+ // First ensure we have latest base branch
118
+ await git(["fetch", "origin", baseBranch], { cwd });
119
+ // Create branch from remote base
120
+ return git(["checkout", "-b", branchName, `origin/${baseBranch}`], { cwd });
121
+ }
122
+ /**
123
+ * Switch to an existing branch
124
+ */
125
+ export async function checkoutBranch(cwd, branchName) {
126
+ logger.debug("git.checkout", { branchName });
127
+ return git(["checkout", branchName], { cwd });
128
+ }
129
+ /**
130
+ * Delete a local branch
131
+ */
132
+ export async function deleteBranch(cwd, branchName, force = false) {
133
+ logger.info("git.delete_branch", { branchName, force });
134
+ const flag = force ? "-D" : "-d";
135
+ return git(["branch", flag, branchName], { cwd });
136
+ }
137
+ /**
138
+ * Stage specific files
139
+ */
140
+ export async function stageFiles(cwd, files) {
141
+ if (files.length === 0) {
142
+ return { success: true, stdout: "", stderr: "" };
143
+ }
144
+ logger.debug("git.stage_files", { count: files.length });
145
+ return git(["add", ...files], { cwd });
146
+ }
147
+ /**
148
+ * Get list of modified files (staged and unstaged)
149
+ */
150
+ export async function getModifiedFiles(cwd) {
151
+ const result = await git(["status", "--porcelain"], { cwd });
152
+ if (!result.success) {
153
+ return [];
154
+ }
155
+ return (result.stdout ?? "")
156
+ .split("\n")
157
+ .filter((line) => line.length > 0)
158
+ .map((line) => line.slice(3).trim());
159
+ }
160
+ /**
161
+ * Get list of staged files
162
+ */
163
+ export async function getStagedFiles(cwd) {
164
+ const result = await git(["diff", "--cached", "--name-only"], { cwd });
165
+ if (!result.success) {
166
+ return [];
167
+ }
168
+ return (result.stdout ?? "").split("\n").filter((line) => line.length > 0);
169
+ }
170
+ /**
171
+ * Check if working tree is clean
172
+ */
173
+ export async function isWorkingTreeClean(cwd) {
174
+ const result = await git(["status", "--porcelain"], { cwd });
175
+ return result.success && result.stdout === "";
176
+ }
177
+ /**
178
+ * Push branch to remote
179
+ */
180
+ export async function pushBranch(cwd, branchName, remote = "origin", setUpstream = true) {
181
+ logger.info("git.push", { branchName, remote, setUpstream });
182
+ const args = ["push"];
183
+ if (setUpstream) {
184
+ args.push("-u");
185
+ }
186
+ args.push(remote, branchName);
187
+ return git(args, { cwd, timeout: 60000 });
188
+ }
189
+ /**
190
+ * Stash current changes
191
+ */
192
+ export async function stash(cwd, message) {
193
+ const args = ["stash", "push"];
194
+ if (message) {
195
+ args.push("-m", message);
196
+ }
197
+ return git(args, { cwd });
198
+ }
199
+ /**
200
+ * Pop stashed changes
201
+ */
202
+ export async function stashPop(cwd) {
203
+ return git(["stash", "pop"], { cwd });
204
+ }
205
+ /**
206
+ * Get branch info including tracking
207
+ */
208
+ export async function getBranchInfo(cwd, branchName) {
209
+ const name = branchName ?? (await getCurrentBranch(cwd));
210
+ if (!name) {
211
+ return undefined;
212
+ }
213
+ const current = (await getCurrentBranch(cwd)) === name;
214
+ // Get tracking info
215
+ const trackingResult = await git(["rev-parse", "--abbrev-ref", `${name}@{upstream}`], { cwd });
216
+ const tracking = trackingResult.success ? trackingResult.stdout : undefined;
217
+ // Get ahead/behind counts
218
+ let ahead = 0;
219
+ let behind = 0;
220
+ if (tracking) {
221
+ const countResult = await git(["rev-list", "--left-right", "--count", `${name}...${tracking}`], { cwd });
222
+ if (countResult.success && countResult.stdout) {
223
+ const [a, b] = countResult.stdout.split("\t").map(Number);
224
+ ahead = a || 0;
225
+ behind = b || 0;
226
+ }
227
+ }
228
+ return {
229
+ name,
230
+ current,
231
+ remote: tracking ? tracking.split("/")[0] : undefined,
232
+ tracking,
233
+ ahead,
234
+ behind,
235
+ };
236
+ }
237
+ /**
238
+ * Reset branch to a specific commit
239
+ */
240
+ export async function resetToCommit(cwd, commitish, mode = "mixed") {
241
+ logger.warn("git.reset", { commitish, mode });
242
+ return git(["reset", `--${mode}`, commitish], { cwd });
243
+ }
244
+ /**
245
+ * Get the remote URL for origin
246
+ */
247
+ export async function getRemoteUrl(cwd, remote = "origin") {
248
+ const result = await git(["remote", "get-url", remote], { cwd });
249
+ return result.success ? result.stdout : undefined;
250
+ }
251
+ /**
252
+ * Parse GitHub owner/repo from remote URL
253
+ */
254
+ export function parseGitHubRemote(url) {
255
+ // SSH format: git@github.com:owner/repo.git
256
+ const sshMatch = url.match(/git@github\.com:([^/]+)\/(.+?)(\.git)?$/);
257
+ if (sshMatch) {
258
+ return { owner: sshMatch[1], repo: sshMatch[2] };
259
+ }
260
+ // HTTPS format: https://github.com/owner/repo.git
261
+ const httpsMatch = url.match(/https:\/\/github\.com\/([^/]+)\/(.+?)(\.git)?$/);
262
+ if (httpsMatch) {
263
+ return { owner: httpsMatch[1], repo: httpsMatch[2] };
264
+ }
265
+ return undefined;
266
+ }
267
+ /**
268
+ * Generate a unique branch name
269
+ */
270
+ export function generateBranchName(prefix, identifier) {
271
+ const timestamp = Date.now().toString(36);
272
+ const sanitized = identifier
273
+ .toLowerCase()
274
+ .replace(/[^a-z0-9-]/g, "-")
275
+ .replace(/-+/g, "-")
276
+ .slice(0, 30);
277
+ return `${prefix}/${sanitized}-${timestamp}`;
278
+ }
279
+ /**
280
+ * Ensure we're on a clean working tree before operations
281
+ */
282
+ export async function ensureCleanWorkingTree(cwd, stashIfDirty = true) {
283
+ const clean = await isWorkingTreeClean(cwd);
284
+ if (clean) {
285
+ return { clean: true, stashed: false };
286
+ }
287
+ if (stashIfDirty) {
288
+ const result = await stash(cwd, "vaspera-autofix: temporary stash");
289
+ if (result.success) {
290
+ logger.info("git.stashed_changes", { message: "Working tree had changes, stashed" });
291
+ return { clean: true, stashed: true };
292
+ }
293
+ }
294
+ return { clean: false, stashed: false };
295
+ }
296
+ /**
297
+ * Restore original branch state after operations
298
+ */
299
+ export async function restoreOriginalState(cwd, originalBranch, wasStashed) {
300
+ // Switch back to original branch
301
+ await checkoutBranch(cwd, originalBranch);
302
+ // Pop stash if we stashed changes
303
+ if (wasStashed) {
304
+ await stashPop(cwd);
305
+ logger.info("git.restored_stash", { branch: originalBranch });
306
+ }
307
+ }
308
+ //# sourceMappingURL=branch-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"branch-manager.js","sourceRoot":"","sources":["../../src/autofix/branch-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Commit Generator
3
+ *
4
+ * Generates conventional commit messages for autofix PRs.
5
+ *
6
+ * @module autofix/commit-generator
7
+ */
8
+ import type { Severity } from "../certification/types.js";
9
+ import type { FixResult } from "../certification/autofix.js";
10
+ import type { AutofixCommit } from "./types.js";
11
+ /**
12
+ * Generate a commit message for a batch of fixes
13
+ */
14
+ export declare function generateCommitMessage(fixes: FixResult[], severity?: Severity, options?: {
15
+ includeEmoji?: boolean;
16
+ includeSeverity?: boolean;
17
+ maxLength?: number;
18
+ }): string;
19
+ /**
20
+ * Generate extended commit body with details
21
+ */
22
+ export declare function generateCommitBody(fixes: FixResult[], severity?: Severity): string;
23
+ /**
24
+ * Create a commit with the staged changes
25
+ */
26
+ export declare function createCommit(cwd: string, message: string, body?: string, options?: {
27
+ coAuthors?: string[];
28
+ signOff?: boolean;
29
+ }): Promise<AutofixCommit | {
30
+ error: string;
31
+ }>;
32
+ /**
33
+ * Generate PR title based on fixes
34
+ */
35
+ export declare function generatePRTitle(fixes: FixResult[], severity?: Severity, template?: string): string;
36
+ /**
37
+ * Generate PR body/description
38
+ */
39
+ export declare function generatePRBody(fixes: FixResult[], severity?: Severity, options?: {
40
+ certificationId?: string;
41
+ includeBeforeAfter?: boolean;
42
+ }): string;
43
+ /**
44
+ * Categorize fixes by severity
45
+ */
46
+ export declare function groupFixesBySeverity(fixes: FixResult[], findingSeverities: Map<string, Severity>): Map<Severity, FixResult[]>;
47
+ /**
48
+ * Categorize fixes by file
49
+ */
50
+ export declare function groupFixesByFile(fixes: FixResult[]): Map<string, FixResult[]>;
51
+ /**
52
+ * Categorize fixes by pattern
53
+ */
54
+ export declare function groupFixesByPattern(fixes: FixResult[]): Map<string, FixResult[]>;
55
+ //# sourceMappingURL=commit-generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commit-generator.d.ts","sourceRoot":"","sources":["../../src/autofix/commit-generator.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAoChD;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,SAAS,EAAE,EAClB,QAAQ,CAAC,EAAE,QAAQ,EACnB,OAAO,CAAC,EAAE;IACR,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GACA,MAAM,CAiER;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,SAAS,EAAE,EAClB,QAAQ,CAAC,EAAE,QAAQ,GAClB,MAAM,CAmCR;AAED;;GAEG;AACH,wBAAsB,YAAY,CAChC,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,EACf,IAAI,CAAC,EAAE,MAAM,EACb,OAAO,CAAC,EAAE;IACR,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,GACA,OAAO,CAAC,aAAa,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAwD5C;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,SAAS,EAAE,EAClB,QAAQ,CAAC,EAAE,QAAQ,EACnB,QAAQ,CAAC,EAAE,MAAM,GAChB,MAAM,CAiBR;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,SAAS,EAAE,EAClB,QAAQ,CAAC,EAAE,QAAQ,EACnB,OAAO,CAAC,EAAE;IACR,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B,GACA,MAAM,CAwDR;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,SAAS,EAAE,EAClB,iBAAiB,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,GACvC,GAAG,CAAC,QAAQ,EAAE,SAAS,EAAE,CAAC,CAW5B;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,CAU7E;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,CAchF"}
@@ -0,0 +1,277 @@
1
+ /**
2
+ * Commit Generator
3
+ *
4
+ * Generates conventional commit messages for autofix PRs.
5
+ *
6
+ * @module autofix/commit-generator
7
+ */
8
+ import { git, getStagedFiles } from "./branch-manager.js";
9
+ import { logger } from "../logger.js";
10
+ /**
11
+ * Map severity to commit urgency indicators
12
+ */
13
+ const SEVERITY_INDICATORS = {
14
+ critical: "🚨",
15
+ high: "⚠️",
16
+ medium: "🔧",
17
+ low: "📝",
18
+ info: "ℹ️",
19
+ };
20
+ /**
21
+ * Map pattern categories to commit types
22
+ */
23
+ function getCommitType(patternId) {
24
+ if (patternId.startsWith("sec-")) {
25
+ return "security";
26
+ }
27
+ if (patternId.startsWith("perf-")) {
28
+ return "perf";
29
+ }
30
+ if (patternId.startsWith("type-") || patternId.startsWith("qual-")) {
31
+ return "refactor";
32
+ }
33
+ return "fix";
34
+ }
35
+ /**
36
+ * Generate a commit message for a batch of fixes
37
+ */
38
+ export function generateCommitMessage(fixes, severity, options) {
39
+ const { includeEmoji = false, includeSeverity = true, maxLength = 72, } = options ?? {};
40
+ const appliedFixes = fixes.filter((f) => f.applied || f.diff);
41
+ if (appliedFixes.length === 0) {
42
+ return "chore: attempted autofix (no changes applied)";
43
+ }
44
+ // Group by pattern type
45
+ const patterns = new Map();
46
+ const files = new Set();
47
+ for (const fix of appliedFixes) {
48
+ files.add(fix.file);
49
+ // Extract pattern from findingId (e.g., "sec-001" -> "sec")
50
+ const parts = fix.findingId.split("-");
51
+ if (parts.length >= 1) {
52
+ const prefix = parts[0];
53
+ patterns.set(prefix, (patterns.get(prefix) || 0) + 1);
54
+ }
55
+ }
56
+ // Determine primary commit type
57
+ const patternEntries = Array.from(patterns.entries());
58
+ const primaryPattern = patternEntries.sort((a, b) => b[1] - a[1])[0]?.[0] ?? "fix";
59
+ const commitType = primaryPattern === "sec" ? "security" : "fix";
60
+ // Build message parts
61
+ const parts = [];
62
+ // Emoji prefix
63
+ if (includeEmoji && severity) {
64
+ parts.push(SEVERITY_INDICATORS[severity]);
65
+ }
66
+ // Commit type and scope
67
+ const scope = commitType === "security" ? "security" : undefined;
68
+ const typeScope = scope ? `fix(${scope})` : "fix";
69
+ parts.push(`${typeScope}:`);
70
+ // Summary
71
+ if (appliedFixes.length === 1) {
72
+ parts.push(`Apply autofix for ${appliedFixes[0].findingId}`);
73
+ }
74
+ else {
75
+ parts.push(`Apply ${appliedFixes.length} automated fixes`);
76
+ }
77
+ // Severity tag
78
+ if (includeSeverity && severity) {
79
+ parts.push(`[${severity}]`);
80
+ }
81
+ let message = parts.join(" ");
82
+ // Truncate if needed
83
+ if (message.length > maxLength) {
84
+ message = message.slice(0, maxLength - 3) + "...";
85
+ }
86
+ return message;
87
+ }
88
+ /**
89
+ * Generate extended commit body with details
90
+ */
91
+ export function generateCommitBody(fixes, severity) {
92
+ const lines = [];
93
+ const appliedFixes = fixes.filter((f) => f.applied || f.diff);
94
+ if (appliedFixes.length === 0) {
95
+ return "";
96
+ }
97
+ // Summary
98
+ lines.push("## Automated Security Fixes\n");
99
+ if (severity) {
100
+ lines.push(`Severity: **${severity.toUpperCase()}**\n`);
101
+ }
102
+ // Group fixes by file
103
+ const byFile = new Map();
104
+ for (const fix of appliedFixes) {
105
+ const existing = byFile.get(fix.file) || [];
106
+ existing.push(fix);
107
+ byFile.set(fix.file, existing);
108
+ }
109
+ lines.push("### Changes\n");
110
+ for (const [file, fileFixes] of byFile) {
111
+ lines.push(`- **${file}**`);
112
+ for (const fix of fileFixes) {
113
+ lines.push(` - ${fix.findingId}: Line ${fix.diff?.lineNumber || "unknown"}`);
114
+ }
115
+ }
116
+ lines.push("\n---");
117
+ lines.push("Generated by Vaspera Hardening MCP");
118
+ return lines.join("\n");
119
+ }
120
+ /**
121
+ * Create a commit with the staged changes
122
+ */
123
+ export async function createCommit(cwd, message, body, options) {
124
+ const stagedFiles = await getStagedFiles(cwd);
125
+ if (stagedFiles.length === 0) {
126
+ return { error: "No staged files to commit" };
127
+ }
128
+ // Build full commit message
129
+ const fullMessage = body ? `${message}\n\n${body}` : message;
130
+ // Add co-authors
131
+ let finalMessage = fullMessage;
132
+ const coAuthors = options?.coAuthors ?? ["Claude <noreply@anthropic.com>"];
133
+ if (coAuthors.length > 0) {
134
+ const coAuthorLines = coAuthors
135
+ .map((author) => `Co-Authored-By: ${author}`)
136
+ .join("\n");
137
+ finalMessage = `${finalMessage}\n\n${coAuthorLines}`;
138
+ }
139
+ // Build commit args
140
+ const args = ["commit", "-m", finalMessage];
141
+ if (options?.signOff) {
142
+ args.push("--signoff");
143
+ }
144
+ logger.info("git.commit", {
145
+ files: stagedFiles.length,
146
+ messagePreview: message.slice(0, 50),
147
+ });
148
+ const result = await git(args, { cwd });
149
+ if (!result.success) {
150
+ logger.error("git.commit_failed", {
151
+ error: result.stderr,
152
+ exitCode: result.exitCode,
153
+ });
154
+ return { error: result.stderr || "Commit failed" };
155
+ }
156
+ // Get the commit SHA
157
+ const shaResult = await git(["rev-parse", "HEAD"], { cwd });
158
+ const sha = shaResult.success ? shaResult.stdout : undefined;
159
+ logger.info("git.commit_success", { sha, files: stagedFiles.length });
160
+ return {
161
+ message,
162
+ sha,
163
+ files: stagedFiles,
164
+ author: "vaspera-hardening",
165
+ coAuthors,
166
+ signed: false,
167
+ };
168
+ }
169
+ /**
170
+ * Generate PR title based on fixes
171
+ */
172
+ export function generatePRTitle(fixes, severity, template) {
173
+ const appliedFixes = fixes.filter((f) => f.applied || f.diff);
174
+ const count = appliedFixes.length;
175
+ const files = new Set(appliedFixes.map((f) => f.file)).size;
176
+ if (template) {
177
+ return template
178
+ .replace("{{count}}", String(count))
179
+ .replace("{{severity}}", severity ?? "mixed")
180
+ .replace("{{files}}", String(files));
181
+ }
182
+ if (severity) {
183
+ return `fix(security): Apply ${count} ${severity}-severity autofix${count !== 1 ? "es" : ""}`;
184
+ }
185
+ return `fix(security): Apply ${count} automated security fix${count !== 1 ? "es" : ""}`;
186
+ }
187
+ /**
188
+ * Generate PR body/description
189
+ */
190
+ export function generatePRBody(fixes, severity, options) {
191
+ const lines = [];
192
+ const appliedFixes = fixes.filter((f) => f.applied || f.diff);
193
+ lines.push("## Summary\n");
194
+ lines.push("This PR contains automated security fixes generated by Vaspera Hardening MCP.\n");
195
+ if (severity) {
196
+ lines.push(`**Severity Level:** ${severity.toUpperCase()}\n`);
197
+ }
198
+ if (options?.certificationId) {
199
+ lines.push(`**Certification ID:** \`${options.certificationId}\`\n`);
200
+ }
201
+ lines.push("## Fixes Applied\n");
202
+ // Group by file
203
+ const byFile = new Map();
204
+ for (const fix of appliedFixes) {
205
+ const existing = byFile.get(fix.file) || [];
206
+ existing.push(fix);
207
+ byFile.set(fix.file, existing);
208
+ }
209
+ for (const [file, fileFixes] of byFile) {
210
+ lines.push(`### \`${file}\`\n`);
211
+ for (const fix of fileFixes) {
212
+ lines.push(`- **${fix.findingId}** (line ${fix.diff?.lineNumber || "?"})`);
213
+ if (options?.includeBeforeAfter && fix.diff) {
214
+ lines.push("");
215
+ lines.push("<details>");
216
+ lines.push("<summary>View changes</summary>\n");
217
+ lines.push("**Before:**");
218
+ lines.push("```");
219
+ lines.push(fix.diff.before);
220
+ lines.push("```\n");
221
+ lines.push("**After:**");
222
+ lines.push("```");
223
+ lines.push(fix.diff.after);
224
+ lines.push("```");
225
+ lines.push("</details>\n");
226
+ }
227
+ }
228
+ }
229
+ lines.push("\n## Review Checklist\n");
230
+ lines.push("- [ ] Changes are semantically correct");
231
+ lines.push("- [ ] No regressions introduced");
232
+ lines.push("- [ ] Tests pass");
233
+ lines.push("\n---");
234
+ lines.push("🤖 Generated with [Vaspera Hardening MCP](https://github.com/RCOLKITT/hardening-mcp)");
235
+ return lines.join("\n");
236
+ }
237
+ /**
238
+ * Categorize fixes by severity
239
+ */
240
+ export function groupFixesBySeverity(fixes, findingSeverities) {
241
+ const groups = new Map();
242
+ for (const fix of fixes) {
243
+ const severity = findingSeverities.get(fix.findingId) ?? "medium";
244
+ const existing = groups.get(severity) || [];
245
+ existing.push(fix);
246
+ groups.set(severity, existing);
247
+ }
248
+ return groups;
249
+ }
250
+ /**
251
+ * Categorize fixes by file
252
+ */
253
+ export function groupFixesByFile(fixes) {
254
+ const groups = new Map();
255
+ for (const fix of fixes) {
256
+ const existing = groups.get(fix.file) || [];
257
+ existing.push(fix);
258
+ groups.set(fix.file, existing);
259
+ }
260
+ return groups;
261
+ }
262
+ /**
263
+ * Categorize fixes by pattern
264
+ */
265
+ export function groupFixesByPattern(fixes) {
266
+ const groups = new Map();
267
+ for (const fix of fixes) {
268
+ // Extract pattern from findingId (e.g., "sec-hardcoded-secret-001" -> "sec-hardcoded-secret")
269
+ const parts = fix.findingId.split("-");
270
+ const patternId = parts.slice(0, -1).join("-") || fix.findingId;
271
+ const existing = groups.get(patternId) || [];
272
+ existing.push(fix);
273
+ groups.set(patternId, existing);
274
+ }
275
+ return groups;
276
+ }
277
+ //# sourceMappingURL=commit-generator.js.map