Skip to content

test(windows): unblock advisory by fixing 8 fixture incompatibilities#429

Merged
Astro-Han merged 8 commits into
devfrom
claude/fix-windows-advisory-426
May 4, 2026
Merged

test(windows): unblock advisory by fixing 8 fixture incompatibilities#429
Astro-Han merged 8 commits into
devfrom
claude/fix-windows-advisory-426

Conversation

@Astro-Han
Copy link
Copy Markdown
Owner

@Astro-Han Astro-Han commented May 4, 2026

Summary

Unblock the windows-advisory workflow by repairing eight Windows-only test
fixture failures. All eight commits touch test code, fixtures, or
.gitattributes only; no product code is modified. The advisory has been
red on every run since it was added on 2026-05-03 (9 / 9 failures), and
roughly thirty individual test failures all trace back to fixtures that
assumed POSIX path separators, LF line endings, POSIX file modes, or POSIX
shell quoting.

Each commit is independently revertable and addresses one fixture surface:

  • test(windows): exclude self by absolute path in agent-rename sweep — replaces a hardcoded forward-slash SELF_PATH with path.resolve(__filename) (lowercased on win32 to absorb NTFS drive-letter casing drift). Fixes 17 agent rename literal sweep failures where the sweep was finding its own pattern table.
  • test(windows): unblock 4 prompt-effect timeouts under runner load — adds a slowIOTimeout constant (10s on Windows, 3s elsewhere) for two no-shell tests that need more headroom on Windows runners, and switches two shell-dependent tests to the existing unix(...) helper because they rely on sleep 0.2 (a Unix-only command).
  • test(windows): load env-probe script from a file in bash env-filter test — writes the env-probe JS to a tmp file and runs bun <script> instead of bun -e '<inline JS with embedded double quotes>'. PowerShell 5.1 and cmd reparse the embedded quotes before forwarding to native exes (PS7 avoids this via $PSNativeCommandArgumentPassing), which is why the [pwsh] variant kept passing while [powershell] and [cmd] failed at expect(result.metadata.exit).toBe(0).
  • test(windows): normalize CRLF in models-snapshot fixture and pin file to LF — normalizes CRLF to LF before the prefix comparison and pins packages/opencode/src/provider/models-snapshot.js to text eol=lf via .gitattributes. Without this, Git for Windows' default core.autocrlf flips line endings and the LF-only prefix string never matches, which made both embedded-server tests fail in 16-47ms before any build ran.
  • test(windows): make preload bridge assertion platform-aware — replaces toEndWith("/preload/index.js") with path.join("preload", "index.js") so the suffix matches both POSIX and Windows separators.
  • test(windows): canonicalize the renderer-protocol fixture root — runs the fixture root through path.resolve once so received and expected paths agree on the drive letter that resolveRendererFile adds internally on Windows.
  • test(windows): skip POSIX file mode assertion in migrateDefaultAgent — gates the 0600 stays 0600 assertion behind test.skipIf(process.platform === "win32") because NTFS reports a fixed mode mask regardless of chmod.
  • test(windows): unblock primary-mode allowlist match and skip POSIX-only ci-smoke — same path-separator class as the agent-rename fix (allowlist stored in POSIX form vs. backslash path.relative), plus a win32 skip for a packaged-smoke fixture whose ENOEXEC trigger has no Windows equivalent and is testing the spawn error format itself.

Why

windows-advisory is non-blocking by design but supplies an early Windows
signal for desktop work. With every run red, the signal is unreadable; any
real future Windows regression would be lost in the noise. None of these
failures are recent regressions, they are fixture incompatibilities that
became visible only when the workflow itself landed.

Related Issue

Closes #426.

The two real Windows runtime concerns remaining (path canonicalization in
permission boundaries) live in #427 and are intentionally out of scope here.

Human Review Status

Pending. A human should make the final merge decision after reviewing the
final diff and verification evidence.

