Repository navigation
Conversation
Use deny-mode FileHelper I/O for integration state independently of lifecycle observers. Preserve structured read errors and transaction notifications, and cover linked state files and directories. Assisted-by: GitHub Copilot (model: GPT-6.1 Sol, autonomous) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
🟡 Changes recommended
The integration-state error recommends enabling symlinks even though state handling always denies them, giving affected projects guidance that cannot resolve the failure.
1 open issue
What changed in this PR
Hardens Specify CLI’s integration-state I/O against symlinks below the trusted project root, independently of lifecycle transactions and the operational symlink opt-in.
Changes:
- Route integration-state reads and writes through deny-mode
FileHelper. - Reject linked destinations before lifecycle observers run, while retaining notifications and structured errors.
- Add regression coverage for linked state, installation rejection, normal updates, and trusted root aliases.
Validation was limited to isolated standard-library checks; the full suite and before/after regression comparison were not rerun.
| File | Description |
|---|---|
tests/specify_cli/integrations/test_command_status.py |
Expect a state-read error when project-root resolution fails. |
tests/specify_cli/integrations/test_command_install.py |
Verify installation rejects linked state before setup under either symlink policy. |
tests/integrations/test_integration_state.py |
Cover link rejection, observer behavior, normal state updates, and trusted root aliases. |
src/specify_cli/integration_state.py |
Enforce deny-mode state I/O and validate destinations before observer access. |
Review effort: Max (auto)
Replace FileHelper's generic opt-in hint with state-specific guidance to replace linked entries and clarify that allow_symlinks does not apply. Preserve deny-only behavior and cover read, write, and CLI diagnostics. Assisted-by: GitHub Copilot (model: GPT-6.1 Sol, autonomous) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
Updated in a999552: integration-state read and write diagnostics now tell users to replace linked entries and clarify that allow_symlinks does not apply to integration state, without changing deny-only behavior. The regression assertions also cover CLI output under both symlink-policy settings. Posted on behalf of @mnriem by GitHub Copilot using GPT-6.1 Sol (gpt-6.1-sol), autonomous execution with runtime-configured reasoning settings not exposed; AI assistance covered the fix, regression tests, and this summary. |
There was a problem hiding this comment.
🟡 Changes recommended
The integration test’s symlink assertion can fail spuriously on Windows because Path.readlink() may return a prefixed absolute path that differs from the expected target even when the link is unchanged.
1 open issue
1 resolved since last review
Review effort: Max (auto)
Compare the recorded readlink value before and after denied integration-state writes instead of comparing it with the requested target spelling. This avoids Windows extended-path prefix mismatches. Assisted-by: GitHub Copilot (model: GPT-6.1 Sol, autonomous) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
Updated in 10aaf36: the integration-state preservation test now compares the link target returned by readlink before and after the denied write, avoiding assumptions about Windows path-prefix spelling. Posted on behalf of @mnriem by GitHub Copilot using GPT-6.1 Sol (gpt-6.1-sol), autonomous execution with runtime-configured reasoning settings not exposed; AI assistance covered the test change and this summary. |
Document integration state as managed metadata outside the operational symlink opt-in. Cover contained state links with allow_symlinks enabled in the shared readers, writer, and installation CLI while confirming the general configured helper still permits contained links. Assisted-by: GitHub Copilot (model: GPT-6.1 Sol, autonomous) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
Updated in c88e098: following the maintainer’s decision, the filesystem-policy design now explicitly identifies integration state as deny-only managed metadata. Added coverage showing that contained state links remain rejected with allow_symlinks enabled while the general configured helper still permits them, and extended installation checks to contained targets. Runtime behavior is unchanged. Posted on behalf of @mnriem by GitHub Copilot using GPT-6.1 Sol (gpt-6.1-sol), autonomous execution with runtime-configured reasoning settings not exposed; AI assistance covered the approved design clarification, tests, and this summary. |
Clarify that deny-only state I/O applies to specify_cli.integration_state, not unmigrated bundle readers that retain containment-checked reads. No runtime behavior changes. Assisted-by: GitHub Copilot (model: GPT-6.1 Sol, autonomous) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
Updated in 13c2235: the filesystem-policy guarantee now explicitly applies to specify_cli.integration_state rather than every reader of integration.json. The design and PR description distinguish the legacy bundle reader, which retains containment-checked reads and can follow contained links. Bundle runtime behavior is unchanged. Posted on behalf of @mnriem by GitHub Copilot using GPT-6.1 Sol (gpt-6.1-sol), autonomous execution with runtime-configured reasoning settings not exposed; AI assistance covered the documentation correction and this summary. |


Description
Use deny-mode
FileHelperI/O inspecify_cli.integration_statefor.specify/integration.jsonreads and writes, independently of lifecycle transactions or operational symlink opt-in. Reject linked state files and.specifydirectories before lifecycle observers access them, while preserving existing write notifications and structured read errors.Add regression coverage for existing, dangling, contained, and cyclic links, built-in integration installation, normal state updates, and trusted project-root aliases. Clarify in the existing filesystem-policy design that the
specify_cli.integration_statehelpers are an explicit deny-only managed-metadata exception, with coverage proving that these helpers reject contained state links whenallow_symlinksis true while the general configured helper still permits contained links. This guarantee does not cover unmigrated consumers such asbundles.project.active_integration, which retains containment-checked reads and can follow contained state-file links.Testing
uv run specify --helpuv sync && uv run pytestuv run specify --helppassed. The full suite at8355df49used the documented worktree-local interpreter rather thanuv run pytest:LC_ALL=en_US.UTF-8 .venv/bin/python -m pytest tests -qpassed with 13,690 passed, 130 skipped on macOS with Python 3.13.17. Test dependencies were installed withuv sync --extra test(passed).For the policy clarification at
c88e0980,.venv/bin/python -m pytest tests/integrations/test_integration_state.py tests/specify_cli/integrations/test_command_install.py tests/specify_cli/test_file_policy.py -q --tb=shortpassed with 254 passed. The full suite was not rerun after the review follow-ups. The follow-up at13c22352only narrows documentation wording;git diff --checkpassed and no additional tests were run for that documentation-only change.Sample-project checks are automated tests using temporary initialized projects, including normal installation and rejection of linked state before setup. No manual coding-agent slash-command testing was run; command templates and scripts are unchanged.
AI Disclosure
AI disclosure: Prepared on behalf of @mnriem with GitHub Copilot using GPT-6.1 Sol (
gpt-6.1-sol), with runtime-configured reasoning settings not exposed to the agent, in autonomous execution under user direction. A security-review subagent was also used; its model was not exposed. AI assistance covered assessment, implementation, the approved design clarification, regression tests, automated validation, commit text, and this PR description.