test: skip symlink fixtures where the host cannot create symlinks#9566

merged1
windows-tests/posix-fixtures
windows-tests/symlinks
openedSep 4, 2026byJJulius Marminge
View on GitHubTwo-way sync enabledPR last imported 3d ago

Creating a symlink on Windows needs Developer Mode or elevation, so every test that plants one to prove containment or escape detection failed at setup there. workflowScriptQuery planted its link at module scope and took the whole file down at collection.

Add a once-per-process probe, @t3tools/shared/testing/symlinks, and gate those tests on it across server, desktop, and scripts.

Part of the Windows test-suite stack rooted at #9564; the manual Windows lane comes from #9538.

Model: Claude Fable 5 in Claude Code.

๐Ÿค– Generated with Claude Code

Note

Skip symlink-dependent tests on hosts without symlink support

  • Adds symlinksSupported probe in symlinks.ts, exported via ./testing/symlinks in package.json
  • Wraps symlink fixture tests across server, desktop, and scripts in conditional skips using the new probe
  • Risk: none โ€” test-only change; production code is unchanged

Macroscope summarized 00bf96a.


Note

Low Risk Test-only changes; production behavior is unchanged. Symlink security tests are skipped on hosts without symlink support rather than run vacuously.

Overview Adds symlinksSupported (@t3tools/shared/testing/symlinks), a one-time probe that detects whether the host can create symlinks without elevation (notably missing on default Windows).

Symlink-dependent tests across desktop, server, and scripts are gated with skipIf(!symlinksSupported) so they skip instead of failing during fixture setup. workflowScriptQuery.test.ts only plants its module-scope escape symlink when symlinks work, avoiding collection-time failures on restricted hosts.

Reviewed by Cursor Bugbot for commit f0f033b505abc42842e5de3fea67d06548e9a9ce. Bugbot is set up for automated code reviews on this repo. Configure here.

packages/shared/src/testing/symlinks.tslines 21โ€“21Outdated ยท 13f4759Open thread
โ€ฆโ€ฆ@@ -0,0 +1,23 @@
18+ } catch {
19+ return false;
20+ } finally {
21+ if (directory !== undefined) NodeFS.rmSync(directory, { recursive: true, force: true });
MmacroscopeappBoton lines 21โ€“21Sep 4, 2026

๐ŸŸก Medium testing/symlinks.ts:21

A cleanup error from rmSync escapes the probe and makes importing this helper throw instead of returning false or true, so every importing test fails during module initialization when Windows temporarily reports EPERM or EBUSY. Catch cleanup failures so they cannot override the probe result.

No longer relevant as of 8b79a693fbb1e76f4ffa6256b03e21162dabedf1

Good call โ€” a failed cleanup shouldn't decide the probe. Caught and ignored now.

I still see rmSync called without a nested try/catch, so a cleanup error can still escape the probe.

Synced from GitHub

Thread transfer impact

โœ… Thread transfer remains within every enforced ceiling.

โ„น๏ธ No successful main baseline artifact is available yet. This run establishes the initial measurement.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wireโ€”13.7 KiBโ€”15.1 KiBโœ…
CodexThread snapshot wireโ€”7.0 KiBโ€”7.3 KiBโœ…
CodexLive turn WebSocket wireโ€”6.7 KiBโ€”7.8 KiBโœ…
CodexLive turn WebSocket decodedโ€”58.5 KiBโ€”66.4 KiBโœ…
CodexLive turn messagesโ€”10โ€”21โœ…
ClaudeTotal thread wireโ€”13.8 KiBโ€”15.1 KiBโœ…
ClaudeThread snapshot wireโ€”7.0 KiBโ€”7.3 KiBโœ…
ClaudeLive turn WebSocket wireโ€”6.7 KiBโ€”7.8 KiBโœ…
ClaudeLive turn WebSocket decodedโ€”59.3 KiBโ€”66.4 KiBโœ…
ClaudeLive turn messagesโ€”10โ€”21โœ…

Baseline: unavailable ยท PR result: 00bf96a ยท Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 113.8 KiB
  • Claude decoded thread snapshot: 114.5 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

CcursorBotreviewed ยท 1 inline threadSep 4, 2026
Synced from GitHub

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is ON, but a cloud agent failed to start.

Reviewed by Cursor Bugbot for commit 41b026ab4328737b724ffaa40b10e644195c423e. Configure here.

apps/server/src/provider/Drivers/CodexHomeLayout.test.tsline 140Outdated ยท 41b026aOpen thread
โ€ฆโ€ฆ@@ -84,54 +85,59 @@ it.layer(NodeServices.layer)("CodexHomeLayout", (it) => {
137+ expect(modelsCacheExists).toBe(false);
138+ expect(authLinkResult._tag).toBe("Failure");
139+ expect(authContents).toContain("shadow");
140+ }),
CcursorBoton line 140Sep 4, 2026

Shadow home tests still need symlinks

Medium Severity

Only the fixture-planting materializeCodexShadowHome case is gated on symlinksSupported. Sibling tests still call materializeCodexShadowHome, which creates file and directory links via ensureSymlink. On hosts that cannot create them those cases fail at setup or with CodexShadowHomeFileSystemError instead of the expected conflict, so the Windows skip does not cover this file.

Additional Locations (2)

Reviewed by Cursor Bugbot for commit 41b026ab4328737b724ffaa40b10e644195c423e. Configure here.

Synced from GitHub

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable โ€” This is primarily a test portability change that skips symlink fixtures on hosts unable to create them and does not modify product behavior. It also adds a static-analysis diagnostic suppression directive, so the change warrants human review.

No code changes detected at 00bf96a. Prior analysis still applies.

You can add or adjust custom eligibility rules. Learn more.

Added 1 commit

  • test: skip symlink fixtures where the host cannot create symlinks00bf96a