diff --git a/server/src/__tests__/server-package-build-script.test.ts b/server/src/__tests__/server-package-build-script.test.ts index b4cfe4ff38..83b9ea8fa4 100644 --- a/server/src/__tests__/server-package-build-script.test.ts +++ b/server/src/__tests__/server-package-build-script.test.ts @@ -1,4 +1,7 @@ -import { readFileSync } from "node:fs"; +import { execFileSync } from "node:child_process"; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import path from "node:path"; import { fileURLToPath } from "node:url"; import { describe, expect, it } from "vitest"; @@ -58,17 +61,39 @@ describe("server package build script", () => { "pnpm --filter @paperclipai/paperclip-runner build", ); expect(packageJson.scripts?.build).toContain( - "cp -R ../packages/paperclip-runner/dist/. dist/vendor/paperclip-runner/", + "cp -Rf ../packages/paperclip-runner/dist/. dist/vendor/paperclip-runner/", ); }); + it("replaces an existing read-only image manifest with the build's copy step", () => { + const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8")); + const step = packageJson.scripts.build.split(" && ").find((command: string) => + command.includes("../packages/paperclip-runner/dist/.")); + expect(step).toBeDefined(); + const [command, ...args] = step.split(" "); + const root = mkdtempSync(path.join(tmpdir(), "runner-vendor-copy-")); + try { + const relative = "remote-provider-packs/linux-x64/provider-pack.json"; + const source = path.join(root, "packages/paperclip-runner/dist", relative); + const destination = path.join(root, "server/dist/vendor/paperclip-runner", relative); + mkdirSync(path.dirname(source), { recursive: true }); + mkdirSync(path.dirname(destination), { recursive: true }); + writeFileSync(source, "qualified image identity", { mode: 0o444 }); + writeFileSync(destination, "previous image identity", { mode: 0o444 }); + execFileSync(command, args, { cwd: path.join(root, "server") }); + expect(readFileSync(destination, "utf8")).toBe("qualified image identity"); + } finally { + rmSync(root, { recursive: true, force: true }); + } + }); + it("verifies vendored runner dependencies are mirrored before building", () => { const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8")) as { scripts?: Record; }; // See scripts/verify-runner-vendor-dependencies.mjs: packages/paperclip-runner - // is vendored with a raw `cp -R` of its compiled dist/, so every runtime + // is vendored with a raw copy of its compiled dist/, so every runtime // dependency it imports must also be a direct dependency of server. This // check derives that requirement from an esbuild scan of the vendored // entry points instead of relying on a human to have kept a hand-copied