From 6883f688e8da11481a5d0f91dfab4e4ba6e9f871 Mon Sep 17 00:00:00 2001 From: Vignesh Natarajan Date: Sat, 28 Mar 2026 20:45:46 -0700 Subject: [PATCH] Docker setup: force BuildKit for local builds --- CHANGELOG.md | 1 + scripts/docker/setup.sh | 10 ++++++++-- src/docker-setup.e2e.test.ts | 19 ++++++++++++++++++- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a428823d0b3..7bddc5a16f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ Docs: https://docs.openclaw.ai - TUI/chat: keep optimistic outbound user messages visible during active runs by deferring local-run binding until the first gateway chat event reveals the real run id, preventing premature history reloads from wiping pending local sends. (#54722) Thanks @seanturner001. - TUI/model picker: keep searchable `/model` and `/models` input mode from hijacking `j`/`k` as navigation keys, and harden width bounds under `m`-filtered model lists so search no longer crashes on long rows. (#30156) Thanks @briannicholls. - Agents/Kimi: preserve already-valid Anthropic-compatible tool call argument objects while still clearing cached repairs when later trailing junk exceeds the repair allowance. (#54491) Thanks @yuanaichi. +- Docker/setup: force BuildKit for local image builds (including sandbox image builds) so `./docker-setup.sh` no longer fails on `RUN --mount=...` when hosts default to Docker's legacy builder. (#56681) Thanks @zhanghui-china. ## 2026.3.28 diff --git a/scripts/docker/setup.sh b/scripts/docker/setup.sh index e2b5b03a72b..2be33bdd2f5 100755 --- a/scripts/docker/setup.sh +++ b/scripts/docker/setup.sh @@ -24,6 +24,12 @@ require_cmd() { fi } +run_docker_build() { + # Dockerfile uses BuildKit-only syntax (RUN --mount=type=cache). Force + # BuildKit so hosts defaulting to the legacy builder do not fail. + DOCKER_BUILDKIT=1 docker build "$@" +} + is_truthy_value() { local raw="${1:-}" raw="$(printf '%s' "$raw" | tr '[:upper:]' '[:lower:]')" @@ -464,7 +470,7 @@ upsert_env "$ENV_FILE" \ if [[ "$IMAGE_NAME" == "openclaw:local" ]]; then echo "==> Building Docker image: $IMAGE_NAME" - docker build \ + run_docker_build \ --build-arg "OPENCLAW_DOCKER_APT_PACKAGES=${OPENCLAW_DOCKER_APT_PACKAGES}" \ --build-arg "OPENCLAW_EXTENSIONS=${OPENCLAW_EXTENSIONS}" \ --build-arg "OPENCLAW_INSTALL_DOCKER_CLI=${OPENCLAW_INSTALL_DOCKER_CLI:-}" \ @@ -536,7 +542,7 @@ if [[ -n "$SANDBOX_ENABLED" ]]; then # Build sandbox image if Dockerfile.sandbox exists. if [[ -f "$ROOT_DIR/Dockerfile.sandbox" ]]; then echo "Building sandbox image: openclaw-sandbox:bookworm-slim" - docker build \ + run_docker_build \ -t "openclaw-sandbox:bookworm-slim" \ -f "$ROOT_DIR/Dockerfile.sandbox" \ "$ROOT_DIR" diff --git a/src/docker-setup.e2e.test.ts b/src/docker-setup.e2e.test.ts index f4c7f8d788e..97b08e34ce9 100644 --- a/src/docker-setup.e2e.test.ts +++ b/src/docker-setup.e2e.test.ts @@ -28,7 +28,7 @@ if [[ "\${1:-}" == "build" ]]; then echo "build-fail $*" >>"$log" exit 1 fi - echo "build $*" >>"$log" + echo "build DOCKER_BUILDKIT=\${DOCKER_BUILDKIT:-} $*" >>"$log" exit 0 fi if [[ "\${1:-}" == "compose" ]]; then @@ -258,6 +258,23 @@ describe("scripts/docker/setup.sh", () => { ); }); + it("forces BuildKit for local and sandbox docker builds", async () => { + const activeSandbox = requireSandbox(sandbox); + await writeFile(join(activeSandbox.rootDir, "Dockerfile.sandbox"), "FROM scratch\n"); + await resetDockerLog(activeSandbox); + + const result = runDockerSetup(activeSandbox, { + OPENCLAW_SANDBOX: "1", + }); + + expect(result.status).toBe(0); + const buildLines = (await readDockerLogLines(activeSandbox)).filter((line) => + line.startsWith("build "), + ); + expect(buildLines.length).toBeGreaterThanOrEqual(2); + expect(buildLines.every((line) => line.includes("DOCKER_BUILDKIT=1"))).toBe(true); + }); + it("precreates config identity dir for CLI device auth writes", async () => { const activeSandbox = requireSandbox(sandbox); const configDir = join(activeSandbox.rootDir, "config-identity");