From efe019a79f50440d7bd6c3bc6c75fb8f18953093 Mon Sep 17 00:00:00 2001 From: Dotta Date: Thu, 1 Oct 2026 20:14:01 -0500 Subject: [PATCH] fix(runner): preserve plain Node Pi materializer imports Co-Authored-By: Paperclip --- .../scripts/materialize-pi-distribution.test.mjs | 12 ++++++++++++ .../src/drivers/acpx/pi-verified-runtime.ts | 5 +++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/packages/paperclip-runner/scripts/materialize-pi-distribution.test.mjs b/packages/paperclip-runner/scripts/materialize-pi-distribution.test.mjs index 39ecc7a460..54e7780cbb 100644 --- a/packages/paperclip-runner/scripts/materialize-pi-distribution.test.mjs +++ b/packages/paperclip-runner/scripts/materialize-pi-distribution.test.mjs @@ -1,4 +1,5 @@ import assert from "node:assert/strict"; +import { spawnSync } from "node:child_process"; import { mkdtemp, mkdir, readFile, readdir, rm, symlink, writeFile } from "node:fs/promises"; import { tmpdir } from "node:os"; import { dirname, join } from "node:path"; @@ -13,6 +14,17 @@ async function fixture(t) { return { root, write }; } +test("plain Node loads the source materializer without a TypeScript import resolver", () => { + const materializer = new URL("./materialize-pi-distribution.mjs", import.meta.url).href; + const result = spawnSync(process.execPath, ["--input-type=module", "-e", ` + const { materializePiDistribution } = await import(${JSON.stringify(materializer)}); + const assert = await import("node:assert/strict"); + await assert.rejects(materializePiDistribution({ outputRoot: "relative" }), /must be absolute/); + `], { env: { PATH: process.env.PATH ?? "", LANG: "en_US.UTF-8" }, encoding: "utf8", timeout: 10_000 }); + assert.ifError(result.error); + assert.equal(result.status, 0, result.stderr); +}); + test("distribution lock closes exact wrapper, SDK and upstream Pi graph with integrity", async () => { const pkg = JSON.parse(await readFile(new URL("./pi-distribution/package.json", import.meta.url), "utf8")); const lock = JSON.parse(await readFile(new URL("./pi-distribution/package-lock.json", import.meta.url), "utf8")); diff --git a/packages/paperclip-runner/src/drivers/acpx/pi-verified-runtime.ts b/packages/paperclip-runner/src/drivers/acpx/pi-verified-runtime.ts index d5399439b5..15b69dca49 100644 --- a/packages/paperclip-runner/src/drivers/acpx/pi-verified-runtime.ts +++ b/packages/paperclip-runner/src/drivers/acpx/pi-verified-runtime.ts @@ -3,8 +3,6 @@ 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; @@ -173,6 +171,9 @@ export async function verifyPiRuntimeLayoutForNativeSnapshot( root: string, manifest: PiRuntimeManifest, nativeManifest: unknown, expectedClosureSha256: string, ): Promise<{ manifestDigest: string }> { + // The materializer imports the generic verifier directly from TypeScript. + // Resolve the compiled native helper only on the runtime snapshot path. + const { parseNativeAcpxDistributionEntries } = await import("./native-distribution-integrity.js"); 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}` }))