You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
feat(windows): make provider-input tree operations handle-bound or private-parent (close check-then-use race) #669
🤖: AI agent (OpenCode), filing on behalf of @mogul. Split out of the epic #461 (Increment 2: harden path handling) so it is tracked on its own.
Problem
On Windows the provider-input tree operations (marking a published generation read-only, removing generations and staging trees, publishing the current pointer) cannot use the descriptor-bound O_NOFOLLOW walk that the POSIX path uses; native Windows Python has no os.O_DIRECTORY/dir_fd. The portable fallback checks each entry with lstat and then operates on it by name, so it is check-then-use: a process that can write inside the tree can swap an entry for a junction or symlink between the check and the chmod/unlink. The boundary therefore relies on the tree being private to the current user.
This was raised in review on #644 (wz-gsa) and is documented honestly in docs/BACKEND_GUIDE.md rather than claimed as race-safe. It is a hardening gap against a same-user or administrator racer, not a new remote or cross-user exposure; it is filed publicly because it is already discussed in the public review.
Deliverables
Decide the mechanism: handle-bound operations (open with FILE_FLAG_OPEN_REPARSE_POINT and operate through the handle, via ctypes/pywin32 or a small helper), or a verified private, non-attacker-writable parent for the tree. Record the choice as an ADR (docs/adr/), since it may add a dependency or a native helper.
Implement it for the tree walk, the read-only marking, removal, and the current pointer swap.
Add a swap test that plants a link between check and use, and show it is rejected; run it on a real Windows host.
Update docs/BACKEND_GUIDE.md to the new guarantee, or keep the residual-risk statement if the mechanism only narrows the window.
Blocked on
#667 and #644 merging (they define the current helpers and path forms). Trigger to start: both merged.
Activity