code-auditor-mcp 4.0.2 → 4.0.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.
@@ -10,7 +10,7 @@
10
10
  "name": "code-auditor",
11
11
  "source": "./plugin",
12
12
  "description": "Diff-scoped code quality auditing on every edit. Indexes your codebase, enforces invariants, and feeds violations back to the agent so fixes happen inline.",
13
- "version": "4.0.2",
13
+ "version": "4.0.3",
14
14
  "author": {
15
15
  "name": "Ben Hammond"
16
16
  },
package/CHANGELOG.md CHANGED
@@ -2,7 +2,53 @@
2
2
 
3
3
  All notable changes to the Code Auditor MCP project.
4
4
 
5
- ## [4.0.2] — 2026-09-19
5
+ ## [4.0.3] — 2026-09-20
6
+
7
+ ### SQL injection: parameterized-query false positives fixed
8
+
9
+ Two parameterized-query idioms were misread as `sql-injection-risk` at every
10
+ prior count. The safety analysis now proves them safe instead of flagging them:
11
+
12
+ - **Placeholder list** — `filePaths.map(() => '?').join(', ')` is a constant
13
+ list of `?` placeholders regardless of the source array's contents; the values
14
+ are bound out-of-band, so the interpolated text is never raw data.
15
+ - **Literal clause template** — `['run_id = ?', 'rule = ?'].join(' AND ')` is a
16
+ join over literal `col = ?` fragments with values bound out-of-band. A new
17
+ `isSafeJoin` proves the receiver and every `.push()`ed element are safe, so a
18
+ `.push(userInput)` before the join is still flagged.
19
+
20
+ The two patterns were clearing real findings in `codeIndexDB`, `blastRadius`,
21
+ and `ledger`. Both are now correctly recognized as safe; the remaining
22
+ `sql-injection-risk` findings are genuine dynamic SQL (table/column identifier
23
+ interpolation, escaped name lists, reassigned `let` clauses) rather than
24
+ parameterized queries. Guard coverage is pinned by new fixtures
25
+ (`placeholder-list.ts`, `clause-template.ts`) asserting exact zero counts.
26
+
27
+ This also fixed a latent scope-resolution bug: `findEnclosingScope` fell back to
28
+ file-level first-match when a wrapped node was detached from its parent chain,
29
+ so `const where: string[] = [...]` in one function could resolve against a
30
+ different function's `let where` of the same name. The enclosing scope is now
31
+ resolved through the raw parent chain.
32
+
33
+ ### SARIF: version-control provenance and schema validity
34
+
35
+ SARIF 2.1.0 output now carries GitHub Code Scanning metadata and emits only
36
+ schema-valid fields:
37
+
38
+ - `versionControlProvenance` (`repositoryUri` + `revisionId`) is read
39
+ best-effort from the project's git remote and HEAD, so uploaded alerts are
40
+ tied to a commit.
41
+ - `automationDetails.id` is set to `<tool>/<version>`, giving this tool's
42
+ uploads a distinct analysis category alongside CodeQL and others.
43
+ - Suggestions are emitted as `properties.resolution` (and a `help` string per
44
+ rule) instead of a bare `fixes` array — a SARIF fix requires `artifactChanges`,
45
+ which this tool does not produce, so the old output was schema-invalid.
46
+ - `startColumn` is omitted rather than clamped for 0-based/unknown columns
47
+ (SARIF requires a minimum of 1).
48
+ - Partial fingerprints are computed from the repo-relative path so GitHub alert
49
+ identity is stable across checkouts and machines.
50
+
51
+
6
52
 
7
53
  ### Severity vocabulary restored: `advisory` → `high`
8
54
 
@@ -14,15 +60,16 @@ tool results. The three non-severity meanings of "advisory" are unchanged: hook
14
60
  mode (`hookType: 'blocking' | 'advisory' | 'none'`), the non-invariant
15
61
  "advisory findings" report channel, and consultative "advisory" (= non-fatal).
16
62
 
17
- ### Fifteen rules restored from `severe` to `high`
63
+ ### Sixteen rules restored from `severe` to `high`
18
64
 
19
- The same recalibration escalated fifteen rules to `severe` that Spec 54 had
65
+ The same recalibration escalated sixteen rules to `severe` that Spec 54 had
20
66
  deliberately placed at `high`. They return to `high`:
21
67
 
22
68
  `solid/class-size`, `solid/method-complexity`, `solid/dependency-inversion`,
23
69
  `interface-size`, `parameter-count`, `function-length`, `function-size`,
24
70
  `struct-size`, `switch-size`, `dry/duplicate`, `complex-query`,
25
- `unfiltered-query`, `imports/import-style`, `tight-coupling`, `hub-nodes`.
71
+ `unfiltered-query`, `react/performance`, `imports/import-style`, `tight-coupling`,
72
+ `hub-nodes`.
26
73
 
27
74
  ### Severity-ledger conformance guard
28
75
 
package/dist/cli.js CHANGED
@@ -419,7 +419,12 @@ program
419
419
  process.exit(1);
420
420
  }
421
421
  const { generateReport } = await import('./reporting/reportGenerator.js');
422
- const report = generateReport(result, options.format);
422
+ const { readVersionControlProvenance } = await import('./reporting/sarifReportGenerator.js');
423
+ const rootDir = resolve(options.path || process.cwd());
424
+ const config = options.format === 'sarif'
425
+ ? { rootDir, ...readVersionControlProvenance(rootDir) }
426
+ : { rootDir };
427
+ const report = generateReport(result, options.format, config);
423
428
  const outputDir = options.output || process.cwd();
424
429
  const ext = options.format === 'sarif' ? 'sarif' : options.format;
425
430
  const reportPath = join(outputDir, `audit-report.${ext}`);
@@ -573,8 +578,9 @@ program
573
578
  const { blocking, resolutionGaps } = computeGatingDecision(violations, BLOCKING_SEVERITIES);
574
579
  // JSON output
575
580
  if (options.format === 'sarif') {
576
- const { generateSARIFReport } = await import('./reporting/sarifReportGenerator.js');
577
- const sarifOutput = generateSARIFReport(result);
581
+ const { generateSARIFReport, readVersionControlProvenance } = await import('./reporting/sarifReportGenerator.js');
582
+ const projectDir = resolve(options.path || process.cwd());
583
+ const sarifOutput = generateSARIFReport(result, { rootDir: projectDir, ...readVersionControlProvenance(projectDir) });
578
584
  process.stdout.write(sarifOutput + '\n');
579
585
  }
580
586
  else if (options.json) {