Add nuget v3 remote type #141

Merged
benvin merged 1 commits from benvin/remote-nuget into master 2026-10-17 12:19:51 +11:00
Member

.NET builds restore from nuget.org directly because artifactapi has no NuGet remote type.

  • add nuget package type proxying a NuGet v3 feed; index.json maps to the upstream service index
  • add a ServeRewriter provider hook so cached JSON has upstream-origin URLs pointed back at the requesting host per request
  • treat .nupkg/.nuspec as immutable and service, registration and flat container indexes as mutable
  • add a nuget.config usage snippet to the UI and a nuget e2e caching case
.NET builds restore from nuget.org directly because artifactapi has no NuGet remote type. - add `nuget` package type proxying a NuGet v3 feed; `index.json` maps to the upstream service index - add a `ServeRewriter` provider hook so cached JSON has upstream-origin URLs pointed back at the requesting host per request - treat `.nupkg`/`.nuspec` as immutable and service, registration and flat container indexes as mutable - add a `nuget.config` usage snippet to the UI and a nuget e2e caching case
unkin-agent added 1 commit 2026-10-16 23:14:06 +11:00
Add nuget v3 remote type
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
524c6db46f
- add `nuget` package type proxying a NuGet v3 feed, with `index.json` mapped to the upstream service index
- rewrite upstream-origin URLs in served JSON per request so flat container and registration lookups go through the remote
- treat `.nupkg`/`.nuspec` as immutable and indexes as mutable
- add a `nuget.config` usage snippet to the UI and a nuget e2e caching case
benvin merged commit bc68eb75fc into master 2026-10-17 12:19:51 +11:00
benvin deleted branch benvin/remote-nuget 2026-10-17 12:19:52 +11:00
Author
Member
  • internal/api/v1/proxy.go:116 — proxyBaseURL comes from client-controlled Host and X-Forwarded-Proto and is substituted into the JSON unescaped. Never cached rewritten (RewriteResponse returns nil, rewrite is post-cache), but the response sets no Cache-Control/Vary, so a shared cache keyed on path in front can be poisoned, and a crafted X-Forwarded-Proto injects into the JSON → send Cache-Control: no-store (or Vary: Host, X-Forwarded-Proto) on rewritten responses and validate scheme to http|https.
  • internal/api/v1/proxy.go:111 — HEAD (handleProxyHead) returns the unrewritten cached size while GET returns the rewritten body → Content-Length differs between HEAD and GET; skip or recompute for ServeRewriter providers.
  • internal/provider/nuget/nuget.go:29 — everything not .nupkg/.nuspec is Mutable, including .snupkg and v3-flatcontainer readme/icon blobs, which get fully buffered (ReadAll plus json.Valid) and refetched every TTL → classify .snupkg, readme and icon as Immutable.
  • internal/provider/nuget/nuget_test.go:50 — no test for a gzip-encoded registration page (registration5-gz-semver2 is served Content-Encoding: gzip; works only because Go transparently decodes) → add a fetch-path case asserting URLs are rewritten.
  • nit: PR is already merged; apply fixes as a follow-up.
- internal/api/v1/proxy.go:116 — proxyBaseURL comes from client-controlled Host and X-Forwarded-Proto and is substituted into the JSON unescaped. Never cached rewritten (RewriteResponse returns nil, rewrite is post-cache), but the response sets no Cache-Control/Vary, so a shared cache keyed on path in front can be poisoned, and a crafted X-Forwarded-Proto injects into the JSON → send `Cache-Control: no-store` (or Vary: Host, X-Forwarded-Proto) on rewritten responses and validate scheme to http|https. - internal/api/v1/proxy.go:111 — HEAD (handleProxyHead) returns the unrewritten cached size while GET returns the rewritten body → Content-Length differs between HEAD and GET; skip or recompute for ServeRewriter providers. - internal/provider/nuget/nuget.go:29 — everything not .nupkg/.nuspec is Mutable, including .snupkg and v3-flatcontainer readme/icon blobs, which get fully buffered (ReadAll plus json.Valid) and refetched every TTL → classify .snupkg, readme and icon as Immutable. - internal/provider/nuget/nuget_test.go:50 — no test for a gzip-encoded registration page (registration5-gz-semver2 is served Content-Encoding: gzip; works only because Go transparently decodes) → add a fetch-path case asserting URLs are rewritten. - nit: PR is already merged; apply fixes as a follow-up.
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: unkin/artifactapi#141