Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
194 changes: 186 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,115 @@ jobs:
exit 1
fi

gateway-composed:
needs: repo-hygiene
runs-on: ubuntu-latest
timeout-minutes: 45
outputs:
sha256: ${{ steps.package.outputs.sha256 }}
steps:
- name: Fail if repo hygiene failed
if: ${{ needs.repo-hygiene.result != 'success' }}
shell: bash
run: |
echo "repo-hygiene failed; see the repo-hygiene job output." >&2
exit 1

- name: Checkout frozen OpenClaw main source
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
with:
repository: openclaw/openclaw
ref: 6277c35d9a97cb128d32ed7ab5632cfc4163c746
fetch-depth: 0

- name: Setup Node 24
uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
with:
node-version: 24

- name: Activate pinned pnpm
shell: bash
run: |
corepack enable
corepack prepare pnpm@11.15.1 --activate

- name: Compose main with exact PR 110382 patch
shell: bash
run: |
set -euo pipefail
base_sha=6277c35d9a97cb128d32ed7ab5632cfc4163c746
wizard_base=6277c35d9a97cb128d32ed7ab5632cfc4163c746
wizard_head=6edc1e40f37b833ec0493ec331eba6cd49db4fb6
fork_repository=https://github.com/TheAngryPit/openclaw.git
wizard_fetch_ref=refs/heads/codex/fix-gateway-wizard-rpc-exits
wizard_paths="$RUNNER_TEMP/pr110382-expected-paths.txt"
staged_paths="$RUNNER_TEMP/staged-paths.txt"
wizard_patch="$RUNNER_TEMP/pr110382.patch"

cat >"$wizard_paths" <<'EOF'
apps/shared/OpenClawKit/Sources/OpenClawProtocol/GatewayModels.swift
packages/gateway-protocol/src/schema/wizard.ts
src/gateway/gateway.test.ts
src/gateway/server-methods/wizard.test.ts
src/gateway/server-methods/wizard.ts
src/gateway/server-wizard-sessions.test.ts
src/gateway/server-wizard-sessions.ts
src/wizard/session.ts
src/wizard/setup.finalize.test.ts
src/wizard/setup.finalize.ts
EOF

test "$(git rev-parse HEAD)" = "$base_sha"
git fetch --no-tags "$fork_repository" \
"+${wizard_fetch_ref}:refs/remotes/fork/pr-110382"
test "$(git rev-parse refs/remotes/fork/pr-110382)" = "$wizard_head"
git merge-base --is-ancestor "$wizard_base" "$wizard_head"
git diff --name-only "$wizard_base" "$wizard_head" | sort | diff -u "$wizard_paths" -
git diff --binary "$wizard_base" "$wizard_head" -- $(cat "$wizard_paths") >"$wizard_patch"
test -s "$wizard_patch"
sha256sum "$wizard_patch" >"$RUNNER_TEMP/pr110382-patch.SHA256SUM"
git apply --index "$wizard_patch"
git diff --cached --name-only | sort >"$staged_paths"
diff -u "$wizard_paths" "$staged_paths"
git diff --cached --check

