mirror of
https://github.com/stablyai/orca.git
synced 2026-10-02 16:02:15 +00:00
* ci(ssh): import the private Windows OpenSSH provisioning harness Copied unchanged from origin/OrcaWin/np-windows-ssh-provider-diagnostic (config/ci/windows-ssh-provider/preview-ssh/ at1242f3c4c8, commits78b3857a0d,c24adccff0,069aa7b38b): a private LocalSystem sshd service on 127.0.0.1 for a dedicated standard user, either the Microsoft-signed Win32-OpenSSH 10.0.0.0p2-Preview ZIP (archive and every binary pinned by sha256) or the inbox OpenSSH.Server capability binaries. The following commits extend it for the pinned-Node relay host lanes. * test(ssh): run hostile-host cells through a host-agnostic driver The Docker matrix drove the relay deploy and inspected the container with inline docker exec calls, so no other host could reuse it. Split it into: - ssh-hostile-host-test-harness.ts: the deploy, ladder observation, terminal echo (per-shell probe), runtime reuse and GC-keeps-in-use assertions, now also capturing every command the deploy sent the host. - ssh-hostile-host-observer.ts: how a driver inspects the host outside SSH; docker exec for containers, the local filesystem for a loopback host. - a legacy_opt_out outcome: the ladder never runs and nothing enters the pinned store, whatever the host-Node path does. Launched cells now also check the runtime's sha256 on the host and that every slot file (the Windows bundled ConPTY pair included) landed in the relay dir. * ci(ssh): Windows SSH-host lanes for the pinned-Node relay Phase 2 exit gate, Windows half: the real deployAndLaunchRelay through a real SshConnection against Win32-OpenSSH on 127.0.0.1, on windows-2022 (x64) and windows-11-arm (arm64), for both the inbox OpenSSH.Server capability and the Microsoft-signed 10.0.0.0p2-Preview release (ZIP; archive and each binary pinned by sha256 and Authenticode, as in the imported harness). Builds on the provisioning harness from origin/OrcaWin/np-windows-ssh-provider-diagnostic (previous import commit): - one private standard account per cell, so every cell starts from an empty runtime store; - -HiddenTools: the private sshd service's own Environment carries a PATH without any machine PATH entry holding node/npm/compilers, led by logging .cmd shims; a session probe fails the job if node.exe still resolves; - DefaultShell set per cell by invoke-pinned-relay-cells.ps1 and restored at cleanup (dispatch proven per cell via %COMSPEC%). Cells (src/main/ssh/ssh-windows-host-cells.ts): pinned-cmd (stock sshd), pinned-powershell (DefaultShell = Windows PowerShell) expect rung A on the pinned node.exe with the relay self-test passing, terminal echo, runtime reuse, GC keeping the in-use runtime, stage identity through node.exe and no Add-Type in any decoded session command; legacy-opt-out expects the ladder never to run and an untouched pinned store. * fix(ssh-ci): tolerate absent-drive PATH entries and retry Windows userData teardown Join-Path throws on a machine PATH entry naming a drive the runner lacks, which would abort provisioning before any cell ran; the toolchain split now probes with [IO.File]::Exists over [IO.Path]::Combine, and the self-test covers an absent drive. The hostile-host harness removes its throwaway userData with removeTreeSync so a transient Windows lock cannot fail the lane's afterAll. * fix(ssh-ci): stop the account list rebinding the typed -Accounts param PowerShell variable names are case-insensitive, so $accounts=[List[hashtable]] assigned into the [int]$Accounts parameter and every Windows host job died before provisioning. Rename the list and make the provisioning self-test reject script-scope assignments that shadow a param. * fix(ssh-ci): hide the host toolchain by ACL, since sessions ignore the service PATH Win32-OpenSSH builds a session's PATH from the machine and user registry values, so the private service's Environment never reached SSH sessions and host node.exe stayed visible. Deny the private accounts the toolchain PATH directories, put the logging shims on each account's own PATH, and record failing sshd and client log lines so a refused login is diagnosable from the receipt. * fix(ssh): resolve the upload root before checking entries stay inside it uploadDirectory compared each entry's realpath against the root as given, so a root reached through a symlink, junction or Windows 8.3 short name (C:\Users\RUNNER~1 in TEMP) rejected every entry as escaped and the pinned runtime upload never started. * fix(ssh-ci): fail cells on a vitest failure and give each account its own keys file The cells script read $LASTEXITCODE under the workflow's GetNewClosure callback, which sees a stale captured copy, so failed cells reported exit 0 and the job passed. Read the global value. Inbox sshd 8.1 checks authorized_keys with read_ok=0, refusing a file other accounts can read; use one keys file per account via %u. * fix(ssh-ci): keep the account name in inbox mode and surface the WMI launch gap The inbox binary-verification loop reused $name, so later SSH and SFTP probes logged in as 'sftp-server.exe'. Before the cells run, probe whether a standard SSH user can call WMI Win32_Process.Create (the Windows relay launch path); when refused, warn and grant the cell accounts Remote Enable on root\cimv2 for the run so the remaining assertions execute. * test(ssh): keep the first terminal session answering keepalives through GC The hostile-host driver disposed the first session's multiplexer before the GC and reconnect steps, so a slow Windows GC let the relay reap the silent owner as 'local' and the reconnect then waited out the full owner grace. Keep the session live until the connection closes, as the app does, and resend the terminal probe until the shell evaluates it: ConPTY PowerShell can drop typeahead sent before its first prompt. * ci(ssh): keep each cell's relay logs in the receipts * fix(relay): detach an ended socket client as peer-closed before destroying it The listener destroyed a socket on 'end' but detached its client only on 'close'. A relay write in that window failed with 'Relay socket is closed', and the dispatcher closed the client as 'local', so its PTY owner kept the full 30s grace instead of the peer-closed floor and a quick reconnect was refused. The Windows host lanes logged this race on the named-pipe endpoint. * test(relay): drive the peer-end listener test with a real dispatcher instead of a cast stub The stub was an unchecked 'as unknown as RelayDispatcher' that failed the changed-code casting gate. --------- Co-authored-by: m4air <m4air@m4airs-Air.localdomain>
84 lines
3.1 KiB
JavaScript
84 lines
3.1 KiB
JavaScript
import { readFileSync } from 'node:fs'
|
|
import { join, resolve } from 'node:path'
|
|
import { describe, expect, it } from 'vitest'
|
|
import { parse } from 'yaml'
|
|
import {
|
|
WINDOWS_FORBIDDEN_TOOLS,
|
|
WINDOWS_HOST_CELL_IDS
|
|
} from '../../src/main/ssh/ssh-windows-host-cells.ts'
|
|
|
|
const projectDir = resolve(import.meta.dirname, '../..')
|
|
const workflow = parse(
|
|
readFileSync(join(projectDir, '.github/workflows/ssh-windows-hosts.yml'), 'utf8')
|
|
)
|
|
const job = workflow.jobs.hosts
|
|
const runStep = job.steps.find((step) => step.name?.startsWith('Run the Windows host cells'))
|
|
const manifest = (arch) =>
|
|
JSON.parse(
|
|
readFileSync(
|
|
join(
|
|
projectDir,
|
|
`config/ci/windows-ssh-provider/preview-ssh/preview-native-inputs-${arch}.json`
|
|
),
|
|
'utf8'
|
|
)
|
|
)
|
|
|
|
describe('SSH Windows-host workflow', () => {
|
|
it('runs on demand and on path-filtered, non-draft pull requests only', () => {
|
|
expect(Object.keys(workflow.on).sort()).toEqual(['pull_request', 'workflow_dispatch'])
|
|
const paths = workflow.on.pull_request.paths
|
|
expect(paths).toContain('src/main/ssh/ssh-relay-*')
|
|
expect(paths).toContain('config/ci/windows-ssh-provider/**')
|
|
expect(paths.indexOf('src/main/ssh/ssh-relay-windows-host-lane.test.ts')).toBeGreaterThan(
|
|
paths.indexOf('!src/**/*.test.ts')
|
|
)
|
|
expect(job.if).toContain('github.event.pull_request.draft != true')
|
|
})
|
|
|
|
it('covers inbox and preview OpenSSH on both Windows architectures', () => {
|
|
const cells = job.strategy.matrix.include.map(({ arch, runner, server }) =>
|
|
[arch, runner, server].join('/')
|
|
)
|
|
expect(cells.sort()).toEqual([
|
|
'arm64/windows-11-arm/inbox',
|
|
'arm64/windows-11-arm/preview',
|
|
'x64/windows-2022/inbox',
|
|
'x64/windows-2022/preview'
|
|
])
|
|
expect(job.env).toMatchObject({ ORCA_BACKGROUND_LAUNCH: '1', ORCA_ISOLATED_SSH_CI: '1' })
|
|
})
|
|
|
|
it('fetches the preview release its hash manifests pin', () => {
|
|
for (const arch of ['x64', 'arm64']) {
|
|
expect(runStep.run).toContain(
|
|
`https://github.com/PowerShell/Win32-OpenSSH/releases/download/${manifest(arch).release}/`
|
|
)
|
|
}
|
|
})
|
|
|
|
it('builds the template for this runner only and shims exactly the cell toolchain list', () => {
|
|
const build = job.steps.map((step) => step.run ?? '').join('\n')
|
|
expect(build).toContain('--targets "win32-${{ matrix.arch }}"')
|
|
expect(build).toContain('pnpm run build:relay')
|
|
const shimmed = /-HiddenTools @\(([^)]*)\)/.exec(runStep.run)?.[1]
|
|
expect(shimmed?.split(',').map((tool) => tool.trim().replaceAll("'", ''))).toEqual([
|
|
...WINDOWS_FORBIDDEN_TOOLS
|
|
])
|
|
})
|
|
|
|
it('defaults to every cell the TypeScript lane knows', () => {
|
|
const defaults = /\{\$cells=@\(([^)]*)\)\}/.exec(runStep.run)?.[1]
|
|
expect(defaults?.split(',').map((id) => id.trim().replaceAll("'", ''))).toEqual([
|
|
...WINDOWS_HOST_CELL_IDS
|
|
])
|
|
const invoker = readFileSync(
|
|
join(projectDir, 'config/ci/windows-ssh-provider/invoke-pinned-relay-cells.ps1'),
|
|
'utf8'
|
|
)
|
|
for (const id of WINDOWS_HOST_CELL_IDS) {
|
|
expect(invoker).toContain(`'${id}'`)
|
|
}
|
|
})
|
|
})
|