Uh oh!
There was an error while loading. Please reload this page.
fix(git): parse GitHub remotes with embedded http(s) credentials - #260
Conversation
`parse_github_remote_url` relied on exact prefix matching against `https://github.com/` and friends. Git-stored remotes of the form `https://token@github.com/owner/repo.git` or `https://user:pass@github.com/owner/repo.git` — which git itself accepts — failed that match and returned `None`, so repo auto-inference broke for anyone using a credential-embedded remote. Normalize http(s) URLs by stripping the `user[:pass]@` credentials from the authority before the prefix check. SSH forms are unaffected. The credential-stripping is scoped to the authority (everything up to the first `/`) so a literal `@` in the path is preserved. Fixes#250. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
| let (authority, path) = rest.split_once('/').unwrap_or((rest, "")); | ||
| if let Some((_, host)) = authority.split_once('@') { | ||
| return Some(format!("{scheme}{host}/{path}")); |
There was a problem hiding this comment.
📝 Info: Trailing slash added when URL has no path after authority
When the input URL has no path (e.g. https://token@github.com), rest.split_once('/').unwrap_or((rest, "")) sets path to "", and the format string "{scheme}{host}/{path}" produces "https://github.com/" — inserting a / that wasn't in the original. This is harmless here because such a URL would never contain an owner/repo path, so parse_github_remote_url correctly returns None regardless. But worth noting if strip_http_credentials is ever reused in a context where the trailing slash matters.
Was this helpful? React with 👍 or 👎 to provide feedback.
| // (or end of string). Anything after the authority — including a | ||
| // `@` in the path — stays untouched. | ||
| let (authority, path) = rest.split_once('/').unwrap_or((rest, "")); | ||
| if let Some((_, host)) = authority.split_once('@') { |
There was a problem hiding this comment.
📝 Info: split_once('@') is correct per RFC 3986 for userinfo delimiter
The use of split_once('@') to separate credentials from the host in the authority component is correct per RFC 3986, which defines the userinfo as everything before the first@. A literal @ in a password must be percent-encoded as %40. This means a malformed URL like https://user:p@ss@github.com/owner/repo (unencoded @ in password) would extract host = "ss@github.com" and fail prefix matching — this is the correct behavior for a non-conformant URL.
Was this helpful? React with 👍 or 👎 to provide feedback.
Uh oh!
There was an error while loading. Please reload this page.
) ## Summary Inputs like `' usedetail/cli'` or `'usedetail / cli'` passed `validate_owner_repo_format` (which used `.trim().is_empty()` only for emptiness checks) but were then compared verbatim against `r.full_name`. The exact match failed and users got a misleading **"Repository not found. Make sure you have access …"** error for what was actually a whitespace typo. Trim the identifier, and trim each half of an `owner/repo` pair, before matching. The "not found" error now quotes the normalized form so the hint itself is accurate. ## Stacked on **#260** (fix for GitHub remote parsing with embedded credentials). Base branch is `siyer/fix-parse-github-remote-creds`; the diff against main is just the repos.rs change. ## Test plan - [x] `cargo test --lib utils::repos` — 22 pass, including 4 new cases (leading/trailing whitespace, whitespace around slash, bare-name trim, normalized error message) - [x] `cargo clippy -- -D warnings` clean - [x] `cargo fmt --check` clean Fixes#230. 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- devin-review-badge-begin --> --- <a href="https://app.devin.ai/review/usedetail/cli/pull/261" target="_blank"> <picture> <source media="(prefers-color-scheme: dark)" srcset="https://static.devin.ai/assets/gh-open-in-devin-review-dark.svg?v=1"> <img src="https://static.devin.ai/assets/gh-open-in-devin-review-light.svg?v=1" alt="Open in Devin Review"> </picture> </a> <!-- devin-review-badge-end --> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
## Summary Patch release rolling up the seven fixes merged since 0.2.1: - fix(bugs): print empty-results hint when `--vulns` alone yields no matches (#264) - fix(datetime): floor sub-second negative timestamps instead of snapping to epoch (#262) - chore(deps): bump rustls-webpki to 0.103.13 for RUSTSEC-2026-0104 (#263) - fix(repos): normalize whitespace in repo identifiers before lookup (#261) - fix(git): parse GitHub remotes with embedded http(s) credentials (#260) - fix(auth): redirect browser and surface OAuth errors on PKCE callback failure (#258) - refactor(config): rewrite `update_config` through the locked handle (#257) On merge, the release workflow will tag `v0.2.2` and publish platform artifacts via cargo-dist. ## Test plan - [x] `cargo build` succeeds with version 0.2.2 - [ ] Tag `v0.2.2` is created on merge and release workflow publishes artifacts 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- devin-review-badge-begin --> --- <a href="https://app.devin.ai/review/usedetail/cli/pull/265" target="_blank"> <picture> <source media="(prefers-color-scheme: dark)" srcset="https://static.devin.ai/assets/gh-open-in-devin-review-dark.svg?v=1"> <img src="https://static.devin.ai/assets/gh-open-in-devin-review-light.svg?v=1" alt="Open in Devin Review"> </picture> </a> <!-- devin-review-badge-end --> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
parse_github_remote_urlused strictstrip_prefixmatches againsthttps://github.com/. Valid remotes of the formhttps://token@github.com/owner/repo.gitorhttps://user:pass@github.com/owner/repo.git— which git itself accepts and stores — fell through and returnedNone, breaking repo auto-inference for anyone using a credential-embedded remote.Normalize http(s) URLs by stripping the
user[:pass]@portion of the authority before the prefix check. The strip is scoped to characters before the first/, so a literal@in the path (e.g..../repo@tag) is left alone. SSH forms (git@github.com:…,ssh://git@github.com/…) are unaffected.Test plan
cargo test --lib utils::git— 20 pass, including 5 new cases (token creds, user:pass creds, http scheme,@in path, non-github host with creds)cargo clippy -- -D warningscleancargo fmt --checkcleanFixes#250.
🤖 Generated with Claude Code