Files
clean-architecture-frontend…/tests/unit/provider-guardian-transaction.test.ts
T

1106 lines
42 KiB
TypeScript

import { spawn } from "node:child_process";
import { createHash } from "node:crypto";
import { closeSync, constants, fchmodSync, openSync, watch } from "node:fs";
import {
lstat,
mkdir,
mkdtemp,
open,
readFile,
readdir,
readlink,
rm,
writeFile,
} from "node:fs/promises";
import { tmpdir } from "node:os";
import path from "node:path";
import { pathToFileURL } from "node:url";
import { afterEach, describe, expect, it } from "vitest";
const roots: string[] = [];
afterEach(async () => {
await Promise.all(roots.splice(0).map((root) => rm(root, { recursive: true, force: true })));
});
describe("provider guardian transaction protocol", () => {
it("encodes a v2 guard without accepting filesystem paths or identities", async () => {
const protocol = await import("../../scripts/lib/provider-guardian-protocol.ts") as
Record<string, unknown>;
expect(protocol.encodeProviderGuardianGuard).toBeTypeOf("function");
const encode = protocol.encodeProviderGuardianGuard as (input: Readonly<{
kind: "vulnerability";
nonce: Buffer;
deadlineEpochMs: number;
}>) => Buffer;
const nonce = Buffer.alloc(32, 0x5a);
const encoded = encode({
kind: "vulnerability",
nonce,
deadlineEpochMs: 1_800_000_000_000,
});
expect(encoded.readUInt32BE(0)).toBe(encoded.byteLength - 4);
expect(JSON.parse(encoded.subarray(4).toString("utf8"))).toEqual({
type: "guard",
version: 2,
kind: "vulnerability",
nonce: "5a".repeat(32),
deadlineEpochMs: 1_800_000_000_000,
});
expect(
(protocol.providerGuardianSealedTempLeaf as (kind: "vulnerability", value: Buffer) => string)(
"vulnerability",
nonce,
),
).toBe(`.vulnerability-report.json.guardian-${"5a".repeat(16)}.tmp`);
expect(
(protocol.providerGuardianRawStagingLeaf as (
kind: "vulnerability",
value: Buffer,
) => string)("vulnerability", nonce),
).toBe(`.vulnerability-report.json.guardian-${"5a".repeat(16)}.raw.tmp`);
});
it("decodes only the exact canonical v2 guard within the lease window", async () => {
const protocol = await import("../../scripts/lib/provider-guardian-protocol.ts") as
Record<string, unknown>;
expect(protocol.decodeProviderGuardianGuard).toBeTypeOf("function");
const decode = protocol.decodeProviderGuardianGuard as (
payload: Buffer,
options: Readonly<{ nowEpochMs: number; maxLeaseMs: number }>,
) => Readonly<{ kind: string; nonce: Buffer; deadlineEpochMs: number }>;
const canonical = JSON.stringify({
type: "guard",
version: 2,
kind: "provenance",
nonce: "3c".repeat(32),
deadlineEpochMs: 5_000,
});
expect(decode(Buffer.from(canonical), { nowEpochMs: 1_000, maxLeaseMs: 5_000 }))
.toEqual({
kind: "provenance",
nonce: Buffer.alloc(32, 0x3c),
deadlineEpochMs: 5_000,
});
for (const invalid of [
canonical.replace('"nonce":', '"nonce":"3c'.concat('"'.repeat(0), ',"nonce":')),
canonical.replace(/\}$/u, ',"rawIno":9}'),
`${canonical} `,
canonical.replace("5000", "1000"),
canonical.replace("5000", "7000"),
canonical.replace("3c".repeat(32), "3c".repeat(31)),
]) {
expect(() => decode(Buffer.from(invalid), { nowEpochMs: 1_000, maxLeaseMs: 5_000 }))
.toThrow(/provider guardian/u);
}
expect(() => decode(Buffer.from([0xff]), { nowEpochMs: 1_000, maxLeaseMs: 5_000 }))
.toThrow(/provider guardian/u);
});
it("authenticates READY, publish, PUBLISHED, and v2 commit with exact fields", async () => {
const protocol = await import("../../scripts/lib/provider-guardian-protocol.ts") as
Record<string, unknown>;
for (const name of [
"decodeProviderGuardianReady",
"encodeProviderGuardianPublish",
"decodeProviderGuardianPublish",
"encodeProviderGuardianPublished",
"decodeProviderGuardianPublished",
]) {
expect(protocol[name], name).toBeTypeOf("function");
}
const nonce = Buffer.alloc(32, 0x7a);
const readyPayload = Buffer.from(JSON.stringify({
type: "ready",
version: 2,
nonce: "7a".repeat(32),
rawDev: 12,
rawIno: 34,
sealedTempLeaf: ".vulnerability-report.json.guardian-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.tmp",
sealedDev: 56,
sealedIno: 78,
}));
const decodeReady = protocol.decodeProviderGuardianReady as (
payload: Buffer,
expectedNonce: Buffer,
) => Record<string, unknown>;
expect(decodeReady(readyPayload, nonce)).toEqual({
nonce,
rawDev: 12,
rawIno: 34,
sealedTempLeaf: ".vulnerability-report.json.guardian-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.tmp",
sealedDev: 56,
sealedIno: 78,
});
expect(() => decodeReady(readyPayload, Buffer.alloc(32, 0x7b)))
.toThrow(/authentication/u);
const encodePublish = protocol.encodeProviderGuardianPublish as (input: Record<string, unknown>) => Buffer;
const publishFrame = encodePublish({
nonce,
sealedDev: 56,
sealedIno: 78,
size: 123,
sha256: "ab".repeat(32),
});
expect(JSON.parse(publishFrame.subarray(4).toString("utf8"))).toEqual({
type: "publish",
version: 2,
nonce: "7a".repeat(32),
sealedDev: 56,
sealedIno: 78,
size: 123,
sha256: "ab".repeat(32),
});
const decodePublish = protocol.decodeProviderGuardianPublish as (
payload: Buffer,
expectedNonce: Buffer,
) => Record<string, unknown>;
expect(decodePublish(publishFrame.subarray(4), nonce)).toEqual({
nonce,
sealedDev: 56,
sealedIno: 78,
size: 123,
sha256: "ab".repeat(32),
});
const encodePublished = protocol.encodeProviderGuardianPublished as (
input: Readonly<{ nonce: Buffer; sealedDev: number; sealedIno: number }>,
) => Buffer;
const published = encodePublished({ nonce, sealedDev: 56, sealedIno: 78 });
const decodePublished = protocol.decodeProviderGuardianPublished as (
payload: Buffer,
expectedNonce: Buffer,
expectedIdentity: Readonly<{ dev: number; ino: number }>,
) => void;
expect(() => decodePublished(published.subarray(4), nonce, { dev: 56, ino: 78 }))
.not.toThrow();
const encodeCommit = protocol.encodeProviderGuardianCommit as (value: Buffer) => Buffer;
expect(JSON.parse(encodeCommit(nonce).subarray(4).toString("utf8"))).toEqual({
type: "commit",
version: 2,
nonce: "7a".repeat(32),
});
});
it("creates and returns owned raw and sealed-temp identities before READY", async () => {
const {
decodeProviderGuardianReady,
encodeProviderGuardianGuard,
} = await import("../../scripts/lib/provider-guardian-protocol.ts");
const workspace = await createWorkspace("provider-guardian-ready-");
const rawPath = path.join(
workspace,
"provider-evidence/untrusted/vulnerability-report.json",
);
const nonce = Buffer.alloc(32, 0x4d);
const child = spawnGuardian(workspace, nonce);
const completion = waitForChild(child);
const readyPayload = readFrame(child.stdout!);
child.stdin!.write(encodeProviderGuardianGuard({
kind: "vulnerability",
nonce,
deadlineEpochMs: Date.now() + 2_000,
}));
const ready = decodeProviderGuardianReady(
await within(readyPayload, 1_000, "guardian READY"),
nonce,
);
const raw = await lstat(rawPath);
const sealedTempPath = path.join(workspace, "provider-evidence", ready.sealedTempLeaf);
const sealedTemp = await lstat(sealedTempPath);
expect({ dev: raw.dev, ino: raw.ino, mode: raw.mode & 0o777 }).toEqual({
dev: ready.rawDev,
ino: ready.rawIno,
mode: 0o600,
});
expect({ dev: sealedTemp.dev, ino: sealedTemp.ino, mode: sealedTemp.mode & 0o777 })
.toEqual({ dev: ready.sealedDev, ino: ready.sealedIno, mode: 0o600 });
child.stdin!.end();
await expect(within(completion, 1_000, "guardian abort")).resolves.toEqual({
code: 125,
signal: null,
});
await expect(lstat(rawPath)).rejects.toMatchObject({ code: "ENOENT" });
await expect(lstat(sealedTempPath)).rejects.toMatchObject({ code: "ENOENT" });
await expect(readdir(path.join(workspace, "provider-evidence/untrusted"))).resolves.toEqual([]);
});
it("creates no evidence for empty or truncated guard input", async () => {
const { startProviderGuardian } = await import(
"../../scripts/lib/provider-guardian-client.ts"
);
for (const [label, input, expectedCode] of [
["empty", undefined, 125],
["truncated-prefix", Buffer.from([0, 0]), 126],
] as const) {
const workspace = await createWorkspace(`provider-guardian-${label}-`);
const child = spawnGuardian(workspace);
const completion = waitForChild(child);
if (input) child.stdin!.end(input);
else child.stdin!.end();
await expect(within(completion, 1_000, `${label} guardian EOF`)).resolves.toEqual({
code: expectedCode,
signal: null,
});
await expect(readdir(path.join(workspace, "provider-evidence/untrusted"))).resolves.toEqual([]);
await expect(readdir(path.join(workspace, "provider-evidence"))).resolves.toEqual([
"untrusted",
]);
const retry = await startProviderGuardian({
kind: "vulnerability",
workspaceRoot: workspace,
leaseMs: 3_000,
guardianScript: path.resolve("scripts/lib/provider-raw-guardian.ts"),
});
await retry.abort();
await expect(readdir(path.join(workspace, "provider-evidence/untrusted")))
.resolves.toEqual([]);
await expect(readdir(path.join(workspace, "provider-evidence")))
.resolves.toEqual(["untrusted"]);
}
});
it.each(["raw", "sealed"] as const)(
"cleans the independently bound %s private alias when peer bootstrap validation fails",
async (boundKind) => {
const workspace = await createWorkspace(`provider-guardian-partial-bootstrap-${boundKind}-`);
const nonce = Buffer.alloc(32, boundKind === "raw" ? 0x71 : 0x72);
const fixture = spawnGuardianWithPrivateModes(workspace, nonce, {
rawMode: boundKind === "raw" ? 0o600 : 0o400,
sealedMode: boundKind === "sealed" ? 0o600 : 0o400,
});
await expect(within(
waitForChild(fixture.child),
1_000,
`${boundKind} partial bootstrap exit`,
)).resolves.toEqual({ code: 126, signal: null });
const boundPath = boundKind === "raw" ? fixture.rawStagingPath : fixture.sealedTempPath;
const invalidPath = boundKind === "raw" ? fixture.sealedTempPath : fixture.rawStagingPath;
await expect(lstat(boundPath)).rejects.toMatchObject({ code: "ENOENT" });
await expect(lstat(invalidPath)).resolves.toEqual(expect.objectContaining({
mode: expect.any(Number),
}));
await rm(invalidPath);
await expect(readdir(path.join(workspace, "provider-evidence/untrusted")))
.resolves.toEqual([]);
await expect(readdir(path.join(workspace, "provider-evidence")))
.resolves.toEqual(["untrusted"]);
},
);
it("cleans guardian-created objects when the parent closes immediately after guard", async () => {
const { encodeProviderGuardianGuard } = await import(
"../../scripts/lib/provider-guardian-protocol.ts"
);
const workspace = await createWorkspace("provider-guardian-parent-startup-death-");
const nonce = Buffer.alloc(32, 0x2b);
const child = spawnGuardian(workspace, nonce);
const completion = waitForChild(child);
child.stdin!.end(encodeProviderGuardianGuard({
kind: "vulnerability",
nonce,
deadlineEpochMs: Date.now() + 2_000,
}));
await expect(within(completion, 1_000, "guardian parent startup death"))
.resolves.toEqual({ code: 125, signal: null });
await expect(readdir(path.join(workspace, "provider-evidence/untrusted"))).resolves.toEqual([]);
await expect(readdir(path.join(workspace, "provider-evidence"))).resolves.toEqual(["untrusted"]);
});
it("publishes the pinned sealed inode and preserves it only after commit EOF", async () => {
const {
decodeProviderGuardianPublished,
decodeProviderGuardianReady,
encodeProviderGuardianCommit,
encodeProviderGuardianGuard,
encodeProviderGuardianPublish,
} = await import("../../scripts/lib/provider-guardian-protocol.ts");
const workspace = await createWorkspace("provider-guardian-publish-");
const evidenceRoot = path.join(workspace, "provider-evidence");
const rawPath = path.join(evidenceRoot, "untrusted/vulnerability-report.json");
const sealedPath = path.join(evidenceRoot, "vulnerability-report.json");
const nonce = Buffer.alloc(32, 0x62);
const child = spawnGuardian(workspace, nonce);
const completion = waitForChild(child);
const readyPayload = readFrame(child.stdout!);
child.stdin!.write(encodeProviderGuardianGuard({
kind: "vulnerability",
nonce,
deadlineEpochMs: Date.now() + 3_000,
}));
const ready = decodeProviderGuardianReady(
await within(readyPayload, 1_000, "guardian READY"),
nonce,
);
const sealedTempPath = path.join(evidenceRoot, ready.sealedTempLeaf);
const bytes = Buffer.from('{"validated":true}\n');
const handle = await open(
sealedTempPath,
constants.O_WRONLY | constants.O_NOFOLLOW,
);
try {
const before = await handle.stat();
expect({ dev: before.dev, ino: before.ino }).toEqual({
dev: ready.sealedDev,
ino: ready.sealedIno,
});
await handle.writeFile(bytes);
await handle.chmod(0o400);
await handle.sync();
} finally {
await handle.close();
}
const publishedPayload = readFrame(child.stdout!);
child.stdin!.write(encodeProviderGuardianPublish({
nonce,
sealedDev: ready.sealedDev,
sealedIno: ready.sealedIno,
size: bytes.byteLength,
sha256: createHash("sha256").update(bytes).digest("hex"),
}));
decodeProviderGuardianPublished(
await within(publishedPayload, 1_000, "guardian PUBLISHED"),
nonce,
{ dev: ready.sealedDev, ino: ready.sealedIno },
);
await expect(lstat(sealedTempPath)).rejects.toMatchObject({ code: "ENOENT" });
const published = await lstat(sealedPath);
expect({ dev: published.dev, ino: published.ino, mode: published.mode & 0o777 })
.toEqual({ dev: ready.sealedDev, ino: ready.sealedIno, mode: 0o400 });
await expect(readFile(sealedPath)).resolves.toEqual(bytes);
child.stdin!.write(encodeProviderGuardianCommit(nonce));
await new Promise<void>((resolve) => setTimeout(resolve, 50));
expect(child.exitCode).toBeNull();
child.stdin!.end();
await expect(within(completion, 1_000, "guardian commit EOF")).resolves.toEqual({
code: 0,
signal: null,
});
await expect(lstat(rawPath)).rejects.toMatchObject({ code: "ENOENT" });
await expect(readFile(sealedPath)).resolves.toEqual(bytes);
});
it("owns raw and sealed publication through the authenticated client lease", async () => {
const client = await import("../../scripts/lib/provider-guardian-client.ts") as
Record<string, unknown>;
expect(client.startProviderGuardian).toBeTypeOf("function");
const start = client.startProviderGuardian as (input: Readonly<{
kind: "vulnerability";
workspaceRoot: string;
leaseMs: number;
guardianScript: string;
}>) => Promise<Readonly<{
pid: number;
rawPath: string;
rawIdentity: Readonly<{ dev: number; ino: number }>;
sealedPath: string;
sealedTempPath: string;
sealedIdentity: Readonly<{ dev: number; ino: number }>;
publish(bytes: Buffer): Promise<void>;
commit(): Promise<void>;
}>>;
const workspace = await createWorkspace("provider-guardian-client-v2-");
const guardianScript = path.resolve("scripts/lib/provider-raw-guardian.ts");
const lease = await start({
kind: "vulnerability",
workspaceRoot: workspace,
leaseMs: 3_000,
guardianScript,
});
expect((await readFile(`/proc/${lease.pid}/cmdline`)).toString("utf8")
.split("\0").filter(Boolean)).toEqual([process.execPath, guardianScript]);
await expect(readlink(`/proc/${lease.pid}/fd/3`)).resolves.toBe(
path.join(workspace, "provider-evidence/untrusted"),
);
await expect(readlink(`/proc/${lease.pid}/fd/4`)).resolves.toBe(
path.join(workspace, "provider-evidence"),
);
const rawMetadata = await lstat(lease.rawPath);
expect({ dev: rawMetadata.dev, ino: rawMetadata.ino }).toEqual(lease.rawIdentity);
const sealedTempMetadata = await lstat(lease.sealedTempPath);
expect({ dev: sealedTempMetadata.dev, ino: sealedTempMetadata.ino })
.toEqual(lease.sealedIdentity);
const bytes = Buffer.from('{"validated":"client"}\n');
await lease.publish(bytes);
await expect(lstat(lease.sealedTempPath)).rejects.toMatchObject({ code: "ENOENT" });
await expect(readFile(lease.sealedPath)).resolves.toEqual(bytes);
await lease.commit();
await expect(lstat(lease.rawPath)).rejects.toMatchObject({ code: "ENOENT" });
await expect(readFile(lease.sealedPath)).resolves.toEqual(bytes);
});
it("cleans published evidence on EOF before commit and permits a same-workspace retry", async () => {
const workspace = await createWorkspace("provider-guardian-published-eof-");
const transaction = await establishPublishedGuardian(workspace, Buffer.alloc(32, 0x31));
transaction.child.stdin!.end();
await expect(within(transaction.completion, 1_000, "published guardian EOF"))
.resolves.toEqual({ code: 125, signal: null });
await assertTransactionAbsent(transaction);
const { startProviderGuardian } = await import(
"../../scripts/lib/provider-guardian-client.ts"
);
const retry = await startProviderGuardian({
kind: "vulnerability",
workspaceRoot: workspace,
leaseMs: 2_000,
guardianScript: path.resolve("scripts/lib/provider-raw-guardian.ts"),
});
await retry.abort();
await expect(readdir(path.join(workspace, "provider-evidence/untrusted"))).resolves.toEqual([]);
await expect(readdir(path.join(workspace, "provider-evidence"))).resolves.toEqual(["untrusted"]);
});
it("fails closed when a separate trailing frame arrives after commit", async () => {
const { encodeProviderGuardianCommit } = await import(
"../../scripts/lib/provider-guardian-protocol.ts"
);
const workspace = await createWorkspace("provider-guardian-commit-trailing-");
const nonce = Buffer.alloc(32, 0x47);
const transaction = await establishPublishedGuardian(workspace, nonce);
transaction.child.stdin!.write(encodeProviderGuardianCommit(nonce));
await new Promise<void>((resolve) => setImmediate(resolve));
transaction.child.stdin!.write(Buffer.from([0, 0, 0, 1, 0x7b]));
transaction.child.stdin!.end();
await expect(within(transaction.completion, 1_000, "guardian trailing frame"))
.resolves.toEqual({ code: 126, signal: null });
await assertTransactionAbsent(transaction);
});
it("uses pinned fallback identities after a guardian hard death", async () => {
const { startProviderGuardian } = await import(
"../../scripts/lib/provider-guardian-client.ts"
);
const workspace = await createWorkspace("provider-guardian-hard-death-");
const lease = await startProviderGuardian({
kind: "vulnerability",
workspaceRoot: workspace,
leaseMs: 3_000,
guardianScript: path.resolve("scripts/lib/provider-raw-guardian.ts"),
});
process.kill(lease.pid, "SIGKILL");
await expect(within(lease.prematureExit, 1_000, "guardian hard death"))
.resolves.toEqual(expect.objectContaining({ message: expect.stringMatching(/SIGKILL/u) }));
await lease.abort();
await expect(lstat(lease.rawPath)).rejects.toMatchObject({ code: "ENOENT" });
await expect(lstat(lease.sealedTempPath)).rejects.toMatchObject({ code: "ENOENT" });
await expect(lstat(lease.sealedPath)).rejects.toMatchObject({ code: "ENOENT" });
});
it("cleans a linked raw inode when killed before READY and retries immediately", async () => {
const { startProviderGuardian } = await import(
"../../scripts/lib/provider-guardian-client.ts"
);
const workspace = await createWorkspace("provider-guardian-pre-ready-death-");
const evidenceRoot = path.join(workspace, "provider-evidence");
const rawDirectory = path.join(evidenceRoot, "untrusted");
const rawPath = path.join(rawDirectory, "vulnerability-report.json");
const guardianScript = await createPausedGuardianFixture(workspace);
const existingChildren = await directChildPids(process.pid);
const starting = startProviderGuardian({
kind: "vulnerability",
workspaceRoot: workspace,
leaseMs: 3_000,
guardianScript,
});
const guardianPid = await waitForNewDirectChild(existingChildren);
await waitForStoppedProcess(guardianPid);
const rawLink = waitForDirectoryEntry(rawDirectory, path.basename(rawPath), () => {
process.kill(guardianPid, "SIGKILL");
});
process.kill(guardianPid, "SIGCONT");
await within(rawLink, 1_000, "pre-READY canonical raw link");
await expect(within(starting, 2_000, "pre-READY guardian rejection"))
.rejects.toThrow(/provider guardian/u);
const possibleTempLeaves = (await readdir(evidenceRoot)).filter((leaf) =>
leaf.startsWith(".vulnerability-report.json.guardian-")
);
expect(possibleTempLeaves).toEqual([]);
await expect(lstat(rawPath)).rejects.toMatchObject({ code: "ENOENT" });
const retry = await startProviderGuardian({
kind: "vulnerability",
workspaceRoot: workspace,
leaseMs: 3_000,
guardianScript: path.resolve("scripts/lib/provider-raw-guardian.ts"),
});
expect(path.basename(retry.sealedTempPath)).toMatch(
/^\.vulnerability-report\.json\.guardian-[0-9a-f]{32}\.tmp$/u,
);
await retry.abort();
await expect(readdir(rawDirectory)).resolves.toEqual([]);
await expect(readdir(evidenceRoot)).resolves.toEqual(["untrusted"]);
});
it("preserves an external raw canary created after startup checks", async () => {
const { startProviderGuardian } = await import(
"../../scripts/lib/provider-guardian-client.ts"
);
const workspace = await createWorkspace("provider-guardian-external-canary-");
const rawPath = path.join(
workspace,
"provider-evidence/untrusted/vulnerability-report.json",
);
const { guardianScript, markerPath } = await createStalledGuardianFixture(workspace);
const starting = startProviderGuardian({
kind: "vulnerability",
workspaceRoot: workspace,
leaseMs: 3_000,
guardianScript,
});
const guardianPid = Number(await waitForFile(markerPath));
const canaryBytes = Buffer.from("external-canary\n");
const canaryHandle = await open(
rawPath,
constants.O_CREAT | constants.O_EXCL | constants.O_WRONLY | constants.O_NOFOLLOW,
0o600,
);
await canaryHandle.writeFile(canaryBytes);
const canaryIdentity = await canaryHandle.stat();
await canaryHandle.close();
process.kill(guardianPid, "SIGKILL");
await expect(within(starting, 2_000, "external-canary guardian rejection"))
.rejects.toThrow(/provider guardian/u);
expect(await readFile(rawPath)).toEqual(canaryBytes);
expect(await lstat(rawPath)).toMatchObject({
dev: canaryIdentity.dev,
ino: canaryIdentity.ino,
});
await rm(rawPath);
const retry = await startProviderGuardian({
kind: "vulnerability",
workspaceRoot: workspace,
leaseMs: 3_000,
guardianScript: path.resolve("scripts/lib/provider-raw-guardian.ts"),
});
await retry.abort();
await expect(readdir(path.join(workspace, "provider-evidence/untrusted")))
.resolves.toEqual([]);
await expect(readdir(path.join(workspace, "provider-evidence")))
.resolves.toEqual(["untrusted"]);
});
it("allows exactly one same-kind guardian without deleting the winner", async () => {
const { startProviderGuardian } = await import(
"../../scripts/lib/provider-guardian-client.ts"
);
const workspace = await createWorkspace("provider-guardian-concurrent-kind-");
const input = {
kind: "vulnerability" as const,
workspaceRoot: workspace,
leaseMs: 10_000,
guardianScript: path.resolve("scripts/lib/provider-raw-guardian.ts"),
};
const results = await Promise.allSettled([
startProviderGuardian(input),
startProviderGuardian(input),
]);
const winners = results.filter((result) => result.status === "fulfilled");
const losers = results.filter((result) => result.status === "rejected");
expect(winners).toHaveLength(1);
expect(losers).toHaveLength(1);
const winner = winners[0]!.value;
const rawMetadata = await lstat(winner.rawPath);
expect({ dev: rawMetadata.dev, ino: rawMetadata.ino }).toEqual(winner.rawIdentity);
await winner.abort();
await expect(readdir(path.join(workspace, "provider-evidence/untrusted")))
.resolves.toEqual([]);
await expect(readdir(path.join(workspace, "provider-evidence")))
.resolves.toEqual(["untrusted"]);
const retry = await startProviderGuardian(input);
await retry.abort();
await expect(readdir(path.join(workspace, "provider-evidence/untrusted")))
.resolves.toEqual([]);
await expect(readdir(path.join(workspace, "provider-evidence")))
.resolves.toEqual(["untrusted"]);
});
it("exits nonzero after cleanup when the diagnostic stderr pipe is closed", async () => {
const {
decodeProviderGuardianReady,
encodeProviderGuardianGuard,
} = await import("../../scripts/lib/provider-guardian-protocol.ts");
const workspace = await createWorkspace("provider-guardian-closed-stderr-");
const evidenceRoot = path.join(workspace, "provider-evidence");
const rawDirectory = path.join(evidenceRoot, "untrusted");
const nonce = Buffer.alloc(32, 0x63);
const child = spawnGuardian(workspace, nonce);
const completion = waitForChild(child);
const readyPayload = readFrame(child.stdout!);
child.stdin!.write(encodeProviderGuardianGuard({
kind: "vulnerability",
nonce,
deadlineEpochMs: Date.now() + 3_000,
}));
const ready = decodeProviderGuardianReady(
await within(readyPayload, 1_000, "closed-stderr guardian READY"),
nonce,
);
child.stderr!.destroy();
await new Promise<void>((resolve) => child.stderr!.once("close", resolve));
child.stdin!.end();
await expect(within(completion, 1_000, "closed-stderr guardian exit"))
.resolves.toEqual({ code: 125, signal: null });
await expect(lstat(path.join(rawDirectory, "vulnerability-report.json")))
.rejects.toMatchObject({ code: "ENOENT" });
await expect(lstat(path.join(evidenceRoot, ready.sealedTempLeaf)))
.rejects.toMatchObject({ code: "ENOENT" });
});
it("expires an uncommitted lease only after cleaning every owned object", async () => {
const {
decodeProviderGuardianReady,
encodeProviderGuardianGuard,
} = await import("../../scripts/lib/provider-guardian-protocol.ts");
const workspace = await createWorkspace("provider-guardian-deadline-v2-");
const evidenceRoot = path.join(workspace, "provider-evidence");
const rawPath = path.join(evidenceRoot, "untrusted/vulnerability-report.json");
const nonce = Buffer.alloc(32, 0x58);
const child = spawnGuardian(workspace, nonce);
const completion = waitForChild(child);
const readyPayload = readFrame(child.stdout!);
child.stdin!.write(encodeProviderGuardianGuard({
kind: "vulnerability",
nonce,
deadlineEpochMs: Date.now() + 350,
}));
const ready = decodeProviderGuardianReady(
await within(readyPayload, 1_000, "deadline guardian READY"),
nonce,
);
const sealedTempPath = path.join(evidenceRoot, ready.sealedTempLeaf);
await expect(within(completion, 1_000, "guardian deadline"))
.resolves.toEqual({ code: null, signal: "SIGKILL" });
await expect(lstat(rawPath)).rejects.toMatchObject({ code: "ENOENT" });
await expect(lstat(sealedTempPath)).rejects.toMatchObject({ code: "ENOENT" });
await expect(readdir(evidenceRoot)).resolves.toEqual(["untrusted"]);
});
it("still publishes near the lease deadline when post-processing completes in time", async () => {
const { startProviderGuardian } = await import(
"../../scripts/lib/provider-guardian-client.ts"
);
const workspace = await createWorkspace("provider-guardian-near-timeout-");
const lease = await startProviderGuardian({
kind: "vulnerability",
workspaceRoot: workspace,
leaseMs: 2_000,
guardianScript: path.resolve("scripts/lib/provider-raw-guardian.ts"),
});
await new Promise<void>((resolve) => setTimeout(resolve, 1_000));
const bytes = Buffer.from('{"validated":"near-timeout"}\n');
await lease.publish(bytes);
await lease.commit();
await expect(lstat(lease.rawPath)).rejects.toMatchObject({ code: "ENOENT" });
await expect(readFile(lease.sealedPath)).resolves.toEqual(bytes);
});
it("signals guardian exit only while the provider scope latch is active", async () => {
const lifecycle = await import("../../scripts/lib/provider-guardian-client.ts") as
Record<string, unknown>;
expect(lifecycle.createProviderScopeGuardianLatch).toBeTypeOf("function");
const createLatch = lifecycle.createProviderScopeGuardianLatch as (
guardianExit: Promise<Error>,
) => Readonly<{
activeFailure: Promise<Error>;
close(): Promise<void>;
failure(): Error | undefined;
}>;
let failAtBoundary!: (error: Error) => void;
const boundaryExit = new Promise<Error>((resolve) => { failAtBoundary = resolve; });
const boundary = createLatch(boundaryExit);
const boundaryError = new Error("guardian died at the collection boundary");
failAtBoundary(boundaryError);
await boundary.close();
await expect(boundary.activeFailure).resolves.toBe(boundaryError);
expect(boundary.failure()).toBe(boundaryError);
let failActive!: (error: Error) => void;
const activeExit = new Promise<Error>((resolve) => { failActive = resolve; });
const active = createLatch(activeExit);
const activeError = new Error("guardian died while scope active");
failActive(activeError);
await expect(active.activeFailure).resolves.toBe(activeError);
expect(active.failure()).toBe(activeError);
let failLate!: (error: Error) => void;
const lateExit = new Promise<Error>((resolve) => { failLate = resolve; });
const late = createLatch(lateExit);
await late.close();
const lateError = new Error("guardian died after scope collection");
failLate(lateError);
await Promise.resolve();
expect(late.failure()).toBe(lateError);
await expect(Promise.race([
late.activeFailure.then(() => "active"),
new Promise<string>((resolve) => setTimeout(() => resolve("inactive"), 25)),
])).resolves.toBe("inactive");
});
it("rejects a guardian lease whose derived sealed path differs from the configured target", async () => {
const lifecycle = await import("../../scripts/lib/provider-guardian-client.ts") as
Record<string, unknown>;
expect(lifecycle.assertProviderGuardianLeasePaths).toBeTypeOf("function");
const assertPaths = lifecycle.assertProviderGuardianLeasePaths as (
lease: Readonly<{ rawPath: string; sealedPath: string }>,
expected: Readonly<{ rawPath: string; sealedPath: string }>,
) => void;
const canonical = {
rawPath: "/workspace/provider-evidence/untrusted/vulnerability-report.json",
sealedPath: "/workspace/provider-evidence/vulnerability-report.json",
};
expect(() => assertPaths(canonical, canonical)).not.toThrow();
expect(() => assertPaths(canonical, {
...canonical,
sealedPath: "/workspace/provider-evidence/configured-alias.json",
})).toThrow(/noncanonical sealed path/u);
});
});
async function createWorkspace(prefix: string): Promise<string> {
const workspace = await mkdtemp(path.join(tmpdir(), prefix));
roots.push(workspace);
await mkdir(path.join(workspace, "provider-evidence/untrusted"), { recursive: true });
return workspace;
}
async function createStalledGuardianFixture(
workspace: string,
): Promise<Readonly<{ guardianScript: string; markerPath: string }>> {
const guardianScript = path.join(workspace, "stalled-guardian.mjs");
const markerPath = path.join(workspace, "guardian-spawned");
await writeFile(guardianScript, [
'import { writeFileSync } from "node:fs";',
'import path from "node:path";',
'writeFileSync(path.join(process.cwd(), "guardian-spawned"), String(process.pid));',
"setInterval(() => undefined, 1_000);",
"",
].join("\n"));
return { guardianScript, markerPath };
}
async function createPausedGuardianFixture(workspace: string): Promise<string> {
const guardianScript = path.join(workspace, "paused-guardian.mjs");
const realGuardian = pathToFileURL(
path.resolve("scripts/lib/provider-raw-guardian.ts"),
).href;
await writeFile(guardianScript, [
'process.kill(process.pid, "SIGSTOP");',
`await import(${JSON.stringify(realGuardian)});`,
"",
].join("\n"));
return guardianScript;
}
async function waitForFile(target: string): Promise<Buffer> {
const deadline = Date.now() + 1_000;
while (Date.now() <= deadline) {
try {
return await readFile(target);
} catch (error) {
if (!hasErrorCode(error, "ENOENT")) throw error;
}
await new Promise<void>((resolve) => setTimeout(resolve, 5));
}
throw new Error(`file did not appear: ${target}`);
}
type PublishedGuardian = Readonly<{
child: ReturnType<typeof spawn>;
completion: Promise<Readonly<{
code: number | null;
signal: NodeJS.Signals | null;
}>>;
rawPath: string;
sealedPath: string;
sealedTempPath: string;
}>;
async function establishPublishedGuardian(
workspace: string,
nonce: Buffer,
): Promise<PublishedGuardian> {
const {
decodeProviderGuardianPublished,
decodeProviderGuardianReady,
encodeProviderGuardianGuard,
encodeProviderGuardianPublish,
} = await import("../../scripts/lib/provider-guardian-protocol.ts");
const evidenceRoot = path.join(workspace, "provider-evidence");
const rawPath = path.join(evidenceRoot, "untrusted/vulnerability-report.json");
const sealedPath = path.join(evidenceRoot, "vulnerability-report.json");
const child = spawnGuardian(workspace, nonce);
const completion = waitForChild(child);
const readyPayload = readFrame(child.stdout!);
child.stdin!.write(encodeProviderGuardianGuard({
kind: "vulnerability",
nonce,
deadlineEpochMs: Date.now() + 3_000,
}));
const ready = decodeProviderGuardianReady(
await within(readyPayload, 1_000, "guardian READY"),
nonce,
);
const sealedTempPath = path.join(evidenceRoot, ready.sealedTempLeaf);
const bytes = Buffer.from('{"validated":"pending-commit"}\n');
const handle = await open(sealedTempPath, constants.O_WRONLY | constants.O_NOFOLLOW);
try {
await handle.writeFile(bytes);
await handle.chmod(0o400);
await handle.sync();
} finally {
await handle.close();
}
const publishedPayload = readFrame(child.stdout!);
child.stdin!.write(encodeProviderGuardianPublish({
nonce,
sealedDev: ready.sealedDev,
sealedIno: ready.sealedIno,
size: bytes.byteLength,
sha256: createHash("sha256").update(bytes).digest("hex"),
}));
decodeProviderGuardianPublished(
await within(publishedPayload, 1_000, "guardian PUBLISHED"),
nonce,
{ dev: ready.sealedDev, ino: ready.sealedIno },
);
return { child, completion, rawPath, sealedPath, sealedTempPath };
}
async function assertTransactionAbsent(transaction: PublishedGuardian): Promise<void> {
await expect(lstat(transaction.rawPath)).rejects.toMatchObject({ code: "ENOENT" });
await expect(lstat(transaction.sealedPath)).rejects.toMatchObject({ code: "ENOENT" });
await expect(lstat(transaction.sealedTempPath)).rejects.toMatchObject({ code: "ENOENT" });
}
async function readFrame(stream: NodeJS.ReadableStream): Promise<Buffer> {
return await new Promise((resolve, reject) => {
let pending = Buffer.alloc(0);
const onData = (chunk: Buffer | string): void => {
pending = Buffer.concat([pending, Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)]);
if (pending.byteLength < 4) return;
const payloadBytes = pending.readUInt32BE(0);
if (pending.byteLength < payloadBytes + 4) return;
cleanup();
if (pending.byteLength !== payloadBytes + 4) {
reject(new Error("guardian acknowledgement contained trailing bytes"));
return;
}
resolve(pending.subarray(4));
};
const onEnd = (): void => {
cleanup();
reject(new Error("guardian closed before acknowledgement"));
};
const cleanup = (): void => {
stream.removeListener("data", onData);
stream.removeListener("end", onEnd);
};
stream.on("data", onData);
stream.once("end", onEnd);
});
}
async function waitForChild(
child: ReturnType<typeof spawn>,
): Promise<Readonly<{ code: number | null; signal: NodeJS.Signals | null }>> {
return await new Promise((resolve, reject) => {
child.once("error", reject);
child.once("close", (code, signal) => resolve({ code, signal }));
});
}
function spawnGuardian(
workspace: string,
nonce: Buffer = Buffer.alloc(32, 0x7d),
): ReturnType<typeof spawn> {
const evidenceRoot = path.join(workspace, "provider-evidence");
const rawDirectory = path.join(evidenceRoot, "untrusted");
const noncePrefix = nonce.subarray(0, 16).toString("hex");
const openedFds: number[] = [];
try {
openedFds.push(openSync(
rawDirectory,
constants.O_RDONLY | constants.O_DIRECTORY | constants.O_NOFOLLOW,
));
openedFds.push(openSync(
evidenceRoot,
constants.O_RDONLY | constants.O_DIRECTORY | constants.O_NOFOLLOW,
));
openedFds.push(openSync(
path.join(
rawDirectory,
`.vulnerability-report.json.guardian-${noncePrefix}.raw.tmp`,
),
constants.O_RDWR | constants.O_CREAT | constants.O_EXCL | constants.O_NOFOLLOW,
0o600,
));
openedFds.push(openSync(
path.join(
evidenceRoot,
`.vulnerability-report.json.guardian-${noncePrefix}.tmp`,
),
constants.O_RDWR | constants.O_CREAT | constants.O_EXCL | constants.O_NOFOLLOW,
0o600,
));
return spawn(process.execPath, [path.resolve("scripts/lib/provider-raw-guardian.ts")], {
cwd: workspace,
env: {},
stdio: ["pipe", "pipe", "pipe", ...openedFds],
});
} finally {
for (const fd of openedFds) closeSync(fd);
}
}
function spawnGuardianWithPrivateModes(
workspace: string,
nonce: Buffer,
modes: Readonly<{ rawMode: number; sealedMode: number }>,
): Readonly<{
child: ReturnType<typeof spawn>;
rawStagingPath: string;
sealedTempPath: string;
}> {
const evidenceRoot = path.join(workspace, "provider-evidence");
const rawDirectory = path.join(evidenceRoot, "untrusted");
const noncePrefix = nonce.subarray(0, 16).toString("hex");
const rawStagingPath = path.join(
rawDirectory,
`.vulnerability-report.json.guardian-${noncePrefix}.raw.tmp`,
);
const sealedTempPath = path.join(
evidenceRoot,
`.vulnerability-report.json.guardian-${noncePrefix}.tmp`,
);
const openedFds: number[] = [];
try {
openedFds.push(openSync(
rawDirectory,
constants.O_RDONLY | constants.O_DIRECTORY | constants.O_NOFOLLOW,
));
openedFds.push(openSync(
evidenceRoot,
constants.O_RDONLY | constants.O_DIRECTORY | constants.O_NOFOLLOW,
));
const rawStagingFd = openSync(
rawStagingPath,
constants.O_RDWR | constants.O_CREAT | constants.O_EXCL | constants.O_NOFOLLOW,
0o600,
);
openedFds.push(rawStagingFd);
fchmodSync(rawStagingFd, modes.rawMode);
const sealedTempFd = openSync(
sealedTempPath,
constants.O_RDWR | constants.O_CREAT | constants.O_EXCL | constants.O_NOFOLLOW,
0o600,
);
openedFds.push(sealedTempFd);
fchmodSync(sealedTempFd, modes.sealedMode);
const child = spawn(process.execPath, [path.resolve("scripts/lib/provider-raw-guardian.ts")], {
cwd: workspace,
env: {},
stdio: ["pipe", "pipe", "pipe", ...openedFds],
});
return { child, rawStagingPath, sealedTempPath };
} finally {
for (const fd of openedFds) closeSync(fd);
}
}
async function waitForDirectoryEntry(
directory: string,
expectedLeaf: string,
onEntry: () => void,
): Promise<void> {
await new Promise<void>((resolve, reject) => {
const watcher = watch(directory, (_event, filename) => {
if (filename?.toString() !== expectedLeaf) return;
try {
onEntry();
resolve();
} catch (error) {
reject(error);
} finally {
watcher.close();
}
});
watcher.once("error", (error) => {
watcher.close();
reject(error);
});
});
}
async function within<T>(operation: Promise<T>, timeoutMs: number, label: string): Promise<T> {
let timer: NodeJS.Timeout | undefined;
try {
return await Promise.race([
operation,
new Promise<never>((_resolve, reject) => {
timer = setTimeout(() => reject(new Error(`${label} timed out`)), timeoutMs);
}),
]);
} finally {
if (timer) clearTimeout(timer);
}
}
async function directChildPids(parentPid: number): Promise<Set<number>> {
const value = await readFile(`/proc/${parentPid}/task/${parentPid}/children`, "utf8");
return new Set(value.trim().split(/\s+/u).filter(Boolean).map(Number));
}
async function waitForNewDirectChild(previous: ReadonlySet<number>): Promise<number> {
const deadline = Date.now() + 1_000;
while (Date.now() <= deadline) {
for (const pid of await directChildPids(process.pid)) {
if (!previous.has(pid)) return pid;
}
await new Promise<void>((resolve) => setTimeout(resolve, 5));
}
throw new Error("provider guardian child did not appear");
}
async function waitForStoppedProcess(pid: number): Promise<void> {
const deadline = Date.now() + 1_000;
while (Date.now() <= deadline) {
const status = await readFile(`/proc/${pid}/status`, "utf8");
if (/^State:\s+T/mu.test(status)) return;
await new Promise<void>((resolve) => setTimeout(resolve, 5));
}
throw new Error("provider guardian child did not stop before bootstrap");
}
function hasErrorCode(error: unknown, code: string): boolean {
return Boolean(error && typeof error === "object" && "code" in error && error.code === code);
}