Review Focus

  • Is the fix in commit 1 (agent-rename selfKey helper) sound across both
    case-sensitive POSIX volumes and case-insensitive NTFS volumes? The
    lowercase fold is gated on process.platform === "win32" so it should not
    alter POSIX behavior.
  • Is the unix(...) skip in commit 2 acceptable for the two
    loop waits while shell runs tests? They lose Windows coverage but
    depend on sleep 0.2 which is not portable; an alternative would be a
    cross-platform delay command, but adding that introduces its own quoting
    questions.
  • Is the bun <scriptfile> redesign in commit 3 still exercising the
    intended env-redaction surface? Behavior is identical from the bash tool's
    point of view; only the user command argument format changed.

Risk Notes

  • All changes are test-only or .gitattributes. No product behavior changes.
  • The .gitattributes rule is scoped to a single generated source file
    (packages/opencode/src/provider/models-snapshot.js) so it should not
    affect any other working-tree files. Existing developer checkouts on
    Windows that already have CRLF on disk will continue to work because the
    fixture also normalizes at runtime as a belt-and-suspenders.
  • Windows coverage is reduced for two prompt-effect tests (the
    shell-sleep ones) and the migrateDefaultAgent POSIX-mode case. The
    underlying behavior is still covered on Linux/macOS; the Windows skip is
    intentional because the assertion is platform-conditional or
    Unix-shell-dependent.

How To Verify

opencode targeted tests (8 files):     144 passed, 0 failed
desktop-electron targeted tests (3):    16 passed, 0 failed
app no-mode-picker.test:               801 passed, 0 failed (full app suite)
opencode typecheck (tsgo --noEmit):    exit 0
desktop-electron typecheck (tsgo -b):  exit 0
app typecheck (tsgo -b):               exit 0
crosscheck (Claude reviewer + Codex):  Codex 0 findings; Claude 4 findings (0 P0/P1, 1 P2 fixed via fixup, 3 P3 disagreed with judgment)

The Windows runtime effect is verified only by the next windows-advisory
run on this PR's CI.

Screenshots or Recordings

None. No visible UI changes.

Checklist

  • Human review status is stated above as pending, approved, or not required
  • I linked the related issue, or stated why there is no issue
  • This PR has type, scope, and priority labels, or I requested maintainer labeling
  • I described the review focus and any meaningful risks
  • I listed the relevant verification steps and the key result for each
  • I did not introduce unrelated refactors, dependencies, generated files, or file changes beyond the stated scope
  • I manually checked visible UI or copy changes when needed, with screenshots or recordings
  • I considered macOS and Windows impact for desktop, packaging, updater, signing, paths, shell, or permissions changes
  • I called out docs, release notes, dependencies, permissions, credentials, deletion behavior, generated content, or local file changes when relevant
  • I reviewed the final diff for unrelated changes and suspicious dependency changes
  • I am targeting dev, and my PR title and commit messages use Conventional Commits in English

Maintainer: please add labels ci, windows, test, and a priority label.

Summary by CodeRabbit

  • Bug Fixes

    • Improved cross-platform compatibility for Windows and Unix environments.
    • Fixed path handling and line-ending normalization issues across test suites.
  • Tests

    • Enhanced test reliability with platform-aware timeouts and conditional test execution.
    • Normalized snapshot comparisons and file path assertions for consistent behavior across operating systems.
  • Chores

    • Updated line-ending configuration to prevent Git conversion issues.

Astro-Han added 8 commits May 4, 2026 15:39
Replace the hardcoded forward-slash SELF_PATH string with `path.resolve(__filename)`
and compare absolute resolved paths. The previous comparison treated
`packages/opencode/test/tool/agent-rename.test.ts` (forward slashes) as the
canonical self path, but `path.relative` returns backslashes on Windows so the
self-exclusion never matched and the sweep flagged its own pattern table.

Refs #426
Two of the failing tests rely on a shell `sleep 0.2` command that does not
behave the same across cmd / pwsh / powershell / gitbash, so gate them
unix-only via the existing `unix(...)` helper:
- "loop waits while shell runs and starts after shell exits"
- "shell completion resumes queued loop callers"

The other two tests do not touch any shell. They timed out at 3000ms purely
because the Windows runner is slower for DB writes, fiber scheduling, and the
inner polling loops. Add a `slowIOTimeout` constant (10s on Windows, 3s
elsewhere) and apply it so Windows runs keep the same coverage:
- "prompt submitted during an active run is included in the next LLM input"
- "assertNotBusy throws BusyError when loop running"

