From b9a7fda98d0d7916b2e837fd785e7d01079f0fe1 Mon Sep 17 00:00:00 2001 From: liugddx Date: Wed, 26 Aug 2026 14:18:30 +0800 Subject: [PATCH 1/2] test(storage): match root marker race by basename Generated-by: Codex --- .../src/__tests__/fixtures/root-initialization-race.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/storage/src/__tests__/fixtures/root-initialization-race.ts b/packages/storage/src/__tests__/fixtures/root-initialization-race.ts index 9234c1d756..34c4bdfaa5 100644 --- a/packages/storage/src/__tests__/fixtures/root-initialization-race.ts +++ b/packages/storage/src/__tests__/fixtures/root-initialization-race.ts @@ -18,7 +18,7 @@ */ import fs from 'node:fs'; -import { join } from 'node:path'; +import { basename } from 'node:path'; const [rootArgument, markerFile] = process.argv.slice(2); if (!rootArgument || !markerFile || !process.send) { @@ -26,16 +26,18 @@ if (!rootArgument || !markerFile || !process.send) { } const root = fs.realpathSync(rootArgument); -const markerTempPrefix = join(root, `${markerFile}.`); +const markerTempPrefix = `${markerFile}.`; const originalOpen = fs.promises.open; let intercepted = false; fs.promises.open = (async (path, flags, mode) => { + // This child initializes one root. Match its unique marker basename so the + // cut does not depend on Windows long/short, namespaced, or case spelling. if ( !intercepted && typeof path === 'string' && - path.startsWith(markerTempPrefix) && - path.endsWith('.tmp') + basename(path).startsWith(markerTempPrefix) && + basename(path).endsWith('.tmp') ) { intercepted = true; await send({ type: 'marker_open_pending' }); From e354489615c9940c56d6a99600cb47586d83043d Mon Sep 17 00:00:00 2001 From: liugddx Date: Wed, 26 Aug 2026 14:20:58 +0800 Subject: [PATCH 2/2] ci(windows): require root marker race evidence Generated-by: Codex --- .github/workflows/windows-recovery.yml | 15 +++++++++++++++ scripts/ci-test-plan.test.mjs | 14 ++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/.github/workflows/windows-recovery.yml b/.github/workflows/windows-recovery.yml index 91de576062..fd8703f5f6 100644 --- a/.github/workflows/windows-recovery.yml +++ b/.github/workflows/windows-recovery.yml @@ -67,6 +67,21 @@ jobs: exit 1 } + - name: Verify root initialization replacement race + shell: pwsh + run: | + node.exe --test --test-reporter=tap --test-concurrency=1 ` + --test-name-pattern="rejects replacement before opening the temporary marker" ` + packages/storage/dist/__tests__/root-authority.test.js ` + 2>&1 | Tee-Object -FilePath "$env:RUNNER_TEMP/root-initialization-race.tap" + $exitCode = $LASTEXITCODE + if ($exitCode -ne 0) { exit $exitCode } + $output = Get-Content "$env:RUNNER_TEMP/root-initialization-race.tap" + if ($output -notcontains '# tests 1' -or $output -notcontains '# pass 1' -or $output -notcontains '# skipped 0') { + Write-Error 'Root initialization race gate did not run exactly one passing Windows test' + exit 1 + } + - name: Verify Runtime Host Local IPC trust boundary shell: pwsh run: | diff --git a/scripts/ci-test-plan.test.mjs b/scripts/ci-test-plan.test.mjs index e0e9e9c852..8a85a6e490 100644 --- a/scripts/ci-test-plan.test.mjs +++ b/scripts/ci-test-plan.test.mjs @@ -464,6 +464,20 @@ test('Windows recovery executes the exact managed dependency ADS regressions', ( assert.match(recovery, /# skipped 0/u); }); +test('Windows recovery executes the root initialization replacement race', () => { + const recovery = readWorkflow('windows-recovery.yml'); + + assert.match(recovery, /name: Verify root initialization replacement race/u); + assert.match( + recovery, + /--test-name-pattern="rejects replacement before opening the temporary marker"/u, + ); + assert.match(recovery, /packages\/storage\/dist\/__tests__\/root-authority\.test\.js/u); + assert.match(recovery, /# tests 1/u); + assert.match(recovery, /# pass 1/u); + assert.match(recovery, /# skipped 0/u); +}); + test('workflows never persist the job credential into the checkout', () => { for (const name of readdirSync(WORKFLOW_DIR)) { for (const step of checkoutSteps(name)) {