




















@@ -9,13 +9,16 @@ import { createTempDirTracker } from "../helpers/temp-dir.js";
991010const SCRIPT_PATH = "scripts/test-install-sh-docker.sh";
1111const INSTALL_E2E_DOCKER_PATH = "scripts/test-install-sh-e2e-docker.sh";
12+const INSTALL_E2E_DOCKERFILE_PATH = "scripts/docker/install-sh-e2e/Dockerfile";
1213const INSTALL_E2E_RUNNER_PATH = "scripts/docker/install-sh-e2e/run.sh";
1314const DOCKER_SETUP_PATH = "scripts/docker/setup.sh";
1415const HOST_TIMEOUT_PATH = "scripts/lib/host-timeout.sh";
1516const PODMAN_SETUP_PATH = "scripts/podman/setup.sh";
1617const PODMAN_QUADLET_TEMPLATE_PATH = "scripts/podman/openclaw.container.in";
1718const PODMAN_RUN_PATH = "scripts/run-openclaw-podman.sh";
19+const SMOKE_DOCKERFILE_PATH = "scripts/docker/install-sh-smoke/Dockerfile";
1820const SMOKE_RUNNER_PATH = "scripts/docker/install-sh-smoke/run.sh";
21+const NONROOT_DOCKERFILE_PATH = "scripts/docker/install-sh-nonroot/Dockerfile";
1922const NONROOT_RUNNER_PATH = "scripts/docker/install-sh-nonroot/run.sh";
2023const BUN_GLOBAL_SMOKE_PATH = "scripts/e2e/bun-global-install-smoke.sh";
2124const BUN_GLOBAL_ASSERTIONS_PATH = "scripts/e2e/lib/bun-global-install/assertions.mjs";
@@ -135,6 +138,27 @@ function normalizeInstallE2eAgentOutput(output: string) {
135138}
136139}
137140141+function expectInstallDockerfileContract(
142+dockerfilePath: string,
143+runnerPath: string,
144+entrypoint: string,
145+): string {
146+const dockerfile = readFileSync(dockerfilePath, "utf8");
147+148+expect(dockerfile).toContain("# syntax=docker/dockerfile:1.7");
149+expect(dockerfile).toMatch(/^FROM \S+@sha256:[a-f0-9]{64}$/m);
150+expect(dockerfile).toContain("apt-get");
151+expect(dockerfile).toContain("bash");
152+expect(dockerfile).toContain("ca-certificates");
153+expect(dockerfile).toContain("curl");
154+expect(dockerfile).toContain(
155+"COPY install-sh-common/version-parse.sh /usr/local/install-sh-common/version-parse.sh",
156+);
157+expect(dockerfile).toContain(`COPY --chmod=755 ${runnerPath} ${entrypoint}`);
158+expect(dockerfile).toContain(`ENTRYPOINT ["${entrypoint}"]`);
159+return dockerfile;
160+}
161+138162async function waitForCondition(
139163predicate: () => boolean,
140164label: string,
@@ -269,6 +293,35 @@ describe("test-install-sh-docker", () => {
269293);
270294});
271295296+it("keeps install-sh Dockerfiles wired to their runner contracts", () => {
297+const e2eDockerfile = expectInstallDockerfileContract(
298+INSTALL_E2E_DOCKERFILE_PATH,
299+"install-sh-e2e/run.sh",
300+"/usr/local/bin/openclaw-install-e2e",
301+);
302+const smokeDockerfile = expectInstallDockerfileContract(
303+SMOKE_DOCKERFILE_PATH,
304+"install-sh-smoke/run.sh",
305+"/usr/local/bin/openclaw-install-smoke",
306+);
307+const nonrootDockerfile = expectInstallDockerfileContract(
308+NONROOT_DOCKERFILE_PATH,
309+"install-sh-nonroot/run.sh",
310+"/usr/local/bin/openclaw-install-nonroot",
311+);
312+313+expect(e2eDockerfile).toContain("USER appuser");
314+expect(smokeDockerfile).toContain(
315+"COPY install-sh-common/cli-verify.sh /usr/local/install-sh-common/cli-verify.sh",
316+);
317+expect(nonrootDockerfile).toContain(
318+"COPY install-sh-common/cli-verify.sh /usr/local/install-sh-common/cli-verify.sh",
319+);
320+expect(nonrootDockerfile).toContain("USER app");
321+expect(nonrootDockerfile).toContain("WORKDIR /home/app");
322+expect(nonrootDockerfile).toContain("NPM_CONFIG_UPDATE_NOTIFIER=false");
323+});
324+272325it("can reuse dist from the already-built root Docker smoke image", () => {
273326const script = readFileSync(SCRIPT_PATH, "utf8");
274327const dockerfile = readFileSync("Dockerfile", "utf8");
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。