fix: report provider admission failures as typed codes (#8066)

* fix: report provider admission failures as typed codes

* fix(evm): keep limiter path on admission diagnostics

* fix: assert WABT and CBOR admission codes

* fix: keep admission details on returned failures

* fix(evm): detect repeated CBOR keys in the decoder

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
This commit is contained in:
morlutoandCursor Agent authored and GitHub committed 2026-10-30 06:48:01 +08:00
1 parent 3b647132c6
commit 317bf3fe23
63 files changed
+1021 -432

No files matched your search

+11 -3
View File
@@ -1,5 +1,15 @@
import type { FileHandle } from "node:fs/promises";
/** Close admission for one owned file handle. `code` is the stable identity. */
export class OwnedFileHandleError extends Error {
readonly _tag = "OwnedFileHandleError";
constructor(readonly code: "handle_invalidated") {
super(code);
this.name = "OwnedFileHandleError";
}
}
type CloseState =
| { readonly kind: "open" }
| { readonly kind: "closing"; readonly attempt: Promise<void> }
@@ -20,9 +30,7 @@ export class OwnedFileHandle<
if (this.#state.kind === "closing") return this.#state.attempt;
if (this.#state.kind === "failed") return Promise.reject(this.#state.cause);
if (this.handle.fd < 0) {
const cause = new Error(
"File handle was invalidated before this owner confirmed its close",
);
const cause = new OwnedFileHandleError("handle_invalidated");
this.#state = { kind: "failed", cause };
return Promise.reject(cause);
}
+21 -16
View File
@@ -1,3 +1,4 @@
import { StagedOutputError } from "./StagedOutputError.js";
import { lstat, readdir, rmdir, unlink } from "node:fs/promises";
import type { Stats } from "node:fs";
@@ -48,7 +49,7 @@ export class OwnedStagedOutput {
setFile(file: OwnedFileHandle): void {
if (this.#file !== undefined)
throw new Error("Staged output already owns a file handle");
throw new StagedOutputError("handle_already_owned");
this.#file = file;
}
@@ -58,7 +59,7 @@ export class OwnedStagedOutput {
if (this.#file !== undefined && !this.#fileClosed)
await this.#observeFileIdentity();
if (this.#fileIdentity === undefined)
throw new Error("Cannot verify staged file identity", {
throw new StagedOutputError("identity_unverified", undefined, {
cause: this.#identityFailure,
});
const stagedFile = await lstat(content);
@@ -67,7 +68,7 @@ export class OwnedStagedOutput {
stagedFile.isSymbolicLink() ||
!sameIdentity(stagedFile, this.#fileIdentity)
)
throw new Error(`Staged file identity changed: ${content}`);
throw new StagedOutputError("identity_changed", { path: content });
}
/** Observe the descriptor's identity after its last write, then close it. */
@@ -134,9 +135,11 @@ export class OwnedStagedOutput {
) {
stagedFile = undefined;
} else if (errorCode(cause) === "ENOENT") {
throw new Error(`Owned staged file disappeared: ${content}`, {
cause,
});
throw new StagedOutputError(
"file_disappeared",
{ path: content },
{ cause },
);
} else {
throw cause;
}
@@ -148,7 +151,7 @@ export class OwnedStagedOutput {
this.#fileIdentity === undefined ||
!sameIdentity(stagedFile, this.#fileIdentity)
)
throw new Error(`Staged file identity changed: ${content}`);
throw new StagedOutputError("identity_changed", { path: content });
await unlink(content);
this.#fileRemovedByOwner = true;
}
@@ -156,20 +159,20 @@ export class OwnedStagedOutput {
const remaining = await readdir(this.directory);
if (remaining.length > 0)
throw new Error(
`Unexpected staging entries remain in ${this.directory}: ${remaining.join(", ")}`,
);
throw new StagedOutputError("unexpected_entries", {
count: remaining.length,
entries: remaining.join(","),
});
await this.#verifiedDirectory();
await rmdir(this.directory);
}
async #verifiedDirectory(): Promise<void> {
if (this.directoryIdentity === undefined)
throw new Error(
`Cannot verify staging directory ownership: ${this.directory}`,
{
cause: this.#identityFailure,
},
throw new StagedOutputError(
"directory_unverified",
{ directory: this.directory },
{ cause: this.#identityFailure },
);
const directory = await lstat(this.directory);
if (
@@ -177,7 +180,9 @@ export class OwnedStagedOutput {
directory.isSymbolicLink() ||
!sameIdentity(directory, this.directoryIdentity)
)
throw new Error(`Staging directory identity changed: ${this.directory}`);
throw new StagedOutputError("directory_identity_changed", {
directory: this.directory,
});
}
}
+25
View File
@@ -0,0 +1,25 @@
const STAGED_OUTPUT_CODES = [
"handle_already_owned",
"identity_unverified",
"identity_changed",
"file_disappeared",
"unexpected_entries",
"directory_unverified",
"directory_identity_changed",
] as const;
export type StagedOutputCode = (typeof STAGED_OUTPUT_CODES)[number];
/** Owned staged-output admission failure. `code` is the stable identity. */
export class StagedOutputError extends Error {
readonly _tag = "StagedOutputError";
constructor(
readonly code: StagedOutputCode,
readonly detail?: Readonly<Record<string, string | number>>,
options?: ErrorOptions,
) {
super(code, options);
this.name = "StagedOutputError";
}
}