Refs #426
PowerShell 5.1 and cmd reparse embedded double quotes inside an inline `bun -e
'<code>'` argument before forwarding it to the native exe, which mangled the
JS source enough that bun exited 1 before any env-redaction assertion ran.
PowerShell 7 (pwsh) avoided this through `\$PSNativeCommandArgumentPassing`,
which is why the [pwsh] variant kept passing while [powershell] and [cmd]
both failed at `expect(result.metadata.exit).toBe(0)`.

Write the probe to a temp file and run `bun <script>` instead, which reduces
the user command to a single quoted path argument that all four shells
forward verbatim.

Refs #426
… to LF

The fixture compared the on-disk snapshot byte-for-byte against an LF-only
prefix string. On a Windows runner with `core.autocrlf` enabled (Git for
Windows default), the checked-out file has CRLF line endings, so
`startsWith(prefix)` returned false in the fixture setup. Both
`build:embedded-server emits the runtime entrypoint and wasm sidecars` and
`built node server skill bootstrap` failed at this prefix check in tens of
milliseconds, never reaching the actual build step.

Fix at two layers:

- Normalize CRLF to LF in `writeCurrentModelsFixture` and
  `expectModelsSnapshotUnchanged` so the fixture is platform-agnostic.
- Add `.gitattributes` pinning `packages/opencode/src/provider/models-snapshot.js`
  to `text eol=lf`, so future Windows checkouts also keep LF.

Refs #426
`prefs.preload` is built with `path.join`, which produces backslashes on
Windows. The previous `toEndWith("/preload/index.js")` assertion only
matched POSIX separators, so the test failed on Windows even though the
actual preload path was correct.

Use `path.join("preload", "index.js")` so the suffix matches whichever
separator the platform produces. Sandbox / contextIsolation / nodeIntegration
assertions stay unchanged.

Refs #426
`resolveRendererFile` runs the root through `path.resolve` internally, which
on Windows prepends the CWD's drive letter to a drive-less posix path
(`/Applications/...` -> `D:\\Applications\\...`). The test's expected value
came from `join(root, ...)`, which only flips separators and never adds a
drive, so received and expected diverged on Windows.

Pre-resolve the fixture root once so both sides agree on the canonical form
on every platform without changing what the test verifies.

Refs #426
NTFS does not expose POSIX permission bits, so `fs.stat().mode` returns a
fixed 0o666/0o444 mask on Windows regardless of `chmod 0o600`. The exact
0600-preservation assertion is meaningful only on POSIX.

Gate the test with `test.skipIf(process.platform === "win32")` and keep the
rest of `migrateDefaultAgent`'s coverage running on Windows.

Refs #426
…ly ci-smoke

Two unrelated test fixtures that both keep the windows-advisory advisory red:

- `packages/app/src/no-mode-picker.test.ts`: the allowlist stores entries
  with POSIX-style paths but `path.relative` returns backslashes on Windows,
  so the allowlist never matched and the legitimate
  `context/global-sync/utils.ts` reference flagged as an offender. Normalize
  `relPath` to forward slashes before comparing, mirroring the same fix
  applied earlier to `agent-rename.test.ts`.

- `packages/desktop-electron/scripts/ci-smoke.test.ts`: the
  "packaged smoke reports spawn failures with launch context" fixture relies
  on an empty file + chmod 0o755 to hit ENOEXEC and exercise the
  `Failed to launch desktop app:` branch. Windows has no equivalent (empty
  files via cmd exit cleanly through a different branch), and the assertion
  targets the spawn error format rather than Windows-specific launch
  semantics. Gate the test with `test.skipIf(process.platform === "win32")`.

Refs #426
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 4, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 47e4c486-87ee-4bb0-ba02-f64cab5515f7

📥 Commits

Reviewing files that changed from the base of the PR and between 1dfd7a9 and 8ac15c4.

📒 Files selected for processing (10)
  • .gitattributes
  • packages/app/src/no-mode-picker.test.ts
  • packages/desktop-electron/scripts/ci-smoke.test.ts
  • packages/desktop-electron/src/main/renderer-protocol.test.ts
  • packages/desktop-electron/src/main/windows-security.test.ts
  • packages/opencode/test/config/migrate-default-agent.test.ts
  • packages/opencode/test/server/models-snapshot-fixture.ts
  • packages/opencode/test/session/prompt-effect.test.ts
  • packages/opencode/test/tool/agent-rename.test.ts
  • packages/opencode/test/tool/bash.test.ts

