Skip to content

CU-1: Windows write-gate path matrix (Cursor + Copilot); the witnessed allow does not reproduce - #253

Merged
jothimani-rajendran merged 7 commits into
mainfrom
cu-1-cursor-windows-write-gate
Oct 9, 2026
Merged

jothimani-rajendran merged 7 commits into
mainfrom
cu-1-cursor-windows-write-gate

Conversation

@jothimani-rajendran

@jothimani-rajendran jothimani-rajendran commented Oct 9, 2026 •

Copy link
Copy Markdown
Collaborator

What

CU-1 (org-plan plan/cursor-windows-write-gate.md). On the owner's Windows machine, Cursor's preToolUse let a write to .github/workflows/witness.yml through, even though pin-github-actions covers that path. Copilot CLI did the same. The plan's hypothesis: a case-sensitive or slash-sensitive path comparison on Windows.

This PR adds a Windows reproduction matrix and a CI job that runs it on every PR. It changes no gate code, because the matrix shows main's code already refuses every case.

  • tests/test_cursor_windows_write_gate.py, run through each client's real hook command (Git Bash, as Cursor and Copilot run it):
    • Cursor, path-scoped gate, payload without cwd, hook run from another folder or from home. Every file_path spelling (C:/, C:\, c:\, c:/) against every workspace_roots spelling (/c:/, /C:/, c:\, C:/).
    • Copilot, Claude-format bundle, create with {path, file_text}. cwd as C:\ or c:\, against the 4 path spellings.
    • Real pin-github-actions, merged into a bundle as each client installs it. The witnessed content is an indented uses: actions/checkout@v4 in a new workflow. HEAD is unborn (git init only, as in the owner's repos) or committed.
  • .github/workflows/windows-paths.yml runs that file on windows-latest with Python 3.12.0 (the owner's interpreter), 3.12, 3.13 and 3.14. It is a separate file because ci.yml is held to 300 lines.

Runs

head Windows result
3e219ac 19 errors in the harness: cmd.exe cannot parse the POSIX launcher
571b6a6 19 passed (Cursor adapter called directly; every spelling refused)
993a8a7 Copilot 9 passed; Cursor errored in the harness (cp1252 stdin cannot encode the BOM)
04edfd1 passed (Cursor through the real launcher, plus Copilot)
8795295 80 passed on 3.12.0; green on 3.12, 3.13 and 3.14; full CI green

There is no failing-then-passing pair: the matrix never fails on main's code. Something in the owner's environment differs from all of the above; that is still to be found.

Measured on Linux, not Windows-specific: if the target file is already on disk, uncommitted, with the unpinned line, a write of the same content is allowed at preToolUse. The write-time baseline is the file on disk, while the turn-end gate's baseline is HEAD and it refuses. The orchestrator says this did not apply to the owner's runs. It is reported for a separate decision.

Definition of done

  • pytest on the touched test file: green on Linux and on Windows (4 Pythons)
  • ruff check and ruff format --check clean
  • Workflow: actionlint and zizmor --offline clean; actions pinned by SHA; permissions: contents: read; no secrets; no pull_request_target
  • Changelog fragment: none, since nothing user-facing changed
  • Re-test: Cursor and Copilot, once the cause is found

🤖 Generated with Claude Code

jothimani-rajendran and others added 7 commits October 9, 2026 01:21
Drives the built Cursor plugin with a path-scoped gate, a payload with
no cwd, and the hook run from a folder outside the workspace. On Windows
it crosses file_path spellings (C:/, C:\, c:\, c:/) with workspace_roots
spellings (/c:/, /C:/, c:\, C:/). A new windows-paths CI job runs this
one file on windows-latest, since PR CI is Linux-only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Jothi Mani Rajendran <250249270+jothimani-rajendran@users.noreply.github.com>
The plugin hook command is a POSIX launcher that cmd.exe cannot parse,
so every Windows case failed before reaching the gate. The launcher only
locates Python; the test now runs the bundled cursor.py with this
interpreter, which is the code under test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Jothi Mani Rajendran <250249270+jothimani-rajendran@users.noreply.github.com>
… Cursor

Runs each client's hook command through Git Bash, as the repo's other
hook tests do, and adds Copilot CLI create {path, file_text} payloads
with cwd and path in C:\, c:\ and C:/ spellings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Jothi Mani Rajendran <250249270+jothimani-rajendran@users.noreply.github.com>
ci.yml is held to the 300-line review budget; the job pushed it to 326.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Jothi Mani Rajendran <250249270+jothimani-rajendran@users.noreply.github.com>
The shared hook runner writes stdin in the locale encoding, cp1252 on a
Windows runner, which cannot encode U+FEFF.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Jothi Mani Rajendran <250249270+jothimani-rajendran@users.noreply.github.com>
…ythons

Merges the repo's own pin-github-actions into a bundle as Cursor and
Copilot (Claude format) install it and feeds the witnessed content, an
indented unpinned uses: in a new workflow of a committed repository,
across the Windows path spellings. The Windows job now runs on Python
3.12, 3.13 and 3.14.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Jothi Mani Rajendran <250249270+jothimani-rajendran@users.noreply.github.com>
The owner's witness repos were git init only, and their interpreter is
CPython 3.12.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Jothi Mani Rajendran <250249270+jothimani-rajendran@users.noreply.github.com>
@jothimani-rajendran jothimani-rajendran changed the title CU-1: Cursor on Windows, scoped write gate judges every path spelling CU-1: Windows write-gate path matrix (Cursor + Copilot); the witnessed allow does not reproduce Oct 9, 2026
@jothimani-rajendran
jothimani-rajendran marked this pull request as ready for review October 9, 2026 01:44
@jothimani-rajendran
jothimani-rajendran merged commit a7504b7 into main Oct 9, 2026
23 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant