Resolver for {:ghcr, "ghcr.io/<owner>"} site specs.
Each nbpr package maps to one OCI image at ghcr.io/<owner>/<package_name>.
Build variants (package version, system, system-version, build-opts) become
tags. Anonymous pull works for packages flipped to public visibility — the
resolver does not authenticate.
Wire flow per fetch:
GET /token?service=ghcr.io&scope=repository:<image>:pull→ anonymous JWTGET /v2/<image>/manifests/<tag>(Bearer + Accept manifest media type) → manifest JSON- Pick the first layer whose mediaType matches
application/vnd.nbpr.tarball.v1+tar+gzip GET /v2/<image>/blobs/<digest>(Bearer, autoredirect) → bytes streamed to disk
Summary
Functions
Rewrites a candidate tag into the OCI reference alphabet.
Checks anonymously whether <image>:<tag> already has a manifest published.
Functions
Rewrites a candidate tag into the OCI reference alphabet.
The distribution spec restricts tags to [a-zA-Z0-9_][a-zA-Z0-9._-]{0,127},
which excludes the + that semver build metadata uses — a package whose
upstream version has four components (libjpeg-turbo's 3.1.4.1 becomes
3.1.4+1) carries one into its tag. ghcr.io answers requests for a
reference it can't parse with a bare 404 page not found rather than a
registry error, so out-of-alphabet bytes have to be substituted before the
request goes out.
Every disallowed byte becomes _, following the convention Docker and ORAS
use for build metadata in tags. Both the push (mix nbpr.publish) and pull
(plan/2) sides route through here so they agree on the tag for a build.
Checks anonymously whether <image>:<tag> already has a manifest published.
Returns {:ok, true} for HTTP 200, {:ok, false} for HTTP 404, and
{:error, reason} for other failures (auth, network, malformed JSON).
Uses the same anonymous-pull token flow as get/2, so packages need
public visibility on GHCR for this to work without credentials.
Used by mix nbpr.publish to short-circuit when the artefact's tag is
already published — NBPR's cache-key model treats published tarballs as
immutable, so re-pushing the same key is wasted work.