Skip duplicate /v2/ when artifact domain already contains it - #23062
Conversation
MikeMcQuaid
left a comment
There was a problem hiding this comment.
Why wouldn't you just set the HOMEBREW_ARTIFACT_DOMAIN to https://mirror.example.com/v2/ghcr-io instead?
If the issue is that https://mirror.example.com/ghcr-io can literally never ever be valid with any host in any circumstance: that should error out. I don't think you can state that, though, so it seems better that that would be error message improvement rather than behaviour change.
|
in the current code brew/Library/Homebrew/github_packages.rb Lines 18 to 19 in 586f1c2 then if HOMEBREW_ARTIFACT_DOMAIN is set, it replaces the https://ghcr.io part with HOMEBREW_ARTIFACT_DOMAIN, the final v2 is keptbrew/Library/Homebrew/download_strategy/curl_download_strategy.rb Lines 46 to 49 in 586f1c2 so if I do Containerd use |
How about we skip doing that if there's already a trailing |
|
This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. |
HOMEBREW_ARTIFACT_DOMAIN rewrites ghcr.io bottle URLs by replacing the domain prefix while keeping the URL's /v2/ path. This makes it impossible to point it at an OCI registry proxying ghcr.io under a repository prefix (e.g. a Harbor or Nexus proxy cache): setting it to https://mirror.example.com/v2/ghcr-io produces https://mirror.example.com/v2/ghcr-io/v2/... with a duplicate v2. When the artifact domain already contains the Docker Registry API's /v2 path, skip the v2 from the original URL. Artifact domains without a /v2 path keep the existing behaviour. Apply the same logic to the portable-ruby URL in vendor-install.sh. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
c19e73e to
5983b25
Compare
|
Done — reworked as suggested: when Domains without a |
brewcommands to reproduce the bug?brew lgtm(style, typechecking and tests) locally?I used Claude Code to help draft the patch, tests and this PR text. I manually reviewed the changes and verified them end-to-end against a real Harbor 2.x proxy cache for ghcr.io (
brew fetchandbrew reinstallof bottles, plusbrew vendor-install rubyfor the Bash code path), and ranbrew lgtmsuccessfully.What
As suggested in review: when
HOMEBREW_ARTIFACT_DOMAINalready contains the Docker Registry API's/v2path, skip thev2/from the original ghcr.io URL instead of duplicating it.HOMEBREW_ARTIFACT_DOMAINrewrites ghcr.io bottle URLs by replacing thehttps://ghcr.io/prefix while keeping the URL'sv2/path. This makes it impossible to point it at an OCI registry that proxies ghcr.io under a repository prefix (e.g. a Harbor or Nexus proxy cache), because the OCI Distribution Spec requires/v2/at the root of the host with the prefix inside the repository name:Artifact domains without a
/v2path keep the exact same behaviour as today, as does the fallback to the originalghcr.ioURLs (andHOMEBREW_ARTIFACT_DOMAIN_NO_FALLBACK). The same logic is applied to the portable-ruby URL invendor-install.sh, with cross-referencing comments to keep both implementations in sync.Why
This makes
HOMEBREW_ARTIFACT_DOMAINusable with standard OCI registry proxy caches (Harbor, Nexus, Artifactory) that expose proxied upstreams under a repository prefix rather than a dedicated (sub)domain — a common corporate setup where provisioning one virtual host per proxied registry isn't practical. Related demand: #22115.Reproduction
With a Harbor project
ghcr-ioconfigured as a proxy cache forhttps://ghcr.io:The registry answers 404 for this path and every download falls back to
ghcr.io, defeating the mirror. With this change the duplicatev2is gone and downloads go through the proxy.Verified end-to-end against a real Harbor 2.x proxy-cache project (with
HOMEBREW_DOCKER_REGISTRY_TOKENset so the auth header is kept):brew fetch --bottle-tag=x86_64_linux helloandbrew vendor-install rubyboth download through the proxy, and a fresh Linux bootstrap via install.sh completes withHOMEBREW_ARTIFACT_DOMAIN_NO_FALLBACK=1(portable-ruby pulled through the proxy). Domains without a/v2path still produce the unchanged historical URLs, covered by the unmodified pre-existing tests.🤖 Generated with Claude Code