/** * OFFLINE image runtime gate: exercise the shipped Photon/WASM resize core and * actual worker, with file modules confined to the standalone payload. No app, * provider, canvas, or network needed; a tiny synthetic PNG is generated here. * * node scripts/smoke-image-runtime.mjs [--standalone ] [--runtime ] */ import assert from "node:assert/strict"; import { spawnSync } from "node:child_process"; import * as fs from "node:fs"; import { createRequire } from "node:module"; import * as os from "node:os"; import * as path from "node:path"; import { fileURLToPath, pathToFileURL } from "node:url"; import { Worker } from "node:worker_threads"; import { deflateSync } from "node:zlib"; import { formatProbeError, probeEnv } from "./smoke-demo-runtime.mjs"; export function verifyImageRuntime(standalone, runtime = process.execPath) { const home = fs.mkdtempSync(path.join(os.tmpdir(), "lh-image-runtime-")); try { fs.writeFileSync(path.join(home, "auth.json"), "{}\n", { mode: 0o600 }); const result = spawnSync(runtime, [fileURLToPath(import.meta.url), "--probe", path.resolve(standalone)], { cwd: home, env: { ...probeEnv(process.env, home), ELECTRON_RUN_AS_NODE: "1" }, encoding: "utf8", timeout: 30_000, killSignal: "SIGKILL", maxBuffer: 128 * 1024, }); if (result.status !== 0 || result.error) { throw new Error(`image runtime probe failed (${result.error?.message ?? result.status}):\n${result.stdout ?? ""}${result.stderr ?? ""}`); } assert.match(result.stdout, /Photon in-process and worker resizing passed/, "probe exited without success marker"); process.stdout.write(result.stdout); } finally { fs.rmSync(home, { recursive: true, force: true }); } } // Self-contained so the eval worker can install the SAME guards using only // builtins, before importing any payload module. Module hooks do not otherwise // propagate from the dedicated probe process into Worker threads. function installGuards(require, standalone) { const assert = require("node:assert/strict"); const fs = require("node:fs"); const path = require("node:path"); const { fileURLToPath } = require("node:url"); const { registerHooks, syncBuiltinESMExports } = require("node:module"); const root = fs.realpathSync(standalone); const inside = (file) => { const real = fs.realpathSync(file); const relative = path.relative(root, real); assert.ok(relative !== ".." && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative), `dependency escaped standalone payload: ${file}`); return real; }; const photonRoot = path.join(root, "node_modules/@silvia-odwyer/photon-node"); const manifest = JSON.parse(fs.readFileSync(inside(path.join(photonRoot, "package.json")), "utf8")); assert.equal(manifest.version, "0.3.4", "unexpected Photon engine version"); const photonEntry = inside(path.join(photonRoot, "photon_rs.js")); const photonWasm = inside(path.join(photonRoot, "photon_rs_bg.wasm")); assert.ok(fs.statSync(photonWasm).size > 0, "empty Photon WASM asset"); let attempts = 0; const deny = () => { attempts++; throw new Error("OFFLINE image gate: network forbidden"); }; globalThis.fetch = deny; globalThis.WebSocket = class { constructor() { deny(); } }; for (const [name, methods] of [ ["http", ["request", "get"]], ["https", ["request", "get"]], ["net", ["connect", "createConnection"]], ["tls", ["connect"]], ["dgram", ["createSocket"]], ["dns", ["lookup", "resolve", "resolve4", "resolve6", "resolveAny", "reverse"]], ["dns/promises", ["lookup", "resolve", "resolve4", "resolve6", "resolveAny", "reverse"]], ]) { const module = require(`node:${name}`); for (const method of methods) module[method] = deny; } require("node:net").Socket.prototype.connect = deny; const loaded = new Set(); const wasmReads = new Set(); const originalRead = fs.readFileSync; fs.readFileSync = function (file, ...args) { const filename = file instanceof URL ? fileURLToPath(file) : file; const wasmFile = typeof filename === "string" && filename.endsWith(".wasm") ? inside(filename) : null; const bytes = originalRead.call(this, file, ...args); if (wasmFile) wasmReads.add(wasmFile); return bytes; }; syncBuiltinESMExports(); const hooks = registerHooks({ resolve(specifier, context, nextResolve) { const result = nextResolve(specifier, context); if (result.url.startsWith("file:")) loaded.add(inside(fileURLToPath(result.url))); else assert.ok(result.url.startsWith("node:"), `unexpected dependency URL: ${result.url}`); return result; }, }); return { report() { assert.equal(attempts, 0, "image runtime attempted network access"); assert.ok(loaded.has(photonEntry), "Photon JS was not loaded from the payload"); assert.ok(wasmReads.has(photonWasm), "Photon WASM was not loaded from the payload"); return { modules: loaded.size, wasmFiles: [...wasmReads], networkAttempts: attempts }; }, cleanup() { hooks.deregister(); fs.readFileSync = originalRead; syncBuiltinESMExports(); }, }; } /** Pure Node 2×2 RGBA PNG, with valid PNG CRCs and zlib image data. */ function fixturePng() { const chunk = (type, data) => { const buffer = Buffer.alloc(data.length + 12); buffer.writeUInt32BE(data.length); buffer.write(type, 4, "ascii"); data.copy(buffer, 8); let crc = ~0; for (const byte of buffer.subarray(4, -4)) { crc ^= byte; for (let bit = 0; bit < 8; bit++) crc = (crc >>> 1) ^ (0xedb88320 & -(crc & 1)); } buffer.writeUInt32BE(~crc >>> 0, buffer.length - 4); return buffer; }; const header = Buffer.alloc(13); header.writeUInt32BE(2, 0); header.writeUInt32BE(2, 4); header[8] = 8; // bit depth header[9] = 6; // RGBA const pixels = Buffer.from([ 0, 255, 0, 0, 255, 0, 255, 0, 255, 0, 0, 0, 255, 255, 255, 255, 255, 255, ]); return Buffer.concat([Buffer.from("89504e470d0a1a0a", "hex"), chunk("IHDR", header), chunk("IDAT", deflateSync(pixels)), chunk("IEND", Buffer.alloc(0))]); } function assertResized(result) { assert.ok(result, "resize returned null (missing/broken Photon must not silently pass)"); assert.equal(result.originalWidth, 2); assert.equal(result.originalHeight, 2); assert.equal(result.width, 1); assert.equal(result.height, 1); assert.equal(result.wasResized, true); assert.equal(result.mimeType, "image/png"); const png = Buffer.from(result.data, "base64"); assert.equal(png.subarray(0, 8).toString("hex"), "89504e470d0a1a0a"); assert.equal(png.readUInt32BE(16), 1); assert.equal(png.readUInt32BE(20), 1); } async function probeWorker(root, inputBytes, options, responseType) { const readyType = "lh:image-runtime-ready"; const worker = new Worker(` const { parentPort, workerData } = require("node:worker_threads"); const guards = (${installGuards.toString()})(require, workerData.root); const post = parentPort.postMessage.bind(parentPort); parentPort.postMessage = (message, ...args) => { if (message?.type === workerData.responseType) { post({ ...message, runtimeProof: guards.report() }, ...args); } else post(message, ...args); }; void import(workerData.entry).then(() => post({ type: workerData.readyType })); `, { eval: true, workerData: { root, responseType, readyType, entry: pathToFileURL(path.join(root, "src/agent/image-processing/resize-worker.mjs")).href }, }); try { return await new Promise((resolve, reject) => { const timer = setTimeout(() => reject(new Error("image resize worker timed out")), 10_000); const fail = (error) => { clearTimeout(timer); reject(error); }; let ready = false; worker.once("error", fail); worker.once("exit", (code) => fail(new Error(`image resize worker exited before response: ${code}`))); worker.on("message", (message) => { try { if (message?.type === readyType) { assert.equal(ready, false, "duplicate worker READY"); ready = true; worker.postMessage({ inputBytes, mimeType: "image/png", options }); } else if (message?.type === responseType) { assert.equal(ready, true, "worker replied before its import completed"); assert.equal(message.error, undefined, `worker resize failed: ${message.error}`); assertResized(message.result); assert.ok(message.runtimeProof?.modules > 0, "missing worker module-confinement proof"); assert.equal(message.runtimeProof.networkAttempts, 0); assert.equal(message.runtimeProof.wasmFiles.length, 1); clearTimeout(timer); resolve(message.runtimeProof); } } catch (error) { fail(error); } }); }); } finally { await worker.terminate(); } } async function probe(standalone) { const root = fs.realpathSync(standalone); const guards = installGuards(createRequire(import.meta.url), root); try { const entry = pathToFileURL(path.join(root, "src/agent/image-processing/resize-core.mjs")); const { resizeImageInProcess, IMAGE_RESIZE_WORKER_RESPONSE_TYPE } = await import(entry.href); assert.equal(typeof resizeImageInProcess, "function"); assert.equal(IMAGE_RESIZE_WORKER_RESPONSE_TYPE, "pi:image-resize-response"); const input = fixturePng(); const options = { maxWidth: 1, maxHeight: 1, maxBytes: 1024 * 1024 }; assertResized(await resizeImageInProcess(input, "image/png", options)); const inProcess = guards.report(); console.log(`[smoke-image-runtime] shipped resize core: PNG 2×2 → 1×1; ${inProcess.modules} modules and Photon WASM confined to ${root}`); const worker = await probeWorker(root, input, options, IMAGE_RESIZE_WORKER_RESPONSE_TYPE); guards.report(); console.log(`[smoke-image-runtime] shipped resize worker: READY then tagged PNG 2×2 → 1×1; ${worker.modules} modules and Photon WASM confined to ${root}`); console.log("[smoke-image-runtime] Photon in-process and worker resizing passed; zero network attempts"); } finally { guards.cleanup(); } } async function main() { const args = process.argv.slice(2); if (args[0] === "--probe") return probe(args[1]); const value = (name, fallback) => { const index = args.indexOf(name); if (index < 0) return fallback; assert.ok(args[index + 1] && !args[index + 1].startsWith("--"), `${name} requires a path`); return path.resolve(args[index + 1]); }; verifyImageRuntime(value("--standalone", path.resolve(import.meta.dirname, "../.next/standalone")), value("--runtime", process.execPath)); } if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) { main().catch((error) => { console.error(`[smoke-image-runtime] FAIL: ${formatProbeError(error)}`); process.exitCode = 1; }); }