Skip to content
Open
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
1 change: 1 addition & 0 deletions .github/workflows/release-windows-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ on:
- 'packages/runtime/src/filesystem-worker/**'
- 'packages/runtime/src/sandbox/**'
- 'packages/runtime/src/path-containment.ts'
- 'packages/runtime/src/ripgrep-guidance.ts'
- 'packages/runtime/src/sandbox-boundary-path.ts'
- 'packages/runtime/src/apply-patch-file.ts'
- 'packages/runtime/src/child-fd-input.ts'
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/windows-recovery.yml
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ on:
- 'packages/runtime/src/pipe-process-driver.ts'
- 'packages/runtime/src/process-tree-terminator.ts'
- 'packages/runtime/src/pty-process-driver.ts'
- 'packages/runtime/src/ripgrep-guidance.ts'
- 'packages/runtime/src/sandbox-boundary-declaration.ts'
- 'packages/runtime/src/sandbox/default-sandbox-manager.ts'
- 'packages/runtime/src/sandbox/sandbox-manager.ts'
Expand Down
5 changes: 3 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 | 31 |
| platform-contract | 31 |
| platform-contract | 32 |

Total Windows-excluded declarations: **89**
Total Windows-excluded declarations: **90**

## Inventory

Expand Down Expand Up @@ -82,6 +82,7 @@ Total Windows-excluded declarations: **89**
| platform-contract | `packages/runtime/src/__tests__/shell-run-manager.test.ts` settles after root exit when a detached descendant retains inherited stdout | `process.platform === 'win32' ? 'POSIX detached process-group semantics required' : false` |
| platform-contract | `packages/runtime/src/__tests__/shell-run-manager.test.ts` keeps the first committed lifecycle cause across Stop and timeout races | `process.platform === 'win32' ? 'Windows tree termination has no graceful SIGTERM phase' : false` |
| platform-contract | `packages/runtime/src/__tests__/shell-run-manager.test.ts` keeps SIGTERM final output and escalates an ignored SIGTERM without leaking slots | `process.platform === 'win32' ? 'Windows tree termination has no graceful SIGTERM phase' : false` |
| platform-contract | `packages/runtime/src/__tests__/workspace-executor.test.ts` leaves other spawn failures, such as a non-executable rg, untouched | `process.platform === 'win32' ? 'POSIX execute permissions' : false` |
| portable-candidate | `packages/storage/src/__tests__/atomic-file-write.test.ts` removes its temp file and rethrows after a chmod failure | `process.platform === 'win32'` |
| portable-candidate | `packages/storage/src/__tests__/atomic-file-write.test.ts` creates the target 0600 on POSIX | `process.platform === 'win32'` |
| portable-candidate | `packages/storage/src/__tests__/atomic-file-write.test.ts` re-chmods a pre-existing world-readable target to 0600 on the next write | `process.platform === 'win32'` |
Expand Down
218 changes: 217 additions & 1 deletion packages/runtime/src/__tests__/filesystem-worker-launch-spec.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
*/

import assert from 'node:assert/strict';
import { copyFile, mkdir, mkdtemp, realpath, rm } from 'node:fs/promises';
import { chmod, copyFile, mkdir, mkdtemp, realpath, rm, writeFile } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import { dirname, join } from 'node:path';
import { test } from 'node:test';
Expand Down Expand Up @@ -136,3 +136,219 @@ test('a node runtime worker never receives the Electron-only stdio switch', asyn
assert.equal(result.ok, true);
if (result.ok) assert.equal(result.spec.args.includes('--no-stdio-init'), false);
});

test('a ripgrep installed after the first launch is found by the next one (#5169)', async () => {
const root = await mkdtemp(join(tmpdir(), 'maka-launch-spec-rg-installed-'));
try {
const candidate = join(root, 'bin', 'rg');
const getLaunchSpec = createFilesystemWorkerLaunchSpecProvider({
runtime: 'node',
platform: 'linux',
executable: process.execPath,
resourceLocation: { kind: 'runtime' },
rgCandidates: [candidate],
});
const before = await getLaunchSpec();
assert.equal(before.ok, true);
if (!before.ok) return;
assert.equal(before.spec.args.includes('--grep-executable'), false);

await installExecutable(candidate);
const after = await getLaunchSpec();

assert.equal(after.ok, true);
if (!after.ok) return;
const installed = await realpath(candidate);
assert.deepEqual(after.spec.args.slice(-2), ['--grep-executable', installed]);
assert.ok(after.spec.executableRoots.includes(installed));
} finally {
await rm(root, { recursive: true, force: true });
}
});

