From 4f11982ae6c402d5b9f05c676e216601d650020d Mon Sep 17 00:00:00 2001 From: HCL Date: Mon, 23 Mar 2026 06:41:06 +0800 Subject: [PATCH] fix: emit warn diagnostic for I/O errors, keep silent only for ENOENT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Address Codex P1 + Greptile P2: the previous commit collapsed both "path" (ENOENT) and "io" (EACCES/EMFILE) into silent null returns. Now: - reason="path" (missing file): return null silently — not a security issue - reason="io" (permission/disk): push warn diagnostic — surface anomaly without aborting gateway - reason="validation" (path escape): push error diagnostic — security violation Co-Authored-By: Claude Opus 4.6 Signed-off-by: HCL --- src/plugins/discovery.ts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/plugins/discovery.ts b/src/plugins/discovery.ts index 87c6f01fdef..113ce289308 100644 --- a/src/plugins/discovery.ts +++ b/src/plugins/discovery.ts @@ -476,8 +476,17 @@ function resolvePackageEntrySource(params: { rejectHardlinks: params.rejectHardlinks ?? true, }); if (!opened.ok) { - if (opened.reason !== "validation") { - // File missing (ENOENT) or I/O error — skip silently, not a security violation. + if (opened.reason === "path") { + // File missing (ENOENT) — skip, not a security violation. + return null; + } + if (opened.reason === "io") { + // Filesystem error (EACCES, EMFILE, etc.) — warn but don't abort. + params.diagnostics.push({ + level: "warn", + message: `extension entry unreadable (I/O error): ${params.entryPath}`, + source: params.sourceLabel, + }); return null; } params.diagnostics.push({