mirror of
https://github.com/stablyai/orca.git
synced 2026-10-18 00:03:20 +00:00
test(ssh): isolate Windows no-input pipe EOF
Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
+11
-6
@@ -123,12 +123,17 @@ independently returns the same lifecycle RED. The corrected POSIX contract uses
|
||||
`Writable` facade so ending it cannot half-close the command channel. Exact correction head
|
||||
`4f57b885d24ad1755a5c863eaf37369208cecedb`, artifact run `29545688003`, and Linux x64/ARM64
|
||||
jobs `87777401256`/`87777401218` are green through live SFTP and restricted no-tar POSIX system
|
||||
SSH. Windows x64/ARM64 jobs `87777401200`/`87777401195` independently falsify the standard
|
||||
anonymous-pipe EOF hypothesis with the unchanged four-field timeout and profile RED. Next compare a
|
||||
console-independent overlapped pipe against inherited stdin as a diagnostic control; do not change
|
||||
the production Windows handle until native evidence selects it. The disconnected bounded diagnostic
|
||||
and workflow ordering are locally green under
|
||||
`E-M6-WINDOWS-NOINPUT-HANDLE-DIAGNOSTIC-LOCAL-001`; native x64/ARM64 execution is next.
|
||||
SSH. Windows x64/ARM64 jobs `87777401200`/`87777401195` reproduce the unchanged four-field timeout
|
||||
with a standard pipe plus mandatory `-n`. Exact diagnostic head
|
||||
`da938a7405d0a6c760979358a6c0a38030d9acaf`, artifact run `29546702916`, and Windows x64/ARM64 jobs
|
||||
`87780486286`/`87780486259` prove that inherited and overlapped handles also time out when every
|
||||
candidate retains `-n`; the invalid inherited control and shared `-n` mean these runs do not isolate
|
||||
the child handle. `E-M6-WINDOWS-NOINPUT-HANDLE-DIAGNOSTIC-CI-RED-001` therefore requires the next
|
||||
single-variable diagnostic to use the upstream-recommended standard stdin pipe with immediate EOF
|
||||
and omit `-n` only on Windows. POSIX retains ignored stdin plus `-n`; production stays unchanged
|
||||
until x64 and ARM64 select the same console-independent strategy. The replacement disconnected
|
||||
diagnostic is locally green under `E-M6-WINDOWS-NOINPUT-PIPE-NO-N-LOCAL-001`; commit and run that
|
||||
exact head next.
|
||||
`E-M6-WINDOWS-SYSTEM-SSH-TREE-LIVE-AUDIT-001` fixes the loopback-only official Microsoft
|
||||
server, fixture-owned non-admin account/ACL, exact host-key trust, Windows PowerShell 5.1,
|
||||
serial/default and four-channel metrics, cancellation/collision/cleanup, and deterministic teardown
|
||||
|
||||
+70
-7
@@ -9,7 +9,7 @@ work; keep exact commands, runner identities, hashes, metrics, and residual gaps
|
||||
Date created: 2026-07-14<br>
|
||||
Last updated: 2026-07-15<br>
|
||||
Current phase: Milestone 6 / Work Package 5 bounded runtime transfer — **In progress — 2026-07-15, Codex implementation owner: native Windows no-input handle qualification**. Keep every capability disconnected from every production/default SSH path. Real Apple/SignPath rehearsals remain an explicit late gate and are not on this package's critical path.<br>
|
||||
Session checkpoint: **POSIX EOF CORRECTION NATIVELY GREEN / STANDARD WINDOWS PIPE NATIVELY RED / HANDLE DIAGNOSTIC LOCALLY GREEN — 2026-07-15, Codex implementation owner** — exact correction head `4f57b885d24ad1755a5c863eaf37369208cecedb`, artifact run `29545688003`, and Linux x64/ARM64 jobs `87777401256`/`87777401218` prove the separate no-input facade through live SFTP and restricted no-tar POSIX system SSH with bounded full-size transfer, four-file concurrency, cancellation, and cleanup. Windows x64/ARM64 jobs `87777401200`/`87777401195` independently falsify the standard anonymous-pipe EOF hypothesis: official OpenSSH authenticates and the remote command closes, but clients time out after 31.36/31.82 seconds with `sentinel=false`, `stdoutEnded=false`, `processExit=not-observed`, and `channelClosed=false`; exact profile teardown remains RED. `E-M6-WINDOWS-NOINPUT-HANDLE-DIAGNOSTIC-LOCAL-001` adds a bounded, non-sensitive native comparison of a console-independent overlapped pipe and inherited-stdin upstream control before the unchanged full-size measurement; focused 117+2, 283-contract, typecheck, full lint/reliability/max-lines, all three PowerShell parse, formatting, diff, and protected-resolver gates pass locally. Commit/push and require native x64/ARM64 diagnostic output before selecting another production handle. Do not advance Milestone 6. Production runtime bytes still cross authenticated SSH and no product remote downloads anything. Do not connect a product caller, change legacy upload/fallback/default behavior, enable a tuple, publish an artifact, or perform SignPath work. Merging to `main` remains prohibited, SignPath is deferred, and legacy remains the production default.<br>
|
||||
Session checkpoint: **POSIX EOF CORRECTION NATIVELY GREEN / WINDOWS `-n` HANDLE DIAGNOSTIC NATIVELY RED / NO-`-n` PIPE DIAGNOSTIC LOCALLY GREEN — 2026-07-15, Codex implementation owner** — exact correction head `4f57b885d24ad1755a5c863eaf37369208cecedb`, artifact run `29545688003`, and Linux x64/ARM64 jobs `87777401256`/`87777401218` prove the separate no-input facade through live SFTP and restricted no-tar POSIX system SSH with bounded full-size transfer, four-file concurrency, cancellation, and cleanup. Windows x64/ARM64 jobs `87777401200`/`87777401195` reproduce the no-input hang with a standard pipe plus mandatory `-n`. Exact diagnostic head `da938a7405d0a6c760979358a6c0a38030d9acaf`, artifact run `29546702916`, and Windows x64/ARM64 jobs `87780486286`/`87780486259` prove that inherited and overlapped handles also time out when every candidate retains `-n`; both inherited controls are invalid on redirected hosted-runner stdin, so the runs do not isolate the child handle. Each x64 attempt reports 8.03/8.02 seconds and each ARM64 attempt 8.04/8.02 seconds with `sentinel=false`, `stdoutEnded=true`, termination-only null exit/close codes, zero stderr bytes, and exact profile teardown RED. `E-M6-WINDOWS-NOINPUT-PIPE-NO-N-LOCAL-001` replaces only the disconnected diagnostic with the upstream-recommended standard stdin pipe, immediate parent EOF, ordinary stdout/stderr, and no `-n`; focused 117+2, 283-contract, format, typecheck, full lint/reliability/max-lines, diff, and protected-resolver gates pass locally. Commit/push and require a fresh exact-head x64/ARM64 result next. Do not change production or advance Milestone 6 without both native results. Production runtime bytes still cross authenticated SSH and no product remote downloads anything. Do not connect a product caller, change legacy upload/fallback/default behavior, enable a tuple, publish an artifact, or perform SignPath work. Merging to `main` remains prohibited, SignPath is deferred, and legacy remains the production default.<br>
|
||||
Primary design: [SSH relay GitHub Release plan](./2026-07-14-ssh-relay-github-release-plan.html)<br>
|
||||
Motivating issues: [#8450](https://github.com/stablyai/orca/issues/8450), [#1693](https://github.com/stablyai/orca/issues/1693)
|
||||
|
||||
@@ -19433,6 +19433,69 @@ config/scripts/ssh-relay-runtime-workflow.test.mjs` passes 117 cases with two de
|
||||
- Residual boundary: local macOS intentionally skips the live case. Require exact-head native x64
|
||||
and ARM64 output before selecting any Windows handle; keep profile teardown, full-size transfer,
|
||||
default behavior, fallback, Beta, tuple publication, and SignPath separately gated.
|
||||
- Native proof result: exact diagnostic head `da938a7405d0a6c760979358a6c0a38030d9acaf`, artifact run
|
||||
`29546702916`, Windows x64 job `87780486286`, and Windows ARM64 job `87780486259` are RED as
|
||||
recorded by `E-M6-WINDOWS-NOINPUT-HANDLE-DIAGNOSTIC-CI-RED-001`; the workflow correctly stops
|
||||
before the following unchanged product full-size result.
|
||||
|
||||
### E-M6-WINDOWS-NOINPUT-HANDLE-DIAGNOSTIC-CI-RED-001 — mandatory `-n` invalidates every hosted handle control
|
||||
|
||||
- Date/owner/head/run: 2026-07-15, Codex implementation owner; exact pushed head
|
||||
`da938a7405d0a6c760979358a6c0a38030d9acaf`, artifact run `29546702916`, Windows x64 job
|
||||
`87780486286` on `windows-2022`, and Windows ARM64 job `87780486259` on `windows-11-arm`.
|
||||
- Exact log command: `gh api repos/stablyai/orca/actions/jobs/<job-id>/logs | rg -n -C 10
|
||||
'ssh_windows_no_input_handle_diagnostic|Windows no-input handle diagnostic failed|profile
|
||||
teardown:|UsrClass.dat'` for each job.
|
||||
- X64 result: inherited and overlapped attempts both return `success=false`, `timedOut=true`,
|
||||
`sentinel=false`, `stdoutEnded=true`, `processExit=null`, `channelClosed=true`, `closeCode=null`,
|
||||
and `stderrBytes=0` after 8029.88/8021.57 milliseconds. ARM64 independently returns the same
|
||||
fields after 8044.18/8015.22 milliseconds. These exit/close fields are termination settlement,
|
||||
not remote-command success.
|
||||
- Teardown result: both exact jobs fail `_Classes` hive unload, retain locked `UsrClass.dat`, and
|
||||
retain the fixture profile directory. The workflow correctly stops before the unchanged product
|
||||
full-size test; no Windows transport cell is green and no tuple is enabled.
|
||||
- Interpretation: the inherited control is invalid because hosted-runner stdin is itself redirected.
|
||||
More importantly, inherited, standard-pipe, and overlapped candidates all retained OpenSSH `-n`,
|
||||
which routes Windows no-input handling through the same null-input boundary implicated by
|
||||
Win32-OpenSSH #856/#1330. These runs cannot reject the child pipe independently of `-n`.
|
||||
- Course correction: before production changes, run one bounded single-variable diagnostic using
|
||||
Node's standard stdin pipe, destroy the parent writer immediately, keep stdout/stderr as ordinary
|
||||
pipes, and omit `-n` only for that Windows attempt. This is the upstream-recommended pipe EOF
|
||||
boundary without the confounding null-input option. Test an overlapped stdin pipe without `-n`
|
||||
only if the standard pipe remains RED. POSIX keeps ignored stdin plus `-n`.
|
||||
- Residual boundary: require exact-head x64 and ARM64 lifecycle and exact teardown proof. Keep the
|
||||
product handle, default, legacy fallback, Beta, tuple publication, and SignPath unchanged.
|
||||
|
||||
### E-M6-WINDOWS-NOINPUT-PIPE-NO-N-LOCAL-001 — unconfounded standard-pipe EOF diagnostic is locally green
|
||||
|
||||
- Date/owner/base/runner: 2026-07-15, Codex implementation owner; uncommitted replacement atop exact
|
||||
RED head `da938a7405d0a6c760979358a6c0a38030d9acaf` on Apple arm64, macOS 26.2 build 25C56,
|
||||
Node 26.5.0, pnpm 10.24.0.
|
||||
- Diagnostic boundary: the disconnected Windows live test now spawns `ssh.exe` with standard stdin,
|
||||
stdout, and stderr pipes, destroys the parent stdin writer immediately, and deliberately calls
|
||||
`buildSshArgs` without `noInput` so OpenSSH receives no `-n`. The 8-second timeout and 10-second
|
||||
hard settlement bound, non-sensitive lifecycle fields, workflow ordering, and fail-closed step
|
||||
remain unchanged. Production args, handles, no-input facade, and product full-size test are not
|
||||
changed.
|
||||
- Focused command: `/usr/bin/time -l pnpm exec vitest run --config config/vitest.config.ts
|
||||
--maxWorkers=1 src/main/ssh/ssh-connection.test.ts src/main/ssh/ssh-system-fallback.test.ts
|
||||
src/main/ssh/ssh-system-no-input-windows-openssh.test.ts
|
||||
src/main/ssh/ssh-relay-runtime-windows-system-ssh-openssh-full-size.test.ts
|
||||
config/scripts/ssh-relay-runtime-workflow.test.mjs` passes 117 cases with two expected native
|
||||
skips in 4.07 seconds real; maximum RSS is 168,067,072 bytes and peak footprint 97,589,080 bytes.
|
||||
- Release contracts: `/usr/bin/time -l pnpm exec vitest run --config config/vitest.config.ts
|
||||
--maxWorkers=1 --reporter=dot config/scripts/ssh-relay-runtime-*.test.mjs` passes 50 files and
|
||||
283/283 cases in 25.92 seconds real; maximum RSS is 195,493,888 bytes and peak footprint
|
||||
97,687,288 bytes.
|
||||
- Static gates: `/usr/bin/time -l pnpm typecheck` passes in 5.73 seconds real with maximum RSS
|
||||
1,225,736,192 bytes and peak footprint 96,687,936 bytes. `/usr/bin/time -l pnpm lint` passes in
|
||||
24.85 seconds real with the same 26 pre-existing warnings, all 41 reliability gates, and the
|
||||
355-entry max-lines ratchet; maximum RSS is 2,055,323,648 bytes and peak footprint 98,260,872
|
||||
bytes. `pnpm exec oxfmt --check <four changed files>`, `git diff --check`, and the protected
|
||||
resolver zero-diff gate pass after formatting.
|
||||
- Residual boundary: local macOS skips both native live cases. Commit the diagnostic and evidence,
|
||||
then require a fresh exact-head artifact run with the same successful lifecycle on Windows x64
|
||||
and ARM64 plus exact profile/directory teardown before any production handle change.
|
||||
|
||||
## Accepted Gaps
|
||||
|
||||
@@ -19492,12 +19555,12 @@ The project is not complete until every applicable item below is checked with ev
|
||||
|
||||
## Next Required Action
|
||||
|
||||
Implement the purpose-named disconnected Windows no-input handle diagnostic required by
|
||||
`E-M6-WINDOWS-NOINPUT-STANDARD-PIPE-CI-RED-001`. Compare an overlapped pipe with immediate parent
|
||||
destruction against inherited stdin, keep each attempt bounded, and record sentinel/stdout-end/
|
||||
process-exit/channel-close on native x64 and ARM64. Do not change the production Windows handle or
|
||||
check the broad Milestone 6 Windows system-SSH item until the diagnostic selects a console-independent
|
||||
strategy. Do not add an Electron/startup/product importer, per-target mode wiring, fallback, tuple
|
||||
Commit and push the disconnected no-`-n` standard-pipe diagnostic recorded by
|
||||
`E-M6-WINDOWS-NOINPUT-PIPE-NO-N-LOCAL-001`, then run the exact head on Windows x64 and ARM64 and
|
||||
record sentinel/stdout-end/process-exit/channel-close plus exact profile/directory teardown. Do not
|
||||
change the production Windows handle or check the broad Milestone 6 Windows system-SSH item until
|
||||
both architectures select the same console-independent strategy. Do not add an
|
||||
Electron/startup/product importer, per-target mode wiring, fallback, tuple
|
||||
enablement, release publication, or default behavior.
|
||||
Keep Node upstream `.tar.xz` inputs, Windows ZIP, `ORCA_RELAY_PATH`, existing desktop required-assets
|
||||
behavior, detached-signature byte encoding, Windows arm64 build 26100, macOS 13.5, Linux kernel 4.18,
|
||||
|
||||
@@ -1646,13 +1646,15 @@
|
||||
stdout-end, sentinel, and channel-close settlement; POSIX no-input probes use an
|
||||
OS-level ignored stdin handle plus OpenSSH <code>-n</code>; Windows must not map
|
||||
stdin to <code>NUL</code> because Win32-OpenSSH issues #856/#1330 document a
|
||||
redirected-handle hang; a standard anonymous pipe with its parent write end
|
||||
destroyed is also rejected by native x64/arm64 evidence; qualify a
|
||||
console-independent overlapped-pipe EOF strategy against an inherited-stdin
|
||||
control before selecting the Windows handle, always with <code>-n</code>;
|
||||
fixture-owned Windows session processes settle before profile hives are
|
||||
boundedly unloaded and native profile deletion begins;
|
||||
<code>MaxSessions=1</code>; interrupted upload; stale lock
|
||||
redirected-handle hang; native x64/arm64 evidence also proves that inherited,
|
||||
standard-pipe, and overlapped-pipe handles all hang when the Windows client is
|
||||
simultaneously forced through <code>-n</code>, so those runs do not isolate the
|
||||
child handle. Qualify the upstream-recommended standard-pipe EOF with Windows
|
||||
<code>-n</code> omitted as the next single-variable diagnostic; only test an
|
||||
overlapped stdin pipe, also without <code>-n</code>, if the standard pipe fails.
|
||||
POSIX retains ignored stdin plus <code>-n</code>; fixture-owned Windows session
|
||||
processes settle before profile hives are boundedly unloaded and native profile
|
||||
deletion begins; <code>MaxSessions=1</code>; interrupted upload; stale lock
|
||||
</td>
|
||||
<td>
|
||||
Bundled Node hashes the full staged tree before sentinel write;
|
||||
|
||||
@@ -7,7 +7,7 @@ import type { SshTarget } from '../../shared/ssh-types'
|
||||
import { buildSshArgs } from './system-ssh-args'
|
||||
import { findSystemSsh } from './system-ssh-binary'
|
||||
|
||||
type DiagnosticMode = 'inherited' | 'overlapped'
|
||||
type DiagnosticMode = 'pipe-eof-no-n'
|
||||
|
||||
type DiagnosticResult = {
|
||||
mode: DiagnosticMode
|
||||
@@ -42,28 +42,20 @@ function createTarget(): SshTarget {
|
||||
}
|
||||
}
|
||||
|
||||
async function runDiagnostic(mode: DiagnosticMode): Promise<DiagnosticResult> {
|
||||
async function runDiagnostic(): Promise<DiagnosticResult> {
|
||||
const sshPath = findSystemSsh()
|
||||
if (!sshPath) {
|
||||
throw new Error('Native Windows OpenSSH client is unavailable')
|
||||
}
|
||||
const mode: DiagnosticMode = 'pipe-eof-no-n'
|
||||
const startedAt = performance.now()
|
||||
const child = spawn(
|
||||
sshPath,
|
||||
[...buildSshArgs(createTarget(), { noInput: true }), 'echo ORCA-SYSTEM-SSH-OK'],
|
||||
{
|
||||
// Why: qualify a console-independent overlapped pipe against the
|
||||
// upstream inherited-handle control before changing production.
|
||||
stdio:
|
||||
mode === 'overlapped'
|
||||
? ['overlapped', 'overlapped', 'overlapped']
|
||||
: ['inherit', 'pipe', 'pipe'],
|
||||
windowsHide: true
|
||||
}
|
||||
)
|
||||
if (mode === 'overlapped') {
|
||||
child.stdin?.destroy()
|
||||
}
|
||||
const child = spawn(sshPath, [...buildSshArgs(createTarget()), 'echo ORCA-SYSTEM-SSH-OK'], {
|
||||
// Why: isolate the upstream-recommended pipe EOF from Win32-OpenSSH's
|
||||
// null-input path before changing the production no-input command.
|
||||
stdio: ['pipe', 'pipe', 'pipe'],
|
||||
windowsHide: true
|
||||
})
|
||||
child.stdin?.destroy()
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
let stdout = ''
|
||||
@@ -141,18 +133,14 @@ async function runDiagnostic(mode: DiagnosticMode): Promise<DiagnosticResult> {
|
||||
|
||||
describe.skipIf(!hasLiveInput)('Windows OpenSSH no-input child-handle diagnostic', () => {
|
||||
it(
|
||||
'compares inherited stdin with a console-independent overlapped EOF pipe',
|
||||
{ timeout: 30_000 },
|
||||
'qualifies a standard EOF pipe without the Windows null-input option',
|
||||
{ timeout: 15_000 },
|
||||
async () => {
|
||||
expect(process.platform).toBe('win32')
|
||||
const inherited = await runDiagnostic('inherited')
|
||||
const overlapped = await runDiagnostic('overlapped')
|
||||
console.log(
|
||||
`ssh_windows_no_input_handle_diagnostic=${JSON.stringify({ inherited, overlapped })}`
|
||||
)
|
||||
const pipeEofNoN = await runDiagnostic()
|
||||
console.log(`ssh_windows_no_input_handle_diagnostic=${JSON.stringify({ pipeEofNoN })}`)
|
||||
|
||||
// The inherited control must settle or this fixture cannot distinguish handle strategies.
|
||||
expect(inherited.success).toBe(true)
|
||||
expect(pipeEofNoN.success).toBe(true)
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user