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
fix: contain persisted feature paths and protect plan creation - #5178
Constrain feature paths loaded from .specify/feature.json to the project after resolving symbolic links and parent-directory components. External feature directories remain supported through an explicit SPECIFY_FEATURE_DIRECTORY override on every invocation.
Apply the same policy across Python, Bash, and PowerShell. Plan setup rejects symbolic-link destinations and creates new plans exclusively while preserving existing regular files. Update the shared reference and add cross-port regression coverage.
Testing
Tested locally with uv run specify --help
Ran existing tests with uv sync && uv run pytest
Tested with a sample project (if applicable)
The full suite used this worktree's own interpreter, as recommended by CONTRIBUTING.md, instead of the literal generic uv run pytest command above.
Sample-project coverage is automated through temporary project fixtures for Python, Bash, and the available PowerShell runtime. Windows PowerShell 5.1 cases are explicitly included but skipped on this macOS host; Windows PowerShell 5.1 runtime verification remains outstanding. No manual agent-driven process test is claimed.
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), autonomously generated the implementation, tests, documentation, commit, and PR body on behalf of @mnriem, following the user's approved path policy. Work occurred in an interactive session; reasoning effort was not explicitly specified. The initial read-only assessment used a security-review subagent whose model was not reported. Validation was automated; no human line-by-line review or manual testing is claimed.
Require stored feature directories to resolve within the project while retaining explicit external overrides. Reject linked plan destinations and create new plans exclusively across all three script ports.
Assisted-by: GitHub Copilot (model: GPT-6.1 Sol, autonomous)
Co-authored-by: Copilot App <[email protected]>
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
A Windows parity assertion fails when directory symlink creation succeeds, while FIFO handling and PowerShell link-resolution defects can block execution or misdirect paths.
Hardens Spec Kit’s shared feature-path resolution and plan setup across Python, Bash, and PowerShell.
Changes:
Restricts persisted feature paths to the project after resolving symbolic links and parent components; external paths require an explicit override on each invocation.
Adds plan-destination link checks and exclusive-create handling while preserving existing regular plans.
Documents the policy and expands cross-port regression coverage.
File
Description
tests/test_setup_plan_python_parity.py
Adds containment, symlink, override, and Windows PowerShell cases.
scripts/python/setup_plan.py
Rejects plan symlinks and uses exclusive file creation.
scripts/python/common.py
Resolves and validates persisted feature-path containment.
scripts/powershell/setup-plan.ps1
Checks destination links and creates plans with CreateNew.
scripts/powershell/common.ps1
Adds component-wise path resolution and containment checks.
scripts/bash/setup-plan.sh
Adds symlink rejection and noclobber-based creation.
scripts/bash/common.sh
Resolves persisted paths and checks the project boundary.
docs/reference/core.md
Documents containment, external overrides, and plan protection.
Fixed in 10b557989ca821d0794e87b21e4cec24feaa4938: Bash now publishes completed plans atomically without opening existing destinations; PowerShell shares one 40-traversal budget, uses platform-correct name matching, and permits non-redirecting reparse directories while still validating links. The Windows-specific path assertion is corrected, and Python now propagates strict-resolution errors to fix the additional Windows link-loop failure. Added before-and-after regressions, including FIFO handling, exact traversal limits, and reparse-directory classification. The affected local suites passed (370 passed, 79 skipped), and all upstream checks passed, including all six full-suite matrix jobs and the Windows PowerShell 5.1 cases. On behalf of @mnriem, GitHub Copilot using GPT-6.1 Sol (gpt-6.1-sol) autonomously generated these code, test, documentation, and comment changes in an interactive session; reasoning effort was not explicitly specified. No human line-by-line review or manual testing is claimed.
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
A critical mixed-separator path handling flaw can bypass PowerShell containment checks, allowing plan setup to write outside the project without an override.
Both readlink here and dirname at line 175 lose trailing newlines through command substitution. A valid path under a directory named feature\n then resolves to feature, causing setup to write the plan in a different directory. Preserve the target bytes when capturing readlink and remove parent components with parameter expansion.
AI-generated review for the requester: GitHub Copilot; model/reasoning settings unavailable; autonomous analysis and suggested fixes.
Allow non-redirecting cloud-backed plan files
scripts/powershell/setup-plan.ps1:47
An existing OneDrive/Cloud Files plan.md can have the ReparsePoint attribute without being a symbolic link. This blanket check rejects those regular plans instead of preserving them, even though the new directory resolver explicitly accommodates non-redirecting cloud placeholders. Distinguish redirecting links from cloud-backed files here too, and cover an existing cloud-backed plan in the preservation tests.
AI-generated review for the requester: GitHub Copilot; model/reasoning settings unavailable; autonomous analysis and suggested fixes.
Updated in 29e96d23de9f04445c109467d883e1cd17a1ac9e: PowerShell now resolves both path-separator styles before containment checks and probes the literal plan destination so filesystem aliases are recognized. Case-sensitive fallback matching remains in place for distinct siblings on non-Windows systems. A shared link classifier preserves non-redirecting cloud-backed plans while still rejecting symbolic links. Bash now preserves trailing newlines through feature metadata, symlink targets, and parent-component resolution. The new regressions and affected local suites passed (530 passed, 90 skipped); all upstream checks passed, including all six full-suite matrix jobs and the Windows PowerShell 5.1 cases. On behalf of @mnriem, GitHub Copilot using GPT-6.1 Sol (gpt-6.1-sol) autonomously generated these code, test, and comment changes in an interactive session; reasoning effort was not explicitly specified. No human line-by-line review or manual testing is claimed.
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
Bash path validation rejects valid features when the project root is /, while outdated command-template guidance can leave downstream commands unable to locate external features.
No open issues 🎉
2 previously missed issues
In code that hasn't changed since last review
Require external feature directory override for downstream commands
docs/reference/core.md:86
templates/commands/specify.md:99–106 still tells agents that persisting the selected feature path lets downstream commands locate it. For external directories, the new readers reject that value unless SPECIFY_FEATURE_DIRECTORY is supplied again, so following the template can leave /speckit.plan unable to find the feature. Update the command template to require the override on every downstream invocation for external directories, including paths through symlinks outside the project.
Trim root trailing slash before building physical feature paths
scripts/bash/common.sh:255
When the project root is /, $physical_root/ becomes //, so this condition rejects every descendant, such as /specs/001-feature, as outside the project. All Bash consumers of get_feature_paths then fail unless an explicit feature override is supplied. Trim the root's trailing slash before appending the separator, as the PowerShell implementation already does.
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
Constrain feature paths loaded from
.specify/feature.jsonto the project after resolving symbolic links and parent-directory components. External feature directories remain supported through an explicitSPECIFY_FEATURE_DIRECTORYoverride on every invocation.Apply the same policy across Python, Bash, and PowerShell. Plan setup rejects symbolic-link destinations and creates new plans exclusively while preserving existing regular files. Update the shared reference and add cross-port regression coverage.
Testing
uv run specify --helpuv sync && uv run pytestThe full suite used this worktree's own interpreter, as recommended by CONTRIBUTING.md, instead of the literal generic
uv run pytestcommand above.LC_ALL=en_US.UTF-8 .venv/bin/python -m pytest tests -q -n 4- passed: 13,712 passed, 167 skipped, 63 warnings.uvx [email protected] check src tests- passed.uv run specify --help- passed.git diff --check- passed.Sample-project coverage is automated through temporary project fixtures for Python, Bash, and the available PowerShell runtime. Windows PowerShell 5.1 cases are explicitly included but skipped on this macOS host; Windows PowerShell 5.1 runtime verification remains outstanding. No manual agent-driven process test is claimed.
AI Disclosure
AI disclosure: GitHub Copilot, powered by GPT-6.1 Sol (
gpt-6.1-sol), autonomously generated the implementation, tests, documentation, commit, and PR body on behalf of @mnriem, following the user's approved path policy. Work occurred in an interactive session; reasoning effort was not explicitly specified. The initial read-only assessment used a security-review subagent whose model was not reported. Validation was automated; no human line-by-line review or manual testing is claimed.