Skip to content

Commit 33a23b1

Browse files
committed
fix: address PR #74 CodeRabbit review (6 findings, all real)
Fact-checked each finding against the codebase; all valid. Two were critical correctness bugs (T2, T3, T5) that would have shipped silently broken behavior. T2 (Major) — `scripts/detect-pm.mjs` wrong package-name keys `codemapInDevDependencies` checked `manifest?.dependencies?.codemap` but the published package is `@stainless-code/codemap` — the project-installed branch was dead code for all real consumers; `dlx-pinned` / `dlx-latest` also pulled the unscoped `codemap` package (a different npm namespace entirely). Fixed: - Lookup checks both scoped (`@stainless-code/codemap`) and bare (`codemap`) keys — the latter for monorepos that alias via `"codemap": "workspace:*"`. - `'execute'` (dlx) commandArgs now use the scoped published name so npm/pnpm/yarn/bun resolve the right registry entry. - `'execute-local'` keeps `["codemap"]` because that's the bin alias per `package.json#bin`, regardless of the scoped name. - Tests updated: scoped-dev-dep / bare-dev-dep / scoped-dlx-pinned cases. Old tests that asserted dlx-with-unscoped-`codemap@<v>` were themselves testing a bug. T3 (Critical) — no-op `expect()` in formatAuditSarif test `expect(run.results.every(...))` without a chained matcher creates and discards the expectation. If formatAuditSarif reverted to severity `note`, the test would still pass. Added `.toBe(true)`. T5 (Major) — `require()` in ESM module `readStdinSync` in `cmd-pr-comment.ts` used `require("node:fs").readSync` but the file loads via `await import()` (ESM); `require` is undefined at runtime. `codemap pr-comment -` would have crashed for every user. My unit tests passed file paths, not stdin — caught nothing. Imported `readSync` from `node:fs` at the top, used directly. T4 (Major) — pr-comment SARIF renderer dropped runs[1+] `renderSarifComment` only read `doc.runs?.[0]?.results`. Valid SARIF allows multiple runs (merged / multi-tool docs). Now flattens via `(doc.runs ?? []).flatMap(run => run.results ?? [])`. New test `aggregates results across multi-run SARIF docs (not just runs[0])`. T1 (Minor) — `mode: command` without `command:` input falls through The validate step accepted `mode=command` but didn't guard against empty `command:`. Run step's if/elif only handled `audit` + `recipe`, so `$EXEC` would invoke with empty `$ARGS`. Added an explicit guard mirroring the `mode=recipe` pattern. T6 (Minor) — `--ci` doc said "no-findings warning"; actual is "no-locatable-rows" Both `.agents/rules/codemap.md` and `templates/agents/rules/codemap.md` described the suppressed warning incorrectly. Aligned wording with the implementation in `printFormattedQuery`.
1 parent f7762d0 commit 33a23b1

9 files changed

Lines changed: 81 additions & 21 deletions

File tree

