fix: detect port-like segment in SCP shorthand and suggest ssh:// form#787
Conversation
microsoft#784) When a user writes `git@host:7999/project/repo.git` (SCP shorthand intending port 7999), the parser silently treats `7999/project/repo` as the repo path. The subsequent git clone fails with a 404 — no actionable error from APM. Detect when the first path segment after `:` in SCP shorthand is a valid TCP port number (1-65535) and raise a ValueError with a suggested ssh:// URL that preserves the port correctly.
Review panel verdict: Approve -- with two non-blocking suggestionsExternal contribution (@edenfunf) closing #784. Fix is small (29/+1 lines), surgical, well-tested (15 new test cases), and turns a silent 404 from a remote into an actionable APM-level error. Ran it past the full panel; key findings below. Python Architect: pass
Supply Chain Security Expert: pass (with a note)
CLI Logging Expert: pass
DevX UX Expert: pass with one polish suggestion
APM CEO: approve, request CHANGELOG line
OSS Growth Hacker: positive signal
Recommended path to merge
LGTM after #1. Thanks @edenfunf for the clean fix and thorough tests. |
There was a problem hiding this comment.
Pull request overview
Improves DependencyReference parsing to detect a common misconfiguration where users provide an SCP-style SSH shorthand URL with a port-like first path segment (which SCP syntax cannot represent), and raises an actionable error suggesting the correct ssh:// form.
Changes:
- Add port-like first-segment detection to
_parse_ssh_urlforgit@host:port/pathinputs and raise a helpfulValueErrorwith anssh://suggestion. - Add unit tests covering valid port boundaries, leading zeros, ref/alias handling, and non-detection for out-of-range values.
Show a summary per file
| File | Description |
|---|---|
src/apm_cli/models/dependency/reference.py |
Adds SCP-shorthand port-like segment detection and improved error messaging with an ssh:// suggestion. |
tests/unit/test_generic_git_urls.py |
Adds a new test class validating the new detection logic and key edge cases. |
Copilot's findings
- Files reviewed: 2/2 changed files
- Comments generated: 2
…entry Address review feedback: - Thread reference and alias into the suggested ssh:// URL so users don't have to re-add them manually after switching from SCP form. - Add CHANGELOG entry under [Unreleased] -> Fixed for microsoft#784. - Add test for combined #ref@alias preservation.
Address Copilot review: - git@host:7999/ (trailing slash, empty remaining path) now falls into the "no repository path follows" branch instead of building a suggestion ending with '/'. - Switch test_suggestion_omits_git_suffix_when_absent from try/except to pytest.raises for consistency with the rest of the file.
|
Thanks @danielmeppiel for the thorough panel review. Both items addressed: 1. CHANGELOG entry (required) — added under
2. Preserve Added a dedicated test ( Also addressed Copilot inline findings:
All 4208 unit tests pass. |
danielmeppiel
left a comment
There was a problem hiding this comment.
@edenfunf excellent PR - thank you for this!
Fixes #784.
Root Cause
_parse_ssh_urluses^git@([^:]+):(.+)$to parse SCP shorthand. Everything after:becomes the repo path. When a user writes:The parser produces
repo_url = "7999/project/repo"withport = None. Phase 3 validation accepts"7999"as a valid segment ([a-zA-Z0-9._-]+). The subsequentgit clonefails with a 404 from the remote — no actionable error from APM.The user intended port 7999 with repo
project/repo, but SCP shorthand (git@host:path) uses:as the path separator and cannot carry a port. The correct form isssh://git@host:7999/project/repo.git, which is handled by_parse_ssh_protocol_urlviaurlparse.Fix
After alias/ref extraction and
.gitstripping in_parse_ssh_url, check if the first path segment is a valid TCP port number (1–65535). If so, raise aValueErrorwith an actionable suggestion:Before
After
Design decisions
re.fullmatch(r"[0-9]+", ...)instead ofstr.isdigit()): Python'sisdigit()returnsTruefor Unicode superscript digits (²³) whereint()raisesValueError. Using an ASCII-only regex avoids this edge case.validate_path_segments: a port-like first segment is a more specific and actionable error than a generic traversal/segment error. It takes priority..gitsuffix: if the user wrote.git, the suggested URL includes it for copy-paste-ability. If omitted, the suggestion omits it too.git@host:7999with no remaining path): detected separately with a distinct message ("no repository path follows").False positive analysis
Purely numeric org/owner names in the range 1–65535 would be a false positive. GitHub explicitly disallows numeric-only usernames; GitLab and Bitbucket require at least one letter. Self-hosted instances could theoretically allow it, but this is vanishingly rare. The error message clearly explains the issue and suggests the
ssh://form, which unambiguously separates port from path.Changes
src/apm_cli/models/dependency/reference.py_parse_ssh_url(~28 lines)tests/unit/test_generic_git_urls.pyTestSCPPortDetectionclass with 15 test casesTests
New
TestSCPPortDetectionclass covering:ssh://suggestion007999) — detected and normalized#refand@alias— still detected after extraction.gitsuffix based on user inputacme,v2) — parse normally, no changessh://URL with port — continues to work (regression guard)Validation
Refs: #661, #665