SwiftPM binary dependency in private GitHub release

I have a project that produces an XCFramework which I zip and upload to the GitHub releases page of the private repository. I've added my personal access token to ~/.netrc and verified it working correctly against api.github.com. Following the GitHub REST reference I am able to find the relevant asset_id and declare a binary dependency as such:

.binaryTarget(
    name: privateName,
    url: "https://api.github.com/repos/\(owner)/\(repo)/releases/assets/\(assetId).zip", // must have .zip extension otherwise get "invalid extension" error - but seems GitHub API doesn't mind the file extension being added
    checksum: checksum
)

This however fails to pull in the binary content. When proxying the network traffic I can see that SPM is making the request without including the Accept: application/octet-stream header, and according to GitHub docs, without adding this header the response will just be a JSON output description of the asset. Based on this, SPM then fails the resolution with a checksum mismatch failure, since the response it got back is actually a JSON document rather than the zipped XCFramework.

Understandably SPM isn't setting any special request headers based on location; but:

  • Am I missing a more obvious way to depend on a binary hosted in a private GitHub release?
  • Is there a way to set custom headers on binary requests?
  • If there isn't a way currently, would it be considered to introduce a new parameter to Target.binaryTarget like customRequestHeaders: [String: String] = [:]?

As a point of reference, this is possible in Carthage via the use of the github origin keyword in the Cartfile, such as:

github "owner/repo" "release_tag"

For the special github case, Carthage first gets a release by tag name, then pulls in files that have .framework.zip (or .xcframework.zip when passing --use-xcframeworks arg) by correctly (for this scenario) setting the Accept: application/octet-stream.

Though from what I understand, this was a somewhat controversial feature introduction, as it gave special preference to GitHub integration over any other code repository. I imagine anything so custom wouldn't be desirable here, but any thoughts towards custom headers for binary targets?

3 Likes

I have seen these examples of using Github releases for the binary dependency download:

Although. I am not sure if this would be different for a private Github repository.

Unfortunately when trying that with a private repository it doesn't seem that you are able to authenticate the request using basic auth. I've attempted this with a working .netrc in my home directory using the following curl:

curl -OLn "<<Private GitHub Release Page Asset Download URL>>"

But I always get "Not Found".

I recently faced the same issue, and after researching all the available information online, I decided not to distribute binary dependencies in private GitHub releases with SwiftPM. It seems to be an unresolvable limitation of SPM, and there are no valid workarounds. Sad story.

We do this regularly using the process linked below. This works by NOT using the URL that you see on the Github releases page, but instead pointing the Package.swift to the actually binary resource URL, which is obtained using the GitHub CLI client.

2 Likes

Thank you for this reply and clarification.