fix(repos): parse and preserve custom-user SSH remotes - #337
Conversation
SSH remotes with a non-git user (e.g. company@company.ghe.com:orga/repo.git) were misparsed as GitHub shorthand and stored as https://github.com/company@company.ghe.com:orga/repo. The scp-style matcher hardcoded the git@ user, so custom-user remotes fell through to the owner/repo shorthand branch. SSH URL parsing is now unified in shared/utils/repo.ts and applied across backend and frontend: any user@host:path remote is detected, preserved, and deduplicated correctly. The compare key also converges the scp-with-port and ssh:// spellings, strips embedded credentials, and fails closed on malformed host segments.
📝 WalkthroughWalkthroughSSH and SCP URL handling moved to shared utilities. The shared implementation supports custom SSH users, ports, host extraction, and comparison normalization. Backend and frontend consumers now use these helpers, with expanded repository URL tests. ChangesSSH URL utility migration
Estimated code review effort: 3 (Moderate) | ~20 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@backend/src/services/repo.ts`:
- Around line 960-962: Update the SSH URL matching in the repository URL parsing
logic around sshMatch to reuse the shared SCP_STYLE_URL_PATTERN from
shared/src/utils/repo.ts instead of the local regex. Preserve the existing host
and path extraction behavior while ensuring malformed host segments containing
“/” are rejected consistently.
🪄 Autofix
✅ Autofix completed
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: eeb52925-081d-4430-8f57-96d9d3dd9d58
📒 Files selected for processing (8)
backend/src/services/git-auth.tsbackend/src/services/git/GitService.tsbackend/src/services/repo.tsbackend/src/services/schedule-worktree.tsbackend/src/utils/git-auth.tsbackend/test/utils/repo-url.test.tsfrontend/src/components/repo/AddRepoDialog.tsxshared/src/utils/repo.ts
💤 Files with no reviewable changes (1)
- backend/src/utils/git-auth.ts
| const sshMatch = url.match(/^([^@/:]+)@([^:]+):(.+?)(?:\.git)?$/) | ||
| if (sshMatch) { | ||
| const [, host, pathPart] = sshMatch | ||
| const [, , host, pathPart] = sshMatch |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Reject malformed SCP-style host segments.
Line 960 permits / in the host segment. For example, git@github.com/owner:repo becomes https://github.com/owner/repo instead of remaining invalid. This differs from SCP_STYLE_URL_PATTERN in shared/src/utils/repo.ts.
Use the shared pattern here so all consumers apply the same SSH URL contract.
Proposed fix
-import { normalizeRepoDirectoryName, sanitizeRepoDirectoryName, sanitizeBranchForDirectory, normalizeRepoUrlForCompare, isSSHUrl, normalizeSSHUrl } from '`@opencode-manager/shared/utils`'
+import { normalizeRepoDirectoryName, sanitizeRepoDirectoryName, sanitizeBranchForDirectory, normalizeRepoUrlForCompare, isSSHUrl, normalizeSSHUrl, SCP_STYLE_URL_PATTERN } from '`@opencode-manager/shared/utils`'
...
- const sshMatch = url.match(/^([^`@/`:]+)@([^:]+):(.+?)(?:\.git)?$/)
+ const sshMatch = url.match(SCP_STYLE_URL_PATTERN)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const sshMatch = url.match(/^([^@/:]+)@([^:]+):(.+?)(?:\.git)?$/) | |
| if (sshMatch) { | |
| const [, host, pathPart] = sshMatch | |
| const [, , host, pathPart] = sshMatch | |
| const sshMatch = url.match(SCP_STYLE_URL_PATTERN) | |
| if (sshMatch) { | |
| const [, , host, pathPart] = sshMatch |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@backend/src/services/repo.ts` around lines 960 - 962, Update the SSH URL
matching in the repository URL parsing logic around sshMatch to reuse the shared
SCP_STYLE_URL_PATTERN from shared/src/utils/repo.ts instead of the local regex.
Preserve the existing host and path extraction behavior while ensuring malformed
host segments containing “/” are rejected consistently.
Fixes Applied SuccessfullyFixed 1 file(s) based on 1 unresolved review comment. Files modified:
Commit: The changes have been pushed to the Time taken: |
Fixed 1 file(s) based on 1 unresolved review comment. Co-authored-by: CodeRabbit <noreply@coderabbit.ai>
Custom-user SSH remotes (e.g.
company@company.ghe.com:orga/repo.git) were misparsed: the scp-style matcher hardcoded thegit@user, so the URL fell through to theowner/reposhorthand and was stored ashttps://github.com/company@company.ghe.com:orga/repo. SSH URL syntax handling is now unified inshared/utils/repo.tsand applied across backend and frontend, so anyuser@host:pathremote is detected, preserved, and deduplicated correctly. The compare key also converges the scp-with-port andssh://spellings, strips embedded credentials, and fails closed on malformed host segments. Fixes #336.Summary
Type of Change
Checklist
pnpm lintpasses locallypnpm typecheckpasses locallySummary by CodeRabbit
New Features
Bug Fixes