.agents/rules/codemap.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ A local database (default **`.codemap/index.db`**) indexes structure: symbols, i
3737
| Impact (blast-radius walker) || `bun src/index.ts impact <target> [--direction up\|down\|both] [--depth N] [--via <b>] [--limit N] [--summary] [--json]` — replaces hand-composed `WITH RECURSIVE` queries |
3838
| Coverage ingest || `bun src/index.ts ingest-coverage <path> [--json]` — Istanbul (`coverage-final.json`) or LCOV (`lcov.info`); format auto-detected. Joinable to `symbols` for "untested AND dead" queries. |
3939
| SARIF / GH annotations || `bun src/index.ts query --recipe deprecated-symbols --format sarif` · `… --format annotations` |
40-
| `--ci` aggregate flag || `bun src/index.ts query -r deprecated-symbols --ci` (or `audit --base origin/main --ci`) — aliases `--format sarif` + non-zero exit when findings/additions surfaced + suppresses no-findings stderr warning. Mutually exclusive with `--json` / `--format <other>`. |
40+
| `--ci` aggregate flag || `bun src/index.ts query -r deprecated-symbols --ci` (or `audit --base origin/main --ci`) — aliases `--format sarif` + non-zero exit when findings/additions surfaced + suppresses the no-locatable-rows stderr warning. Mutually exclusive with `--json` / `--format <other>`. |
4141
| PR-comment renderer || `bun src/index.ts pr-comment <input.json>` (or `-` for stdin) — renders an audit JSON envelope or SARIF doc as a markdown PR-summary comment. Pipe to `gh pr comment <PR> -F -`. Useful for private repos without GHAS, aggregate audit deltas, or bot-context seeding. |
4242
| Mermaid graph (≤50 edges) || `bun src/index.ts query --format mermaid 'SELECT from_path AS "from", to_path AS "to" FROM dependencies LIMIT 50'` — recipes / SQL must alias columns to `{from, to, label?, kind?}`; rejects unbounded inputs. |
4343
| Diff preview || `bun src/index.ts query --format diff '<SQL returning file_path, line_start, before_pattern, after_pattern>'` — read-only unified diff; `--format diff-json` returns structured hunks for agents. |

action.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,11 @@ runs:
180180
exit 1
181181
fi
182182
183+
if [ "$MODE" = "command" ] && [ -z "$COMMAND" ]; then
184+
echo "::error::codemap action: mode='command' requires the 'command' input (raw CLI args)."
185+
exit 1
186+
fi
187+
183188
- name: Run codemap
184189
if: steps.gate.outputs.skip != 'true'
185190
id: run

scripts/detect-pm.mjs

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,21 +41,23 @@ async function main() {
4141
agent = detected?.agent ?? "npm";
4242
}
4343

44-
// Per Q3's three-branch resolution (docs/plans/github-marketplace-action.md).
44+
// Per Q3 (docs/plans/github-marketplace-action.md). `execute-local` resolves
45+
// the `codemap` bin alias; `execute` (dlx) needs the scoped registry name.
46+
const PUBLISHED_NAME = "@stainless-code/codemap";
4547
let intent;
4648
let commandArgs;
4749
let installMethod;
4850
if (versionInput !== "") {
4951
intent = "execute";
50-
commandArgs = [`codemap@${versionInput}`];
52+
commandArgs = [`${PUBLISHED_NAME}@${versionInput}`];
5153
installMethod = "dlx-pinned";
5254
} else if (codemapInDevDependencies(workingDir)) {
5355
intent = "execute-local";
5456
commandArgs = ["codemap"];
5557
installMethod = "project-installed";
5658
} else {
5759
intent = "execute";
58-
commandArgs = ["codemap@latest"];
60+
commandArgs = [`${PUBLISHED_NAME}@latest`];
5961
installMethod = "dlx-latest";
6062
}
6163

@@ -82,16 +84,24 @@ async function main() {
8284
);
8385
}
8486

