Skip to content

test(desktop): prove the .git directory marker race fails closed - #433

Merged
BunsDev merged 3 commits into
mainfrom
fix/git-dir-directory-marker-toctou-coverage
Sep 10, 2026
Merged

test(desktop): prove the .git directory marker race fails closed#433
BunsDev merged 3 commits into
mainfrom
fix/git-dir-directory-marker-toctou-coverage

Conversation

@BunsDev

@BunsDev BunsDev commented Sep 10, 2026

Copy link
Copy Markdown
Member

Outcome

An independent code-review agent flagged a High-severity TOCTOU concern in git_dir_for_worktree's Directory marker branch: it classifies .git with a no-follow symlink_metadata() stat and returns a plain path, without opening/pinning that directory itself. The theoretical risk: swapping .git for a symlink between that classification and later reads could redirect a snapshot.

Analysis

The narrower race window (marker swapped strictly between classification and later reads) is closed structurally, independent of timing: open_directory_no_follow uses O_NOFOLLOW, so GitInspectionRepository::snapshot's pinned git_dir_handle open (the first thing it does with the resolved path) fails closed on a symlink no matter when the swap happens. That guarantee doesn't depend on winning a race against an attacker; it's true by construction.

Change

  • Adds git_inspection_rejects_a_worktree_whose_git_directory_marker_is_a_symlink: an end-to-end regression test proving that a symlinked .git directory marker is rejected when routed through the full GitInspectionRepository::snapshot entrypoint (previously only git_dir_for_worktree in isolation had this coverage).
  • Documents, precisely, what this test does and does not prove: it confirms rejection holds at the entrypoint layer external callers use; it does not itself exercise a mid-flight swap timing window (that narrower guarantee comes from O_NOFOLLOW's structural fail-closed behavior, not from this test's timing).
  • No production logic changes; this is regression-proofing and documentation for an already-safe path.

(Revised after automated review feedback correctly pointed out the first draft's comment overclaimed what the test itself exercised versus what the code structurally guarantees.)

Risk class

  • R1 — documentation or isolated tests

Validation and evidence

Command: cargo test --lib --locked (native/desktop/psyche-build-tauri/src-tauri)
Result: 457 passed, 0 failed

An independent code review of git_dir_for_worktree's Directory branch
flagged that it classifies the .git marker with a no-follow stat and
returns a path, without itself opening or pinning that directory. The
concern: if the marker is swapped from a real directory to a symlink
between that classification and later reads, the returned path could
redirect a snapshot's reads.

The only production caller (GitInspectionRepository::snapshot) already
closes this window: it opens the resolved Git directory with a
no-follow (O_NOFOLLOW) handle as the very first step after resolving
the path, before deriving or reading anything else from inside it. A
marker swapped for a symlink in the interim causes that open to fail
safely rather than being followed.

Add an end-to-end regression test exercising this through
GitInspectionRepository::snapshot (not just git_dir_for_worktree in
isolation) so the guarantee is proven at the same layer external
callers use, and document the reasoning inline at the Directory branch
so a future change can't silently reopen the gap.

Addresses a High-severity finding from an independent review agent
following #426/#431.
Copilot AI lite review requested due to automatic review settings September 10, 2026 11:34
@vercel

vercel Bot commented Sep 10, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
psyche-build-docs Skipped Skipped Sep 10, 2026 11:57am UTC

Request Review

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

The new test’s explanatory comment claims to prove a snapshot-layer pin/open rejection that the current control flow doesn’t actually exercise (it fails earlier in .git marker classification), so the documentation should be corrected to match what is truly being tested.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR strengthens regression coverage and in-code reasoning around Git worktree .git marker handling in the desktop Rust Git inspection layer, aiming to ensure symlink-based marker scenarios fail closed at the GitInspectionRepository::snapshot entrypoint.

Changes:

  • Adds an end-to-end-ish regression test that calls GitInspectionRepository::snapshot and asserts a symlinked .git directory marker is rejected.
  • Adds an inline comment in git_dir_for_worktree documenting why returning a plain .git directory path is safe given downstream pinning behavior.
File summaries
File Description
native/desktop/psyche-build-tauri/src-tauri/src/git_control.rs Adds explanatory comment in .git directory-marker handling and a new regression test invoking GitInspectionRepository::snapshot for symlinked .git marker rejection.
Review details
  • Files reviewed: 1/1 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread native/desktop/psyche-build-tauri/src-tauri/src/git_control.rs Outdated
Address automated review feedback: the regression test proves snapshot()
rejects a .git directory marker that is already a symlink when routed
through the full entrypoint (a fact the prior comment understated by
overclaiming it specifically exercised a mid-flight race), while the
narrower marker-swapped-mid-flight window is closed structurally by
O_NOFOLLOW in open_directory_no_follow, independent of timing. Correct
the inline comments to state this precisely instead of overclaiming
what the test itself exercises.
@BunsDev
BunsDev merged commit a42dc61 into main Sep 10, 2026
21 of 23 checks passed
@BunsDev
BunsDev deleted the fix/git-dir-directory-marker-toctou-coverage branch September 10, 2026 12:09
BunsDev added a commit that referenced this pull request Sep 11, 2026
Addresses #426 (remaining scope after #431/#433)

Follow the independent review by snapshotting the live index into the isolated inspection repository, writing alternates immediately before each Git subprocess handoff from a pinned objects-directory handle, pinning shallow/info snapshot reads to the opened common-directory identity, and preserving Unix directory enumeration errors during recursive ref traversal.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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.

2 participants