From c867ecb1361e9bf2eea9cb04939987e97074bc4e Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Tue, 26 May 2026 19:29:40 +0200 Subject: [PATCH] fix(ci): kill wedged checkout fetches --- .../workflows/ci-build-artifacts-testbox.yml | 2 +- .github/workflows/ci-check-testbox.yml | 2 +- .github/workflows/ci.yml | 20 ++++++++--------- CHANGELOG.md | 1 + test/scripts/ci-workflow-guards.test.ts | 22 +++++++++++++++++++ 5 files changed, 35 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci-build-artifacts-testbox.yml b/.github/workflows/ci-build-artifacts-testbox.yml index b0fb5b288f6..d6e314c3000 100644 --- a/.github/workflows/ci-build-artifacts-testbox.yml +++ b/.github/workflows/ci-build-artifacts-testbox.yml @@ -61,7 +61,7 @@ jobs: git -C "$workdir" remote add origin "https://github.com/${CHECKOUT_REPO}" git -C "$workdir" config gc.auto 0 - timeout --signal=TERM 30s git -C "$workdir" \ + timeout --signal=TERM --kill-after=10s 30s git -C "$workdir" \ -c protocol.version=2 \ -c "http.extraheader=AUTHORIZATION: basic ${auth_header}" \ fetch --no-tags --prune --no-recurse-submodules --depth=1 origin \ diff --git a/.github/workflows/ci-check-testbox.yml b/.github/workflows/ci-check-testbox.yml index 066fdbf9fd6..09d8cda8518 100644 --- a/.github/workflows/ci-check-testbox.yml +++ b/.github/workflows/ci-check-testbox.yml @@ -59,7 +59,7 @@ jobs: git -C "$workdir" remote add origin "https://github.com/${CHECKOUT_REPO}" git -C "$workdir" config gc.auto 0 - timeout --signal=TERM 30s git -C "$workdir" \ + timeout --signal=TERM --kill-after=10s 30s git -C "$workdir" \ -c protocol.version=2 \ -c "http.extraheader=AUTHORIZATION: basic ${auth_header}" \ fetch --no-tags --prune --no-recurse-submodules --depth=1 origin \ diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fe783579028..a23006b4d2e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -435,7 +435,7 @@ jobs: git -C "$workdir" remote add origin "https://github.com/${CHECKOUT_REPO}.git" git -C "$workdir" config gc.auto 0 - timeout --signal=TERM 30s git -C "$workdir" \ + timeout --signal=TERM --kill-after=10s 30s git -C "$workdir" \ -c protocol.version=2 \ fetch --no-tags --prune --no-recurse-submodules --depth=1 origin \ "+${CHECKOUT_SHA}:refs/remotes/origin/ci-target" || return 1 @@ -659,7 +659,7 @@ jobs: git -C "$workdir" remote add origin "https://github.com/${CHECKOUT_REPO}.git" git -C "$workdir" config gc.auto 0 - timeout --signal=TERM 30s git -C "$workdir" \ + timeout --signal=TERM --kill-after=10s 30s git -C "$workdir" \ -c protocol.version=2 \ fetch --no-tags --prune --no-recurse-submodules --depth=1 origin \ "+${CHECKOUT_SHA}:refs/remotes/origin/ci-target" || return 1 @@ -745,7 +745,7 @@ jobs: git -C "$workdir" remote add origin "https://github.com/${CHECKOUT_REPO}.git" git -C "$workdir" config gc.auto 0 - timeout --signal=TERM 30s git -C "$workdir" \ + timeout --signal=TERM --kill-after=10s 30s git -C "$workdir" \ -c protocol.version=2 \ fetch --no-tags --prune --no-recurse-submodules --depth=1 origin \ "+${CHECKOUT_SHA}:refs/remotes/origin/ci-target" || return 1 @@ -825,7 +825,7 @@ jobs: git -C "$workdir" remote add origin "https://github.com/${CHECKOUT_REPO}.git" git -C "$workdir" config gc.auto 0 - timeout --signal=TERM 30s git -C "$workdir" \ + timeout --signal=TERM --kill-after=10s 30s git -C "$workdir" \ -c protocol.version=2 \ fetch --no-tags --prune --no-recurse-submodules --depth=1 origin \ "+${CHECKOUT_SHA}:refs/remotes/origin/ci-target" || return 1 @@ -902,7 +902,7 @@ jobs: git -C "$workdir" remote add origin "https://github.com/${CHECKOUT_REPO}.git" git -C "$workdir" config gc.auto 0 - timeout --signal=TERM 30s git -C "$workdir" \ + timeout --signal=TERM --kill-after=10s 30s git -C "$workdir" \ -c protocol.version=2 \ fetch --no-tags --prune --no-recurse-submodules --depth=1 origin \ "+${CHECKOUT_SHA}:refs/remotes/origin/ci-target" || return 1 @@ -977,7 +977,7 @@ jobs: git -C "$workdir" remote add origin "https://github.com/${CHECKOUT_REPO}.git" git -C "$workdir" config gc.auto 0 - timeout --signal=TERM 30s git -C "$workdir" \ + timeout --signal=TERM --kill-after=10s 30s git -C "$workdir" \ -c protocol.version=2 \ fetch --no-tags --prune --no-recurse-submodules --depth=1 origin \ "+${CHECKOUT_SHA}:refs/remotes/origin/ci-target" || return 1 @@ -1099,7 +1099,7 @@ jobs: git -C "$workdir" remote add origin "https://github.com/${CHECKOUT_REPO}.git" git -C "$workdir" config gc.auto 0 - timeout --signal=TERM 30s git -C "$workdir" \ + timeout --signal=TERM --kill-after=10s 30s git -C "$workdir" \ -c protocol.version=2 \ fetch --no-tags --prune --no-recurse-submodules --depth=1 origin \ "+${CHECKOUT_SHA}:refs/remotes/origin/ci-target" || return 1 @@ -1229,7 +1229,7 @@ jobs: git -C "$workdir" remote add origin "https://github.com/${CHECKOUT_REPO}.git" git -C "$workdir" config gc.auto 0 - timeout --signal=TERM 30s git -C "$workdir" \ + timeout --signal=TERM --kill-after=10s 30s git -C "$workdir" \ -c protocol.version=2 \ fetch --no-tags --prune --no-recurse-submodules --depth=1 origin \ "+${CHECKOUT_SHA}:refs/remotes/origin/ci-target" || return 1 @@ -1378,7 +1378,7 @@ jobs: git -C "$workdir" remote add origin "https://github.com/${CHECKOUT_REPO}.git" git -C "$workdir" config gc.auto 0 - timeout --signal=TERM 30s git -C "$workdir" \ + timeout --signal=TERM --kill-after=10s 30s git -C "$workdir" \ -c protocol.version=2 \ fetch --no-tags --prune --no-recurse-submodules --depth=1 origin \ "+${CHECKOUT_SHA}:refs/remotes/origin/ci-target" || return 1 @@ -1748,7 +1748,7 @@ jobs: git -C "$workdir" remote add origin "https://github.com/${CHECKOUT_REPO}.git" git -C "$workdir" config gc.auto 0 - timeout --signal=TERM 30s git -C "$workdir" \ + timeout --signal=TERM --kill-after=10s 30s git -C "$workdir" \ -c protocol.version=2 \ fetch --no-tags --prune --no-recurse-submodules --depth=1 origin \ "+${CHECKOUT_SHA}:refs/remotes/origin/ci-target" || return 1 diff --git a/CHANGELOG.md b/CHANGELOG.md index 510663963d9..62ebb09db5f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ Docs: https://docs.openclaw.ai - Telegram: treat `/command@TargetBot` bot-command entities as explicit mentions for the addressed bot so `requireMention` groups no longer drop targeted commands or captions. Fixes #84462. (#86553) Thanks @luoyanglang. - CI: bound Docker/Bash E2E tarball npm installs with `OPENCLAW_E2E_NPM_INSTALL_TIMEOUT` so package, onboarding, plugin, and upgrade lanes fail instead of hanging on a stuck npm install. - CI: keep `OPENCLAW_TESTBOX=1 pnpm check:changed` delegating to Blacksmith Testbox through Crabbox without forwarding local Testbox or worker env into the remote command. +- CI: send KILL after the TERM grace period for manual checkout fetch timeouts so stuck Testbox and workflow checkout retries cannot hang behind a wedged `git fetch`. - iMessage: thread current channel/account inbound attachment roots into the image tool so iMessage-saved attachments under `~/Library/Messages/Attachments` (including the wildcard `/Users/*/Library/Messages/Attachments` root) are read through the existing inbound path policy instead of being rejected as `path-not-allowed`. Literal `localRoots` stays workspace-scoped. Fixes #30170. (#86569) - QQ Bot: respect `OPENCLAW_HOME` for outbound media path resolution so `` sends no longer silently fail when `HOME` and `OPENCLAW_HOME` differ (Docker / multi-user hosts). Persisted QQ Bot data (sessions, known users, refs) stays anchored on the OS home for upgrade compatibility. Fixes #83562. Thanks @sliverp. - Update: report the primary malformed `openclaw.extensions` payload error without adding a duplicate missing-main diagnostic. (#86596) Thanks @ferminquant. diff --git a/test/scripts/ci-workflow-guards.test.ts b/test/scripts/ci-workflow-guards.test.ts index 3b9e0173f05..867db8e7d00 100644 --- a/test/scripts/ci-workflow-guards.test.ts +++ b/test/scripts/ci-workflow-guards.test.ts @@ -2,6 +2,28 @@ import { readFileSync } from "node:fs"; import { describe, expect, it } from "vitest"; describe("ci workflow guards", () => { + it("kills timed manual checkout fetches after the grace period", () => { + const workflowPaths = [ + ".github/workflows/ci.yml", + ".github/workflows/ci-check-testbox.yml", + ".github/workflows/ci-build-artifacts-testbox.yml", + ]; + + for (const workflowPath of workflowPaths) { + const workflow = readFileSync(workflowPath, "utf8"); + const fetchTimeouts = workflow.match( + /timeout --signal=TERM[^\n]* 30s git -C "\$workdir"/g, + ); + + expect(fetchTimeouts?.length, workflowPath).toBeGreaterThan(0); + expect(fetchTimeouts, workflowPath).toEqual( + fetchTimeouts?.map( + () => 'timeout --signal=TERM --kill-after=10s 30s git -C "$workdir"', + ), + ); + } + }); + it("runs dependency policy guards in PR CI preflight", () => { const workflow = readFileSync(".github/workflows/ci.yml", "utf8"); const preflightGuards = workflow.slice(