Add Alpine APK repository proxy support - #293
Conversation
- Serve named APK repositories at /apk/{repository}/ with the official
Alpine mirror as the default repository
- Cache v2 APKINDEX.tar.gz and v3 Packages.adb indexes and detached
signatures via the metadata cache, serving stored bytes unchanged so
apk signature verification keeps working
- Cache .apk packages in the shared artifact cache keyed by the full
repository path, since APK filenames do not include the architecture
- Add configurable upstream repositories via upstream.apk with
validation, plus dashboard registry instructions
- Add tests for index/signature byte fidelity, per-arch caching, cache
hits, offline reads, upstream authentication, and 404 handling
- Document apk usage in README, config example, and configuration docs
There was a problem hiding this comment.
Pull request overview
This pull request adds Alpine APK repository proxy support to the proxy server, enabling read-only caching and proxying of Alpine repository metadata and .apk packages via a new /apk/{repository}/... endpoint, with configurable upstream repositories.
Changes:
- Add a new
/apkhandler that proxies Alpine repository paths and caches indexes/signatures (metadata cache) and packages (artifact cache). - Extend configuration to support
upstream.apknamed repositories with validation and update dashboard/README/docs accordingly. - Add test coverage for APK routing, cache behavior (including offline reads), per-architecture package caching, and upstream auth.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| README.md | Documents APK usage and marks Alpine as supported. |
| internal/server/server.go | Wires the new APK handler and mounts it at /apk. |
| internal/server/dashboard.go | Adds Alpine to supported ecosystem UI and adds APK registry instructions. |
| internal/handler/notfound_ecosystems_test.go | Extends 404 behavior coverage to APK package downloads. |
| internal/handler/apk.go | Implements the APK proxy/caching handler (new). |
| internal/handler/apk_test.go | Adds handler tests for parsing, caching, offline reads, auth, and collision avoidance (new). |
| internal/config/config.go | Adds upstream.apk config and validates named upstreams. |
| internal/config/config_test.go | Adds validation tests for APK upstream names/URLs. |
| docs/configuration.md | Documents upstream.apk behavior and caching semantics. |
| config.example.yaml | Adds example configuration for APK upstreams. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| if result.ContentType == "" { | ||
| result.ContentType = "application/octet-stream" | ||
| } | ||
| ServeArtifact(w, result) |
There was a problem hiding this comment.
Good catch — fixed in 5b0c32a. The handler now uses the method-aware serveArtifact helper (same pattern as container.go), so HEAD responses carry Content-Length but omit the body. Added a regression test.
| func (h *APKHandler) handleMetadata(w http.ResponseWriter, r *http.Request, repository, upstreamURL, path string) { | ||
| h.proxy.ProxyCached(w, r, upstreamURL+"/"+path, apkEcosystem, | ||
| h.metadataCacheKey(repository, upstreamURL, path), "*/*") | ||
| } |
There was a problem hiding this comment.
The mechanism is real, but it isn't specific to this PR: the code path is the shared fetchUpstreamMetadata in internal/handler/handler.go, and the debian, rpm, helm, and conda handlers go through exactly the same transport behavior for their signed/hash-pinned metadata. This handler only inherits it.
A narrow fix here would also be incomplete: explicitly setting Accept-Encoding: identity disables Go's transparent decompression, but an upstream that mislabels stored .gz objects with Content-Encoding: gzip would then have its raw gzip bytes cached and re-served without that header — the metadata cache stores a content type but no content encoding. Doing this properly means persisting/forwarding Content-Encoding in the metadata cache and fixing all ecosystems at once.
I'd prefer to track that as a separate hardening issue against the shared metadata fetch path rather than grow this PR's scope.
Use the method-aware serveArtifact helper (as container.go does) so HEAD responses carry Content-Length but omit the body; add a regression test.
Related to #262