test('a ripgrep that disappears is replaced by the next launch, and only the replacement is granted (#5169)', async () => {
const root = await mkdtemp(join(tmpdir(), 'maka-launch-spec-rg-replaced-'));
try {
const first = join(root, 'keg-14.1.0', 'rg');
const second = join(root, 'keg-14.1.1', 'rg');
await installExecutable(first);
const firstReal = await realpath(first);
const getLaunchSpec = createFilesystemWorkerLaunchSpecProvider({
runtime: 'node',
platform: 'linux',
executable: process.execPath,
resourceLocation: { kind: 'runtime' },
rgCandidates: [first, second],
});
const before = await getLaunchSpec();
assert.equal(before.ok, true);
if (!before.ok) return;
assert.deepEqual(before.spec.args.slice(-2), ['--grep-executable', firstReal]);

// A package upgrade removes the old keg and installs the new one.
await rm(dirname(first), { recursive: true, force: true });
await installExecutable(second);
const after = await getLaunchSpec();

assert.equal(after.ok, true);
if (!after.ok) return;
const secondReal = await realpath(second);
assert.deepEqual(after.spec.args.slice(-2), ['--grep-executable', secondReal]);
assert.ok(after.spec.executableRoots.includes(secondReal));
assert.ok(!after.spec.executableRoots.includes(firstReal));
} finally {
await rm(root, { recursive: true, force: true });
}
});

test('a resolved ripgrep is inspected once while it is still there (#5169)', async () => {
const executable = await realpath(process.execPath);
let inspections = 0;
const getLaunchSpec = createFilesystemWorkerLaunchSpecProvider({
runtime: 'node',
platform: 'darwin',
executable,
resourceLocation: { kind: 'runtime' },
rgCandidates: [executable],
inspectMacosExecutableDependencies: async () => {
inspections += 1;
return { ok: true, dependencyCount: 0, runtimeReadableRoots: [], executableRoots: [] };
},
});

await getLaunchSpec();
await getLaunchSpec();

assert.equal(inspections, 1);
});

test('the worker is told where it runs so Grep can say where to install ripgrep (#5169)', async () => {
const getLaunchSpec = createFilesystemWorkerLaunchSpecProvider({
runtime: 'node',
platform: 'linux',
executable: process.execPath,
resourceLocation: { kind: 'runtime' },
rgCandidates: [],
hostEnv: { WSL_DISTRO_NAME: 'Ubuntu-24.04' },
});

const result = await getLaunchSpec();

assert.equal(result.ok, true);
if (!result.ok) return;
const index = result.spec.args.indexOf('--ripgrep-environment');
assert.notEqual(index, -1);
assert.equal(result.spec.args[index + 1], 'wsl:Ubuntu-24.04');
});

test('outside WSL the worker is not told a machine name (#5169)', async () => {
const getLaunchSpec = createFilesystemWorkerLaunchSpecProvider({
runtime: 'node',
platform: 'linux',
executable: process.execPath,
resourceLocation: { kind: 'runtime' },
rgCandidates: [],
hostEnv: {},
});

const result = await getLaunchSpec();

assert.equal(result.ok, true);
if (result.ok) assert.equal(result.spec.args.includes('--ripgrep-environment'), false);
});

test('a ripgrep whose libraries cannot be granted is not inspected again on every launch (#5169)', async () => {
const executable = await realpath(process.execPath);
let inspections = 0;
const getLaunchSpec = createFilesystemWorkerLaunchSpecProvider({
runtime: 'node',
platform: 'darwin',
executable,
resourceLocation: { kind: 'runtime' },
rgCandidates: [executable],
inspectMacosExecutableDependencies: async () => {
inspections += 1;
return { ok: false, reason: 'dependency_unresolved', message: 'fixture failure' };
},
});

for (let launch = 0; launch < 3; launch += 1) {
const result = await getLaunchSpec();
assert.equal(result.ok, true);
if (result.ok) assert.equal(result.spec.args.includes('--grep-executable'), false);
}

assert.equal(inspections, 1);
});

