Handle trailing slashes when parsing a repo url in init - #715
Handle trailing slashes when parsing a repo url in init#715Muhtasim-Munif-Fahim wants to merge 3 commits into
Conversation
`init(url=...)` split the url on "/" and took the last two segments without
normalizing it first. A url copied from the browser address bar carries a
trailing slash, which shifted every segment by one:
"https://dagshub.com/owner/repo/" -> repo_owner="repo", repo_name=""
`RepoAPI("repo/")` and `create_repo("", ...)` were then called with those
empty values instead of failing. A ".git" suffix combined with a trailing
slash was worse still, yielding repo_owner="repo.git", because the suffix
was only stripped when it sat at the very end of the string.
Strips trailing slashes before the ".git" suffix is removed, and raises
ValueError when the url carries no owner/name pair rather than continuing
with empty segments.
Adds cases to tests/common/test_init.py for the trailing slash, the
".git" + slash combination, repeated slashes, and the urls that should now
raise. All six fail without this change.
Fixes DagsHub#701
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
Included review availability: Your plan includes up to 2 reviews per rolling hour; 1 remains after this review. 📜 Recent review details🔇 Additional comments (2)
📝 WalkthroughWalkthrough
ChangesRepository URL validation
Estimated code review effort: 2 (Simple) | ~10 minutes Merge Risk: 🔵 Low · up to The change correctly handles trailing slashes but still leaves a bounded URL-parsing gap for .git URLs with query parameters, which can target the wrong repository name. The PR is otherwise localized and mergeable with explicit owner follow-up to normalize or reject query and fragment components. Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✨ Finishing Touches🧪 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
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: a39d5eef-886e-47d4-8cb2-308d103f70a4
📒 Files selected for processing (2)
dagshub/common/init.pytests/common/test_init.py
📜 Review details
🔇 Additional comments (2)
dagshub/common/init.py (1)
104-104: LGTM!tests/common/test_init.py (1)
87-109: LGTM!
Review caught a real hole in the previous commit. Taking the last two
slash-separated pieces of the whole url lets the hostname stand in for the
owner when the path has only one segment:
https://dagshub.com/my-repo -> ("dagshub.com", "my-repo")
That is malformed input the code was supposed to reject, and it sailed through
to RepoAPI as a plausible-looking owner/name pair.
Owner and name are now taken from the url *path* via urlparse, and a path with
fewer than two non-empty segments raises. With a scheme present the hostname
lands in `netloc` and is never a candidate; without one, urlparse puts
everything in `path`, so a bare "owner/repo" still works.
Extends the raising cases with the reported url and its trailing-slash form.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Good catch, and it was a real hole — thanks.
Fixed in e8af285 by parsing the url path with Added the reported url and its trailing-slash form to the raising cases. Worth noting the old behaviour made the test suite hang rather than fail — the malformed url reached the API instead of raising, which is exactly the failure mode this was meant to prevent. |
There was a problem hiding this comment.
Actionable comments posted: 2
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 3298e8c5-e165-4bef-8e9b-f0f5f667c031
📒 Files selected for processing (2)
dagshub/common/init.pytests/common/test_init.py
🚧 Files skipped from review as they are similar to previous changes (1)
- tests/common/test_init.py
📜 Review details
🔇 Additional comments (1)
dagshub/common/init.py (1)
123-123: LGTM!
Two follow-ups from review, both on the url that `init` derives.
The parse skips empty path segments when reading owner and name, but the url
itself was passed through untouched, so the two could disagree:
https://dagshub.com/my-org//my-repo
-> RepoAPI("my-org/my-repo")
-> MLFLOW_TRACKING_URI = "https://dagshub.com/my-org//my-repo.mlflow"
The url is now rebuilt from the same segments the owner and name come from, so
whatever reaches MLflow and DVC agrees with what reached the API.
Rebuilding also drops any userinfo. That matters beyond tidiness: `url` is
written into .dvc/config, which is a committed file, so a token pasted into the
url as "https://user:token@dagshub.com/owner/repo" would have been committed to
the repository. MLflow and DVC are both handed credentials separately from the
token, so nothing depended on the userinfo being carried.
The same redaction applies to the "could not determine the repo owner and name"
error, which quotes the url back and is likely to end up in a log.
Four of the five new cases fail without this change; the `.git` one passes
already and is there as a guard.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Pushed The url is now rebuilt from the same segments the owner and name are read from, so the two cannot disagree. Previously One thing worth flagging beyond the finding as written: rebuilding also drops any userinfo, and that closes a real leak rather than just tidying the string. Five new cases cover this; four of them fail without the change, and the |
Fixes #701.
The bug
init(url=...)takes the last two segments of the url without normalizing it first:A url copied from the browser address bar carries a trailing slash, which shifts every segment by one:
repo_ownerrepo_namehttps://dagshub.com/owner/repoownerrepohttps://dagshub.com/owner/repo/repo""https://dagshub.com/owner/repo.gitownerrepohttps://dagshub.com/owner/repo.git/repo.git""The
.gitcase is worse because the suffix is only stripped when it sits at the very end of the string, so a trailing slash defeats that too.Nothing catches the empty value afterwards —
RepoAPI("repo/")is constructed and, on the not-found branch,create_repo("", ...)is called.The fix
Strip trailing slashes before the
.gitsuffix is removed, and fail loudly when the url carries no owner/name pair rather than continuing with empty segments:All four rows above now yield
("owner", "repo"), as do repeated slashes.I used
ValueErrorfor the malformed-url case.initalready raisesAttributeErrorfor the mismatched-args case just above, so say the word if you would rather these were consistent.Tests
Extends
tests/common/test_init.pyusing the fixtures already there:test_init_from_url_tolerates_trailing_slash, parametrized over the trailing slash, the.git+ slash combination, and repeated slashes, assertingRepoAPIandcreate_reporeceivemy-org/my-repo;test_init_from_url_without_owner_and_name_raises, parametrized over urls with no owner/name pair.All six fail without the change and pass with it.
tests/commonplustests/test_misc.pyis 54 passed.tests/common/test_determine_repo.pyfails to collect on my machine for want ofpytest_git; that is unrelated to this change and reproduces on a clean checkout. I also left the surrounding formatting alone —black --line-length 120wants to reformat parts oftest_init.pythat predate this PR, so I kept the diff to the new cases.🤖 Generated with Claude Code