fix(runner): preserve provider root mode across Docker export
This commit is contained in:
parent
f98fb8059e
commit
56cf3dbb69
|
|
@ -44,7 +44,9 @@ RUN pnpm --filter @paperclipai/paperclip-runner build:typescript \
|
|||
|
||||
# The trusted qualification entry exports the identical canonical provider stage.
|
||||
FROM scratch AS provider-pack-export
|
||||
COPY --from=provider-pack-build /provider-pack /
|
||||
# Keep the pack beneath the exporter-owned outer directory: BuildKit gives
|
||||
# that directory host-local permissions rather than the source root's mode.
|
||||
COPY --from=provider-pack-build /provider-pack /provider-pack
|
||||
|
||||
# Fleet sandbox base image. Keep this section aligned with
|
||||
# paperclipai/paperclip-cloud/fleet-sandbox-image/Dockerfile. The only Paperclip
|
||||
|
|
|
|||
|
|
@ -48,12 +48,12 @@ export function buildProviderPack({ workspaceRoot = defaultWorkspaceRoot, output
|
|||
// Same filesystem as OUTPUT, so successful publication is an atomic rename.
|
||||
// Docker reads its inputs before this empty directory receives exported files.
|
||||
const temporaryParent = mkdtempSync(join(dirname(outputRoot), ".paperclip-provider-pack-"));
|
||||
const exported = join(temporaryParent, "exported"), backup = join(temporaryParent, "previous");
|
||||
const exportRoot = join(temporaryParent, "exported"), exported = join(exportRoot, "provider-pack"), backup = join(temporaryParent, "previous");
|
||||
let previousMoved = false, published = false;
|
||||
try {
|
||||
const build = run("docker", ["build", "--platform", "linux/amd64", "--target", "provider-pack-export",
|
||||
"--file", dockerfile, "--build-arg", `PAPERCLIP_RUNNER_SOURCE_REVISION=${revision}`,
|
||||
"--output", `type=local,dest=${exported}`, workspaceRoot],
|
||||
"--output", `type=local,dest=${exportRoot}`, workspaceRoot],
|
||||
{ cwd: workspaceRoot, stdio: "inherit", timeout: 12 * 60 * 1000, killSignal: "SIGTERM" });
|
||||
if (build.error || build.status !== 0) throw new Error("Canonical provider-pack build failed");
|
||||
const manifest = verifyProviderPack(exported, { revision, lockSha256: expectedLock });
|
||||
|
|
|
|||
|
|
@ -19,7 +19,12 @@ function fixture(runTest) {
|
|||
writeFileSync(join(workspaceRoot, "pnpm-lock.yaml"), "different CI resolution");
|
||||
const calls = [];
|
||||
function exported(args, tamper) {
|
||||
const destination = args[args.indexOf("--output") + 1].slice("type=local,dest=".length);
|
||||
const exportRoot = args[args.indexOf("--output") + 1].slice("type=local,dest=".length);
|
||||
// BuildKit's local exporter owns the outer directory and creates it 0700.
|
||||
// The nested pack must retain the mode bound in its integrity manifest.
|
||||
mkdirSync(exportRoot, { recursive: true, mode: 0o700 });
|
||||
chmodSync(exportRoot, 0o700);
|
||||
const destination = join(exportRoot, "provider-pack");
|
||||
const paths = {
|
||||
nodeCommand: "node_modules/node/bin/node", productionLock: "pnpm-lock.yaml",
|
||||
opencodeCommand: "node_modules/.bin/opencode", opencodeExecutable: "node_modules/opencode-ai/bin/opencode.exe",
|
||||
|
|
@ -125,6 +130,7 @@ for (const [name, tamper] of [
|
|||
["extra dependency", root => writeFileSync(join(root, "node_modules/unexpected"), "extra")],
|
||||
["lost executable mode", root => chmodSync(join(root, "node_modules/pi/vendor/pi"), 0o644)],
|
||||
["directory mode", root => chmodSync(join(root, "node_modules/pi/vendor"), 0o700)],
|
||||
["pack root mode", root => chmodSync(root, 0o700)],
|
||||
["changed internal symlink", root => { unlinkSync(join(root, "node_modules/pi-link")); symlinkSync(".bin/pi", join(root, "node_modules/pi-link")); }],
|
||||
["escaping symlink", root => { unlinkSync(join(root, "node_modules/pi-link")); symlinkSync("../../", join(root, "node_modules/pi-link")); }],
|
||||
["absolute symlink", root => { unlinkSync(join(root, "node_modules/pi-link")); symlinkSync(join(root, "node_modules/pi/vendor/pi"), join(root, "node_modules/pi-link")); }],
|
||||
|
|
|
|||
Loading…
Reference in New Issue