fix(orcad): a managed SSH/WSL server falls back when port 6768 is taken; WSL lane skips the MSI on 3.0.1 images (#29522)

* ci(wsl-orcad): skip the WSL MSI when the image already has 3.0.1

windows-2025 image 20261007.264.1 ships WSL 3.0.1.0, and reinstalling the
pinned 3.0.1 MSI over it exits 1603, failing every run. Install only when the
image is older, print the msiexec log on failure, and gate on >= 3.0.1 after.

* fix(orcad): let a managed launch fall back when its default port is taken

#29432 made any --port mandatory, but managed SSH/WSL launches pass the
default 6768 as a preference and read the bound port from readiness. WSL2
distros share one VM loopback, so a second distro's orcad now failed with
pinned_port_unavailable. Only an operator --port is required now.
This commit is contained in:
Neil
2026-10-16 01:23:57 -07:00
committed by GitHub
parent 941ad1e2e0
commit c4f1dedad4
4 changed files with 91 additions and 14 deletions
+39 -11
View File
@@ -80,20 +80,32 @@ jobs:
- uses: actions/checkout@v6
with:
persist-credentials: false
# The image ships WSL 2.7.14, where stopping a systemd distro drops the VM-wide WSLInterop
# entry (microsoft/WSL#13885, fixed in 3.0.1). The lane asserts the fixed behavior, so it
# installs a pinned 3.0.1 MSI; `wsl --update` asks the GitHub API and gets rate-limited (403).
# WSL before 3.0.1 drops the VM-wide WSLInterop entry when a systemd distro stops
# (microsoft/WSL#13885). Images from 20261007 ship 3.0.1, where reinstalling the MSI fails
# with 1603, so install only when older; `wsl --update` gets rate-limited by the GitHub API.
- name: Check the installed WSL version
id: wsl-version
run: |
"ImageOS=$env:ImageOS ImageVersion=$env:ImageVersion"
$details = (wsl.exe --version) -join "`n"
$details
$match = [regex]::Match($details, '(?m)^WSL version:\s*(\d+(?:\.\d+){2,3})\s*$')
# Inbox WSL has no --version, so an unreadable version means the package is needed.
$installed = if ($LASTEXITCODE -eq 0 -and $match.Success) { [version]$match.Groups[1].Value } else { [version]'0.0.0' }
$needsInstall = $installed -lt [version]'3.0.1'
"Installed WSL $installed; minimum 3.0.1; install needed: $needsInstall"
"needs-install=$($needsInstall.ToString().ToLowerInvariant())" >> $env:GITHUB_OUTPUT
- name: Restore the pinned WSL package
id: wsl-msi-cache
if: steps.wsl-version.outputs.needs-install == 'true'
uses: actions/cache/restore@v5
with:
path: ${{ runner.temp }}/wsl-msi
key: wsl-orcad-msi-${{ env.WSL_MSI_SHA256 }}
- name: Install WSL 3.0.1
if: steps.wsl-version.outputs.needs-install == 'true'
timeout-minutes: 8
run: |
"ImageOS=$env:ImageOS ImageVersion=$env:ImageVersion"
wsl.exe --version
$dir = Join-Path $env:RUNNER_TEMP 'wsl-msi'
New-Item -ItemType Directory -Force $dir | Out-Null
$msi = Join-Path $dir 'wsl.msi'
@@ -101,18 +113,34 @@ jobs:
if ((Get-FileHash $msi -Algorithm SHA256).Hash.ToLowerInvariant() -ne $env:WSL_MSI_SHA256) {
Remove-Item $msi; throw 'WSL package checksum mismatch'
}
$install = Start-Process msiexec.exe -ArgumentList @('/i', $msi, '/qn', '/norestart', '/l*v', (Join-Path $env:RUNNER_TEMP 'wsl-msi.log')) -Wait -PassThru
if ($install.ExitCode -notin 0, 3010) { throw "WSL install failed: $($install.ExitCode)" }
# Kept beside the receipts so the always() upload carries it.
New-Item -ItemType Directory -Force $env:ORCA_WSL_ORCAD_LANE_RECEIPTS | Out-Null
$log = Join-Path $env:ORCA_WSL_ORCAD_LANE_RECEIPTS 'wsl-msi-install.log'
$install = Start-Process msiexec.exe -ArgumentList @('/i', $msi, '/qn', '/norestart', '/l*v', $log) -Wait -PassThru
if ($install.ExitCode -notin 0, 3010) {
if (Test-Path $log) {
$lines = @(Get-Content $log)
$failed = ($lines | Select-String -SimpleMatch 'Return value 3' | Select-Object -First 1).LineNumber
if ($failed) { '--- msiexec log before the failing action'; $lines[[math]::Max(0, $failed - 40)..($failed - 1)] }
'--- msiexec log tail'; $lines | Select-Object -Last 60
}
throw "WSL install failed: $($install.ExitCode)"
}
wsl.exe --shutdown
$version = [version](((wsl.exe --version) -join "`n") -replace '(?s)^\D*?(\d+\.\d+\.\d+).*$', '$1')
wsl.exe --version
if ($version -lt [version]'3.0.1') { throw "WSL $version is older than 3.0.1" }
- name: Save the pinned WSL package
if: steps.wsl-msi-cache.outputs.cache-hit != 'true'
if: steps.wsl-version.outputs.needs-install == 'true' && steps.wsl-msi-cache.outputs.cache-hit != 'true'
uses: actions/cache/save@v5
with:
path: ${{ runner.temp }}/wsl-msi
key: wsl-orcad-msi-${{ env.WSL_MSI_SHA256 }}
- name: Verify WSL is at least 3.0.1
run: |
$details = (wsl.exe --version) -join "`n"
if ($LASTEXITCODE -ne 0) { throw "Could not read the WSL version: $details" }
$details
$match = [regex]::Match($details, '(?m)^WSL version:\s*(\d+(?:\.\d+){2,3})\s*$')
if (-not $match.Success) { throw 'Could not parse the WSL version' }
if ([version]$match.Groups[1].Value -lt [version]'3.0.1') { throw "WSL $($match.Groups[1].Value) is older than 3.0.1" }
- name: Restore the pinned rootfs
id: rootfs-cache
uses: actions/cache/restore@v5
+2 -3
View File
@@ -42,6 +42,7 @@ import {
import { stampRuntimeSourceEnv } from '../../shared/runtime-source-env'
import { adoptWslHostLoginEnvironment } from './orcad-wsl-host-login-environment'
import { installOrcadProcessErrorGuards } from './orcad-process-error-guards'
import { orcadWsPortOptions } from './orcad-ws-port-policy'
export { parseArgs }
@@ -340,9 +341,7 @@ async function startOrcadRuntime(
// once a device has connected, so a loopback deployment would silently go wide one
// restart after its first client paired.
pinnedBindHost: bindHost,
...(options.port !== undefined
? { wsPort: options.port, preferPinnedWsPort: true, requirePinnedWsPort: true }
: {})
...orcadWsPortOptions(options.port)
})
// Stops first: no RPC may write while the rest of the runtime is torn down.
registerCleanup(() => rpc.stop())
@@ -0,0 +1,23 @@
import { describe, expect, it } from 'vitest'
import { ORCAD_MANAGED_ACTIVATION_ROOT_ENV } from '../../shared/orcad-managed-launch-env'
import { orcadWsPortOptions } from './orcad-ws-port-policy'
describe('orcadWsPortOptions', () => {
it('leaves the default port and its fallback alone without --port', () => {
expect(orcadWsPortOptions(undefined, {})).toEqual({})
})
it('requires an operator --port', () => {
expect(orcadWsPortOptions(7001, {})).toEqual({
wsPort: 7001,
preferPinnedWsPort: true,
requirePinnedWsPort: true
})
})
it('lets a managed launch fall back when its port is taken', () => {
expect(
orcadWsPortOptions(6768, { [ORCAD_MANAGED_ACTIVATION_ROOT_ENV]: '/home/u/.orca-remote' })
).toEqual({ wsPort: 6768, preferPinnedWsPort: true })
})
})
+27
View File
@@ -0,0 +1,27 @@
import { ORCAD_MANAGED_ACTIVATION_ROOT_ENV } from '../../shared/orcad-managed-launch-env'
export type OrcadWsPortOptions = {
wsPort?: number
preferPinnedWsPort?: boolean
requirePinnedWsPort?: boolean
}
/**
* An operator's `--port` must bind exactly that port. A managed launch passes the default port as
* a preference and reads the bound port back from readiness: WSL2 distros share one VM loopback,
* and an SSH host's 6768 may already be taken, so it must keep the fallback ladder.
*/
export function orcadWsPortOptions(
port: number | undefined,
env: NodeJS.ProcessEnv = process.env
): OrcadWsPortOptions {
if (port === undefined) {
return {}
}
const managed = Boolean(env[ORCAD_MANAGED_ACTIVATION_ROOT_ENV])
return {
wsPort: port,
preferPinnedWsPort: true,
...(managed ? {} : { requirePinnedWsPort: true })
}
}