From 01e855608c45327771bb186911a9ef2677d8358b Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sat, 14 Mar 2026 17:47:55 -0400 Subject: [PATCH] Handle credential-embedded GitHub URLs in parse_github_owner_repo URLs like https://x-access-token:TOKEN@github.com/owner/repo.git are used by Daytona sandboxes. Strip the credentials before matching the github.com prefix so pr_create and other callers work in those envs. Co-Authored-By: Claude Opus 4.6 (1M context) --- lib/crates/fabro-github/src/lib.rs | 32 ++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/lib/crates/fabro-github/src/lib.rs b/lib/crates/fabro-github/src/lib.rs index 9818a60a9..af6481af4 100644 --- a/lib/crates/fabro-github/src/lib.rs +++ b/lib/crates/fabro-github/src/lib.rs @@ -50,7 +50,14 @@ pub struct GitHubAppCredentials { /// - `https://github.com/owner/repo.git` /// - `https://github.com/owner/repo` /// - `https://github.com/owner/repo/` +/// - `https://x-access-token:TOKEN@github.com/owner/repo.git` pub fn parse_github_owner_repo(url: &str) -> Result<(String, String), String> { + // Strip credentials from URLs like https://x-access-token:TOKEN@github.com/... + let stripped = url.strip_prefix("https://").and_then(|rest| { + rest.split_once('@') + .map(|(_, after)| format!("https://{after}")) + }); + let url = stripped.as_deref().unwrap_or(url); let path = url .strip_prefix("https://github.com/") .ok_or_else(|| format!("Not a GitHub HTTPS URL: {url}"))?; @@ -1192,6 +1199,31 @@ mod tests { ); } + #[test] + fn parse_github_url_with_credentials() { + let (owner, repo) = parse_github_owner_repo( + "https://x-access-token:ghs_abc123@github.com/acme/widgets.git", + ) + .unwrap(); + assert_eq!(owner, "acme"); + assert_eq!(repo, "widgets"); + } + + #[test] + fn parse_github_url_with_credentials_no_password() { + let (owner, repo) = + parse_github_owner_repo("https://token@github.com/acme/widgets.git").unwrap(); + assert_eq!(owner, "acme"); + assert_eq!(repo, "widgets"); + } + + #[test] + fn parse_credentials_non_github_still_errors() { + let result = parse_github_owner_repo("https://user:pass@gitlab.com/owner/repo"); + assert!(result.is_err()); + assert!(result.unwrap_err().contains("Not a GitHub HTTPS URL")); + } + #[test] fn parse_non_github_url_errors() { let result = parse_github_owner_repo("https://gitlab.com/owner/repo");