Files
reverse-engineering-anything/src/process/DetachedPgpSignature.test.ts
T
Alex GorevskiandCopilot 4e28166626 fix(cancellation): preserve caller abort reason in cancellation errors (#6144)
* fix(cancellation): preserve caller abort reason in cancellation errors

Several application, provider, and MCP boundaries constructed
AnalysisCancelledError, ArtifactReaderFailure, or
DetachedPgpSignatureError for an already-observed or newly-observed abort
without passing the caller's signal.reason as the error cause. The typed
result then reported cancellation with an undefined reason even though the
exact object supplied to AbortController.abort(reason) was still available.

Pass signal.reason as the cause at each producing cancellation site:
JavaScript artifact reconstruction and file abort checks, derived MCP
operation checkpoints, detached PGP verification, ASAR listing admission,
Dart AOT inspection and its provider guard, evidence-file analysis views,
binary layout and recorded crash admission, WASM inspection admission,
and the Kuna shared assembly-index wait.

Cancellation classification and cleanup behavior are unchanged.

Fixes morluto/rea#5935
Fixes morluto/rea#5944
Fixes morluto/rea#6100
Fixes morluto/rea#6101
Fixes morluto/rea#6110
Fixes morluto/rea#6113
Fixes morluto/rea#6121
Fixes morluto/rea#6131
Fixes morluto/rea#6132

* test(cancellation): assert the exact caller reason identity

Copied reasons satisfied toMatchObject, so the tests would pass even if the
caller's abort reason were replaced by a structurally equal copy. Capture the
rejection and assert the cause is the same object.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 35b247e9-c793-4b8f-979a-807c27112cf5

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 35b247e9-c793-4b8f-979a-807c27112cf5
2026-10-22 04:11:15 +08:00

149 lines
4.2 KiB
TypeScript

import { beforeAll, describe, expect, it } from "vitest";
import { createMessage, generateKey, readPrivateKey, sign } from "openpgp";
import { verifyDetachedPgpSignature } from "./DetachedPgpSignature.js";
const bytes = Buffer.from("binary package fixture\0\xff", "latin1");
let publicKey: string;
let fingerprint: string;
let signatures: Uint8Array[];
let signingFingerprints: string[];
beforeAll(async () => {
const generated = await generateKey({
type: "ecc",
curve: "curve25519Legacy",
userIDs: [{ name: "Fixture publisher" }],
subkeys: [{ sign: true }, { sign: true }],
format: "armored",
});
const privateKey = await readPrivateKey({ armoredKey: generated.privateKey });
publicKey = generated.publicKey;
fingerprint = privateKey.getFingerprint().toUpperCase();
signingFingerprints = privateKey.subkeys.map((subkey) =>
subkey.getFingerprint().toUpperCase(),
);
signatures = [];
for (const subkey of privateKey.subkeys)
signatures.push(
await sign({
message: await createMessage({ binary: bytes }),
signingKeys: privateKey,
signingKeyIDs: [subkey.getKeyID()],
detached: true,
format: "binary",
}),
);
});
describe("detached binary PGP publisher verification", () => {
it("accepts independently selected signing subkeys through one pinned primary", async () => {
for (const [index, signature] of signatures.entries())
expect(
await verifyDetachedPgpSignature(
bytes,
signature,
publicKey,
fingerprint,
),
).toEqual({
ok: true,
value: {
primaryFingerprint: fingerprint,
signingFingerprint: signingFingerprints[index],
},
});
});
it("rejects a valid signature belonging to another primary", async () => {
expect(
await verifyDetachedPgpSignature(
bytes,
signatures[0]!,
publicKey,
"0".repeat(40),
),
).toMatchObject({ ok: false, error: { reason: "wrong_publisher" } });
});
it("rejects tampered payload bytes", async () => {
const tampered = Buffer.from(bytes);
tampered[0] = (tampered[0] ?? 0) ^ 1;
expect(
await verifyDetachedPgpSignature(
tampered,
signatures[0]!,
publicKey,
fingerprint,
),
).toMatchObject({ ok: false, error: { reason: "invalid_signature" } });
});
it("rejects malformed signatures and public keys", async () => {
expect(
await verifyDetachedPgpSignature(
bytes,
new Uint8Array([1, 2, 3]),
publicKey,
fingerprint,
),
).toMatchObject({ ok: false, error: { reason: "invalid_signature" } });
expect(
await verifyDetachedPgpSignature(
bytes,
signatures[0]!,
"malformed",
fingerprint,
),
).toMatchObject({ ok: false, error: { reason: "invalid_signature" } });
});
it("preserves cancellation", async () => {
expect(
await verifyDetachedPgpSignature(
bytes,
signatures[0]!,
publicKey,
fingerprint,
AbortSignal.abort(),
),
).toMatchObject({ ok: false, error: { reason: "cancelled" } });
});
it.each([null, "caller stop", { phase: "publisher-key" }])(
"preserves the caller's exact abort reason %j as the cancellation cause",
async (reason) => {
const controller = new AbortController();
controller.abort(reason);
const result = await verifyDetachedPgpSignature(
bytes,
signatures[0]!,
publicKey,
fingerprint,
controller.signal,
);
expect(result).toMatchObject({
ok: false,
error: { reason: "cancelled" },
});
expect(result.ok ? undefined : result.error.cause).toBe(reason);
},
);
it("preserves cancellation while loading the publisher key, before classifying its identity", async () => {
const controller = new AbortController();
const verification = verifyDetachedPgpSignature(
bytes,
signatures[0]!,
publicKey,
"0".repeat(40),
controller.signal,
);
queueMicrotask(() => controller.abort());
expect(await verification).toMatchObject({
ok: false,
error: { reason: "cancelled" },
});
});
});