85-
/** False on read errors / missing manifest. */
87+
// Scoped published name + bare bin name (workspace aliases use the latter).
88+
const CODEMAP_DEP_KEYS = ["@stainless-code/codemap", "codemap"];
89+
8690
function codemapInDevDependencies(workingDir) {
8791
try {
8892
const manifestPath = join(workingDir, "package.json");
8993
if (!existsSync(manifestPath)) return false;
9094
const manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
91-
return Boolean(
92-
manifest?.dependencies?.codemap ||
93-
manifest?.devDependencies?.codemap ||
94-
manifest?.optionalDependencies?.codemap,
95+
const buckets = [
96+
manifest?.dependencies,
97+
manifest?.devDependencies,
98+
manifest?.optionalDependencies,
99+
];
100+
return buckets.some(
101+
(b) =>
102+
b !== null &&
103+
b !== undefined &&
104+
CODEMAP_DEP_KEYS.some((k) => b[k] !== undefined),
95105
);
96106
} catch {
97107
return false;

scripts/detect-pm.test.mjs

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -86,30 +86,43 @@ describe("scripts/detect-pm.mjs", () => {
8686
expect(out.install_method).toBe("dlx-latest");
8787
});
8888

89-
it("uses execute-local when codemap is in devDependencies", () => {
90-
const dir = makeFixture("dev-dep-fixture", {
89+
it("uses execute-local when @stainless-code/codemap is in devDependencies (scoped name)", () => {
90+
const dir = makeFixture("scoped-dev-dep-fixture", {
9191
"package.json": JSON.stringify({
92-
devDependencies: { codemap: "^1.0.0" },
92+
devDependencies: { "@stainless-code/codemap": "^1.0.0" },
9393
}),
9494
"package-lock.json": "{}",
9595
});
9696
const out = runDetect({ WORKING_DIRECTORY: dir });
9797
expect(out.agent).toBe("npm");
9898
expect(out.install_method).toBe("project-installed");
99+
// bin alias is `codemap` regardless of the scoped package name
99100
expect(out.exec).toContain("codemap");
100-
expect(out.exec).not.toContain("codemap@");
101+
expect(out.exec).not.toContain("@stainless-code/codemap@");
101102
});
102103

103-
it("uses dlx-pinned when version input is set (overrides project install)", () => {
104+
it("uses execute-local when bare `codemap` key is set (workspace alias case)", () => {
105+
const dir = makeFixture("bare-dev-dep-fixture", {
106+
"package.json": JSON.stringify({
107+
devDependencies: { codemap: "workspace:*" },
108+
}),
109+
"package-lock.json": "{}",
110+
});
111+
const out = runDetect({ WORKING_DIRECTORY: dir });
112+
expect(out.install_method).toBe("project-installed");
113+
});
114+
115+
it("uses dlx-pinned with scoped published name when version input is set", () => {
104116
const dir = makeFixture("pinned-fixture", {
105117
"package.json": JSON.stringify({
106-
devDependencies: { codemap: "^1.0.0" },
118+
devDependencies: { "@stainless-code/codemap": "^1.0.0" },
107119
}),
108120
"package-lock.json": "{}",
109121
});
110122
const out = runDetect({ WORKING_DIRECTORY: dir, VERSION: "1.2.3" });
111123
expect(out.install_method).toBe("dlx-pinned");
112-
expect(out.exec).toContain("codemap@1.2.3");
124+
// dlx must use the scoped name so the right registry entry resolves
125+
expect(out.exec).toContain("@stainless-code/codemap@1.2.3");
113126
});
114127

115128
it("respects PACKAGE_MANAGER override", () => {

src/application/output-formatters.test.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -610,7 +610,9 @@ describe("formatAuditSarif", () => {
610610
]);
611611
expect(run.results).toHaveLength(3);
612612
// Severity = warning (audit deltas are more actionable than per-recipe `note`)
613-
expect(run.results.every((r: { level: string }) => r.level === "warning"));
613+
expect(
614+
run.results.every((r: { level: string }) => r.level === "warning"),
615+
).toBe(true);
614616
// Locations auto-detected per row
615617
expect(
616618
run.results[0].locations[0].physicalLocation.artifactLocation.uri,

src/application/pr-comment-engine.test.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,4 +217,33 @@ describe("renderSarifComment", () => {
217217
expect(r.findings_count).toBe(75);
218218
expect(r.markdown).toContain("… and 25 more");
219219
});
220+
221+
it("aggregates results across multi-run SARIF docs (not just runs[0])", () => {
222+
// SARIF spec allows multiple runs (merged / multi-tool); aggregator
223+
// shouldn't drop entries from runs[1+].
224+
const r = renderSarifComment({
225+
version: "2.1.0",
226+
runs: [
227+
{
228+
tool: {
229+
driver: { name: "codemap", rules: [{ id: "rule.a", name: "a" }] },
230+
},
231+
results: [{ ruleId: "rule.a", message: { text: "from run 0" } }],
232+
},
233+
{
234+
tool: {
235+
driver: { name: "other", rules: [{ id: "rule.b", name: "b" }] },
236+
},
237+
results: [
238+
{ ruleId: "rule.b", message: { text: "from run 1" } },
239+
{ ruleId: "rule.b", message: { text: "another from run 1" } },
240+
],
241+
},
242+
],
243+
});
244+
expect(r.findings_count).toBe(3);
245+
expect(r.markdown).toContain("from run 0");
246+
expect(r.markdown).toContain("from run 1");
247+
expect(r.markdown).toContain("another from run 1");
248+
});
220249
});

src/application/pr-comment-engine.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,8 @@ export function renderSarifComment(doc: SarifDocument): RenderedComment {
146146
lines.push("## codemap findings");
147147
lines.push("");
148148

149-
const results = doc.runs?.[0]?.results ?? [];
149+
// SARIF supports multi-run docs (merged / multi-tool); flatten so we don't under-report.
150+
const results = (doc.runs ?? []).flatMap((run) => run.results ?? []);
150151
if (results.length === 0) {
151152
lines.push("✅ No findings.");
152153
return {

src/cli/cmd-pr-comment.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { readFileSync } from "node:fs";
1+
import { readFileSync, readSync } from "node:fs";
22

33
import {
44
detectCommentInputShape,
@@ -199,7 +199,7 @@ function readStdinSync(): string {
199199
while (true) {
200200
let n: number;
201201
try {
202-
n = require("node:fs").readSync(0, buffer, 0, buffer.length, null);
202+
n = readSync(0, buffer, 0, buffer.length, null);
203203
} catch {
204204
break;
205205
}

templates/agents/rules/codemap.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ Install **[@stainless-code/codemap](https://www.npmjs.com/package/@stainless-cod
4242
| Impact (blast-radius walker) | `codemap impact <target> [--direction up\|down\|both] [--depth N] [--via <b>] [--limit N] [--summary] [--json]` — replaces hand-composed `WITH RECURSIVE` queries |
4343
| Coverage ingest | `codemap ingest-coverage <path> [--json]` — Istanbul (`coverage-final.json`) or LCOV (`lcov.info`); format auto-detected. Joinable to `symbols` for "untested AND dead" queries. |
4444
| SARIF / GH annotations | `codemap query --recipe deprecated-symbols --format sarif` · `… --format annotations` |
45-
| `--ci` aggregate flag | `codemap query -r deprecated-symbols --ci` (or `audit --base origin/main --ci`) — aliases `--format sarif` + non-zero exit when findings/additions surfaced + suppresses no-findings stderr warning. Mutually exclusive with `--json` / `--format <other>`. |
45+
| `--ci` aggregate flag | `codemap query -r deprecated-symbols --ci` (or `audit --base origin/main --ci`) — aliases `--format sarif` + non-zero exit when findings/additions surfaced + suppresses the no-locatable-rows stderr warning. Mutually exclusive with `--json` / `--format <other>`. |
4646
| PR-comment renderer | `codemap pr-comment <input.json>` (or `-` for stdin) — renders an audit JSON envelope or SARIF doc as a markdown PR-summary comment. Pipe to `gh pr comment <PR> -F -`. Useful for private repos without GHAS, aggregate audit deltas, or bot-context seeding. |
4747
| Mermaid graph (≤50 edges) | `codemap query --format mermaid 'SELECT from_path AS "from", to_path AS "to" FROM dependencies LIMIT 50'` — recipes / SQL must alias columns to `{from, to, label?, kind?}`; rejects unbounded inputs. |
4848
| Diff preview | `codemap query --format diff '<SQL returning file_path, line_start, before_pattern, after_pattern>'` — read-only unified diff; `--format diff-json` returns structured hunks for agents. |

0 commit comments

Comments
 (0)