test('a ripgrep reinstalled in place is inspected again and granted its new libraries (#5169)', async () => {
const root = await mkdtemp(join(tmpdir(), 'maka-launch-spec-rg-in-place-'));
try {
const candidate = join(root, 'bin', 'rg');
await installExecutable(candidate);
const libraries = ['/opt/ripgrep-14.1.0/lib', '/opt/ripgrep-14.1.1/lib'];
let inspections = 0;
const getLaunchSpec = createFilesystemWorkerLaunchSpecProvider({
runtime: 'node',
platform: 'darwin',
executable: process.execPath,
resourceLocation: { kind: 'runtime' },
rgCandidates: [candidate],
inspectMacosExecutableDependencies: async () => {
const library = libraries[Math.min(inspections, 1)]!;
inspections += 1;
return {
ok: true,
dependencyCount: 1,
runtimeReadableRoots: [library],
executableRoots: [library],
};
},
});
const before = await getLaunchSpec();
assert.equal(before.ok, true);
if (!before.ok) return;
assert.ok(before.spec.executableRoots.includes(libraries[0]!));

// Same path, new binary: a reinstall rewrites the file in place.
await writeFile(candidate, '#!/bin/sh\n# 14.1.1\n', 'utf8');
const after = await getLaunchSpec();

assert.equal(after.ok, true);
if (!after.ok) return;
assert.equal(inspections, 2);
assert.ok(after.spec.executableRoots.includes(libraries[1]!));
assert.ok(!after.spec.executableRoots.includes(libraries[0]!));
} finally {
await rm(root, { recursive: true, force: true });
}
});

test('on Windows the winget links directory is searched even when PATH predates the install (#5169)', async () => {
const root = await mkdtemp(join(tmpdir(), 'maka-launch-spec-winget-'));
try {
const linked = join(root, 'Microsoft', 'WinGet', 'Links', 'rg.exe');
await installExecutable(linked);
const getLaunchSpec = createFilesystemWorkerLaunchSpecProvider({
runtime: 'node',
platform: 'win32',
executable: process.execPath,
resourceLocation: { kind: 'runtime' },
hostEnv: { PATH: '', LOCALAPPDATA: root },
});

const result = await getLaunchSpec();

assert.equal(result.ok, true);
if (!result.ok) return;
assert.deepEqual(result.spec.args.slice(-2), ['--grep-executable', await realpath(linked)]);
} finally {
await rm(root, { recursive: true, force: true });
}
});

async function installExecutable(path: string): Promise<void> {
await mkdir(dirname(path), { recursive: true });
await writeFile(path, '#!/bin/sh\n', 'utf8');
await chmod(path, 0o755);
}
67 changes: 67 additions & 0 deletions packages/runtime/src/__tests__/filesystem-worker.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,73 @@ describe('filesystem worker operations', () => {
});
});

test('names ripgrep, where to install it, and a retry when no usable copy was found (#5167)', async () => {
const root = await temporaryDirectory('maka-worker-grep-missing-');
const target = join(root, 'file.ts');
await writeFile(target, 'const healthSignal = true;', 'utf8');

const response = await executeFilesystemWorkerRequest(
await requestFor(
{
kind: 'grep',
cwd: root,
path: target,
pattern: 'healthSignal',
maxCountPerFile: 50,
limit: 200,
timeoutMs: 1_000,
},
{ enforcementPath: target, access: 'read', scope: 'exact', targetType: 'file' },
),
{ ripgrepEnvironment: { kind: 'wsl', name: 'Ubuntu-24.04' } },
);

assert.equal(response.ok, false);
if (!response.ok) {
assert.equal(response.error.code, 'grep_unavailable');
assert.match(response.error.message, /ripgrep/);
assert.match(response.error.message, /the WSL distribution "Ubuntu-24\.04"/);
assert.match(response.error.message, /then retry/);
assert.doesNotMatch(response.error.message, /restart/i);
}
});

test('reports a ripgrep that vanished after startup as unavailable, not as a missing search path', async () => {
// The launch configuration checks the executable before every launch, so
// this is the narrow window where it disappears after that check.
const root = await temporaryDirectory('maka-worker-grep-vanished-');
const target = join(root, 'file.ts');
const vanished = join(root, 'uninstalled', 'rg');
await writeFile(target, 'const healthSignal = true;', 'utf8');

const response = await executeFilesystemWorkerRequest(
await requestFor(
{
kind: 'grep',
cwd: root,
path: target,
pattern: 'healthSignal',
maxCountPerFile: 50,
limit: 200,
timeoutMs: 1_000,
},
{ enforcementPath: target, access: 'read', scope: 'exact', targetType: 'file' },
),
{ grepExecutable: vanished },
);

assert.equal(response.ok, false);
if (!response.ok) {
assert.equal(response.error.code, 'grep_unavailable');
assert.ok(response.error.message.includes(vanished));
assert.match(
response.error.message,
/for a remote Host, that server rather than this computer/,
);
assert.match(response.error.message, /then retry/);
}
});

test('passes option-like Grep patterns after a `--` separator', async () => {
const root = await temporaryDirectory('maka-worker-grep-option-like-');
const target = join(root, 'file.ts');
Expand Down
Loading