fix: resolve GitHub release asset API URL for private repo extension downloads#2792
Conversation
For private or SSO-protected GitHub repos, browser release download URLs redirect to HTML/SSO instead of the ZIP asset. This commit resolves the asset via the GitHub REST API and downloads with Accept: application/octet-stream, falling back to the original URL if the API call fails. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Just curious, can it refer to the REST URL directly? |
…oads When a catalog download_url is already a GitHub REST release asset URL (https://api.github.com/repos/<owner>/<repo>/releases/assets/<id>), skip the release metadata lookup and download directly with Accept: application/octet-stream. This complements the browser URL resolution from the previous commit, covering catalogs that reference the REST API directly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Yes, it can refer to the REST asset URL directly, but the downloader still needs to send I used the browser release URL as the input because catalogs commonly get/store GitHub’s That said, I think it makes sense to support both. Have updated the PR so if
we skip the lookup and just download it with |
There was a problem hiding this comment.
Pull request overview
This PR fixes specify extension add for extensions whose catalog download_url points to GitHub release assets in private or SSO-protected repositories by ensuring the downloader retrieves the actual ZIP payload (rather than an HTML redirect/metadata response) via the GitHub REST API.
Changes:
- Adds logic to detect GitHub release “browser” URLs and resolve them to the corresponding GitHub REST release asset API URL before downloading.
- Supports direct GitHub REST release asset URLs by downloading them with
Accept: application/octet-streamto obtain the binary ZIP content. - Expands extension download tests to cover both URL shapes and verify auth +
Acceptheader behavior.
Show a summary per file
| File | Description |
|---|---|
src/specify_cli/extensions.py |
Resolves GitHub release asset URLs to API asset URLs and adds Accept: application/octet-stream for correct binary downloads. |
tests/test_extensions.py |
Adds/updates tests to validate the new GitHub release-asset download behavior (browser URL resolution + direct REST asset URL). |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 2/2 changed files
- Comments generated: 0
|
Thank you! |
… workflow downloads (#2855) * fix: resolve GitHub release asset API URL for private repo preset and workflow downloads - Add shared `resolve_github_release_asset_api_url` utility to `_github_http.py` for reuse across preset and workflow download paths - Apply the same private-repo fix from PR #2792 (extensions) to: - `PresetCatalog.download_pack` — ZIP downloads via catalog `download_url` - `preset add --from <url>` — ZIP downloads from a direct URL - `workflow add <url>` — workflow YAML downloads from a direct URL - `workflow add <id>` (catalog) — workflow YAML downloads via catalog `url` - For browser release URLs (`github.com/…/releases/download/…`), the asset is resolved via the GitHub REST API and downloaded with `Accept: application/octet-stream` - Direct REST API asset URLs (`api.github.com/…/releases/assets/<id>`) are downloaded directly with `Accept: application/octet-stream` - Auth is preserved end-to-end through the existing `open_url` infrastructure - Update `test_download_pack_sends_auth_header` and add `test_download_pack_accepts_direct_github_rest_asset_url` to cover both paths Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: URL-encode tag in release API URL to handle special characters Encode the tag as a path segment (using quote with safe='') when building the releases/tags/<tag> API URL. This prevents malformed URLs when tags contain reserved characters like '/' or '#'. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * test: add CLI-level tests for preset add --from GitHub release URL resolution Adds regression tests covering: - resolve_github_release_asset_api_url unit tests (passthrough, resolution, network error, URL encoding of special chars in tags) - CLI-level 'preset add --from <github-release-url>' end-to-end flow - CLI-level 'preset add --from <api-asset-url>' direct passthrough Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * refactor: deduplicate release URL resolution; fix test issues - ExtensionCatalog._resolve_github_release_asset_api_url now delegates to the shared helper in _github_http.py (also gains URL-encoding fix) - Remove unused 'io' import from test_github_http.py - Remove duplicate 'provides' dict keys accidentally added to test_presets.py Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: align resolver timeout with download timeout; add workflow CLI tests - Pass timeout=30 to resolve_github_release_asset_api_url in both workflow add paths so worst-case latency matches the download timeout - Add CLI-level regression tests for 'workflow add <url>' covering browser URL resolution and direct API asset URL passthrough Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: remove unused urllib.request import; add catalog workflow test - Remove unused 'import urllib.request' in preset add --from path - Add CLI test for catalog-based 'workflow add <id>' with GitHub release URL resolution Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * style: remove unused MagicMock imports from tests Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Manfred Riem <mnriem@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Summary
specify extension addwhen the catalogdownload_urlpoints at a GitHub release URL for a private or SSO-protected repositoryhttps://github.com/<owner>/<repo>/releases/download/<tag>/<asset>.zip) redirect to an HTML/SSO page instead of the ZIP asset, causing installation to fail withBadZipFile: File is not a zip fileFix — two download URL shapes are now handled
Browser release URL (commit 1):
GET /repos/<owner>/<repo>/releases/tags/<tag>Accept: application/octet-streamDirect REST asset URL (commit 2):
download_urlis already a GitHub REST release asset URL (https://api.github.com/repos/<owner>/<repo>/releases/assets/<id>), skips the metadata lookup and downloads directly withAccept: application/octet-streamAccept: application/octet-streamreturns the ZIP payloadOther URLs: existing downloader behavior is unchanged.
Auth is preserved end-to-end through the existing
specify_cli.authentication.http.open_urlinfrastructure.Test plan
specify extension addagainst an extension hosted on a private GitHub repo using a browser release URL — asset should be resolved via the API and downloaded correctlyspecify extension addagainst a catalog using a direct REST asset URL (api.github.com/repos/.../releases/assets/<id>) — should download directly with auth andAccept: application/octet-streamspecify extension addstill works for public GitHub release URLs and non-GitHub URLs (fallback paths not triggered)🤖 Generated with Claude Code