Skip to content

Fix SSH shorthand URLs joined with '/' instead of ':' (#1247)#1248

Merged
spoorcc merged 3 commits into
mainfrom
claude/dfetch-issue-1247-fuVlQ
Jun 4, 2026
Merged

Fix SSH shorthand URLs joined with '/' instead of ':' (#1247)#1248
spoorcc merged 3 commits into
mainfrom
claude/dfetch-issue-1247-fuVlQ

Conversation

@spoorcc

@spoorcc spoorcc commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

When url-base is an SSH SCP-style shorthand like git@git.mycompany.com,
dfetch was joining it with repo-path using '/' (producing the invalid
git@git.mycompany.com/my-repo.git) instead of ':' (the correct
git@git.mycompany.com:my-repo.git).

Add _is_ssh_shorthand helper to detect these URLs (has '@', no '://'),
use ':' as separator in remote_url, and fix set_remote to strip both
'/' and ':' separators when decomposing a full SSH URL against a remote base.

https://claude.ai/code/session_01MhZACpoBQKKtSFVwjZcuo7

Summary by CodeRabbit

  • Bug Fixes
    • Fixed SSH shorthand URLs (e.g., git@host:path) being joined with "/" when combining URL base and repository path, ensuring correct separator and normalization.
  • Tests
    • Added unit tests covering remote URL construction and normalization for SSH vs HTTPS bases and related edge cases.
  • Documentation
    • Updated changelog entry for the unreleased 0.14.0 release.

When `url-base` is an SSH SCP-style shorthand like `git@git.mycompany.com`,
dfetch was joining it with `repo-path` using '/' (producing the invalid
`git@git.mycompany.com/my-repo.git`) instead of ':' (the correct
`git@git.mycompany.com:my-repo.git`).

Add `_is_ssh_shorthand` helper to detect these URLs (has '@', no '://'),
use ':' as separator in `remote_url`, and fix `set_remote` to strip both
'/' and ':' separators when decomposing a full SSH URL against a remote base.

https://claude.ai/code/session_01MhZACpoBQKKtSFVwjZcuo7
@coderabbitai

coderabbitai Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 05813b31-f30a-461b-b32a-fc56e7e91bc7

📥 Commits

Reviewing files that changed from the base of the PR and between 9018cc6 and eeccb34.

📒 Files selected for processing (2)
  • dfetch/manifest/project.py
  • tests/test_project_entry.py

Walkthrough

Detect SSH SCP-style shorthand remotes (e.g., git@host:path) and use ':' when joining url-base and repo-path; adjust set_remote prefix stripping and add tests plus a changelog entry documenting the fix.

Changes

SSH shorthand remote URL support

Layer / File(s) Summary
SSH shorthand detection helper
dfetch/manifest/project.py
New private _is_ssh_shorthand(url) helper detects SSH user@host shorthand by checking for @ without :// and no extra :.
Remote URL construction with SSH separator support
dfetch/manifest/project.py
set_remote derives _repo_path by slicing away the remote prefix and trimming leading /:; remote_url strips the base, chooses : for SSH shorthand bases or / otherwise, and concatenates base + separator + repo-path with final slash normalization.
Tests and changelog
tests/test_project_entry.py, CHANGELOG.rst
Imports Remote, adds tests validating SSH vs HTTPS remote URL composition, prefix-stripping, trailing-slash normalization, and updates CHANGELOG.rst with the unreleased 0.14.0 entry describing the fix.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.77% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and clearly describes the main bug fix: SSH shorthand URLs being incorrectly joined with '/' instead of ':', matching the core change across all modified files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/dfetch-issue-1247-fuVlQ

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 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 `@dfetch/manifest/project.py`:
- Around line 495-497: The concatenation in the method that builds the remote
path can emit a trailing ":" for SSH shorthand when self._repo_path is empty;
detect when self._repo_path is falsy and avoid leaving a terminal separator by
trimming a trailing ":" (for SSH) or "/" (for HTTPS) after composing base +
separator + self._repo_path, or alternatively skip adding the separator when
self._repo_path is empty; use the existing _is_ssh_shorthand(base) check and
self._remote_obj.url/self._repo_path to implement this defensive handling.

In `@tests/test_project_entry.py`:
- Around line 55-76: Tests currently cover core SSH vs HTTPS separators and
round-trip preservation but miss edge cases; add tests for trailing slash in
Remote({"url-base": ...}) and for empty repo-path behavior. Create new test
functions (e.g., test_remote_url_with_trailing_slash_in_base and
test_remote_url_with_empty_repo_path) that construct ProjectEntry and Remote,
call ProjectEntry.set_remote(Remote(...)), and assert ProjectEntry.remote_url
handles a base with a trailing slash (should not produce double slashes) and
handles an empty repo-path without adding an extra separator; reference
ProjectEntry.set_remote, Remote, remote_url and repo-path when locating where to
exercise the behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 18c051cb-1a3e-4e8c-8f2b-1c125f1f58e9

📥 Commits

Reviewing files that changed from the base of the PR and between 062c92d and 9826045.

📒 Files selected for processing (3)
  • CHANGELOG.rst
  • dfetch/manifest/project.py
  • tests/test_project_entry.py

Comment thread dfetch/manifest/project.py
Comment thread tests/test_project_entry.py
When _repo_path is empty, the previous code emitted a trailing ':' for
SSH shorthand bases (strip("/") only removes slashes, not colons).
Return base directly when there is no repo-path to join.

Also add edge-case tests for trailing slash in url-base and empty repo-path.

https://claude.ai/code/session_01MhZACpoBQKKtSFVwjZcuo7
@spoorcc

spoorcc commented Jun 4, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
dfetch/manifest/project.py (1)

357-359: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Handle SSH bases that already include a path segment.

_is_ssh_shorthand() also returns True for valid bases like git@host:org, so remote_url now recomposes them as git@host:org:repo.git. That breaks the path-prefixed SSH remotes the import/matching logic already supports, which expect git@host:org/repo.git instead. Please only use : for host-only shorthand bases and keep / once the shorthand already contains its host/path separator.

Proposed fix
 def _is_ssh_shorthand(url: str) -> bool:
-    """Return True if *url* is an SSH SCP-style shorthand (``git@host``, no scheme)."""
-    return "@" in url and "://" not in url
+    """Return True if *url* is a host-only SSH SCP-style shorthand (``git@host``)."""
+    if "@" not in url or "://" in url:
+        return False
+    return ":" not in url.rsplit("@", maxsplit=1)[1]
         if self._remote_obj:
             base = self._remote_obj.url.strip("/")
             if not self._repo_path:
                 return base
             separator = ":" if _is_ssh_shorthand(base) else "/"
             return (base + separator + self._repo_path).strip("/")

A regression test with url-base="git@host:org" and repo-path="repo.git" would lock this down.

Also applies to: 495-499

🤖 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 `@dfetch/manifest/project.py` around lines 357 - 359, The SSH-shorthand
detection currently used by _is_ssh_shorthand() treats strings like
"git@host:org" as shorthand and causes recomposition into
"git@host:org:repo.git"; change _is_ssh_shorthand to only return True for
host-only shorthands (e.g., "git@host") by requiring "@" present, "://" absent,
and no ":" present in the URL so path-prefixed SSH bases (those already
containing the host/path separator) are not treated as host-only; update any
recomposition logic that relies on _is_ssh_shorthand (the remote_url
construction around the current remote recomposition and the block referenced at
the other occurrence) to preserve the existing "/" path separator when the base
already contains ":"; add a regression test with url-base="git@host:org" and
repo-path="repo.git".
🤖 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.

Outside diff comments:
In `@dfetch/manifest/project.py`:
- Around line 357-359: The SSH-shorthand detection currently used by
_is_ssh_shorthand() treats strings like "git@host:org" as shorthand and causes
recomposition into "git@host:org:repo.git"; change _is_ssh_shorthand to only
return True for host-only shorthands (e.g., "git@host") by requiring "@"
present, "://" absent, and no ":" present in the URL so path-prefixed SSH bases
(those already containing the host/path separator) are not treated as host-only;
update any recomposition logic that relies on _is_ssh_shorthand (the remote_url
construction around the current remote recomposition and the block referenced at
the other occurrence) to preserve the existing "/" path separator when the base
already contains ":"; add a regression test with url-base="git@host:org" and
repo-path="repo.git".

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 31af8c7c-e94f-413e-aa1d-b59cbceac106

📥 Commits

Reviewing files that changed from the base of the PR and between 9826045 and 9018cc6.

📒 Files selected for processing (2)
  • dfetch/manifest/project.py
  • tests/test_project_entry.py

A url-base such as 'git@host:org' already contains ':' as the SCP
separator between host and path; treating it as a host-only shorthand
caused remote_url to produce a double colon ('git@host:org:repo.git').

Add ':' not in url to _is_ssh_shorthand so only pure host shorthands
(e.g. 'git@host') get ':' as separator; bases that already carry a
path component continue to use '/'.

https://claude.ai/code/session_01MhZACpoBQKKtSFVwjZcuo7
@spoorcc

spoorcc commented Jun 4, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@spoorcc spoorcc merged commit a6e3c1c into main Jun 4, 2026
36 checks passed
@spoorcc spoorcc deleted the claude/dfetch-issue-1247-fuVlQ branch June 4, 2026 14:54
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