Skip to content

Commit 146564a

Browse files
committed
[kensai] deny excluded dirs in readFile fallback
Direct filesystem fallback in readFile bypassed the WALK_EXCLUDE_DIRS guard, allowing reads into .git/. Now checks the first path segment against the exclusion set before falling through to stat. Also fixes isBinary JSDoc to reflect extension-based detection.
1 parent 30bd746 commit 146564a

2 files changed

Lines changed: 7 additions & 3 deletions

File tree

claude/kensai/mcp/review/src/repofs/pathindex/pathindex.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import picomatch from "picomatch";
99
import { ErrBinaryContent, LineIter } from "../lineiter/lineiter.ts";
1010

1111
/** Directory names skipped during filesystem walk. Never descended into. */
12-
const WALK_EXCLUDE_DIRS: ReadonlySet<string> = new Set([".git"]);
12+
export const WALK_EXCLUDE_DIRS: ReadonlySet<string> = new Set([".git"]);
1313

1414
/** Extensions treated as binary without opening the file. Stat-only — no line counting, no fd consumed. */
1515
const BINARY_EXTENSIONS: ReadonlySet<string> = new Set([
@@ -152,7 +152,7 @@ export type IndexEntryFile = {
152152
lineCount: number;
153153
/** Byte length of the longest line (excluding `\n`). 0 for binary/empty files. */
154154
maxLineLen: number;
155-
/** True when the file's leading bytes contain a null byte. */
155+
/** Extension-based hint. Content-based detection (null byte probe) runs at read/scan time. */
156156
isBinary: boolean;
157157
};
158158

claude/kensai/mcp/review/src/repofs/repofs.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import path from "node:path";
33

44
import { Repo } from "./git/git.ts";
55
import type { FilterOptions } from "./pathindex/pathindex.ts";
6-
import { PathIndex } from "./pathindex/pathindex.ts";
6+
import { PathIndex, WALK_EXCLUDE_DIRS } from "./pathindex/pathindex.ts";
77
import type { GrepOptions, GrepResult } from "./rg/rg.ts";
88
import { grep } from "./rg/rg.ts";
99

@@ -92,6 +92,10 @@ export class RepoFs {
9292
const absPath = path.resolve(this.#root, rel);
9393

9494
if (!entry) {
95+
const firstSegment = rel.split("/")[0];
96+
if (firstSegment && WALK_EXCLUDE_DIRS.has(firstSegment)) {
97+
throw new RepoFsError(`file not found: ${rel}`);
98+
}
9599
const stat = await fsp.stat(absPath).catch(() => null);
96100
if (!stat?.isFile()) {
97101
throw new RepoFsError(`file not found: ${rel}`);

0 commit comments

Comments
 (0)