From a0073bfb9b6d2b276eede26ef1dcc7ef8a5bf743 Mon Sep 17 00:00:00 2001 From: zeroaltitude Date: Sun, 8 Mar 2026 18:16:03 -0700 Subject: [PATCH] =?UTF-8?q?fix:=20address=20remaining=20greptile=204/5=20i?= =?UTF-8?q?tems=20=E2=80=94=20random=20guard,=20ENOENT=20comment,=20array?= =?UTF-8?q?=20snapshot?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Math.random() === 0 guard: (0).toString(36).slice(2,6) returns '' producing a trailing-hyphen slug. Added || '0000' fallback. 2. Misleading ENOENT comment: said 'when blockSessionSave was set before writeFileWithinRoot' but that branch requires writtenEntry !== null (blockSessionSave was false). Real scenario: external file deletion between inline write and post-hook drain. Comment corrected. 3. Live-array drain: for...of on postHookActions is a live iterator — a self-scheduling action could loop infinitely. Snapshot the array with [...(event.postHookActions ?? [])] before draining. --- src/hooks/bundled/session-memory/handler.ts | 13 +++++++------ src/hooks/internal-hooks.ts | 8 +++++++- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/hooks/bundled/session-memory/handler.ts b/src/hooks/bundled/session-memory/handler.ts index e9aea24aa20..323ed371e71 100644 --- a/src/hooks/bundled/session-memory/handler.ts +++ b/src/hooks/bundled/session-memory/handler.ts @@ -332,7 +332,7 @@ const saveSessionToMemory: HookHandler = async (event) => { // one silently overwrites the earlier memory entry. if (!slug) { const timeSlug = now.toISOString().split("T")[1].split(".")[0].replace(/:/g, ""); - const rand = Math.random().toString(36).slice(2, 6); // 4-char alphanumeric + const rand = Math.random().toString(36).slice(2, 6) || "0000"; // 4-char alphanumeric slug = `${timeSlug.slice(0, 6)}-${rand}`; log.debug("Using fallback timestamp slug", { slug }); } @@ -439,11 +439,12 @@ const saveSessionToMemory: HookHandler = async (event) => { await fs.unlink(memoryFilePath); log.debug("Session save retracted by post-hook (blockSessionSave)"); } catch (err) { - // ENOENT is expected when the inline write didn't happen - // (e.g. blockSessionSave was set before writeFileWithinRoot). - // Re-throw so triggerInternalHook logs it. Note: the error - // is caught per-action and does NOT propagate to the caller; - // the file may remain on disk if unlink fails (e.g. EACCES). + // ENOENT can occur if the file was externally deleted between + // the inline write and the post-hook drain — not a concern. + // Re-throw non-ENOENT errors (e.g. EACCES, EROFS) so + // triggerInternalHook logs them. Note: errors are caught + // per-action and do NOT propagate to the session caller; + // the file may remain on disk under adversarial FS conditions. if ((err as NodeJS.ErrnoException).code !== "ENOENT") { throw err; } diff --git a/src/hooks/internal-hooks.ts b/src/hooks/internal-hooks.ts index 1d02a4aa2b3..4dcf3040d89 100644 --- a/src/hooks/internal-hooks.ts +++ b/src/hooks/internal-hooks.ts @@ -292,7 +292,13 @@ export async function triggerInternalHook(event: InternalHookEvent): Promise