- name: Build immutable composed gateway package
id: package
shell: bash
run: |
set -euo pipefail
test "$(node -p "require('./package.json').version")" = "2026.7.2"
pnpm install --frozen-lockfile --ignore-scripts=false --config.engine-strict=false --config.enable-pre-post-scripts=true
node scripts/package-openclaw-for-docker.mjs \
--allow-unreleased-changelog \
--source-dir . \
--output-dir "$RUNNER_TEMP/gateway-composed" \
--output-name openclaw-2026.7.2-main-pr110382.tgz
tarball="$RUNNER_TEMP/gateway-composed/openclaw-2026.7.2-main-pr110382.tgz"
sha256="$(sha256sum "$tarball" | awk '{print $1}')"
packaged_version="$(tar -xOf "$tarball" package/package.json | node -e "let s='';process.stdin.on('data',c=>s+=c).on('end',()=>process.stdout.write(JSON.parse(s).version))")"
test "$packaged_version" = "2026.7.2"
wizard_patch_sha256="$(awk '{print $1}' "$RUNNER_TEMP/pr110382-patch.SHA256SUM")"
test "${#sha256}" -eq 64
test "${#wizard_patch_sha256}" -eq 64
printf '%s %s\n' "$sha256" "$(basename "$tarball")" >"$RUNNER_TEMP/gateway-composed/SHA256SUMS"
printf '{"source_ref":"main","source_sha":"%s","included_upstream_prs":[{"pr":111956,"merge_commit":"2296e898e13a5b250bf557e9632e000c093e61f1"}],"fixes":[{"pr":110382,"base":"%s","head":"%s","fetch_repository":"TheAngryPit/openclaw","fetch_ref":"codex/fix-gateway-wizard-rpc-exits","patch_sha256":"%s"}],"changed_paths":["apps/shared/OpenClawKit/Sources/OpenClawProtocol/GatewayModels.swift","packages/gateway-protocol/src/schema/wizard.ts","src/gateway/gateway.test.ts","src/gateway/server-methods/wizard.test.ts","src/gateway/server-methods/wizard.ts","src/gateway/server-wizard-sessions.test.ts","src/gateway/server-wizard-sessions.ts","src/wizard/session.ts","src/wizard/setup.finalize.test.ts","src/wizard/setup.finalize.ts"],"package_version":"%s","package_sha256":"%s"}\n' \
6277c35d9a97cb128d32ed7ab5632cfc4163c746 \
6277c35d9a97cb128d32ed7ab5632cfc4163c746 \
6edc1e40f37b833ec0493ec331eba6cd49db4fb6 \
"$wizard_patch_sha256" \
"$packaged_version" \
"$sha256" >"$RUNNER_TEMP/gateway-composed/provenance.json"
echo "sha256=$sha256" >>"$GITHUB_OUTPUT"

- name: Upload composed gateway package
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: openclaw-main-pr110382-composed
path: ${{ runner.temp }}/gateway-composed/
if-no-files-found: error
retention-days: 7

test:
needs: repo-hygiene
if: ${{ !cancelled() }}
Expand Down Expand Up @@ -338,29 +447,52 @@ jobs:
majorMinorPatch: ${{ steps.gitversion.outputs.majorMinorPatch }}

e2etests:
needs: repo-hygiene
if: ${{ !cancelled() }}
needs: [repo-hygiene, gateway-composed]
if: ${{ needs.repo-hygiene.result == 'success' && needs.gateway-composed.result == 'success' }}
runs-on: windows-latest
continue-on-error: ${{ matrix.continue_on_error || false }}
timeout-minutes: ${{ matrix.timeout_minutes }}
strategy:
fail-fast: false
matrix:
include:
- name: setup-connect
- name: lkg-setup-connect
gateway_source: lkg
gateway_version: ""
scenario: setup-connect
timeout_minutes: 45
filter: "FullyQualifiedName~OpenClaw.E2ETests.Setup.SetupAndConnectTests|FullyQualifiedName~OpenClaw.E2ETests.Setup.MxcSetupAndConnectTests"
- name: official-beta-setup-connect
gateway_source: official
gateway_version: 2026.7.2-beta.3
scenario: setup-connect
continue_on_error: true
timeout_minutes: 45
filter: "FullyQualifiedName~OpenClaw.E2ETests.Setup.SetupAndConnectTests|FullyQualifiedName~OpenClaw.E2ETests.Setup.MxcSetupAndConnectTests"
- name: revocation-recovery
- name: composed-setup-connect
gateway_source: composed
gateway_version: ""
scenario: setup-connect
timeout_minutes: 45
filter: "FullyQualifiedName~OpenClaw.E2ETests.Setup.SetupAndConnectTests|FullyQualifiedName~OpenClaw.E2ETests.Setup.MxcSetupAndConnectTests"
- name: composed-revocation-recovery
gateway_source: composed
gateway_version: ""
scenario: revocation-recovery
timeout_minutes: 25
filter: FullyQualifiedName~OpenClaw.E2ETests.Setup.RevocationAndRecoveryTests
- name: network-recovery
- name: composed-network-recovery
gateway_source: composed
gateway_version: ""
scenario: network-recovery
timeout_minutes: 25
filter: FullyQualifiedName~OpenClaw.E2ETests.Setup.NetworkRecoveryTests
steps:
- name: Fail if repo hygiene failed
if: ${{ needs.repo-hygiene.result != 'success' }}
if: ${{ needs.repo-hygiene.result != 'success' || needs.gateway-composed.result != 'success' }}
shell: pwsh
run: |
Write-Error "repo-hygiene failed; see the repo-hygiene job output."
Write-Error "A prerequisite failed; see repo-hygiene and gateway-composed job output."
exit 1

