From 7d74c13d92ce361e40e079863e19eebca03c3a60 Mon Sep 17 00:00:00 2001 From: Seimizu Joukan Date: Tue, 27 Jan 2026 20:47:11 +0900 Subject: [PATCH] Fix asset download for private repositories Use GitHub API endpoint with asset ID instead of browser_download_url to ensure authentication header is preserved. The browser_download_url redirects to a CDN where the auth header is not forwarded, causing 404 errors for private repos. Co-Authored-By: Claude Opus 4.5 --- src/main.rs | 21 ++++++++++++++++++--- src/models.rs | 1 + 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/main.rs b/src/main.rs index 4c76aa9..3817c0a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -332,6 +332,17 @@ async fn main() -> Result<()> { Vec::new() }; + // Parse owner/repo for API URL construction + let parts: Vec<&str> = repo.split('/').collect(); + if parts.len() != 2 { + return Err(GhrError::Generic(format!( + "Invalid repository format '{}'. Expected 'owner/repo'", + repo + ))); + } + let owner = parts[0]; + let repo_name = parts[1]; + // Collect assets to download with filtering let mut assets_to_download = Vec::new(); for asset in &release.assets { @@ -343,8 +354,12 @@ async fn main() -> Result<()> { continue; } - // Get download URL - let download_url = &asset.browser_download_url; + // Use API URL for downloading (works with private repos) + // Format: https://api.github.com/repos/{owner}/{repo}/releases/assets/{asset_id} + let download_url = format!( + "{}/repos/{}/{}/releases/assets/{}", + cli.api_url, owner, repo_name, asset.id + ); // Get asset size for progress bar let size = asset.size; @@ -356,7 +371,7 @@ async fn main() -> Result<()> { PathBuf::from(name) }; - assets_to_download.push((name.clone(), download_url.clone(), output_path, size)); + assets_to_download.push((name.clone(), download_url, output_path, size)); } if assets_to_download.is_empty() { diff --git a/src/models.rs b/src/models.rs index 778aa8c..ba99555 100644 --- a/src/models.rs +++ b/src/models.rs @@ -4,6 +4,7 @@ use std::fmt::Display; /// GitHub release asset #[derive(Debug, Deserialize, Serialize)] pub struct Asset { + pub id: u64, pub name: String, pub browser_download_url: String, pub size: u64,