📝 Walkthrough

Walkthrough

This PR addresses Windows compatibility issues across the test suite and configuration. Changes include normalizing line endings in snapshots, handling platform-specific path separators, skipping Windows-incompatible tests, adjusting timeouts for slower I/O on Windows, and refactoring test execution to avoid shell quoting issues.

Changes

Windows Test Compatibility

Layer / File(s) Summary
Line Ending Normalization
.gitattributes, packages/opencode/test/server/models-snapshot-fixture.ts
.gitattributes pins models-snapshot.js to LF line endings. models-snapshot-fixture.ts adds a normalize() helper to convert CRLF to LF before snapshot comparisons, making fixtures platform-agnostic.
Path Resolution & Separator Handling
packages/app/src/no-mode-picker.test.ts, packages/desktop-electron/src/main/renderer-protocol.test.ts, packages/desktop-electron/src/main/windows-security.test.ts, packages/opencode/test/tool/agent-rename.test.ts
Path assertions now use path.resolve(), path.join(), or manual forward-slash normalization to handle Windows backslashes. agent-rename.test.ts introduces selfKey() to resolve and lowercase file paths on Windows for comparison.
Platform-Specific Test Gating & Timeouts
packages/desktop-electron/scripts/ci-smoke.test.ts, packages/opencode/test/config/migrate-default-agent.test.ts, packages/opencode/test/session/prompt-effect.test.ts
Tests skip on Windows via test.skipIf(process.platform === "win32") for POSIX-only behaviors (file mode bits, ENOEXEC spawn errors). Introduces slowIOTimeout (10s on Windows, 3s elsewhere) and gates shell tests to Unix only via unix() wrapper.
Test Execution Method
packages/opencode/test/tool/bash.test.ts
Replaces inline bun -e JavaScript execution with a temporary .mjs file written to disk and executed via the shell, avoiding platform-specific quoting and parsing issues.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

  • Issue #426: The changes directly address Windows-incompatible test fixtures and path handling across the same files and patterns mentioned in that issue.

Possibly related PRs

  • PR #148: Both address Windows compatibility in packages/opencode by normalizing line endings, path resolution, and test behavior.
  • PR #125: Both modify test suites in packages/opencode and packages/desktop-electron to make assertions platform-agnostic and reduce flaky CI failures.
  • PR #308: Both refactor packages/opencode/test/session/prompt-effect.test.ts to make shell-related tests platform-aware.

Suggested labels

ci, windows, flaky-test, P1

Poem

🐰 A rabbit's ode to cross-platform cheer:
Windows paths were once a murky fear,
Now forward slashes dance hand in hand,
While timeouts wait for I/O's demand,
The CI pipeline hops without a care! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: fixing eight Windows fixture incompatibilities to unblock the advisory workflow.
Description check ✅ Passed The description is comprehensive and well-structured, covering summary, rationale, related issues, review focus, risks, and verification steps. All major template sections are properly addressed.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/fix-windows-advisory-426

Review rate limit: 8/10 reviews remaining, refill in 7 minutes and 55 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements various fixes to ensure the test suite and build processes are compatible with Windows. Changes include normalizing line endings for generated files, using platform-agnostic path separators, and handling case-insensitive drive letters in path comparisons. It also skips POSIX-specific tests on Windows, increases timeouts for slow I/O, and refactors shell command tests to use temporary files to avoid quoting issues in PowerShell and cmd. I have no feedback to provide.

@Astro-Han Astro-Han added ci Continuous integration / GitHub Actions windows Windows-specific P2 Medium priority task Maintainer or agent execution task labels May 4, 2026
@Astro-Han Astro-Han merged commit 96983dc into dev May 4, 2026
23 checks passed
@Astro-Han Astro-Han deleted the claude/fix-windows-advisory-426 branch May 4, 2026 07:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci Continuous integration / GitHub Actions P2 Medium priority task Maintainer or agent execution task windows Windows-specific

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Task] Unblock windows-advisory: fix Windows-incompatible test fixtures

1 participant