test(parallels): harden npm update smoke transport

This commit is contained in:
Peter Steinberger
2026-04-30 23:16:41 +01:00
parent 231e5c618f
commit af5a1fbddb
2 changed files with 79 additions and 17 deletions

View File

@@ -11,6 +11,7 @@ export interface NpmUpdateScriptInput {
export function macosUpdateScript(input: NpmUpdateScriptInput): string {
return String.raw`set -euo pipefail
export PATH=/opt/homebrew/bin:/opt/homebrew/opt/node/bin:/opt/homebrew/sbin:/usr/bin:/bin:/usr/sbin:/sbin
scrub_future_plugin_entries() {
python3 - <<'PY'
import json
@@ -63,7 +64,7 @@ wait_for_gateway() {
}
scrub_future_plugin_entries
stop_openclaw_gateway_processes
OPENCLAW_DISABLE_BUNDLED_PLUGINS=1 /opt/homebrew/bin/openclaw update --tag ${shellQuote(input.updateTarget)} --yes --json
OPENCLAW_DISABLE_BUNDLED_PLUGINS=1 /opt/homebrew/bin/openclaw update --tag ${shellQuote(input.updateTarget)} --yes --json --no-restart
${posixVersionCheck("/opt/homebrew/bin/openclaw", input.expectedNeedle)}
start_openclaw_gateway
wait_for_gateway
@@ -100,11 +101,15 @@ function Stop-OpenClawGatewayProcesses {
Get-CimInstance Win32_Process -ErrorAction SilentlyContinue |
Where-Object { $_.CommandLine -match 'openclaw.*gateway' } |
ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue }
Get-NetTCPConnection -LocalPort 18789 -State Listen -ErrorAction SilentlyContinue |
Select-Object -ExpandProperty OwningProcess -Unique |
ForEach-Object { Stop-Process -Id $_ -Force -ErrorAction SilentlyContinue }
Start-Sleep -Seconds 2
}
Remove-FuturePluginEntries
Stop-OpenClawGatewayProcesses
$env:OPENCLAW_DISABLE_BUNDLED_PLUGINS = '1'
Invoke-OpenClaw update --tag ${psSingleQuote(input.updateTarget)} --yes --json
Invoke-OpenClaw update --tag ${psSingleQuote(input.updateTarget)} --yes --json --no-restart
if ($LASTEXITCODE -ne 0) { throw "openclaw update failed with exit code $LASTEXITCODE" }
$version = Invoke-OpenClaw --version
$version
@@ -120,6 +125,7 @@ Invoke-OpenClaw agent --local --agent main --session-id parallels-npm-update-win
export function linuxUpdateScript(input: NpmUpdateScriptInput): string {
return String.raw`set -euo pipefail
export PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/snap/bin
scrub_future_plugin_entries() {
node - <<'JS'
const fs = require("node:fs");
@@ -167,7 +173,7 @@ wait_for_gateway() {
}
scrub_future_plugin_entries
stop_openclaw_gateway_processes
OPENCLAW_DISABLE_BUNDLED_PLUGINS=1 openclaw update --tag ${shellQuote(input.updateTarget)} --yes --json
OPENCLAW_DISABLE_BUNDLED_PLUGINS=1 openclaw update --tag ${shellQuote(input.updateTarget)} --yes --json --no-restart
${posixVersionCheck("openclaw", input.expectedNeedle)}
start_openclaw_gateway
wait_for_gateway

View File

@@ -442,14 +442,23 @@ class NpmUpdateSmoke {
ctx: UpdateJobContext,
): Promise<void> {
const macosExecArgs = this.resolveMacosUpdateExecArgs(ctx);
const status = await this.runStreamingToJobLog(
"prlctl",
["exec", macosVm, ...macosExecArgs, "/bin/bash", "-lc", script],
timeoutMs,
ctx,
const scriptPath = this.writeGuestScript(
macosVm,
script,
"openclaw-parallels-npm-update-macos",
);
if (status !== 0) {
throw new Error(`macOS update command failed with exit code ${status}`);
try {
const status = await this.runStreamingToJobLog(
"prlctl",
["exec", macosVm, ...macosExecArgs, "/bin/bash", scriptPath],
timeoutMs,
ctx,
);
if (status !== 0) {
throw new Error(`macOS update command failed with exit code ${status}`);
}
} finally {
this.removeGuestScript(macosVm, scriptPath);
}
}
@@ -688,17 +697,64 @@ Remove-Item -Path $scriptPath, $logPath, $donePath, $exitPath -Force -ErrorActio
timeoutMs: number,
ctx: UpdateJobContext,
): Promise<void> {
const status = await this.runStreamingToJobLog(
"prlctl",
["exec", this.linuxVm, "/usr/bin/env", "HOME=/root", "bash", "-lc", script],
timeoutMs,
ctx,
const scriptPath = this.writeGuestScript(
this.linuxVm,
script,
"openclaw-parallels-npm-update-linux",
);
if (status !== 0) {
throw new Error(`Linux update command failed with exit code ${status}`);
try {
const status = await this.runStreamingToJobLog(
"prlctl",
[
"exec",
this.linuxVm,
"/usr/bin/env",
"HOME=/root",
"PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/snap/bin",
"bash",
scriptPath,
],
timeoutMs,
ctx,
);
if (status !== 0) {
throw new Error(`Linux update command failed with exit code ${status}`);
}
} finally {
this.removeGuestScript(this.linuxVm, scriptPath);
}
}
private writeGuestScript(vm: string, script: string, prefix: string): string {
const scriptPath = `/tmp/${prefix}-${process.pid}-${Date.now()}.sh`;
const write = run("prlctl", ["exec", vm, "/usr/bin/tee", scriptPath], {
check: false,
input: script,
quiet: true,
timeoutMs: 120_000,
});
if (write.status !== 0) {
throw new Error(`failed to write guest script ${scriptPath}: ${write.stderr.trim()}`);
}
const chmod = run("prlctl", ["exec", vm, "/bin/chmod", "700", scriptPath], {
check: false,
quiet: true,
timeoutMs: 30_000,
});
if (chmod.status !== 0) {
throw new Error(`failed to chmod guest script ${scriptPath}: ${chmod.stderr.trim()}`);
}
return scriptPath;
}
private removeGuestScript(vm: string, scriptPath: string): void {
run("prlctl", ["exec", vm, "/bin/rm", "-f", scriptPath], {
check: false,
quiet: true,
timeoutMs: 30_000,
});
}
private async runStreamingToJobLog(
command: string,
args: string[],