Skip to content

Support SCP-style Git URLs without user@ prefix#138

Open
turian wants to merge 2 commits intonephila:masterfrom
turian:support-userless-scp-style-urls
Open

Support SCP-style Git URLs without user@ prefix#138
turian wants to merge 2 commits intonephila:masterfrom
turian:support-userless-scp-style-urls

Conversation

@turian
Copy link
Copy Markdown

@turian turian commented Mar 18, 2026

Summary

parse() crashes with AttributeError on SCP-style Git URLs without a user prefix (e.g., github.com:owner/repo.git). These are commonly produced by credential sanitization layers that strip user@ from remote URLs.

Root cause

All SSH regex patterns require user@ before the domain — either hardcoded git@ (GitHub, Bitbucket, Assembla) or a mandatory capture group (GitLab, Base).

Changes

SSH pattern fix (all 5 platforms):

  • user@ is now optional via (?:(?P<_user>[^@]+)@)?, defaulting to the platform's configured user (typically "git")
  • Added (?:...://|(?!.*://)) alternation to prevent git:// and https:// URLs from incorrectly matching SSH patterns (previously git@ served as an implicit anchor)
  • Domain character classes tightened to [^/:@]+ to reject malformed inputs like @github.com:Org/Repo.git

False-positive hardening:

  • BasePlatform SSH domain now requires a dot (FQDN) — rejects generic host:path like foo:bar, localhost:repo, C:\repo
  • GitLab SSH owner excludes colon ([^/:]+) — prevents regex backtracking from parsing host:/repo.git with owner=":"

GitLab port format fix:

  • GitLab GIT format now uses %(port_colon)s instead of %(port)s — fixes git://host.org:9999/... output (was git://host.org9999/...)

Files changed

File Change
platforms/github.py Optional user, protocol disambiguation, tighter domain
platforms/gitlab.py Optional user, protocol disambiguation, owner excludes :, GIT port format fix
platforms/bitbucket.py Optional user, protocol disambiguation, tighter domain
platforms/assembla.py Optional user, protocol disambiguation, tighter domain
platforms/base.py Optional user, FQDN-only domain, :// negative lookahead
result.py port_colon format helper
tests/test_parse.py +11 valid parse cases, +6 invalid input guards
tests/test_rewrite.py +14 rewrite round-trip cases

Test plan

  • All existing tests pass (no regressions)
  • Userless SCP-style: github.com:Org/Repo.git, bitbucket.org:Org/Repo.git, host.org:Org/Repo.git, host.org:9999/Org/Repo.git, git.assembla.com:SomeRepoID.git
  • Non-git SSH users: alice@github.com:Org/Repo.git, alice@host.org:Org/Repo.git, bob@git.assembla.com:SomeRepoID.git
  • Explicit SSH scheme: ssh://alice@host.org/Org/Repo.git
  • GitLab port variants: alice@host.org:9999/Org/Repo.git, ssh://git@host.org:9999/Org/Repo.git
  • Unknown host fallback: git.example.com:team/repo.git → gitlab
  • Rewrite round-trips: userless SCP → ssh, https, git for GitHub, GitLab, Bitbucket, Assembla
  • Invalid inputs rejected: foo:bar, a:b, localhost:repo, C:\repo, host:/repo.git, :Org/Repo.git
  • @github.com:Org/Repo.git (@ without username) remains invalid
  • Non-SSH protocols (git://, https://) unaffected

🤖 Generated with Claude Code

turian and others added 2 commits March 18, 2026 04:44
…r/repo.git)

Previously, all SSH patterns required a user@ prefix (either hardcoded git@ or
a regex capture group). URLs like github.com:owner/repo.git — commonly produced
by credential sanitization layers — would crash with AttributeError.

The fix makes user@ optional in all SSH patterns across all platforms, defaulting
to the platform's configured user (typically "git"). A negative lookahead
(?!.*://) prevents git:// and https:// URLs from incorrectly matching SSH
patterns, and domain character classes now exclude @ to reject malformed inputs
like @github.com:Org/Repo.git.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… SCP change

Tests added (per ROI-prioritized test plan):
- Invalid inputs: foo:bar, a:b, localhost:repo, C:\repo, host:/repo.git, :Org/Repo.git
- Platform disambiguation: assembla, github, gitlab, bitbucket userless SCP
- Rewrite round-trips: userless SCP → ssh, https, git for all platforms
- Non-git users: alice@github.com, alice@host.org, bob@git.assembla.com
- GitLab port variants: alice@host.org:9999, ssh://alice@host.org
- Unknown host fallback: git.example.com:team/repo.git → gitlab

Code fixes:
- BasePlatform SSH domain now requires a dot (FQDN) to reject generic host:path
- GitLab SSH owner excludes colon to prevent backtracking parse of host:/repo.git
- GitLab GIT format uses port_colon for correct git://host:port/path output
- result.py adds port_colon format helper

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@protoroto
Copy link
Copy Markdown
Member

@turian Hi, thanks for opening this pr! In order to make the CI pass may I ask you to:

  • open an issue (if it's not already opened)
  • add a changes/<number-of-issue-created>.feature file with a brief explaination of what's in this pr, so that when it will be merged and released this message will appear in the changelog
    Thanks again!

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants