From 847eeb839fad21607aca12a457c1bfc45bb604e2 Mon Sep 17 00:00:00 2001 From: Ben Vincent Date: Fri, 26 Jun 2026 23:34:00 +1000 Subject: [PATCH] fix: don't rewrite helm chart URLs pointing to a different host (#56) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Problem Helm charts like Intel device plugins have download URLs on `github.com` but the chart index is served from `intel.github.io`. The merger rewrites all URLs through the proxy, constructing: ``` https://artifactapi/api/v1/remote/intel-helm/intel/helm-charts/releases/download/... ``` Which proxies to `https://intel.github.io/helm-charts/intel/helm-charts/releases/download/...` — a 404. ## Fix Compare the download URL host against the remote's base URL host. If they differ, leave the URL as-is so helm downloads directly from the source. Same-host URLs are still rewritten through the proxy. Also adds `BaseURL` to `MemberIndex` so the merger has the context it needs, and uses the correct `/local/` vs `/remote/` route prefix. Reviewed-on: https://git.unkin.net/unkin/artifactapi/pulls/56 Co-authored-by: Ben Vincent Co-committed-by: Ben Vincent --- internal/virtual/engine.go | 4 ++-- internal/virtual/helm_merger.go | 28 ++++++++++++++++++++++++++-- internal/virtual/merger.go | 1 + 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/internal/virtual/engine.go b/internal/virtual/engine.go index b80393b..bcc352e 100644 --- a/internal/virtual/engine.go +++ b/internal/virtual/engine.go @@ -79,7 +79,7 @@ func (e *Engine) fetchMemberIndexes(ctx context.Context, virt models.Virtual, pa results[idx] = result{err: fmt.Errorf("local index %q: %w", name, err)} return } - results[idx] = result{index: MemberIndex{RemoteName: name, RepoType: remote.RepoType, Body: body}} + results[idx] = result{index: MemberIndex{RemoteName: name, RepoType: remote.RepoType, BaseURL: remote.BaseURL, Body: body}} return } @@ -102,7 +102,7 @@ func (e *Engine) fetchMemberIndexes(ctx context.Context, virt models.Virtual, pa return } - results[idx] = result{index: MemberIndex{RemoteName: name, RepoType: remote.RepoType, Body: body}} + results[idx] = result{index: MemberIndex{RemoteName: name, RepoType: remote.RepoType, BaseURL: remote.BaseURL, Body: body}} }(i, memberName) } diff --git a/internal/virtual/helm_merger.go b/internal/virtual/helm_merger.go index 70a47e7..db1d206 100644 --- a/internal/virtual/helm_merger.go +++ b/internal/virtual/helm_merger.go @@ -54,15 +54,26 @@ func (m *HelmMerger) MergeIndexes(members []MemberIndex, proxyBaseURL string) ([ seen[chart][ver.Version] = true if proxyBaseURL != "" { + routePrefix := "remote" + if member.RepoType == "local" { + routePrefix = "local" + } + baseHost := extractHost(member.BaseURL) + for i, u := range ver.URLs { if strings.HasPrefix(u, "http://") || strings.HasPrefix(u, "https://") { - ver.URLs[i] = fmt.Sprintf("%s/api/v1/remote/%s/%s", + if baseHost != "" && extractHost(u) != baseHost { + continue + } + ver.URLs[i] = fmt.Sprintf("%s/api/v1/%s/%s/%s", strings.TrimRight(proxyBaseURL, "/"), + routePrefix, member.RemoteName, extractPath(u)) } else { - ver.URLs[i] = fmt.Sprintf("%s/api/v1/remote/%s/%s", + ver.URLs[i] = fmt.Sprintf("%s/api/v1/%s/%s/%s", strings.TrimRight(proxyBaseURL, "/"), + routePrefix, member.RemoteName, u) } @@ -78,6 +89,19 @@ func (m *HelmMerger) MergeIndexes(members []MemberIndex, proxyBaseURL string) ([ return yaml.Marshal(merged) } +func extractHost(rawURL string) string { + idx := strings.Index(rawURL, "://") + if idx == -1 { + return "" + } + rest := rawURL[idx+3:] + slashIdx := strings.Index(rest, "/") + if slashIdx == -1 { + return rest + } + return rest[:slashIdx] +} + func extractPath(rawURL string) string { idx := strings.Index(rawURL, "://") if idx == -1 { diff --git a/internal/virtual/merger.go b/internal/virtual/merger.go index 4080bf3..d089994 100644 --- a/internal/virtual/merger.go +++ b/internal/virtual/merger.go @@ -9,6 +9,7 @@ import ( type MemberIndex struct { RemoteName string RepoType models.RepoType + BaseURL string Body []byte }