Skip to content

feat(update): authenticate self-update downloads for private GitHub releases - #6

Merged
Ryan Zhu (underthestars-zhy) merged 1 commit into
mainfrom
ryan/self-update
May 24, 2026
Merged

feat(update): authenticate self-update downloads for private GitHub releases#6
Ryan Zhu (underthestars-zhy) merged 1 commit into
mainfrom
ryan/self-update

Conversation

@underthestars-zhy

@underthestars-zhy Ryan Zhu (underthestars-zhy) commented May 24, 2026

Copy link
Copy Markdown
Member

Summary

.githubToken(token) already flowed through to release-metadata fetches, but the actual asset download still hit browser_download_url unauthenticated — so private repos returned 404 and the self-updater silently failed at the download step. This wires the token through the download path too.

For private releases we now hit the release-asset API URL (https://api.github.com/repos/{owner}/{repo}/releases/assets/{id}) with Accept: application/octet-stream + Authorization: Bearer <token>. GitHub responds with a signed redirect to the actual artifact. Public releases (no token) keep using browser_download_url unchanged.

Changes

File Change
Steps/Pkg/GitHubReleaseFetcher.swift New makeAssetDownloadRequest(asset:token:) builds the auth'd request; decode url from the asset payload into apiURL; whitespace-trim tokens via shared normalizedToken helper.
Steps/Pkg/GitHubPackage.swift Pkg(.gitHub(...)) uses the new request builder and checks the HTTP status on download.
Update/GitHubReleaseSource.swift ReleaseDescriptor now carries the auth'd URL + headers built from the same helper.
Update/UpdateSource.swift ReleaseDescriptor gains downloadHeaders and a makeDownloadRequest() convenience. Existing initializer stays source-compatible (headers default to [:]).
Update/UpdateLoop.swift Updater downloads via the descriptor's request instead of a raw URL.
Tests/AstrolabeTests/UpdateConfigurationTests.swift Four new tests: asset decoding picks up both URLs; download request falls back to browser URL without a token; with a token it targets the API URL with the right headers (and trims whitespace); ReleaseDescriptor.makeDownloadRequest() propagates headers.

Test plan

  • swift test --filter UpdateConfigurationTests
  • Manual: self-update against a private GitHub repo with .githubToken(...) configured downloads and installs the .pkg
  • Manual: self-update against a public repo without a token still works (regression check)

View with Codesmith Autofix with Codesmith
Need help on this PR? Tag @codesmith with what you need. Autofix is disabled.

Summary by CodeRabbit

  • Bug Fixes

    • GitHub package downloads now validate HTTP response status codes and provide clearer error messages when downloads fail
    • Improved authenticated downloads from GitHub releases with enhanced error handling and request validation
  • Tests

    • Added tests verifying download behavior, authentication support, and error scenarios for GitHub asset downloads

Review Change Stack

Copilot AI review requested due to automatic review settings May 24, 2026 00:14
@coderabbitai

coderabbitai Bot commented May 24, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d760b9e3-3fe6-45f4-8742-797aa072a8eb

📥 Commits

Reviewing files that changed from the base of the PR and between 360f06d and 18d4ab0.

📒 Files selected for processing (6)
  • Sources/Astrolabe/Steps/Pkg/GitHubPackage.swift
  • Sources/Astrolabe/Steps/Pkg/GitHubReleaseFetcher.swift
  • Sources/Astrolabe/Update/GitHubReleaseSource.swift
  • Sources/Astrolabe/Update/UpdateLoop.swift
  • Sources/Astrolabe/Update/UpdateSource.swift
  • Tests/AstrolabeTests/UpdateConfigurationTests.swift
📜 Recent review details
🔇 Additional comments (6)
Tests/AstrolabeTests/UpdateConfigurationTests.swift (1)

89-102: LGTM!

Also applies to: 104-116, 118-130, 132-149

Sources/Astrolabe/Update/UpdateSource.swift (1)

31-32: LGTM!

Also applies to: 36-42, 46-46, 50-56

Sources/Astrolabe/Steps/Pkg/GitHubReleaseFetcher.swift (1)

56-70: LGTM!

Also applies to: 86-96, 118-124

Sources/Astrolabe/Update/GitHubReleaseSource.swift (1)

58-65: LGTM!

Sources/Astrolabe/Update/UpdateLoop.swift (1)

61-61: LGTM!

Sources/Astrolabe/Steps/Pkg/GitHubPackage.swift (1)

111-115: LGTM!


📝 Walkthrough

Walkthrough

This PR implements authenticated GitHub asset downloads by centralizing HTTP header management in a ReleaseDescriptor contract, extending GitHubAsset to support API-endpoint requests, and adding HTTP status-code validation across the package installation and update loops.

Changes

Authenticated GitHub Asset Downloads

Layer / File(s) Summary
ReleaseDescriptor contract and download request construction
Sources/Astrolabe/Update/UpdateSource.swift
ReleaseDescriptor gains a downloadHeaders property and makeDownloadRequest() method. The initializer now accepts optional headers that default to an empty dictionary, enabling callers to apply custom HTTP headers when constructing URLRequests from the release metadata.
GitHubAsset model and authenticated request building
Sources/Astrolabe/Steps/Pkg/GitHubReleaseFetcher.swift
GitHubAsset decodes an apiURL field for authenticated downloads. makeAssetDownloadRequest(asset:token:) conditionally builds unauthenticated requests to downloadURL or authenticated requests to apiURL with Bearer authorization and octet-stream Accept headers. Token normalization is centralized in normalizedToken().
Integration through release source, updater loop, and installer
Sources/Astrolabe/Update/GitHubReleaseSource.swift, Sources/Astrolabe/Update/UpdateLoop.swift, Sources/Astrolabe/Steps/Pkg/GitHubPackage.swift
GitHubReleaseSource.latestRelease() builds authenticated download requests and populates ReleaseDescriptor with headers. UpdateLoop.tickOnce() uses release.makeDownloadRequest() to construct authenticated requests. GitHubPackage.install() validates HTTP 200 status and throws requestFailed on non-success responses.
Test coverage for assets, requests, and download headers
Tests/AstrolabeTests/UpdateConfigurationTests.swift
New tests validate GitHubAsset JSON decoding, makeAssetDownloadRequest behavior with and without token (header conditionals, URL selection, token trimming), and ReleaseDescriptor.makeDownloadRequest() header application.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

  • photon-hq/Astrolabe#2: Introduces the GitHub-based self-update mechanism that this PR refines with authenticated asset downloads and HTTP validation.

Poem

🐰 A GitHub asset hops with care,
With tokens trimmed, no auth to spare,
When needed, Bearer leads the way,
Two hundred means a joyful day!
Headers flow through every gate,
Astrolabe downloads— fresh and great!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding authentication to self-update downloads for private GitHub releases, which is the core objective of this changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ryan/self-update

Comment @coderabbitai help to get the list of available commands and usage tips.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes self-update and .pkg installation failures for private GitHub releases by ensuring the configured GitHub token is used not only for release metadata fetches, but also for the actual asset download. When a token is present, downloads are performed via the GitHub Release Asset API URL with the required headers so GitHub can return a signed redirect to the artifact; without a token, the existing public browser_download_url path remains unchanged.

Changes:

  • Add an authenticated asset download request builder (Accept: application/octet-stream + Authorization: Bearer …) and decode each asset’s API URL (url) alongside browser_download_url.
  • Route both the self-updater and Pkg(.gitHub(...)) installer through request-based downloads, including HTTP status checks.
  • Extend ReleaseDescriptor to carry download headers and provide a makeDownloadRequest() helper; add targeted tests for decoding and request construction (including token trimming).

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.

Show a summary per file
File Description
Tests/AstrolabeTests/UpdateConfigurationTests.swift Adds tests for asset decoding, authenticated vs unauthenticated download request construction, and ReleaseDescriptor request building.
Sources/Astrolabe/Update/UpdateSource.swift Extends ReleaseDescriptor with downloadHeaders and a helper to build a URLRequest.
Sources/Astrolabe/Update/UpdateLoop.swift Switches updater download to use ReleaseDescriptor.makeDownloadRequest() so headers can be applied.
Sources/Astrolabe/Update/GitHubReleaseSource.swift Builds the release descriptor using the shared authenticated download request builder (URL + headers).
Sources/Astrolabe/Steps/Pkg/GitHubReleaseFetcher.swift Adds makeAssetDownloadRequest, trims tokens via a shared normalization helper, and decodes asset API URL from url.
Sources/Astrolabe/Steps/Pkg/GitHubPackage.swift Uses authenticated download requests for .pkg installation and verifies HTTP status codes.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@underthestars-zhy
Ryan Zhu (underthestars-zhy) merged commit 3591618 into main May 24, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants