Skip to content

fix: contain persisted feature paths and protect plan creation - #5178

Open
mnriem wants to merge 2 commits into
github:mainfrom
mnriem:mnriem-feature-path-containment
Open

mnriem wants to merge 2 commits into
github:mainfrom
mnriem:mnriem-feature-path-containment

Conversation

@mnriem

@mnriem mnriem commented Oct 29, 2026

Copy link
Copy Markdown
Collaborator

Description

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.

  • LC_ALL=en_US.UTF-8 .venv/bin/python -m pytest tests -q -n 4 - passed: 13,712 passed, 167 skipped, 63 warnings.
  • uvx ruff@0.15.0 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

  • 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 <223556219+Copilot@users.noreply.github.com>
Copilot AI auto review requested due to automatic review settings October 29, 2026 14:19

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

A Windows parity assertion fails when directory symlink creation succeeds, while FIFO handling and PowerShell link-resolution defects can block execution or misdirect paths.

5 open issues
What changed in this PR

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.

Review effort: Max (auto)

Comment thread tests/test_setup_plan_python_parity.py
Comment thread scripts/bash/setup-plan.sh Outdated
Comment thread scripts/powershell/common.ps1 Outdated
Comment thread scripts/powershell/common.ps1 Outdated
} elseif (Test-Path -LiteralPath $resolved -PathType Container) {
# Parent enumeration also sees dangling links on Windows PowerShell 5.1.
$entry = Get-ChildItem -LiteralPath $resolved -Force -ErrorAction Stop |
Where-Object { $_.Name -eq $component } | Select-Object -First 1
Comment thread scripts/powershell/common.ps1 Outdated
@mnriem mnriem added the triage-must-have Verdict: high-value, important work for Spec Kit — do first label Oct 29, 2026
Publish Bash plans without opening existing destinations. Bound total PowerShell link traversals, preserve non-link reparse directories, and use platform-correct name matching. Correct Windows path assertions and propagate strict Python resolution failures with regression coverage.

Assisted-by: GitHub Copilot (model: GPT-6.1 Sol, autonomous)

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI auto review requested due to automatic review settings October 29, 2026 16:25
@mnriem

mnriem commented Oct 29, 2026

Copy link
Copy Markdown
Collaborator Author

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.

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

A critical mixed-separator path handling flaw can bypass PowerShell containment checks, allowing plan setup to write outside the project without an override.

3 open issues
2 previously missed issues

In code that hasn't changed since last review

Medium severity Preserve trailing newlines in resolved paths

scripts/​bash/​common.sh:181

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.

Medium severity 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.

4 resolved since last review

Review effort: Max (auto)

Comment on lines +171 to +174
$separators = [regex]::Escape(
[string][System.IO.Path]::DirectorySeparatorChar +
[string][System.IO.Path]::AltDirectorySeparatorChar
)
Comment on lines +45 to +46
$planEntry = Get-ChildItem -LiteralPath $paths.FEATURE_DIR -Force -ErrorAction Stop |
Where-Object { $_.Name.Equals('plan.md', $pathComparison) } | Select-Object -First 1

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

triage-must-have Verdict: high-value, important work for Spec Kit — do first

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants