Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 25 additions & 2 deletions .github/workflows/windows-recovery.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,14 +94,17 @@ on:
- 'packages/runtime-host/src/server/host-resource-probe.ts'
- 'packages/runtime-host/src/server/skill-catalog-repository.ts'
- 'packages/runtime-host/src/server/skill-catalog-transaction.ts'
- 'packages/runtime/src/__tests__/owned-child-process.test.ts'
- 'packages/runtime/src/__tests__/pipe-process-driver.test.ts'
- 'packages/runtime/src/__tests__/runtime-continuation-crash.test.ts'
- 'packages/runtime/src/__tests__/runtime-resume-crash.test.ts'
- 'packages/runtime/src/__tests__/shell-owner-death.test.ts'
- 'packages/runtime/src/builtin-tools.ts'
- 'packages/runtime/src/file-stable-write.ts'
- 'packages/runtime/src/filesystem-worker/client.ts'
- 'packages/runtime/src/filesystem-worker/launch-spec.ts'
- 'packages/runtime/src/filesystem-worker/process-runner.ts'
- 'packages/runtime/src/pipe-process-driver.ts'
- 'packages/runtime/src/owned-child-process.ts'
- 'packages/runtime/src/process-tree-terminator.ts'
- 'packages/runtime/src/pty-process-driver.ts'
- 'packages/runtime/src/ripgrep-guidance.ts'
Expand All @@ -112,7 +115,6 @@ on:
- 'packages/runtime/src/sandbox/windows-profile.ts'
- 'packages/runtime/src/sandbox/windows-sandbox.ts'
- 'packages/runtime/src/shell-detect.ts'
- 'packages/runtime/src/shell-exec.ts'
- 'packages/storage/src/__tests__/managed-dependency-environment.test.ts'
- 'packages/storage/src/__tests__/root-authority.test.ts'
- 'packages/storage/src/artifact-store.ts'
Expand Down Expand Up @@ -249,6 +251,27 @@ jobs:
packages/runtime/dist/__tests__/runtime-resume-crash.test.js `
packages/runtime/dist/__tests__/runtime-continuation-crash.test.js

# Every Windows Bash command runs under the owning supervisor. Run its
# owner-death and lifecycle suites on a real Windows host. shell-exec's
# suite is written in POSIX shell syntax and is not portable yet.
- name: Verify shell command ownership
Comment thread
chihumyum marked this conversation as resolved.
shell: pwsh
run: |
node.exe --test --test-reporter=tap --test-concurrency=1 `
packages/runtime/dist/__tests__/owned-child-process.test.js `
packages/runtime/dist/__tests__/shell-owner-death.test.js `
packages/runtime/dist/__tests__/pipe-process-driver.test.js `
2>&1 | Tee-Object -FilePath "$env:RUNNER_TEMP/shell-command-ownership.tap"
$exitCode = $LASTEXITCODE
if ($exitCode -ne 0) { exit $exitCode }
$output = Get-Content "$env:RUNNER_TEMP/shell-command-ownership.tap"
# Most of these suites carry POSIX-only skips; pin how many still run
# here so a widened skip cannot leave the lane green while testing less.
if ($output -notcontains '# tests 20' -or $output -notcontains '# pass 12' -or $output -notcontains '# skipped 8') {
Write-Error 'Shell command ownership gate did not run exactly 12 passing Windows tests'
exit 1
}

- name: Verify Runtime Host owner-death recovery
shell: pwsh
run: |
Expand Down
10 changes: 8 additions & 2 deletions docs/windows-test-inventory.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ Locations intentionally omit line numbers so unrelated edits do not invalidate t
|---|---:|
| windows-backend-gap | 27 |
| portable-candidate | 53 |
| platform-contract | 40 |
| platform-contract | 46 |

Total Windows-excluded declarations: **120**
Total Windows-excluded declarations: **126**

## Inventory

Expand Down Expand Up @@ -87,8 +87,14 @@ Total Windows-excluded declarations: **120**
| platform-contract | `packages/runtime/src/__tests__/filesystem-worker-smoke.test.ts` macOS filesystem worker smoke | `process.platform !== 'darwin'` |
| platform-contract | `packages/runtime/src/__tests__/glob-search.test.ts` both Glob paths report permission failures and recover after permissions are restored | `process.platform === 'win32' \|\| process.getuid?.() === 0` |
| portable-candidate | `packages/runtime/src/__tests__/node-pty-write-lifecycle.test.ts` does not carry queued Unix PTY writes past native exit | `process.platform === 'win32' ? 'Unix PTY file-descriptor lifecycle only' : false` |
| platform-contract | `packages/runtime/src/__tests__/owned-child-process.test.ts` POSIX cancellation delivers SIGTERM exactly once to the owned command | `process.platform === 'win32' ? 'POSIX detached process-group semantics required' : false` |
| platform-contract | `packages/runtime/src/__tests__/owned-child-process.test.ts` supervisor mirrors a command that dies from ${signal} | `process.platform === 'win32' ? 'POSIX detached process-group semantics required' : false` |
| platform-contract | `packages/runtime/src/__tests__/owned-child-process.test.ts` group-wide signals from the command do not end its supervisor | `process.platform === 'win32' ? 'POSIX detached process-group semantics required' : false` |
| platform-contract | `packages/runtime/src/__tests__/owned-child-process.test.ts` unexpected POSIX supervisor death terminates its command and cannot report success | `process.platform === 'win32' ? 'POSIX detached process-group semantics required' : false` |
| portable-candidate | `packages/runtime/src/__tests__/shell-exec.test.ts` writes a legacy WSL Bash command through stdin | `process.platform === 'win32' ? 'uses /bin/sh as a portable stdin probe' : false` |
| platform-contract | `packages/runtime/src/__tests__/shell-exec.test.ts` bounds output drain after the root exits while a detached descendant retains stdout | `process.platform === 'win32' ? 'POSIX detached process-group semantics required' : false` |
| platform-contract | `packages/runtime/src/__tests__/shell-owner-death.test.ts` ${mode} (stop already requested: ${beginStop}): owner SIGKILL terminates an admitted command before its delayed write | `beginStop && process.platform === 'win32' ? 'POSIX graceful SIGTERM window required' : false` |
| platform-contract | `packages/runtime/src/__tests__/shell-owner-death.test.ts` owner SIGKILL also terminates a descendant that left the command group with setsid | `process.platform === 'win32' ? 'POSIX detached process-group semantics required' : false` |
| platform-contract | `packages/runtime/src/__tests__/shell-run-manager.test.ts` latches timeout when the root exits during POSIX process discovery | `process.platform === 'win32' ? 'POSIX process discovery only' : false` |
| platform-contract | `packages/runtime/src/__tests__/shell-run-manager.test.ts` preserves cancellation when timeout fires during POSIX process discovery | `process.platform === 'win32' ? 'POSIX process discovery only' : false` |
| platform-contract | `packages/runtime/src/__tests__/shell-run-manager.test.ts` ignores a Stop abort that occurs after another admitted Stop commits termination | `process.platform === 'win32' ? 'Windows termination has no asynchronous POSIX snapshot window' : false` |
Expand Down
55 changes: 55 additions & 0 deletions packages/runtime/src/__tests__/fixtures/shell-owner.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import { runProcessWithBoundedTail } from '../../shell-exec.js';
import { PipeProcessDriver } from '../../pipe-process-driver.js';
const [mode, directory, script] = process.argv.slice(2) as [string, string, string];
if (mode === 'bounded') {
const controller = new AbortController();
process.on('message', () => controller.abort());
const result = await runProcessWithBoundedTail(process.execPath, [script], {
cwd: directory,
timeoutMs: 30_000,
killGraceMs: 5000,
abortSignal: controller.signal,
});
process.send?.(result);
process.disconnect?.();
} else if (mode === 'wrapped') {
// A shell root whose child runs the script, as `sh -c` or `cmd /c` commands do.
const [program, args]: [string, string[]] =
process.platform === 'win32'
? [process.env.ComSpec ?? 'cmd.exe', ['/d', '/c', process.execPath, script]]
: ['/bin/sh', ['-c', '"$0" "$1"; exit $?', process.execPath, script]];
await runProcessWithBoundedTail(program, args, { cwd: directory, timeoutMs: 30_000 });
} else {
const driver = new PipeProcessDriver({
plan: { file: process.execPath, args: [script], useShellOption: false },
cwd: directory,
outputDrainMs: 100,
onData: () => {},
onRootExit: () => {},
onExit: () => {},
onFailure: (error) => {
throw error;
},
});
process.on('message', () => driver.kill('SIGTERM'));
await driver.ready;
}
Loading
Loading