- uses: actions/checkout@v7
Expand Down Expand Up @@ -395,9 +527,46 @@ jobs:
- name: Build E2E Tests
run: dotnet build tests/OpenClaw.E2ETests -c Debug -r win-x64

- name: Run gateway package selector tests
if: ${{ matrix.name == 'official-beta-setup-connect' }}
shell: pwsh
run: |
dotnet test tests/OpenClaw.E2ETests `
--no-build `
-c Debug `
-r win-x64 `
--verbosity normal `
--filter "FullyQualifiedName~OpenClaw.E2ETests.Setup.GatewayE2EPackageSpecTests"
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }

- name: Download composed gateway package
if: ${{ matrix.gateway_source == 'composed' }}
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: openclaw-main-pr110382-composed
path: TestResults/GatewayComposed

- name: Start disposable WSL package host
if: ${{ matrix.gateway_source == 'composed' }}
id: gateway_package_host
shell: pwsh
run: |
.\scripts\Start-E2EGatewayPackageHost.ps1 `
-PackagePath "TestResults\GatewayComposed\openclaw-2026.7.2-main-pr110382.tgz" `
-ExpectedSha256 "${{ needs.gateway-composed.outputs.sha256 }}" `
-DistroName "OpenClawE2EPackageHost-${{ matrix.name }}" `
-InstallLocation "${{ runner.temp }}\OpenClawE2EPackageHost-${{ matrix.name }}" `
-OwnershipToken "${{ github.run_id }}-${{ github.run_attempt }}-${{ matrix.name }}" `
-GitHubOutput $env:GITHUB_OUTPUT

- name: Run E2E Tests (${{ matrix.name }})
env:
OPENCLAW_RUN_E2E: 1
OPENCLAW_E2E_GATEWAY_SOURCE: ${{ matrix.gateway_source }}
OPENCLAW_E2E_GATEWAY_VERSION: ${{ matrix.gateway_version }}
OPENCLAW_E2E_GATEWAY_PACKAGE_SPEC: ${{ matrix.gateway_source == 'composed' && steps.gateway_package_host.outputs.package_spec || '' }}
OPENCLAW_E2E_GATEWAY_PACKAGE_SHA256: ${{ matrix.gateway_source == 'composed' && steps.gateway_package_host.outputs.package_sha256 || '' }}
OPENCLAW_E2E_GATEWAY_PACKAGE_HOST_DISTRO: ${{ matrix.gateway_source == 'composed' && steps.gateway_package_host.outputs.distro_name || '' }}
shell: pwsh
run: |
dotnet test tests/OpenClaw.E2ETests `
Expand All @@ -417,7 +586,7 @@ jobs:
Write-Error "E2E shard '${{ matrix.name }}' executed zero tests. Check OPENCLAW_RUN_E2E gating/filter before merging."
exit 1
}
if ("${{ matrix.name }}" -eq "setup-connect") {
if ("${{ matrix.scenario }}" -eq "setup-connect") {
$mxcProofNames = @(
"RealGateway_SystemRun_ExecutesThroughWindowsNodeMxcSandbox",
"RealGateway_SystemRun_BlocksWritesToTrayDataDirectoryInMxcSandbox"
Expand Down Expand Up @@ -448,6 +617,15 @@ jobs:
}
}

- name: Stop disposable WSL package host
if: ${{ always() && matrix.gateway_source == 'composed' }}
shell: pwsh
run: |
.\scripts\Stop-E2EGatewayPackageHost.ps1 `
-DistroName "OpenClawE2EPackageHost-${{ matrix.name }}" `
-InstallLocation "${{ runner.temp }}\OpenClawE2EPackageHost-${{ matrix.name }}" `
-OwnershipToken "${{ github.run_id }}-${{ github.run_attempt }}-${{ matrix.name }}"

- name: Upload E2E Test Results & Logs
if: always()
uses: actions/upload-artifact@v7
Expand Down
58 changes: 43 additions & 15 deletions .github/workflows/gateway-lkg-update.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ jobs:
if not match:
raise SystemExit("Could not parse LkgVersion constant from GatewayLkgVersion.cs")
pinned = match.group(1)
if not re.fullmatch(r'[0-9]+\.[0-9]+\.[0-9]+([.\-+][A-Za-z0-9.\-]+)*', pinned):
raise SystemExit(f"Pinned LkgVersion has unexpected format: {pinned}")
if not re.fullmatch(r'[0-9]+\.[0-9]+\.[0-9]+', pinned):
raise SystemExit(f"Pinned LkgVersion must be an exact stable version: {pinned}")
print(pinned)
PY
)"
Expand All @@ -45,8 +45,8 @@ jobs:
with urllib.request.urlopen('https://registry.npmjs.org/openclaw/latest', timeout=30) as r:
payload = json.load(r)
latest = payload['version']
if not re.fullmatch(r'[0-9]+\.[0-9]+\.[0-9]+([.\-+][A-Za-z0-9.\-]+)*', latest):
raise SystemExit(f"Resolved npm latest version has unexpected format: {latest}")
if not re.fullmatch(r'[0-9]+\.[0-9]+\.[0-9]+', latest):
raise SystemExit(f"Resolved npm latest must be an exact stable version: {latest}")
print(latest)
PY
)"
Expand All @@ -56,7 +56,13 @@ jobs:
echo "latest=${latest}"
} >> "$GITHUB_OUTPUT"

if [[ "$pinned" != "$latest" ]]; then
if python3 - "$pinned" "$latest" <<'PY'
import sys
pinned = tuple(map(int, sys.argv[1].split(".")))
latest = tuple(map(int, sys.argv[2].split(".")))
raise SystemExit(0 if latest > pinned else 1)
PY
then
echo "drifted=true" >> "$GITHUB_OUTPUT"
else
echo "drifted=false" >> "$GITHUB_OUTPUT"
Expand Down Expand Up @@ -84,27 +90,47 @@ jobs:
import os
import pathlib, re
latest = os.environ["LATEST_VERSION"]
path = pathlib.Path("src/OpenClaw.SetupEngine/GatewayLkgVersion.cs")
source = path.read_text(encoding="utf-8")
pattern = r'(LkgVersion\s*=\s*")([^"]+)(")'
updated, count = re.subn(pattern, lambda m: f"{m.group(1)}{latest}{m.group(3)}", source, count=1)
if count != 1:
raise SystemExit("Failed to rewrite LkgVersion constant")
path.write_text(updated, encoding="utf-8")
replacements = (
(
pathlib.Path("src/OpenClaw.SetupEngine/GatewayLkgVersion.cs"),
r'(LkgVersion\s*=\s*")([^"]+)(")',
"LkgVersion constant",
),
(
pathlib.Path("tests/OpenClaw.SetupEngine.Tests/GatewayLkgVersionTests.cs"),
r'(ExpectedLkgVersion\s*=\s*")([^"]+)(")',
"ExpectedLkgVersion constant",
),
)
for path, pattern, label in replacements:
source = path.read_text(encoding="utf-8")
updated, count = re.subn(
pattern,
lambda m: f"{m.group(1)}{latest}{m.group(3)}",
source,
count=1,
)
if count != 1:
raise SystemExit(f"Failed to rewrite {label}")
path.write_text(updated, encoding="utf-8")
PY

- name: Commit and push branch
if: ${{ steps.versions.outputs.drifted == 'true' }}
shell: bash
run: |
if git diff --quiet -- src/OpenClaw.SetupEngine/GatewayLkgVersion.cs; then
update_paths=(
src/OpenClaw.SetupEngine/GatewayLkgVersion.cs
tests/OpenClaw.SetupEngine.Tests/GatewayLkgVersionTests.cs
)
if git diff --quiet -- "${update_paths[@]}"; then
echo "No LKG change detected after update write."
exit 0
fi

git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add src/OpenClaw.SetupEngine/GatewayLkgVersion.cs
git add "${update_paths[@]}"
git commit -m "chore(setup): bump gateway LKG to ${{ steps.versions.outputs.latest }}"
git push --force-with-lease origin "${BRANCH_NAME}"

Expand All @@ -121,7 +147,9 @@ jobs:

- Previous pinned LKG: \`${{ steps.versions.outputs.pinned }}\`
- Candidate latest: \`${{ steps.versions.outputs.latest }}\`
- Updated file: \`src/OpenClaw.SetupEngine/GatewayLkgVersion.cs\`
- Updated files: LKG source and its contract test

The automation only proposes exact stable versions newer than the current pin.

This is the standing automation PR used to review and validate gateway LKG bumps before merge.
EOF
Expand Down
Loading
Loading