From 955b4df0939f90b4b6de5e7e6f3149dd125e1e50 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Tue, 28 Apr 2026 23:54:38 +0100 Subject: [PATCH] fix(ci): stabilize full release validation --- .github/workflows/full-release-validation.yml | 17 ++++++++ .../openclaw-live-and-e2e-checks-reusable.yml | 4 ++ scripts/openclaw-cross-os-release-checks.ts | 41 +++++++++++++++++++ scripts/postinstall-bundled-plugins.mjs | 4 ++ scripts/stage-bundled-plugin-runtime-deps.mjs | 4 ++ scripts/test-live-cli-backend-docker.sh | 1 + scripts/test-live-codex-harness-docker.sh | 2 + src/infra/npm-install-env.ts | 4 ++ src/infra/tsdown-config.test.ts | 1 + src/plugins/bundled-runtime-deps.test.ts | 4 ++ .../openclaw-cross-os-release-checks.test.ts | 10 +++++ .../postinstall-bundled-plugins.test.ts | 4 ++ .../test-live-cli-backend-docker.test.ts | 1 + tsdown.config.ts | 1 + 14 files changed, 98 insertions(+) diff --git a/.github/workflows/full-release-validation.yml b/.github/workflows/full-release-validation.yml index 01d83d4b00f..4bdeb59268f 100644 --- a/.github/workflows/full-release-validation.yml +++ b/.github/workflows/full-release-validation.yml @@ -246,6 +246,23 @@ jobs: echo "- Target SHA: \`${TARGET_SHA}\`" } >> "$GITHUB_STEP_SUMMARY" + cancel_same_sha_push_ci() { + local run_ids run_id + run_ids="$( + gh run list --workflow ci.yml --limit 100 --json databaseId,event,headSha,status \ + --jq 'map(select(.event == "push" and .headSha == env.TARGET_SHA and (.status == "queued" or .status == "in_progress" or .status == "waiting" or .status == "pending"))) | .[].databaseId' + )" + if [[ -z "${run_ids// }" ]]; then + return 0 + fi + while IFS= read -r run_id; do + [[ -n "${run_id// }" ]] || continue + echo "Cancelling same-SHA push CI run ${run_id}; Full Release Validation dispatches the full manual CI child for ${TARGET_SHA}." + gh run cancel "$run_id" || gh api -X POST "repos/${GITHUB_REPOSITORY}/actions/runs/${run_id}/force-cancel" || true + done <<< "$run_ids" + } + + cancel_same_sha_push_ci dispatch_and_wait ci.yml -f target_ref="$TARGET_SHA" release_checks: diff --git a/.github/workflows/openclaw-live-and-e2e-checks-reusable.yml b/.github/workflows/openclaw-live-and-e2e-checks-reusable.yml index 8448323d832..499d1f78799 100644 --- a/.github/workflows/openclaw-live-and-e2e-checks-reusable.yml +++ b/.github/workflows/openclaw-live-and-e2e-checks-reusable.yml @@ -1893,6 +1893,7 @@ jobs: echo 'OPENCLAW_LIVE_CLI_BACKEND_RESUME_ARGS=["exec","resume","{sessionId}","-c","sandbox_mode=\"danger-full-access\"","--skip-git-repo-check"]' >> "$GITHUB_ENV" echo "OPENCLAW_LIVE_CLI_BACKEND_DEBUG=1" >> "$GITHUB_ENV" echo "OPENCLAW_CLI_BACKEND_LOG_OUTPUT=1" >> "$GITHUB_ENV" + echo "OPENCLAW_TEST_CONSOLE=1" >> "$GITHUB_ENV" echo "OPENCLAW_LIVE_CLI_BACKEND_USE_CI_SAFE_CODEX_CONFIG=1" >> "$GITHUB_ENV" ;; live-codex-harness-docker) @@ -1900,6 +1901,9 @@ jobs: # is currently stale, but the wrapper still supports codex-auth for # local maintainer reruns without changing Peter's flow. echo "OPENCLAW_LIVE_CODEX_HARNESS_AUTH=api-key" >> "$GITHUB_ENV" + echo "OPENCLAW_LIVE_CODEX_HARNESS_DEBUG=1" >> "$GITHUB_ENV" + echo "OPENCLAW_CLI_BACKEND_LOG_OUTPUT=1" >> "$GITHUB_ENV" + echo "OPENCLAW_TEST_CONSOLE=1" >> "$GITHUB_ENV" ;; live-acp-bind-docker) if [[ -n "${GEMINI_API_KEY:-}" || -n "${GOOGLE_API_KEY:-}" ]]; then diff --git a/scripts/openclaw-cross-os-release-checks.ts b/scripts/openclaw-cross-os-release-checks.ts index 0c3506452be..f59df14e5aa 100644 --- a/scripts/openclaw-cross-os-release-checks.ts +++ b/scripts/openclaw-cross-os-release-checks.ts @@ -55,6 +55,20 @@ const providerConfig = { }, }; +const RELEASE_SMOKE_PLUGIN_ALLOWLIST_BASE = [ + "acpx", + "bonjour", + "browser", + "device-pair", + "memory-core", + "phone-control", + "talk-voice", +]; + +export function buildCrossOsReleaseSmokePluginAllowlist(providerMeta) { + return [...new Set([providerMeta.extensionId, ...RELEASE_SMOKE_PLUGIN_ALLOWLIST_BASE])]; +} + const PACKAGE_DIST_INVENTORY_RELATIVE_PATH = "dist/postinstall-inventory.json"; const OMITTED_QA_EXTENSION_PREFIXES = [ "dist/extensions/qa-channel/", @@ -1844,6 +1858,20 @@ async function runInstalledModelsSet(params) { logPath: params.logPath, timeoutMs: 2 * 60 * 1000, }); + await runInstalledCli({ + cliPath: params.cliPath, + args: [ + "config", + "set", + "plugins.allow", + JSON.stringify(buildCrossOsReleaseSmokePluginAllowlist(params.providerConfig)), + "--strict-json", + ], + cwd: params.cwd, + env: params.env, + logPath: params.logPath, + timeoutMs: 2 * 60 * 1000, + }); await runInstalledCli({ cliPath: params.cliPath, args: ["config", "set", "agents.defaults.skipBootstrap", "true", "--strict-json"], @@ -2600,6 +2628,19 @@ async function runModelsSet(params) { logPath: params.logPath, timeoutMs: 2 * 60 * 1000, }); + await runOpenClaw({ + lane: params.lane, + env: params.env, + args: [ + "config", + "set", + "plugins.allow", + JSON.stringify(buildCrossOsReleaseSmokePluginAllowlist(params.providerConfig)), + "--strict-json", + ], + logPath: params.logPath, + timeoutMs: 2 * 60 * 1000, + }); await runOpenClaw({ lane: params.lane, env: params.env, diff --git a/scripts/postinstall-bundled-plugins.mjs b/scripts/postinstall-bundled-plugins.mjs index f3816d17ab0..0aa9112b72a 100644 --- a/scripts/postinstall-bundled-plugins.mjs +++ b/scripts/postinstall-bundled-plugins.mjs @@ -451,6 +451,10 @@ export function createBundledRuntimeDependencyInstallEnv(env = process.env) { return { ...createNestedNpmInstallEnv(env), npm_config_dry_run: "false", + npm_config_fetch_retries: env.npm_config_fetch_retries ?? "5", + npm_config_fetch_retry_maxtimeout: env.npm_config_fetch_retry_maxtimeout ?? "120000", + npm_config_fetch_retry_mintimeout: env.npm_config_fetch_retry_mintimeout ?? "10000", + npm_config_fetch_timeout: env.npm_config_fetch_timeout ?? "300000", npm_config_legacy_peer_deps: "true", npm_config_package_lock: "false", npm_config_save: "false", diff --git a/scripts/stage-bundled-plugin-runtime-deps.mjs b/scripts/stage-bundled-plugin-runtime-deps.mjs index ffe90358f70..ebb67293638 100644 --- a/scripts/stage-bundled-plugin-runtime-deps.mjs +++ b/scripts/stage-bundled-plugin-runtime-deps.mjs @@ -886,6 +886,10 @@ function runNpmInstall(params) { CI: "1", npm_config_audit: "false", npm_config_dry_run: "false", + npm_config_fetch_retries: process.env.npm_config_fetch_retries ?? "5", + npm_config_fetch_retry_maxtimeout: process.env.npm_config_fetch_retry_maxtimeout ?? "120000", + npm_config_fetch_retry_mintimeout: process.env.npm_config_fetch_retry_mintimeout ?? "10000", + npm_config_fetch_timeout: process.env.npm_config_fetch_timeout ?? "300000", npm_config_fund: "false", npm_config_legacy_peer_deps: "true", npm_config_loglevel: "error", diff --git a/scripts/test-live-cli-backend-docker.sh b/scripts/test-live-cli-backend-docker.sh index b6f8ae1ca7f..ba84c5cc013 100644 --- a/scripts/test-live-cli-backend-docker.sh +++ b/scripts/test-live-cli-backend-docker.sh @@ -471,6 +471,7 @@ DOCKER_RUN_ARGS=(docker run --rm -t \ -e OPENCLAW_LIVE_CLI_BACKEND=1 \ -e OPENCLAW_LIVE_CLI_BACKEND_DEBUG="${OPENCLAW_LIVE_CLI_BACKEND_DEBUG:-}" \ -e OPENCLAW_CLI_BACKEND_LOG_OUTPUT="${OPENCLAW_CLI_BACKEND_LOG_OUTPUT:-}" \ + -e OPENCLAW_TEST_CONSOLE="${OPENCLAW_TEST_CONSOLE:-}" \ -e OPENCLAW_LIVE_CLI_BACKEND_MODEL="$CLI_MODEL" \ -e OPENCLAW_LIVE_CLI_BACKEND_COMMAND="${OPENCLAW_LIVE_CLI_BACKEND_COMMAND:-}" \ -e OPENCLAW_LIVE_CLI_BACKEND_ARGS="${OPENCLAW_LIVE_CLI_BACKEND_ARGS:-}" \ diff --git a/scripts/test-live-codex-harness-docker.sh b/scripts/test-live-codex-harness-docker.sh index 1c236aa2010..eba897983d7 100644 --- a/scripts/test-live-codex-harness-docker.sh +++ b/scripts/test-live-codex-harness-docker.sh @@ -257,6 +257,8 @@ DOCKER_RUN_ARGS=(docker run --rm -t \ -e OPENCLAW_LIVE_CODEX_HARNESS_SUBAGENT_ONLY="${OPENCLAW_LIVE_CODEX_HARNESS_SUBAGENT_ONLY:-}" \ -e OPENCLAW_LIVE_CODEX_HARNESS_SUBAGENT_PROBE="${OPENCLAW_LIVE_CODEX_HARNESS_SUBAGENT_PROBE:-1}" \ -e OPENCLAW_LIVE_CODEX_HARNESS_USE_CI_SAFE_CODEX_CONFIG="${OPENCLAW_LIVE_CODEX_HARNESS_USE_CI_SAFE_CODEX_CONFIG:-1}" \ + -e OPENCLAW_CLI_BACKEND_LOG_OUTPUT="${OPENCLAW_CLI_BACKEND_LOG_OUTPUT:-}" \ + -e OPENCLAW_TEST_CONSOLE="${OPENCLAW_TEST_CONSOLE:-}" \ -e OPENCLAW_LIVE_DOCKER_SCRIPTS_DIR="${DOCKER_TRUSTED_HARNESS_CONTAINER_DIR}/scripts" \ -e OPENCLAW_LIVE_DOCKER_TRUSTED_HARNESS_DIR="$DOCKER_TRUSTED_HARNESS_CONTAINER_DIR" \ -e OPENCLAW_LIVE_CODEX_TRUSTED_HARNESS_DIR="$DOCKER_TRUSTED_HARNESS_CONTAINER_DIR" \ diff --git a/src/infra/npm-install-env.ts b/src/infra/npm-install-env.ts index de42371dea8..16861f14e00 100644 --- a/src/infra/npm-install-env.ts +++ b/src/infra/npm-install-env.ts @@ -23,6 +23,10 @@ export function createNpmProjectInstallEnv( return { ...nextEnv, npm_config_dry_run: "false", + npm_config_fetch_retries: nextEnv.npm_config_fetch_retries ?? "5", + npm_config_fetch_retry_maxtimeout: nextEnv.npm_config_fetch_retry_maxtimeout ?? "120000", + npm_config_fetch_retry_mintimeout: nextEnv.npm_config_fetch_retry_mintimeout ?? "10000", + npm_config_fetch_timeout: nextEnv.npm_config_fetch_timeout ?? "300000", npm_config_global: "false", npm_config_location: "project", npm_config_package_lock: "false", diff --git a/src/infra/tsdown-config.test.ts b/src/infra/tsdown-config.test.ts index ed579373958..031af3a623f 100644 --- a/src/infra/tsdown-config.test.ts +++ b/src/infra/tsdown-config.test.ts @@ -66,6 +66,7 @@ describe("tsdown config", () => { "agents/auth-profiles.runtime", "agents/model-catalog.runtime", "agents/models-config.runtime", + "plugins/memory-state", "subagent-registry.runtime", "task-registry-control.runtime", "agents/pi-model-discovery-runtime", diff --git a/src/plugins/bundled-runtime-deps.test.ts b/src/plugins/bundled-runtime-deps.test.ts index fde5b797335..2abf6fd187e 100644 --- a/src/plugins/bundled-runtime-deps.test.ts +++ b/src/plugins/bundled-runtime-deps.test.ts @@ -186,6 +186,10 @@ describe("resolveBundledRuntimeDepsNpmRunner", () => { PATH: "/usr/bin:/bin", npm_config_cache: "/opt/openclaw/runtime-cache", npm_config_dry_run: "false", + npm_config_fetch_retries: "5", + npm_config_fetch_retry_maxtimeout: "120000", + npm_config_fetch_retry_mintimeout: "10000", + npm_config_fetch_timeout: "300000", npm_config_global: "false", npm_config_legacy_peer_deps: "true", npm_config_location: "project", diff --git a/test/scripts/openclaw-cross-os-release-checks.test.ts b/test/scripts/openclaw-cross-os-release-checks.test.ts index a1c060f3f6e..21fb1d57c54 100644 --- a/test/scripts/openclaw-cross-os-release-checks.test.ts +++ b/test/scripts/openclaw-cross-os-release-checks.test.ts @@ -15,6 +15,7 @@ import { describe, expect, it } from "vitest"; import { LOCAL_BUILD_METADATA_DIST_PATHS } from "../../scripts/lib/local-build-metadata-paths.mjs"; import { agentOutputHasExpectedOkMarker, + buildCrossOsReleaseSmokePluginAllowlist, buildReleaseOnboardArgs, buildWindowsDevUpdateToolchainCheckScript, buildWindowsFreshShellVersionCheckScript, @@ -111,6 +112,15 @@ describe("scripts/openclaw-cross-os-release-checks", () => { ); }); + it("keeps release smoke plugin allowlists focused on agent-turn essentials", () => { + const allowlist = buildCrossOsReleaseSmokePluginAllowlist({ extensionId: "openai" }); + + expect(allowlist).toEqual(expect.arrayContaining(["openai", "memory-core", "acpx"])); + expect(allowlist).not.toContain("document-extract"); + expect(allowlist).not.toContain("microsoft"); + expect(allowlist).not.toContain("web-readability"); + }); + it("keeps cross-OS live smoke agent turns on minimal thinking", () => { const source = readFileSync("scripts/openclaw-cross-os-release-checks.ts", "utf8"); diff --git a/test/scripts/postinstall-bundled-plugins.test.ts b/test/scripts/postinstall-bundled-plugins.test.ts index 06cefb18fee..868cf578538 100644 --- a/test/scripts/postinstall-bundled-plugins.test.ts +++ b/test/scripts/postinstall-bundled-plugins.test.ts @@ -148,6 +148,10 @@ describe("bundled plugin postinstall", () => { ).toEqual({ HOME: "/tmp/home", npm_config_dry_run: "false", + npm_config_fetch_retries: "5", + npm_config_fetch_retry_maxtimeout: "120000", + npm_config_fetch_retry_mintimeout: "10000", + npm_config_fetch_timeout: "300000", npm_config_legacy_peer_deps: "true", npm_config_package_lock: "false", npm_config_save: "false", diff --git a/test/scripts/test-live-cli-backend-docker.test.ts b/test/scripts/test-live-cli-backend-docker.test.ts index 807a175ce17..694053b46c3 100644 --- a/test/scripts/test-live-cli-backend-docker.test.ts +++ b/test/scripts/test-live-cli-backend-docker.test.ts @@ -18,5 +18,6 @@ describe("scripts/test-live-cli-backend-docker.sh", () => { expect(forwardedVars).toContain("OPENCLAW_LIVE_CLI_BACKEND_ARGS"); expect(forwardedVars).toContain("OPENCLAW_LIVE_CLI_BACKEND_RESUME_ARGS"); + expect(forwardedVars).toContain("OPENCLAW_TEST_CONSOLE"); }); }); diff --git a/tsdown.config.ts b/tsdown.config.ts index dd3f1ffcbe0..c371663de99 100644 --- a/tsdown.config.ts +++ b/tsdown.config.ts @@ -212,6 +212,7 @@ function buildCoreDistEntries(): Record { "agents/auth-profiles.runtime": "src/agents/auth-profiles.runtime.ts", "agents/model-catalog.runtime": "src/agents/model-catalog.runtime.ts", "agents/models-config.runtime": "src/agents/models-config.runtime.ts", + "plugins/memory-state": "src/plugins/memory-state.ts", "subagent-registry.runtime": "src/agents/subagent-registry.runtime.ts", "task-registry-control.runtime": "src/tasks/task-registry-control.runtime.ts", "agents/pi-model-discovery-runtime": "src/agents/pi-model-discovery-runtime.ts",