fix(e2e): suppress update checks inside Docker E2E containers (#129931)

* fix(e2e): suppress update checks inside Docker E2E containers

The runner's CI variable does not cross into `docker run`, so containers kept
reporting daily update checks and drowned real operators in the telemetry
aggregates. Inject the existing suppression switch from the shared helper so
every lane inherits it; callers that exercise update behavior keep their own
value.

* test(e2e): record the injected suppression in docker run contracts
This commit is contained in:
Peter Steinberger
2026-08-26 00:14:40 -07:00
committed by GitHub
parent 8c203185d7
commit 10108ca0f2
4 changed files with 110 additions and 11 deletions
+40
View File
@@ -241,6 +241,7 @@ docker_e2e_resolve_pids_limit() {
docker_e2e_docker_run_resource_args() {
DOCKER_E2E_RUN_RESOURCE_ARGS=()
docker_e2e_append_update_check_suppression "$@"
if docker_e2e_resource_limits_disabled; then
return 0
fi
@@ -260,6 +261,45 @@ docker_e2e_docker_run_resource_args() {
pids_limit="$(docker_e2e_resolve_pids_limit "$pids_limit")" || return $?
DOCKER_E2E_RUN_RESOURCE_ARGS+=(--pids-limit "$pids_limit")
fi
}
docker_e2e_run_env_present() {
local name="$1"
shift
local arg
local expect_value=0
for arg in "$@"; do
if [ "$expect_value" = 1 ]; then
expect_value=0
case "$arg" in
"$name" | "$name"=*)
return 0
;;
esac
continue
fi
case "$arg" in
-e | --env)
expect_value=1
;;
-e"$name" | -e"$name"=* | --env="$name" | --env="$name"=*)
return 0
;;
esac
done
return 1
}
# CI containers are not installations. The runner's own CI variable does not
# cross into `docker run`, so without this every E2E container reports a daily
# update check and drowns real operators in the telemetry aggregates. Callers
# that exercise update behavior pass their own value and keep it.
docker_e2e_append_update_check_suppression() {
if docker_e2e_run_env_present OPENCLAW_NO_AUTO_UPDATE "$@"; then
return 0
fi
DOCKER_E2E_RUN_RESOURCE_ARGS+=(-e OPENCLAW_NO_AUTO_UPDATE=1)
}
docker_e2e_container_running() {
+10 -10
View File
@@ -2131,7 +2131,7 @@ set -e
stderr="$(<"$TMPDIR/stderr")"
[[ "$status" = "13" ]]
[[ "$stderr" = *"timeout command not found; using Node watchdog for Docker command timeout 7s"* ]]
[[ "$(<"$TMPDIR/docker-seen")" = "run --memory 8g --cpus 16 --pids-limit 2048 -i demo|payload" ]]
[[ "$(<"$TMPDIR/docker-seen")" = "run -e OPENCLAW_NO_AUTO_UPDATE=1 --memory 8g --cpus 16 --pids-limit 2048 -i demo|payload" ]]
`;
execFileSync("bash", ["-lc", script], { encoding: "utf8" });
@@ -2169,11 +2169,11 @@ OPENCLAW_DOCKER_E2E_AVAILABLE_CPUS=8 OPENCLAW_DOCKER_E2E_MEMORY=12g OPENCLAW_DOC
docker_e2e_docker_cmd run --memory 2g --cpus 3 --pids-limit 99 demo
OPENCLAW_DOCKER_E2E_DISABLE_RESOURCE_LIMITS=1 docker_e2e_docker_cmd run demo
[[ "$(sed -n '1p' "$TMPDIR/docker-seen")" = "run --memory 8g --cpus 16 --pids-limit 2048 demo" ]]
[[ "$(sed -n '2p' "$TMPDIR/docker-seen")" = "run --memory 12g --cpus 4 --pids-limit 512 demo" ]]
[[ "$(sed -n '3p' "$TMPDIR/docker-seen")" = "run --memory 12g --cpus 8 --pids-limit 512 demo" ]]
[[ "$(sed -n '4p' "$TMPDIR/docker-seen")" = "run --memory 2g --cpus 3 --pids-limit 99 demo" ]]
[[ "$(sed -n '5p' "$TMPDIR/docker-seen")" = "run demo" ]]
[[ "$(sed -n '1p' "$TMPDIR/docker-seen")" = "run -e OPENCLAW_NO_AUTO_UPDATE=1 --memory 8g --cpus 16 --pids-limit 2048 demo" ]]
[[ "$(sed -n '2p' "$TMPDIR/docker-seen")" = "run -e OPENCLAW_NO_AUTO_UPDATE=1 --memory 12g --cpus 4 --pids-limit 512 demo" ]]
[[ "$(sed -n '3p' "$TMPDIR/docker-seen")" = "run -e OPENCLAW_NO_AUTO_UPDATE=1 --memory 12g --cpus 8 --pids-limit 512 demo" ]]
[[ "$(sed -n '4p' "$TMPDIR/docker-seen")" = "run -e OPENCLAW_NO_AUTO_UPDATE=1 --memory 2g --cpus 3 --pids-limit 99 demo" ]]
[[ "$(sed -n '5p' "$TMPDIR/docker-seen")" = "run -e OPENCLAW_NO_AUTO_UPDATE=1 demo" ]]
`;
execFileSync("bash", ["-lc", script], { encoding: "utf8" });
@@ -2328,8 +2328,8 @@ source "$ROOT_DIR/scripts/lib/docker-e2e-container.sh"
docker_e2e_docker_run_cmd run demo
[[ "$(<"$TMPDIR/timeout-seen")" = "gtimeout:--kill-after=30s 13s|docker run --memory 8g --cpus 8 --pids-limit 2048 demo" ]]
[[ "$(<"$TMPDIR/docker-seen")" = "run --memory 8g --cpus 8 --pids-limit 2048 demo" ]]
[[ "$(<"$TMPDIR/timeout-seen")" = "gtimeout:--kill-after=30s 13s|docker run -e OPENCLAW_NO_AUTO_UPDATE=1 --memory 8g --cpus 8 --pids-limit 2048 demo" ]]
[[ "$(<"$TMPDIR/docker-seen")" = "run -e OPENCLAW_NO_AUTO_UPDATE=1 --memory 8g --cpus 8 --pids-limit 2048 demo" ]]
`;
execFileSync("bash", ["-lc", script], { encoding: "utf8" });
@@ -2401,8 +2401,8 @@ source "$ROOT_DIR/scripts/lib/docker-e2e-package.sh"
docker_e2e_docker_run_cmd run demo
[[ "$(<"$TMPDIR/timeout-seen")" = "gtimeout:--kill-after=30s 15s|docker run --memory 8g --cpus 8 --pids-limit 2048 demo" ]]
[[ "$(<"$TMPDIR/docker-seen")" = "run --memory 8g --cpus 8 --pids-limit 2048 demo" ]]
[[ "$(<"$TMPDIR/timeout-seen")" = "gtimeout:--kill-after=30s 15s|docker run -e OPENCLAW_NO_AUTO_UPDATE=1 --memory 8g --cpus 8 --pids-limit 2048 demo" ]]
[[ "$(<"$TMPDIR/docker-seen")" = "run -e OPENCLAW_NO_AUTO_UPDATE=1 --memory 8g --cpus 8 --pids-limit 2048 demo" ]]
`;
execFileSync("bash", ["-lc", script], { encoding: "utf8" });
@@ -0,0 +1,56 @@
// Covers the Docker E2E guard that keeps continuous-integration containers out
// of the public telemetry aggregates.
import { execFileSync } from "node:child_process";
import { describe, expect, it } from "vitest";
const CONTAINER_HELPER_PATH = "scripts/lib/docker-e2e-container.sh";
/** Returns the docker run arguments the helper injects for the given caller args. */
function injectedRunArgs(callerArgs: string[], env: Record<string, string> = {}): string[] {
const script = `
set -euo pipefail
source ${CONTAINER_HELPER_PATH}
docker_e2e_docker_run_resource_args ${callerArgs.map((arg) => `'${arg}'`).join(" ")}
printf '%s\\n' "\${DOCKER_E2E_RUN_RESOURCE_ARGS[@]}"
`;
return execFileSync("bash", ["-lc", script], {
encoding: "utf8",
env: { ...process.env, ...env },
})
.split("\n")
.filter(Boolean);
}
describe("docker e2e update-check suppression", () => {
it("suppresses automatic update checks inside every container", () => {
const args = injectedRunArgs(["-d", "--name", "openclaw-e2e", "openclaw:test"]);
expect(args).toContain("-e");
expect(args).toContain("OPENCLAW_NO_AUTO_UPDATE=1");
});
it("still suppresses when resource limits are disabled", () => {
const args = injectedRunArgs(["-d", "openclaw:test"], {
OPENCLAW_DOCKER_E2E_DISABLE_RESOURCE_LIMITS: "1",
});
expect(args).toEqual(["-e", "OPENCLAW_NO_AUTO_UPDATE=1"]);
});
it("keeps a caller-provided value so update lanes stay in control", () => {
for (const callerArgs of [
["-e", "OPENCLAW_NO_AUTO_UPDATE=0", "openclaw:test"],
["-eOPENCLAW_NO_AUTO_UPDATE=0", "openclaw:test"],
["--env", "OPENCLAW_NO_AUTO_UPDATE", "openclaw:test"],
["--env=OPENCLAW_NO_AUTO_UPDATE=0", "openclaw:test"],
]) {
expect(injectedRunArgs(callerArgs)).not.toContain("OPENCLAW_NO_AUTO_UPDATE=1");
}
});
it("does not mistake an image or unrelated flag value for the suppression variable", () => {
const args = injectedRunArgs(["-e", "SOMETHING_ELSE=1", "OPENCLAW_NO_AUTO_UPDATE", "-d"]);
expect(args).toContain("OPENCLAW_NO_AUTO_UPDATE=1");
});
});
+4 -1
View File
@@ -1,7 +1,10 @@
// Vitest tooling Docker config isolates the slow Docker helper contract tests.
import { createScopedVitestConfig } from "./vitest.scoped-config.ts";
export const toolingDockerTestFiles = ["test/scripts/docker-build-helper.test.ts"];
export const toolingDockerTestFiles = [
"test/scripts/docker-build-helper.test.ts",
"test/scripts/docker-e2e-update-suppression.test.ts",
];
export function createToolingDockerVitestConfig(env?: Record<string, string | undefined>) {
return createScopedVitestConfig(toolingDockerTestFiles, {