Skip to content

Commit 1dcbcce

Browse files
authored
fix(docker): make workspace deps portable to Podman (#103814)
Fixes #103741. Reported and verified on amd64 Podman by @sallyom.
1 parent e43f225 commit 1dcbcce

2 files changed

Lines changed: 36 additions & 7 deletions

File tree

Dockerfile

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,13 @@ ARG OPENCLAW_EXTENSIONS
3232
ARG OPENCLAW_BUNDLED_PLUGIN_DIR
3333
# Copy package.json files for workspace packages used by the install layer.
3434
# Manifest-only bundled plugins remain valid selections but need no workspace metadata.
35-
RUN --mount=type=bind,source=packages,target=/tmp/packages,readonly \
36-
--mount=type=bind,source=${OPENCLAW_BUNDLED_PLUGIN_DIR},target=/tmp/${OPENCLAW_BUNDLED_PLUGIN_DIR},readonly \
37-
--mount=type=bind,source=scripts/lib/docker-plugin-selection.mjs,target=/tmp/docker-plugin-selection.mjs,readonly \
38-
mkdir -p /out/packages "/out/${OPENCLAW_BUNDLED_PLUGIN_DIR}" && \
35+
# Use COPY because build-context bind mounts are unreliable across supported
36+
# Podman/Buildah hosts. Full trees stay in this disposable stage; later stages
37+
# receive only extracted manifests.
38+
COPY scripts/lib/docker-plugin-selection.mjs /tmp/docker-plugin-selection.mjs
39+
COPY packages /tmp/packages
40+
COPY ${OPENCLAW_BUNDLED_PLUGIN_DIR} /tmp/${OPENCLAW_BUNDLED_PLUGIN_DIR}
41+
RUN mkdir -p /out/packages "/out/${OPENCLAW_BUNDLED_PLUGIN_DIR}" && \
3942
for manifest in /tmp/packages/*/package.json; do \
4043
[ -f "$manifest" ] || continue; \
4144
pkg_dir="${manifest%/package.json}"; \

src/dockerfile.test.ts

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,35 @@ describe("Dockerfile", () => {
130130
);
131131
});
132132

133+
it("uses portable copies for workspace dependency inputs", async () => {
134+
const dockerfile = await readFile(dockerfilePath, "utf8");
135+
const workspaceDepsStart = dockerfile.indexOf(
136+
"FROM ${OPENCLAW_NODE_BOOKWORM_IMAGE} AS workspace-deps",
137+
);
138+
const workspaceDepsEnd = dockerfile.indexOf("FROM ${OPENCLAW_BUN_IMAGE} AS bun-binary");
139+
140+
expect(workspaceDepsStart).toBeGreaterThan(-1);
141+
expect(workspaceDepsEnd).toBeGreaterThan(workspaceDepsStart);
142+
143+
const workspaceDeps = dockerfile.slice(workspaceDepsStart, workspaceDepsEnd);
144+
const extractionIndex = workspaceDeps.indexOf(
145+
'RUN mkdir -p /out/packages "/out/${OPENCLAW_BUNDLED_PLUGIN_DIR}"',
146+
);
147+
const inputCopies = [
148+
"COPY scripts/lib/docker-plugin-selection.mjs /tmp/docker-plugin-selection.mjs",
149+
"COPY packages /tmp/packages",
150+
"COPY ${OPENCLAW_BUNDLED_PLUGIN_DIR} /tmp/${OPENCLAW_BUNDLED_PLUGIN_DIR}",
151+
];
152+
153+
expect(extractionIndex).toBeGreaterThan(-1);
154+
for (const copy of inputCopies) {
155+
const copyIndex = workspaceDeps.indexOf(copy);
156+
expect(copyIndex, copy).toBeGreaterThan(-1);
157+
expect(copyIndex, copy).toBeLessThan(extractionIndex);
158+
}
159+
expect(workspaceDeps).not.toContain("--mount=type=bind");
160+
});
161+
133162
it("copies install workspace manifests before pnpm install", async () => {
134163
const dockerfile = await readFile(dockerfilePath, "utf8");
135164
const installIndex = dockerfile.indexOf("pnpm install --frozen-lockfile");
@@ -151,9 +180,6 @@ describe("Dockerfile", () => {
151180
expect(packageManifestIndex).toBeGreaterThan(-1);
152181
expect(extensionManifestIndex).toBeGreaterThan(-1);
153182
expect(dockerfile).toContain("for manifest in /tmp/packages/*/package.json");
154-
expect(dockerfile).toContain(
155-
"--mount=type=bind,source=scripts/lib/docker-plugin-selection.mjs,target=/tmp/docker-plugin-selection.mjs,readonly",
156-
);
157183
expect(dockerfile).toContain(
158184
'node /tmp/docker-plugin-selection.mjs "/tmp/${OPENCLAW_BUNDLED_PLUGIN_DIR}" "$OPENCLAW_EXTENSIONS"',
159185
);

0 commit comments

Comments
 (0)