fix(input): support scp-style SSH Git URLs in host validation#208
Open
rodboev wants to merge 3 commits into
Open
fix(input): support scp-style SSH Git URLs in host validation#208rodboev wants to merge 3 commits into
rodboev wants to merge 3 commits into
Conversation
Signed-off-by: Rod Boev <rod.boev@gmail.com>
Signed-off-by: Rod Boev <rod.boev@gmail.com>
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Summary
scp-style SSH Git URLs (
git@github.com:org/repo.git) are silently admitted by_is_git_url()then rejected by_validate_url_host()with the misleading errorURL has no valid hostname. This makes every GitHub/GitLab/Bitbucket SSH clone URL unusable even thoughgit clonesupports the format natively.Closes #202
Root cause
_validate_url_host()(input_handler.py:163-181) usesurlparse(url).hostnamefor host extraction. scp-style syntax has no//authority separator, sourlparse().hostnamereturnsNone,hostbecomes"", and the function raises at line 171 before reaching the allowlist or SSRF checks. The_clone_git()call at line 190 would handle the format correctly if validation passed.Diff Notes
src/skillspector/input_handler.py: addimport re; add private_extract_scp_host()helper matching^[^@/]+@([^:/]+):.+$; add scp fallback inside_validate_url_host()afterurlparse— scp host flows through existing allowlist and_is_private_ip()SSRF checks unchanged. No change to_is_git_url(),_clone_git(), orALLOWED_GIT_HOSTS.tests/unit/test_input_handler.py: seven new test cases covering scp detection, valid-host extraction, disallowed-host rejection, private-IP rejection, https regression, and SSRF gate for scp-extracted hosts (mocked).Before / After
git@github.com:org/repo.gitValueError: URL has no valid hostnamegithub.comextracted, clone proceedsgit@malicious.internal:org/repo.gitValueError: URL has no valid hostnameValueErrorgit@169.254.169.254:org/repo.gitValueError: URL has no valid hostnameValueErrorhttps://github.com/org/repo.git"github.com"(unchanged)"github.com"(scp fallback not reached)Scope
No expansion of
ALLOWED_GIT_HOSTS. No change to SSRF protections or their order. No new runtime dependency (reis stdlib)._is_git_url()and_clone_git()unchanged.Verification
uv sync --all-extras— exit 0.\.venv\Scripts\python.exe -m pytest tests/unit/test_input_handler.py -v— 13 passed, 1 warning, 0.50s (6 original + 7 new)uv run ruff check src/skillspector/input_handler.py tests/unit/test_input_handler.py— exit 0uv run ruff format --check src/skillspector/input_handler.py tests/unit/test_input_handler.py— 2 files already formatted, exit 0Proof matrix:
test_validate_url_host_scp_extracts_githubValueError"github.com"test_scp_valid_host_clonestest_scp_url_is_git_urlTrueTruetest_scp_disallowed_host_raisesValueErrorValueError(allowlist)test_scp_private_ip_raisesValueErrorValueErrortest_https_url_unchanged"github.com""github.com"test_scp_ssrf_gate_firesValueErrormatching"private/internal IP"CI
Lint & Test (Python 3.12),Lint & Test (Python 3.13), andDCO Checkpending maintainer approval if fork checks are gated.Notes
DCO sign-off required on every commit (
git commit -s). Known existing failures (tests/nodes/test_meta_analyzer.py) are unrelated to this surface.