fix(environment): admit an export read against the file instance that is read

The headroom check used a separate stat, so a file replaced by a larger
one before the read was admitted on the old size. The regular-file reader
gains an optional admit hook that runs on the opened handle's own state
before any byte is read, and export refuses there.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Edgar ArakelyanandClaude Opus 5.5 committed 2026-10-18 21:12:44 -07:00
1 parent fca1a0e925
commit 481c9883b3
2 files changed
+12 -4

No files matched your search

+3
View File
@@ -22,6 +22,8 @@ export interface RegularFileReadOptions {
readonly signal?: AbortSignal | undefined;
readonly symlinks?: "follow" | "reject";
readonly resources?: ArtifactResourceScope;
/** Runs on the opened file's own state before any byte is read; throw to refuse the read. */
readonly admit?: (state: Stats) => void;
}
export class InvalidUtf8FileError extends TypeError {
@@ -223,6 +225,7 @@ const readRegularFileContent = <Value>(
withRegularFile(
path,
async (handle, stats) => {
options.admit?.(stats);
const bytes = await readBoundedFileBytes(
handle,
stats.size,
@@ -208,11 +208,16 @@ const readInput = async (
): Promise<Result<EnvironmentExportFile, AnalysisError>> => {
let bytes: Buffer;
try {
// Admit the whole read before materializing it; the bundle needs these exact bytes.
const refused = headroomRefusal(path, (await stat(path)).size);
if (refused !== undefined) return err(refused);
bytes = await readRegularFile(path);
// Admit the whole read against the opened file's own size, before materializing the
// exact bytes the bundle copies.
bytes = await readRegularFile(path, {
admit: (state) => {
const refused = headroomRefusal(path, state.size);
if (refused !== undefined) throw refused;
},
});
} catch (cause: unknown) {
if (cause instanceof AnalysisResourceConstraintError) return err(cause);
if (NOT_A_FILE_CODES.has(systemCode(cause) ?? ""))
return err(
inputError(