diff --git a/scripts/docker/setup.sh b/scripts/docker/setup.sh index 8a3bd076034..5551e5b8cc3 100755 --- a/scripts/docker/setup.sh +++ b/scripts/docker/setup.sh @@ -14,6 +14,7 @@ DOCKER_SOCKET_PATH="${OPENCLAW_DOCKER_SOCKET:-}" TIMEZONE="${OPENCLAW_TZ:-}" RAW_SKIP_ONBOARDING="${OPENCLAW_SKIP_ONBOARDING:-}" SKIP_ONBOARDING="" +DOCKER_PULL_TIMEOUT="${OPENCLAW_DOCKER_SETUP_PULL_TIMEOUT:-600s}" fail() { echo "ERROR: $*" >&2 @@ -33,6 +34,15 @@ run_docker_build() { docker_build_exec "$@" } +run_docker_pull() { + local image="$1" + if command -v timeout >/dev/null 2>&1; then + timeout "$DOCKER_PULL_TIMEOUT" docker pull "$image" + return + fi + docker pull "$image" +} + is_truthy_value() { local raw="${1:-}" raw="$(printf '%s' "$raw" | tr '[:upper:]' '[:lower:]')" @@ -534,7 +544,7 @@ if [[ "$IMAGE_NAME" == "openclaw:local" ]]; then "$ROOT_DIR" else echo "==> Pulling Docker image: $IMAGE_NAME" - if ! docker pull "$IMAGE_NAME"; then + if ! run_docker_pull "$IMAGE_NAME"; then echo "ERROR: Failed to pull image $IMAGE_NAME. Please check the image name and your access permissions." >&2 exit 1 fi diff --git a/test/scripts/test-install-sh-docker.test.ts b/test/scripts/test-install-sh-docker.test.ts index 2899b783186..6741beef85a 100644 --- a/test/scripts/test-install-sh-docker.test.ts +++ b/test/scripts/test-install-sh-docker.test.ts @@ -106,6 +106,16 @@ describe("test-install-sh-docker", () => { expect(script).toContain('--build-arg "OPENCLAW_INSTALL_BROWSER=${OPENCLAW_INSTALL_BROWSER}"'); }); + it("bounds Docker setup image pulls", () => { + const script = readFileSync(DOCKER_SETUP_PATH, "utf8"); + + expect(script).toContain('DOCKER_PULL_TIMEOUT="${OPENCLAW_DOCKER_SETUP_PULL_TIMEOUT:-600s}"'); + expect(script).toContain("run_docker_pull()"); + expect(script).toContain('timeout "$DOCKER_PULL_TIMEOUT" docker pull "$image"'); + expect(script).toContain('run_docker_pull "$IMAGE_NAME"'); + expect(script).not.toContain('docker pull "$IMAGE_NAME"'); + }); + it("passes image-scoped pip packages through Docker and Podman setup", () => { const dockerSetup = readFileSync(DOCKER_SETUP_PATH, "utf8"); const podmanSetup = readFileSync(PODMAN_SETUP_PATH, "utf8");