Files
orca/.github/workflows/ssh-windows-hosts.yml
T
Workflow config file is invalid. Please check your config file: getMatrixes: matrix include must be a list of mappings
OrcaWinandOrcaWin 791502fae4 ci: move secondary, scheduled and contract workflows to GitHub-hosted runners (#34568)
* ci: move secondary, scheduled and contract workflows to GitHub-hosted runners

Public-repo standard hosted runners are free under Enterprise. Release, build,
benchmark, e2e and unit workflows stay on Blacksmith. ci-xterm-cache seeds both
cache stores since its PR consumer's pool is undecided.

* test(pi): resolve the smoke bundle's external packages from the repo

#34148 pulled zod into the commit-message planner graph; the bundle in the
OS temp dir could not resolve it on any runner.

* ci(unit): use four workers on the hosted four-core x64 runner

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-27 16:15:14 -07:00

255 lines
14 KiB
YAML

name: SSH Windows hosts
# Managed orcad against a real Win32-OpenSSH server on 127.0.0.1 (inbox capability and the pinned
# 10.0.0.0p2-Preview release), on x64 and arm64. Each job provisions a private sshd service and one
# standard account per cell (config/ci/windows-ssh-provider/), hides the host toolchain from SSH
# sessions behind logging shims, and deploys orcad on the pinned node.exe in both DefaultShell cases.
on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review, converted_to_draft]
paths:
- 'src/main/ssh/remote-*'
- 'src/main/ssh/*runtime*'
- 'src/main/ssh/orcad-*'
- 'src/main/managed-server/**'
- 'src/main/orcad/orcad-artifact-materializer.ts'
- 'src/main/orcad/orcad-host-unavailable.ts'
- 'src/main/node-runtime/**'
- 'src/main/ssh/ssh-remote-*'
- 'src/main/ssh/hostile-host-test-support/**'
- 'src/main/ssh/ssh-windows-host-*'
- 'src/wsl-guest/**'
- 'src/packages/process-host/**'
- 'pnpm-workspace.yaml'
- 'src/shared/node-runtime-pin.ts'
- 'src/shared/orcad-artifacts.ts'
- 'config/scripts/build-orcad-*.mjs'
- 'config/scripts/orcad-prebuild-*.mjs'
- 'config/scripts/orcad-windows-process-tree.mjs'
- 'config/scripts/orcad-windows-cli-launcher.mjs'
- 'config/scripts/orcad-windows-security.mjs'
- 'config/scripts/build-windows-security-addon.mjs'
- 'native/windows-security/**'
- 'config/scripts/build-windows-cli-launcher.mjs'
- 'config/scripts/windows-rust-executable-build.mjs'
- 'native/windows-cli-launcher/**'
- 'src/main/orcad/orcad-cli-launcher.ts'
- '.github/actions/prepare-windows-cli-launcher/**'
- 'config/patches/node-pty*'
- 'config/patches/@vscode__windows-process-tree*'
- 'config/scripts/build-windows-process-tree-addon.mjs'
- 'config/scripts/windows-process-tree-prepared-addon*.mjs'
- 'config/scripts/windows-process-tree-gyp-rebuild.mjs'
- 'src/shared/windows-breakaway-launch*.ts'
- 'src/main/ipc/ssh/ssh-host-server-*.ts'
# The deploy runs over this SSH transport.
- 'src/main/ssh/connection/**'
- 'src/main/ssh/ssh-reconnect-error-classification.ts'
- 'src/main/ssh/ssh-posix-command-wrapper.ts'
- 'src/shared/shell-argument-quoting.ts'
- '!src/**/*.test.ts'
- 'src/main/managed-server/host-state/orcad-windows-host-lane.test.ts'
- 'tests/e2e/ssh-orcad-auto-convert.spec.ts'
- 'tests/e2e/helpers/orcad-convert-host.ts'
- 'tests/e2e/helpers/orcad-convert-flow.ts'
- 'tests/e2e/helpers/orcad-upgrade-profile.ts'
- 'tests/e2e/ssh-orcad-windows-cli-matrix.spec.ts'
- 'tests/e2e/helpers/compiled-orca-cli.ts'
- 'tests/e2e/helpers/windows-host-orcad-processes.ts'
- 'config/ci/windows-ssh-provider/**'
- 'config/ci/windows-lifecycle-receipt.ps1'
- '.github/workflows/ssh-windows-hosts.yml'
- '.github/actions/prepare-orcad-prebuilds/**'
- '.github/actions/restore-pnpm-verification/**'
- 'config/scripts/orcad-windows-prebuild-cache.mjs'
workflow_dispatch:
inputs:
cells:
description: Comma-separated cell ids from src/main/ssh/ssh-windows-host-cells.ts; empty runs the default set (orcad-cli-* cells run only when named).
required: false
default: ''
preparation_mode:
description: Compare inbox capability preparation overlapping builds or running after them.
type: choice
options: [overlap, serial]
required: false
default: overlap
arm_inbox_only:
description: Run only the native ARM inbox lane for a preparation timing comparison.
type: boolean
required: false
default: false
permissions:
contents: read
concurrency:
group: ssh-windows-hosts-${{ github.event.pull_request.number || github.ref }}${{ github.event_name == 'workflow_dispatch' && inputs.arm_inbox_only && format('-{0}', inputs.preparation_mode || 'overlap') || '' }}
cancel-in-progress: true
jobs:
mobile_web_bundle:
if: github.event_name != 'pull_request' || github.event.pull_request.draft != true
runs-on: ubuntu-24.04
timeout-minutes: 15
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- uses: ./.github/actions/install-node-dependencies
- uses: ./.github/actions/build-mobile-web-bundle
- uses: actions/upload-artifact@v7
with:
name: ${{ format('ssh-windows-mobile-web-{0}', github.sha) }}
path: out/mobile-web/
if-no-files-found: error
retention-days: 1
overwrite: true
hosts:
needs: mobile_web_bundle
if: >-
${{ !cancelled() && needs.mobile_web_bundle.result == 'success' &&
(github.event_name != 'pull_request' || github.event.pull_request.draft != true) }}
strategy:
fail-fast: false
matrix:
include: >-
${{ fromJSON(github.event_name == 'workflow_dispatch' && inputs.arm_inbox_only &&
'[{"arch":"arm64","runner":"windows-11-arm","server":"inbox"}]' ||
'[{"arch":"x64","runner":"windows-2022","server":"inbox"},{"arch":"x64","runner":"windows-2022","server":"preview","archive":"OpenSSH-Win64.zip"},{"arch":"arm64","runner":"windows-11-arm","server":"inbox"},{"arch":"arm64","runner":"windows-11-arm","server":"preview","archive":"OpenSSH-ARM64.zip"}]') }}
runs-on: ${{ matrix.runner }}
# Installing the inbox capability alone can take several minutes on a fresh image; the CLI matrix
# cells launch the e2e app several times each.
timeout-minutes: ${{ contains(github.event.inputs.cells || '', 'orcad-cli') && 160 || 75 }}
env:
ORCA_BACKGROUND_LAUNCH: '1'
ORCA_ISOLATED_SSH_CI: '1'
INBOX_PREPARATION_MODE: ${{ github.event_name == 'workflow_dispatch' && inputs.preparation_mode == 'serial' && 'serial' || 'overlap' }}
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
# Keep complete server/test trees; missing future imports fail the unchanged builds.
# All of src: the orcad-convert cell builds the full e2e app and the bundled CLI.
# mobile: the template ships the mobile web page, which builds from mobile/.
sparse-checkout: |
.github
config
mobile
native
resources
tests
src
- name: Self-test the provisioning scripts before touching the machine
shell: pwsh
run: |
foreach($file in @(Get-ChildItem -Recurse -Filter *.ps1 config/ci/windows-ssh-provider)){
$errors=$null;$tokens=$null
[Management.Automation.Language.Parser]::ParseFile($file.FullName,[ref]$tokens,[ref]$errors)|Out-Null
if($errors.Count){throw "PowerShell parse failed: $($file.FullName)"}
}
& config/ci/windows-ssh-provider/preview-ssh/test-preview-diagnostics.ps1
# ARM inbox servicing can finish while the independent Node artifacts are prepared.
- name: Prepare the Windows inbox SSH capability
id: inbox-capability
background: true
shell: pwsh
run: |
if('${{ matrix.server }}' -eq 'inbox' -and '${{ matrix.arch }}' -eq 'arm64' -and $env:INBOX_PREPARATION_MODE -eq 'overlap'){
$receipts=Join-Path $pwd '.build/ssh-windows-host-receipts'
New-Item -ItemType Directory -Force -Path $receipts | Out-Null
. config/ci/windows-ssh-provider/preview-ssh/windows-ssh-capability.ps1
Initialize-WindowsInboxSshCapability -Arch '${{ matrix.arch }}' -Receipt (Join-Path $receipts 'inbox-capability-preparation.json') -PreparationMode $env:INBOX_PREPARATION_MODE
}
- uses: ./.github/actions/install-node-dependencies
id: dependencies
with:
native-runtime: node
cache-pnpm-store: 'false'
# The deploy materializes rung A from this template; only this runner's slot exists here.
# The process-tree addon carries the launcher that starts orcad outside sshd's job; the orcad
# slot stages it, and a standard-user host has no other launch route.
- name: Build this runner's Windows process-table addon
shell: bash
env:
REUSE_PREPARED_RUNTIME: ${{ github.event_name == 'pull_request' && steps.dependencies.outputs.native-cache-hit == 'true' }}
run: |
reuse_args=()
if [ "$REUSE_PREPARED_RUNTIME" = true ]; then
reuse_args+=(--reuse-prepared-runtime)
fi
node config/scripts/build-windows-process-tree-addon.mjs --arch=${{ matrix.arch }} "${reuse_args[@]}"
- uses: ./.github/actions/prepare-orcad-prebuilds
with:
resolve-windows-cache: ${{ github.event_name == 'pull_request' }}
restore-windows-cache: ${{ github.event_name == 'pull_request' }}
- uses: ./.github/actions/prepare-windows-cli-launcher
with:
arches: ${{ matrix.arch }}
- uses: actions/download-artifact@v8
id: mobile-bundle
continue-on-error: true
with:
name: ${{ format('ssh-windows-mobile-web-{0}', github.sha) }}
path: out/mobile-web/
# A failed-only retry may outlive the producer artifact's retention.
- uses: ./.github/actions/build-mobile-web-bundle
if: steps.mobile-bundle.outcome != 'success'
- name: Verify the mobile bundle before staging it
shell: bash
run: node -e "require('./config/scripts/verify-packaged-mobile-web-bundle.cjs').assertMobileWebBundleBuilt()"
- name: Build the win32 template
shell: bash
env:
ORCA_REUSE_PREPARED_WINDOWS_SECURITY: ${{ github.event_name == 'pull_request' && steps.dependencies.outcome == 'success' }}
run: |
pnpm build:orcad-prebuilds --require-slots "win32-${{ matrix.arch }}"
node config/scripts/build-orcad-template.mjs --targets "win32-${{ matrix.arch }}"
- wait: inbox-capability
- name: Prepare the Windows inbox SSH capability after the builds
if: ${{ matrix.server == 'inbox' && matrix.arch == 'arm64' && env.INBOX_PREPARATION_MODE == 'serial' }}
shell: pwsh
run: |
$receipts=Join-Path $pwd '.build/ssh-windows-host-receipts'
New-Item -ItemType Directory -Force -Path $receipts | Out-Null
. config/ci/windows-ssh-provider/preview-ssh/windows-ssh-capability.ps1
Initialize-WindowsInboxSshCapability -Arch '${{ matrix.arch }}' -Receipt (Join-Path $receipts 'inbox-capability-preparation.json') -PreparationMode $env:INBOX_PREPARATION_MODE
- name: Run the Windows host cells against a private ${{ matrix.server }} sshd
shell: pwsh
timeout-minutes: ${{ contains(github.event.inputs.cells || '', 'orcad-cli') && 130 || 50 }}
env:
CELLS: ${{ github.event.inputs.cells || '' }}
run: |
$tools=Join-Path $pwd 'config/ci/windows-ssh-provider'
$sourceRoot=$pwd.Path
$receipts=Join-Path $pwd '.build/ssh-windows-host-receipts'
New-Item -ItemType Directory -Force -Path $receipts | Out-Null
$cells=@($env:CELLS -split ',' | ForEach-Object {$_.Trim()} | Where-Object {$_})
if(-not $cells.Count){$cells=@('orcad-cmd','orcad-powershell')}
# One Windows host runs the app-level conversion; it is last because it switches native modules.
if(-not $env:CELLS -and '${{ matrix.arch }}' -eq 'x64' -and '${{ matrix.server }}' -eq 'inbox'){$cells+='orcad-convert'}
# App cells reach the managed server through an SSH local forward, which provisioning grants to the last accounts only.
$appCellIds=@('orcad-convert','orcad-cli-managed','orcad-cli-convert')
$cells=@($cells | Where-Object {$appCellIds -notcontains $_})+@($cells | Where-Object {$appCellIds -contains $_})
$forwarding=@($cells | Where-Object {$appCellIds -contains $_}).Count
$archive=''
$preparation=''
if('${{ matrix.server }}' -eq 'inbox' -and '${{ matrix.arch }}' -eq 'arm64'){$preparation=Join-Path $receipts 'inbox-capability-preparation.json'}
if('${{ matrix.server }}' -eq 'preview'){
$archive=Join-Path $env:RUNNER_TEMP 'preview-${{ matrix.archive }}'
# The provisioning script refuses the archive unless its sha256 and every binary's match the pin.
& "$env:WINDIR\System32\curl.exe" --fail --location --connect-timeout 15 --max-time 90 --output $archive 'https://github.com/PowerShell/Win32-OpenSSH/releases/download/10.0.0.0p2-Preview/${{ matrix.archive }}'
if($LASTEXITCODE -ne 0){throw 'SSH archive fetch failed'}
}
$callback={param($context)
& (Join-Path $tools 'invoke-windows-host-cells.ps1') -SourceRoot $sourceRoot -Context $context -Target 'win32-${{ matrix.arch }}' -ReceiptRoot $receipts -Cells $cells
}.GetNewClosure()
& (Join-Path $tools 'preview-ssh/prove-preview-openssh.ps1') -Archive $archive -Arch '${{ matrix.arch }}' -Server '${{ matrix.server }}' -Receipt (Join-Path $receipts 'provider-server.json') -InboxPreparationReceipt $preparation -Accounts $cells.Count -ForwardingAccounts $forwarding -HiddenTools @('npm','npx','node-gyp','gcc','g++','cc','c++','make','cl','clang','clang++','msbuild','cmake') -HostCellProbe $callback 2>&1 | Tee-Object (Join-Path $receipts 'provision.log')
- uses: actions/upload-artifact@v7
if: always()
with:
name: ssh-windows-host-${{ matrix.arch }}-${{ matrix.server }}-receipts
path: .build/ssh-windows-host-receipts/
retention-days: 7