fix: address PR review feedback — path safety, SQL injection, gate scoping

- Resolve relative filePath against input.cwd before statSync; early-return on ENOENT
- Replace LIKE '%path%' with exact json_each equality to prevent false matches
- Sanitize and parameterize LIMIT to prevent NaN SQL errors
- Fix day-sorting to use earliest epoch in group, not first (specificity-sorted) item
- Use exact path equality in deduplicateObservations instead of substring includes
- Scope FileReadGate by session+cwd to prevent worktree collisions
- Refresh lastAccess TTL on active sessions; throttle prune to every 50 calls
- Type params as (string | number)[] instead of any[]
- Remove unused permissionDecision fields from HookResult

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Alex Newman
2026-04-06 17:29:59 -07:00
parent a60f79c44d
commit 31910fb265
6 changed files with 175 additions and 142 deletions
+10 -6
View File
@@ -121,9 +121,11 @@ export function getObservationsByFilePath(
filePath: string,
options?: { projects?: string[]; limit?: number }
): ObservationRecord[] {
const likePattern = `%${filePath}%`;
const limit = options?.limit ?? 15;
const params: any[] = [likePattern, likePattern];
const rawLimit = options?.limit;
const limit = Number.isInteger(rawLimit) && rawLimit! > 0
? Math.min(rawLimit!, 100)
: 15;
const params: (string | number)[] = [filePath, filePath];
let projectClause = '';
if (options?.projects?.length) {
@@ -132,16 +134,18 @@ export function getObservationsByFilePath(
params.push(...options.projects);
}
params.push(limit);
const stmt = db.prepare(`
SELECT *
FROM observations
WHERE (
EXISTS (SELECT 1 FROM json_each(files_read) WHERE value LIKE ?)
OR EXISTS (SELECT 1 FROM json_each(files_modified) WHERE value LIKE ?)
EXISTS (SELECT 1 FROM json_each(files_read) WHERE value = ?)
OR EXISTS (SELECT 1 FROM json_each(files_modified) WHERE value = ?)
)
${projectClause}
ORDER BY created_at_epoch DESC
LIMIT ${limit}
LIMIT ?
`);
return stmt.all(...params) as ObservationRecord[];