From a7b52ecad90bd225be054dd62d44a29bffc07b62 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Fri, 19 Jun 2026 01:08:42 +0200 Subject: [PATCH] fix(e2e): validate cleanup log limits --- scripts/docker/cleanup-smoke/run.sh | 24 ++++++--- test/scripts/docker-build-helper.test.ts | 68 ++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 6 deletions(-) diff --git a/scripts/docker/cleanup-smoke/run.sh b/scripts/docker/cleanup-smoke/run.sh index 59e48492e172..2fcc3374f92d 100755 --- a/scripts/docker/cleanup-smoke/run.sh +++ b/scripts/docker/cleanup-smoke/run.sh @@ -6,14 +6,24 @@ cd /repo export OPENCLAW_STATE_DIR="/tmp/openclaw-test" export OPENCLAW_CONFIG_PATH="${OPENCLAW_STATE_DIR}/openclaw.json" +read_positive_int_env() { + local name="${1:?missing environment variable name}" + local fallback="${2:?missing fallback value}" + local value="${!name-}" + if [ -z "${!name+x}" ]; then + value="$fallback" + fi + if [[ ! "$value" =~ ^[0-9]+$ ]] || (( 10#$value < 1 )); then + echo "invalid $name: $value" >&2 + return 2 + fi + printf '%s\n' "$((10#$value))" +} + print_log_tail() { local log_file="$1" - local max_bytes="${OPENCLAW_CLEANUP_SMOKE_LOG_PRINT_BYTES:-65536}" - if ! [[ "$max_bytes" =~ ^[0-9]+$ ]] || [ "$max_bytes" -lt 1 ]; then - max_bytes="65536" - else - max_bytes="$((10#$max_bytes))" - fi + local max_bytes + max_bytes="$(read_positive_int_env OPENCLAW_CLEANUP_SMOKE_LOG_PRINT_BYTES 65536)" || return $? if [ ! -f "$log_file" ]; then return 0 fi @@ -31,6 +41,8 @@ print_log_tail() { tail -c "$max_bytes" "$log_file" } +read_positive_int_env OPENCLAW_CLEANUP_SMOKE_LOG_PRINT_BYTES 65536 >/dev/null + echo "==> Build" if ! pnpm build >/tmp/openclaw-cleanup-build.log 2>&1; then print_log_tail /tmp/openclaw-cleanup-build.log diff --git a/test/scripts/docker-build-helper.test.ts b/test/scripts/docker-build-helper.test.ts index 570c9c0bb2ee..8ef2b0c9dc4f 100644 --- a/test/scripts/docker-build-helper.test.ts +++ b/test/scripts/docker-build-helper.test.ts @@ -124,6 +124,17 @@ function shellQuote(value: string): string { return `'${value.replace(/'/gu, `'\\''`)}'`; } +function cleanupSmokeLogTailHelpers(): string { + const script = readFileSync(CLEANUP_SMOKE_RUN_PATH, "utf8"); + const match = script.match( + /(read_positive_int_env\(\) \{[\s\S]*?\n\}\n\nprint_log_tail\(\) \{[\s\S]*?\n\})\n\nread_positive_int_env/u, + ); + if (!match) { + throw new Error("cleanup smoke log helpers were not found"); + } + return match[1]; +} + function runCleanupDefaultPlatform(env: Record, hostArch: string): string { const script = readFileSync(CLEANUP_DOCKER_SMOKE_PATH, "utf8"); const match = script.match(/(resolve_default_cleanup_platform\(\) \{[\s\S]*?\n\})\n\nPLATFORM=/u); @@ -228,10 +239,67 @@ docker_build_transient_failure "$LOG_PATH" const cleanupRun = readFileSync(CLEANUP_SMOKE_RUN_PATH, "utf8"); expect(cleanupRun).toContain("OPENCLAW_CLEANUP_SMOKE_LOG_PRINT_BYTES"); + expect(cleanupRun).toContain( + "read_positive_int_env OPENCLAW_CLEANUP_SMOKE_LOG_PRINT_BYTES 65536 >/dev/null", + ); expect(cleanupRun.match(/print_log_tail \/tmp\/openclaw-cleanup-/g)).toHaveLength(3); expect(cleanupRun).not.toContain("cat /tmp/openclaw-cleanup-"); }); + it("rejects invalid cleanup-smoke log byte limits", () => { + const workDir = mkdtempSync(join(tmpdir(), "openclaw-cleanup-smoke-log-invalid-")); + + try { + const logPath = join(workDir, "cleanup.log"); + writeFileSync(logPath, "cleanup output\n"); + const script = ` +set -euo pipefail +LOG_PATH=${shellQuote(logPath)} +export OPENCLAW_CLEANUP_SMOKE_LOG_PRINT_BYTES=64kb + +${cleanupSmokeLogTailHelpers()} + +print_log_tail "$LOG_PATH" +`; + + const result = spawnSync("bash", ["-lc", script], { encoding: "utf8" }); + + expect(result.status).toBe(2); + expect(result.stderr).toContain("invalid OPENCLAW_CLEANUP_SMOKE_LOG_PRINT_BYTES: 64kb"); + expect(result.stdout).toBe(""); + } finally { + rmSync(workDir, { recursive: true, force: true }); + } + }); + + it("normalizes zero-padded cleanup-smoke log byte limits", () => { + const workDir = mkdtempSync(join(tmpdir(), "openclaw-cleanup-smoke-log-tail-")); + + try { + const logPath = join(workDir, "cleanup.log"); + writeFileSync(logPath, "old-cleanup-output-recent\n"); + const script = ` +set -euo pipefail +LOG_PATH=${shellQuote(logPath)} +export OPENCLAW_CLEANUP_SMOKE_LOG_PRINT_BYTES=0008 + +${cleanupSmokeLogTailHelpers()} + +print_log_tail "$LOG_PATH" +`; + + const result = spawnSync("bash", ["-lc", script], { encoding: "utf8" }); + + expect(result.status).toBe(0); + expect(result.stdout).toContain("truncated: showing last 8"); + expect(result.stdout).toContain("-recent\n"); + expect(result.stdout).not.toContain("old-cleanup-output"); + expect(result.stderr).toBe(""); + } finally { + rmSync(workDir, { recursive: true, force: true }); + } + }); + it("prints Docker MCP client logs through the bounded helper", () => { for (const scriptPath of BOUNDED_CLIENT_LOG_DOCKER_E2E_SCRIPTS) { const script = readFileSync(scriptPath, "utf8");