perf(runner): verify Pi launch bytes once into the native snapshot

Cross-bind the Pi layout to its source-pinned native closure before structural discovery. Preserve full byte hashing in every immutable command snapshot and keep the independent generic verifier unchanged.

Add corruption, graph, link, repeated-open and runtime-boundary cleanup regressions.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
DottaandPaperclip committed 2026-10-01 19:53:47 -05:00
1 parent 5a6a531575
commit 7b7fcbf96b
4 files changed
+203 -16

No files matched your search

@@ -4,7 +4,8 @@ import { join } from "node:path";
import { verifyNativeAcpxInstallation, type VerifiedAcpxInstallation } from "./installation-integrity.js";
import { PI_DISTRIBUTION_CLOSURE_SHA256 } from "./pi-closure-pins.js";
import { PI_NODE_VERSION } from "./pi-node-pins.js";
import { verifyPiRuntimeManifest, type PiRuntimeManifest } from "./pi-verified-runtime.js";
import { verifyPiRuntimeLayoutForNativeSnapshot, type PiRuntimeManifest } from "./pi-verified-runtime.js";
import { readNativeAcpxDistributionEntries } from "./native-distribution-integrity.js";
import { resolveRunnerProviderAssetsRoot } from "./provider-assets-root.js";
import { QUALIFIED_ACPX_PROFILES, type QualifiedAcpxProfile } from "./qualified-profiles.js";
@@ -69,16 +70,20 @@ export async function verifyPiInstallation(profile: QualifiedAcpxProfile): Promi
for (const [key, value] of Object.entries(FIXED_PATHS)) {
if (manifest[key as keyof typeof FIXED_PATHS] !== value) throw new Error("Pi distribution changed a fixed launch path");
}
const verified = await verifyPiRuntimeManifest(runtimeRoot, manifest);
if (verified.manifestDigest !== metadata.manifestDigest) throw new Error("Pi runtime manifest digest does not match its distribution");
const native = await verifyNativeAcpxInstallation({
const declaration = {
distributionRoot: runtimeRoot,
manifestPath: join(assets, "native-closure.json"),
expectedClosureSha256: expectedClosure,
executable: FIXED_PATHS.node,
entrypoint: "pi-entry.cjs",
fixedArguments: [],
});
};
// Both declarations must name exactly the same source-pinned bytes. Actual
// content admission remains the descriptor-bound immutable snapshot below.
const entries = await readNativeAcpxDistributionEntries(declaration);
const layout = await verifyPiRuntimeLayoutForNativeSnapshot(runtimeRoot, manifest, { entries }, expectedClosure);
if (layout.manifestDigest !== metadata.manifestDigest) throw new Error("Pi runtime manifest digest does not match its distribution");
const native = await verifyNativeAcpxInstallation(declaration);
return Object.freeze({
commandDigest: profile.commandDigest,
agentServerPackageJsonPath: join(runtimeRoot, "node_modules/pi-acp/package.json"),
@@ -0,0 +1,65 @@
import { createHash } from "node:crypto";
import { chmod, lstat, mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { afterEach, expect, it, vi } from "vitest";
import * as credentials from "./codex-credentials.js";
import * as skills from "./runtime-skill-lease.js";
import * as bridge from "../runner-tool-bridge.js";
import { verifyNativeAcpxInstallation } from "./installation-integrity.js";
import { inventoryPiRuntimeFiles, verifyPiRuntimeLayoutForNativeSnapshot, type PiRuntimeManifest } from "./pi-verified-runtime.js";
import { AcpxRuntimeHost } from "./runtime-host.js";
const roots: string[] = [];
afterEach(async () => {
vi.restoreAllMocks();
await Promise.all(roots.splice(0).map(root => rm(root, { recursive: true, force: true })));
});
it("rejects corrupt Pi bytes at the command boundary before runtime, spawn or bridge and releases lifetime/skills", async () => {
const root = await mkdtemp(join(tmpdir(), "pi-native-admission-")); roots.push(root);
const source = join(root, "provider"); const workspace = join(root, "workspace");
await mkdir(source); await mkdir(workspace); await mkdir(join(root, "runtime"));
for (const name of ["node", "pi.js", "extension.js", "wrapper.js"]) await writeFile(join(source, name), "pinned:" + name);
await chmod(join(source, "node"), 0o500);
const manifest: PiRuntimeManifest = { schema: "paperclip.pi-runtime-files.v1", node: "node", piEntrypoint: "pi.js", extension: "extension.js", wrapperEntrypoint: "wrapper.js", files: await inventoryPiRuntimeFiles(source) };
const entries = await Promise.all(manifest.files.map(async entry => ({ path: entry.path, sha256: entry.sha256.slice(7), size: (await lstat(join(source, entry.path))).size, executable: entry.path === "node" })));
entries.sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
const closure = createHash("sha256").update(JSON.stringify(entries)).digest("hex");
const manifestPath = join(root, "native.json"); await writeFile(manifestPath, JSON.stringify({ entries }));
const installation = await verifyNativeAcpxInstallation({ distributionRoot: source, manifestPath, expectedClosureSha256: closure, executable: "node", entrypoint: "wrapper.js", fixedArguments: [] });
await writeFile(join(source, "wrapper.js"), "x".repeat(entries.find(entry => entry.path === "wrapper.js")!.size));
// Declaration/layout resolution intentionally does not claim byte admission.
await verifyPiRuntimeLayoutForNativeSnapshot(source, manifest, { entries }, closure);
const lifetimeCloses: ReturnType<typeof vi.fn>[] = []; const skillCloses: ReturnType<typeof vi.fn>[] = [];
const acquireLifetime = credentials.acquireAcpxProviderLifetimeLease;
vi.spyOn(credentials, "acquireAcpxProviderLifetimeLease").mockImplementation(async input => {
const lease = await acquireLifetime(input); const close = vi.fn(() => lease.close()); lifetimeCloses.push(close);
return { ...lease, close };
});
const acquireSkills = skills.createAcpxRuntimeSkillLease;
vi.spyOn(skills, "createAcpxRuntimeSkillLease").mockImplementation(async input => {
const lease = await acquireSkills(input); const close = vi.fn(() => lease.close()); skillCloses.push(close);
return { ...lease, close };
});
const toolBridge = vi.spyOn(bridge, "startRunnerToolBridge");
const openRuntime = vi.fn(); const spawn = vi.fn();
const openCommand = vi.fn(async () => {
const lease = await installation.openCommand();
return { close: () => lease.close(), spawn };
});
await expect(AcpxRuntimeHost.open({
runtimeDirectory: join(root, "runtime"), normalizedSessionId: "pi-single-pass-rejection",
workingDirectory: workspace, agent: "pi", model: "openrouter/deepseek/deepseek-v4-flash-0731",
permissionMode: "approve-all", providerPolicy: { readOnly: true },
semanticTools: { tools: [], handler: vi.fn() },
}, {
verifyInstallation: async profile => ({ commandDigest: profile.commandDigest, agentServerPackageJsonPath: join(source, "package.json"), agentRuntimePackageJsonPath: null, openCommand }),
openRuntime, reportRetainedCleanupFailure: vi.fn(),
})).rejects.toThrow("digest mismatch");
expect(openCommand).toHaveBeenCalledOnce();
expect(openRuntime).not.toHaveBeenCalled(); expect(spawn).not.toHaveBeenCalled(); expect(toolBridge).not.toHaveBeenCalled();
expect(lifetimeCloses).toHaveLength(1); expect(lifetimeCloses[0]).toHaveBeenCalledOnce();
expect(skillCloses).toHaveLength(1); expect(skillCloses[0]).toHaveBeenCalledOnce();
expect(lifetimeCloses[0]!.mock.invocationCallOrder[0]).toBeLessThan(skillCloses[0]!.mock.invocationCallOrder[0]!);
});
@@ -1,13 +1,15 @@
import { link, lstat, mkdir, mkdtemp, open, readdir, realpath, rename, rm, symlink, writeFile, type FileHandle } from "node:fs/promises";
import { chmod, link, lstat, mkdir, mkdtemp, open, readdir, realpath, rename, rm, symlink, writeFile, type FileHandle } from "node:fs/promises";
import { createHash } from "node:crypto";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { afterEach, describe, expect, it, vi } from "vitest";
import { inventoryPiRuntimeFiles, PI_RUNTIME_MANIFEST_SCHEMA, verifyPiRuntimeManifest, type PiRuntimeManifest } from "./pi-verified-runtime.js";
import { inventoryPiRuntimeFiles, PI_RUNTIME_MANIFEST_SCHEMA, verifyPiRuntimeManifest, verifyPiRuntimeLayoutForNativeSnapshot, type PiRuntimeManifest } from "./pi-verified-runtime.js";
import { verifyNativeAcpxInstallation } from "./installation-integrity.js";
vi.mock("node:fs/promises", async (importOriginal) => {
const original = await importOriginal<typeof import("node:fs/promises")>();
return { ...original, lstat: vi.fn(original.lstat), readdir: vi.fn(original.readdir) };
return { ...original, open: vi.fn(original.open), lstat: vi.fn(original.lstat), readdir: vi.fn(original.readdir) };
});
const temporary: string[] = [];
@@ -147,3 +149,78 @@ describe("Pi complete runtime manifest", () => {
await expect(inventoryPiRuntimeFiles(root)).rejects.toThrow("writable name");
});
});
async function nativeFixture() {
const { root, manifest } = await fixture();
await chmod(join(root, "node"), 0o500);
const entries = await Promise.all(manifest.files.map(async entry => ({
path: entry.path, sha256: entry.sha256.slice(7), size: (await lstat(join(root, entry.path))).size,
executable: entry.path === "node",
})));
entries.sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
const closure = createHash("sha256").update(JSON.stringify(entries)).digest("hex");
const manifestPath = root + "-native.json"; temporary.push(manifestPath);
await writeFile(manifestPath, JSON.stringify({ entries }));
const input = { distributionRoot: root, manifestPath, expectedClosureSha256: closure, executable: "node", entrypoint: "wrapper.js", fixedArguments: [] };
return { root, manifest, entries, closure, input };
}
describe("Pi native launch layout admission", () => {
it("cross-binds declarations without opening content, then freshly hashes every command snapshot", async () => {
const f = await nativeFixture();
const expected = await verifyPiRuntimeManifest(f.root, f.manifest);
vi.mocked(open).mockClear();
expect(await verifyPiRuntimeLayoutForNativeSnapshot(f.root, f.manifest, { entries: f.entries }, f.closure)).toEqual({ manifestDigest: expected.manifestDigest });
expect(open).not.toHaveBeenCalled();
const installation = await verifyNativeAcpxInstallation(f.input);
const lease = await installation.openCommand(); await lease.close();
const opened = vi.mocked(open).mock.calls.map(([path]) => String(path));
for (const entry of f.entries) expect(opened).toContain(join(await realpath(f.root), entry.path));
// No cached installation verdict may authorize a later mutable source.
await writeFile(join(f.root, "wrapper.js"), "x".repeat(f.entries.find(e => e.path === "wrapper.js")!.size));
await expect(installation.openCommand()).rejects.toThrow("digest mismatch");
});
it("rejects a substituted native pin and any Pi/native declaration disagreement", async () => {
const f = await nativeFixture();
await expect(verifyPiRuntimeLayoutForNativeSnapshot(f.root, f.manifest, { entries: f.entries }, "0".repeat(64))).rejects.toThrow("manifest digest mismatch");
const altered = structuredClone(f.manifest); altered.files[0]!.sha256 = `sha256:${"0".repeat(64)}`;
await expect(verifyPiRuntimeLayoutForNativeSnapshot(f.root, altered, { entries: f.entries }, f.closure)).rejects.toThrow("pinned native closure");
altered.files.shift();
await expect(verifyPiRuntimeLayoutForNativeSnapshot(f.root, altered, { entries: f.entries }, f.closure)).rejects.toThrow("pinned native closure");
});
it("rejects extra or missing files during complete structural discovery", async () => {
const f = await nativeFixture();
await writeFile(join(f.root, "extra"), "not admitted");
await expect(verifyPiRuntimeLayoutForNativeSnapshot(f.root, f.manifest, { entries: f.entries }, f.closure)).rejects.toThrow("package graph");
await rm(join(f.root, "extra")); await rm(join(f.root, "assets/image.wasm"));
await expect(verifyPiRuntimeLayoutForNativeSnapshot(f.root, f.manifest, { entries: f.entries }, f.closure)).rejects.toThrow("package graph");
});
it("rejects links even when their names appear in the pinned closure", async () => {
const f = await nativeFixture();
await rm(join(f.root, "pi.js")); await symlink("wrapper.js", join(f.root, "pi.js"));
await expect(verifyPiRuntimeLayoutForNativeSnapshot(f.root, f.manifest, { entries: f.entries }, f.closure)).rejects.toThrow("package graph");
await rm(join(f.root, "pi.js")); await link(join(f.root, "wrapper.js"), join(f.root, "pi.js"));
await expect(verifyPiRuntimeLayoutForNativeSnapshot(f.root, f.manifest, { entries: f.entries }, f.closure)).rejects.toThrow("writable name");
});
it("never treats layout success as byte admission for same-size corruption", async () => {
const f = await nativeFixture();
await writeFile(join(f.root, "wrapper.js"), "x".repeat(f.entries.find(e => e.path === "wrapper.js")!.size));
await expect(verifyPiRuntimeLayoutForNativeSnapshot(f.root, f.manifest, { entries: f.entries }, f.closure)).resolves.toHaveProperty("manifestDigest");
// The independent generic verifier retains its original full-byte guarantee.
await expect(verifyPiRuntimeManifest(f.root, f.manifest)).rejects.toThrow("package graph");
const installation = await verifyNativeAcpxInstallation(f.input);
await expect(installation.openCommand()).rejects.toThrow("digest mismatch");
});
it("rechecks source identities after layout, before granting any command lease", async () => {
const f = await nativeFixture();
await verifyPiRuntimeLayoutForNativeSnapshot(f.root, f.manifest, { entries: f.entries }, f.closure);
const installation = await verifyNativeAcpxInstallation(f.input);
await rm(join(f.root, "wrapper.js")); await symlink("pi.js", join(f.root, "wrapper.js"));
await expect(installation.openCommand()).rejects.toThrow("symbolic link");
});
});
@@ -3,6 +3,8 @@ import { constants } from "node:fs";
import { lstat, open, readdir, readlink, realpath } from "node:fs/promises";
import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
import { parseNativeAcpxDistributionEntries } from "./native-distribution-integrity.js";
export const PI_RUNTIME_MANIFEST_SCHEMA = "paperclip.pi-runtime-files.v1" as const;
export interface PiRuntimeFile {
path: string;
@@ -33,12 +35,8 @@ const PI_INVENTORY_DISCOVERY_CONCURRENCY = 32;
function hash(bytes: Uint8Array | string): string { return `sha256:${createHash("sha256").update(bytes).digest("hex")}`; }
/**
* Inventory a complete provider pack, not just Pi's cli.js. Native modules,
* WASM, data, package metadata, and the owned extension all participate.
* Used while building a pack; the caller records/signs this immutable result.
*/
export async function inventoryPiRuntimeFiles(root: string): Promise<PiRuntimeFile[]> {
/** Discover the complete graph with the same path, link and identity checks for both callers. */
async function discoverPiRuntimeFiles(root: string): Promise<{ files: PiRuntimeFile[]; regular: Array<{ path: string; entry: PiRuntimeFile }> }> {
const physicalRoot = await realpath(root);
if ((await lstat(root)).isSymbolicLink()) throw new Error("Pi runtime root must not be a symlink");
const files: PiRuntimeFile[] = [];
@@ -80,6 +78,16 @@ export async function inventoryPiRuntimeFiles(root: string): Promise<PiRuntimeFi
}
};
await visit(physicalRoot);
return { files, regular };
}
/**
* Inventory a complete provider pack, not just Pi's cli.js. Native modules,
* WASM, data, package metadata, and the owned extension all participate.
* Used while building a pack; the caller records/signs this immutable result.
*/
export async function inventoryPiRuntimeFiles(root: string): Promise<PiRuntimeFile[]> {
const { files, regular } = await discoverPiRuntimeFiles(root);
// Keep discovery order independent of completion order. Do not cache: every
// admission still reads every regular file through its checked descriptor.
for (let index = 0; index < regular.length; index += PI_INVENTORY_HASH_CONCURRENCY) {
@@ -114,6 +122,13 @@ async function hashFile(path: string): Promise<string> {
export async function verifyPiRuntimeManifest(
root: string, manifest: PiRuntimeManifest,
): Promise<{ environment: Record<string, string>; manifestDigest: string }> {
const { sorted, unique } = validatePiRuntimeManifest(manifest);
const actual = (await inventoryPiRuntimeFiles(root)).sort((a, b) => a.path.localeCompare(b.path, "en"));
if (JSON.stringify(actual) !== JSON.stringify(sorted)) throw new Error("Pi runtime package graph differs from its qualified manifest");
return bindPiRuntimeManifestPaths(root, manifest, sorted, unique);
}
function validatePiRuntimeManifest(manifest: PiRuntimeManifest): { sorted: PiRuntimeFile[]; unique: Set<string> } {
if (manifest.schema !== PI_RUNTIME_MANIFEST_SCHEMA || !Array.isArray(manifest.files) || manifest.files.length === 0 || manifest.files.length > 100_000) throw new Error("Pi runtime manifest is invalid");
const unique = new Set<string>();
for (const entry of manifest.files) {
@@ -125,8 +140,10 @@ export async function verifyPiRuntimeManifest(
? { path: entry.path, kind: entry.kind, sha256: entry.sha256 }
: { path: entry.path, kind: entry.kind, target: entry.target, sha256: entry.sha256 })
.sort((a, b) => a.path.localeCompare(b.path, "en"));
const actual = (await inventoryPiRuntimeFiles(root)).sort((a, b) => a.path.localeCompare(b.path, "en"));
if (JSON.stringify(actual) !== JSON.stringify(sorted)) throw new Error("Pi runtime package graph differs from its qualified manifest");
return { sorted, unique };
}
async function bindPiRuntimeManifestPaths(root: string, manifest: PiRuntimeManifest, sorted: PiRuntimeFile[], unique: Set<string>): Promise<{ environment: Record<string, string>; manifestDigest: string }> {
const physicalRoot = await realpath(root);
const boundPath = async (path: string): Promise<string> => {
if (!safeRelative(path) || !unique.has(path)) throw new Error("Pi executable is absent from its manifest");
@@ -144,3 +161,26 @@ export async function verifyPiRuntimeManifest(
manifestDigest: hash(JSON.stringify({ ...manifest, files: sorted })),
};
}
/**
* Pi's native launch already hashes every byte while creating its immutable
* command snapshot. Check layout and both declarations here, without doing a
* second byte pass. This result is NOT byte admission and cannot launch code;
* the caller must still acquire a freshly verified native command snapshot.
* The generic full-byte verifier above remains independent of this path.
*/
export async function verifyPiRuntimeLayoutForNativeSnapshot(
root: string, manifest: PiRuntimeManifest,
nativeManifest: unknown, expectedClosureSha256: string,
): Promise<{ manifestDigest: string }> {
const entries = parseNativeAcpxDistributionEntries(nativeManifest, expectedClosureSha256);
const { sorted, unique } = validatePiRuntimeManifest(manifest);
const nativeFiles: PiRuntimeFile[] = entries.map((entry): PiRuntimeFile => ({ path: entry.path, kind: "file", sha256: `sha256:${entry.sha256}` }))
.sort((a, b) => a.path.localeCompare(b.path, "en"));
if (JSON.stringify(nativeFiles) !== JSON.stringify(sorted)) throw new Error("Pi runtime manifest differs from its pinned native closure");
const { files } = await discoverPiRuntimeFiles(root);
const layout = (values: PiRuntimeFile[]) => values.map(({ path, kind }) => ({ path, kind })).sort((a, b) => a.path.localeCompare(b.path, "en"));
if (JSON.stringify(layout(files)) !== JSON.stringify(layout(sorted))) throw new Error("Pi runtime package graph differs from its qualified manifest");
const { manifestDigest } = await bindPiRuntimeManifestPaths(root, manifest, sorted, unique);
return { manifestDigest };
}