diff --git a/scripts/e2e/lib/upgrade-survivor/run.sh b/scripts/e2e/lib/upgrade-survivor/run.sh index cad12ae7995..ffd460c8a06 100644 --- a/scripts/e2e/lib/upgrade-survivor/run.sh +++ b/scripts/e2e/lib/upgrade-survivor/run.sh @@ -30,7 +30,6 @@ export PATH="$npm_config_prefix/bin:$PATH" SUMMARY_JSON="${OPENCLAW_UPGRADE_SURVIVOR_SUMMARY_JSON:-$ARTIFACT_ROOT/summary.json}" PHASE_LOG="$ARTIFACT_ROOT/phases.jsonl" -: >"$PHASE_LOG" BASELINE_RAW="${OPENCLAW_UPGRADE_SURVIVOR_BASELINE:?missing OPENCLAW_UPGRADE_SURVIVOR_BASELINE}" CANDIDATE_KIND="${OPENCLAW_UPGRADE_SURVIVOR_CANDIDATE_KIND:-tarball}" CANDIDATE_SPEC="${OPENCLAW_UPGRADE_SURVIVOR_CANDIDATE_SPEC:-${OPENCLAW_CURRENT_PACKAGE_TGZ:-}}" @@ -56,6 +55,17 @@ STATUS_ERR="$ARTIFACT_ROOT/status.err" BASELINE_CONFIG_VALIDATE_LOG="$ARTIFACT_ROOT/baseline-config-validate.log" CONFIG_COVERAGE_JSON="$ARTIFACT_ROOT/config-recipe.json" export OPENCLAW_UPGRADE_SURVIVOR_CONFIG_COVERAGE_JSON="$CONFIG_COVERAGE_JSON" +rm -f "$SUMMARY_JSON" "$CONFIG_COVERAGE_JSON" +: >"$PHASE_LOG" + +validate_baseline_package_spec() { + local spec="$1" + if [[ "$spec" =~ ^openclaw@(beta|latest|[0-9]{4}\.[1-9][0-9]*\.[1-9][0-9]*(-[1-9][0-9]*|-beta\.[1-9][0-9]*)?)$ ]]; then + return 0 + fi + echo "OPENCLAW_UPGRADE_SURVIVOR_BASELINE must be openclaw@latest, openclaw@beta, an exact OpenClaw release version, or a bare release version; got: $spec" >&2 + return 1 +} normalize_baseline() { local raw="${BASELINE_RAW//[[:space:]]/}" @@ -90,6 +100,7 @@ normalize_baseline() { baseline_version_expected="1" ;; esac + validate_baseline_package_spec "$baseline_spec" } json_event() { diff --git a/test/scripts/package-acceptance-workflow.test.ts b/test/scripts/package-acceptance-workflow.test.ts index 9fdda2be104..93aaba4d67a 100644 --- a/test/scripts/package-acceptance-workflow.test.ts +++ b/test/scripts/package-acceptance-workflow.test.ts @@ -8,6 +8,7 @@ const PACKAGE_JSON = "package.json"; const RELEASE_CHECKS_WORKFLOW = ".github/workflows/openclaw-release-checks.yml"; const FULL_RELEASE_VALIDATION_WORKFLOW = ".github/workflows/full-release-validation.yml"; const QA_LIVE_TRANSPORTS_WORKFLOW = ".github/workflows/qa-live-transports-convex.yml"; +const UPGRADE_SURVIVOR_RUN_SCRIPT = "scripts/e2e/lib/upgrade-survivor/run.sh"; describe("package acceptance workflow", () => { it("resolves candidate package sources before reusing Docker E2E lanes", () => { @@ -76,6 +77,7 @@ describe("package artifact reuse", () => { const workflow = readFileSync(LIVE_E2E_WORKFLOW, "utf8"); const packageJson = readFileSync(PACKAGE_JSON, "utf8"); const scheduler = readFileSync("scripts/test-docker-all.mjs", "utf8"); + const publishedUpgradeSurvivor = readFileSync(UPGRADE_SURVIVOR_RUN_SCRIPT, "utf8"); expect(workflow).toContain("package_artifact_name:"); expect(workflow).toContain("package_artifact_run_id:"); @@ -115,6 +117,13 @@ describe("package artifact reuse", () => { '["OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPEC", baseEnv.OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPEC]', ); expect(packageJson).toContain("OPENCLAW_UPGRADE_SURVIVOR_PUBLISHED_BASELINE=1"); + expect(publishedUpgradeSurvivor).toContain("validate_baseline_package_spec"); + expect(publishedUpgradeSurvivor).toContain("openclaw@(beta|latest|"); + expect( + publishedUpgradeSurvivor.indexOf('validate_baseline_package_spec "$baseline_spec"'), + ).toBeLessThan( + publishedUpgradeSurvivor.indexOf('npm install -g --prefix "$npm_config_prefix"'), + ); }); it("bounds shared Docker image pulls so package acceptance cannot stall forever", () => { diff --git a/test/scripts/resolve-openclaw-package-candidate.test.ts b/test/scripts/resolve-openclaw-package-candidate.test.ts index 0ee6822ee99..5796d3aab17 100644 --- a/test/scripts/resolve-openclaw-package-candidate.test.ts +++ b/test/scripts/resolve-openclaw-package-candidate.test.ts @@ -21,6 +21,12 @@ describe("resolve-openclaw-package-candidate", () => { expect(() => validateOpenClawPackageSpec("openclaw@2026.04.27")).toThrow( "package_spec must be openclaw@beta", ); + expect(() => validateOpenClawPackageSpec("openclaw@npm:other-package")).toThrow( + "package_spec must be openclaw@beta", + ); + expect(() => validateOpenClawPackageSpec("openclaw@file:../other-package.tgz")).toThrow( + "package_spec must be openclaw@beta", + ); }); it("parses optional empty workflow inputs without rejecting the command line", () => {