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
Use directory handles for FileHelper.delete() and recursive enumeration, preserving contained parent symlinks, trusted root aliases, and leaf-link deletion that removes the link rather than its target. Share the existing Windows handle primitive with catalog-cache I/O, add deletion and handle-lifetime coverage, and update the FileHelper contract.
Testing
Set up this checkout's .venv and editable install using the local development guide. Run commands from the checkout root.
Tested locally with .venv/bin/specify --help (Windows PowerShell: .\.venv\Scripts\specify.exe --help)
Ran relevant existing tests with .venv/bin/python -m pytest tests -q (Windows PowerShell: .\.venv\Scripts\python.exe -m pytest tests -q); use affected test paths for focused checks and LC_ALL=en_US.UTF-8 on macOS
Result: 599 passed, 82 skipped on macOS. The full suite was not run. Native Windows handle-sharing behavior was not exercised; portable Windows handle-contract checks passed. Sample-project testing is not applicable to this filesystem-helper change.
AI Disclosure
I did not use AI assistance for this contribution
I did use AI assistance (fill in the disclosure below)
AI disclosure: GitHub Copilot, powered by GPT-6.1 Sol (gpt-6.1-sol), performed the implementation, test generation and execution, documentation changes, and commit/PR preparation on behalf of @mnriem in autonomous mode. The reasoning-effort setting was not exposed to the agent.
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
An ancestor-symlink race can redirect deletion outside the trusted root, while requiring read access to every directory also breaks deletion from write-and-execute-only parents.
Reuse one identity-checked root anchor throughout deletion. Use search-only POSIX descriptors for traversal and request read access only for recursive enumeration. Keep Windows canonical ancestors held for the operation.
Assisted-by: GitHub Copilot (model: GPT-6.1 Sol, autonomous)
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Use descriptor-relative metadata and link reads in the existing path walker for POSIX deletion. Keep initial validation, recursive classification, and per-entry checks on the same retained directory tree as removal, while preserving supported symlink behavior.
Assisted-by: GitHub Copilot (model: GPT-6.1 Sol, autonomous)
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
Deletion can target an attacker-replaced root after inode reuse, directory-open costs grow cubically with tree depth, and a permission test fails on POSIX hosts lacking both O_SEARCH and O_PATH.
Pin the root directory handle to prevent replacement
src/specify_cli/file_helper.py:280
If an attacker can remove and recreate the root between helper construction and delete(), inode reuse lets a replacement pass samestat, so deletion can operate on a different directory tree. Keep the established root pinned with a retained handle and explicit cleanup rather than relying solely on stored device and inode numbers.
Skip permission test when search-only flags are unavailable
tests/test_file_helper.py:889
This test assumes deletion works through a write-and-execute-only directory, but _deletion_flags() intentionally falls back to O_RDONLY on POSIX hosts without O_SEARCH or O_PATH. On those hosts, the unreadable parent causes PermissionError, so the test fails despite matching the documented fallback. Skip this case when neither flag is available.
Keep helper roots pinned until explicit close or context exit, and close bootstrap consumers deterministically. Carry parent descriptors through component resolution and both recursive deletion passes. Cover root cleanup, bounded directory opens, and POSIX backends without search-only flags.
Assisted-by: GitHub Copilot (model: GPT-6.1 Sol, autonomous)
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
Outstanding regressions can block ordinary helper operations on Windows, cause deep-tree deletion to raise RecursionError, and leave root descriptors and Windows ancestor locks open on workflow error paths.
Share Darwin search-only flags, preserve deep deletion planning, and keep Windows root identity references distinct from operation-time ancestry pins. Close workflow owners on every exit and cover constructor diagnostics, retained-error cleanup, recursive handles, and overwrite failures.
Assisted-by: GitHub Copilot (model: GPT-6.1 Sol, autonomous)
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Compare metadata from the borrowed Windows root handle with the initial root observation. Use a temporary non-inheritable duplicate for native fstat without closing the original reference. Raise fresh copies of saved capability errors and cover acquisition restoration, error independence, and duplicate cleanup.
Assisted-by: GitHub Copilot (model: GPT-6.1 Sol, autonomous)
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Restore OSError.winerror explicitly after shallow copying, since Windows omits that built-in slot from its copy protocol. Add a portable regression for lossy copies while keeping independent traceback ownership.
Assisted-by: GitHub Copilot (model: GPT-6.1 Sol, autonomous)
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
Windows error copying loses the native winerror and breaks the cached-capability-error test, while the deletion-replacement test fails during construction instead of exercising the intended deletion path.
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
Human assessment is needed to evaluate an unpublished recursive-deletion regression that can exhaust file descriptors on deeply nested directory trees.
Use explicit preflight and postorder worklists with bounded directory caches. Retain the selected parent and root, reopen evicted prefixes without following links, and preserve complete preflight and Windows ancestry locks. Cover both recursive phases under a 64-descriptor process limit, cache eviction, cleanup, and measured open-work budgets.
Assisted-by: GitHub Copilot (model: GPT-6.1 Sol, autonomous)
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
Human assessment is needed because an unpublished compatibility finding indicates cached file-identity query failures can block every deletion on FAT32, exFAT, and some SMB volumes.
Prefer tagged extended IDs and use reliable legacy volume/index identities when the filesystem does not support FileIdInfo. Keep the retained root reference, query both live handles using the selected scheme, and preserve native capability and permission failures. Cover fallback selection, zero/ambiguous IDs, rename/reused-index cases, and native Windows legacy APIs.
Assisted-by: GitHub Copilot (model: GPT-6.1 Sol, autonomous)
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Carry directory handles through entry classification, link reads, enumeration and removal. Mark the classified leaf handle for deletion instead of reopening its pathname, preserving supported links and explicit native errors. Cover in-place junction changes and fix operation cleanup tests so constructor calls cannot satisfy their fstat failures.
Assisted-by: GitHub Copilot (model: GPT-6.1 Sol, autonomous)
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
Two fstat failure-injection tests now pass on constructor errors without reaching the read/overwrite checks, silently losing their intended descriptor-cleanup coverage.
Hook parent replacement at native entry disposition and enumeration instead of pathname functions that Windows deletion no longer uses. Simulate reparse metadata through native handle queries and retain actual acquired-parent and final-validation coverage.
Assisted-by: GitHub Copilot (model: GPT-6.1 Sol, autonomous)
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
Recursive Windows deletion opens directory handles without the required synchronization flags, risking enumeration failures or buffer reads before I/O completion.
Request FILE_SYNCHRONOUS_IO_NONALERT together with SYNCHRONIZE for relative directory opens, preserving existing type and no-follow flags. Update native ABI assertions and cover the actual Windows directory handle mode and enumeration contract.
Assisted-by: GitHub Copilot (model: GPT-6.1 Sol, autonomous)
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
triage-must-haveVerdict: high-value, important work for Spec Kit — do first
2 participants
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Use directory handles for
FileHelper.delete()and recursive enumeration, preserving contained parent symlinks, trusted root aliases, and leaf-link deletion that removes the link rather than its target. Share the existing Windows handle primitive with catalog-cache I/O, add deletion and handle-lifetime coverage, and update the FileHelper contract.Testing
Set up this checkout's
.venvand editable install using the local development guide. Run commands from the checkout root..venv/bin/specify --help(Windows PowerShell:.\.venv\Scripts\specify.exe --help).venv/bin/python -m pytest tests -q(Windows PowerShell:.\.venv\Scripts\python.exe -m pytest tests -q); use affected test paths for focused checks andLC_ALL=en_US.UTF-8on macOS.venv/bin/specify --help— passed.Focused command:
Result: 599 passed, 82 skipped on macOS. The full suite was not run. Native Windows handle-sharing behavior was not exercised; portable Windows handle-contract checks passed. Sample-project testing is not applicable to this filesystem-helper change.
AI Disclosure
AI disclosure: GitHub Copilot, powered by GPT-6.1 Sol (
gpt-6.1-sol), performed the implementation, test generation and execution, documentation changes, and commit/PR preparation on behalf of @mnriem in autonomous mode. The reasoning-effort setting was not exposed to the agent.