Repository navigation
fix: reject trailing newlines in extension IDs - #5186
Conversation
Use fullmatch for extension ID validation and expand invalid-ID regression coverage. 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
A critical active finding remains: an anchored .match() path can allow a catalog ID ending in a newline to reach the suggested command, undermining the shell-safety guarantee.
1 open issue
What changed in this PR
This PR tightens extension ID validation to require the entire value to match the documented lowercase alphanumeric-and-hyphen format.
Changes:
- Replaces anchored matching with full-string validation.
- Adds invalid-ID coverage for newlines, whitespace, empty values, and traversal-shaped inputs.
- Preserves validation of existing valid IDs.
A critical issue remains unresolved: catalog IDs processed by _commands._command_safe_id can still accept trailing newlines and appear unsafely in suggested commands. The full-match invariant should be enforced there as well, with coverage for that path.
| File | Summary |
|---|---|
tests/test_extensions.py |
Adds parameterized coverage for malformed extension IDs, including newline and whitespace handling. |
src/specify_cli/extensions/__init__.py |
Enforces full-string validation for extension IDs loaded from manifests. |
Review effort: Lite (auto)
Use fullmatch in the shared command-safe ID helper and cover newline IDs in extension add and search suggestions. Assisted-by: GitHub Copilot (model: GPT-6.1 Sol, autonomous) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
Updated in commit 11d90af: the shared command-safe ID helper now requires a full-string match, so catalog IDs ending in a newline are replaced with the existing placeholder in suggested commands. Added regression coverage for extension add and search, including install-enabled and discovery-only catalogs and unchanged valid-ID suggestions. The new newline cases failed before the fix; all 764 tests in the extension command/domain and preset-add suites pass afterward. Posted on behalf of @mnriem by GitHub Copilot using GPT-6.1 Sol, default reasoning settings, autonomous mode; AI generated the fix, tests, validation, and this summary. |

Description
Require the entire extension ID to match the documented lowercase alphanumeric-and-hyphen format. Replacing the anchored
re.matchwithre.fullmatchprevents a trailing newline from being accepted.Expand invalid-ID coverage to include trailing and embedded newlines, surrounding whitespace, empty IDs, and traversal-shaped input. Valid extension IDs retain their existing behavior.
Testing
uv run specify --helpuv sync && uv run pytestUsed the documented worktree-local interpreter rather than bare
uv run pytest:uv sync --extra test --quiet— passed.uv run specify --help— passed..venv/bin/python -m pytest tests/test_extensions.py -q— passed, 493 tests.LC_ALL=en_US.UTF-8 .venv/bin/python -m pytest tests -q— passed, 13,668 passed, 130 skipped, 63 warnings.git diff --check— passed.Sample-project and agent slash-command testing are not applicable: this change only tightens extension manifest ID validation.
AI Disclosure
AI disclosure: GitHub Copilot using GPT-6.1 Sol, with default reasoning settings and autonomous execution under user direction, assessed the validation issue, generated the fix and tests, ran validation, and prepared the commit and pull request. The assessment also used Copilot's security-review subagent with its runtime-default model; that model identity was not reported.