From 039e3ce99fdb09bbbb2129b2155f6a4d0edd5739 Mon Sep 17 00:00:00 2001 From: dawn Date: Wed, 2 Sep 2026 21:49:53 +0900 Subject: [PATCH] spindle/engines/microvm: restrict nix cache upload requests and answer probes locally Signed-off-by: dawn --- spindle/engines/microvm/upload_cache_http.go | 35 +++++++++++++++++++ .../engines/microvm/upload_cache_nix_store.go | 8 ----- .../microvm/upload_cache_nix_store_test.go | 4 +-- spindle/engines/microvm/upload_staging.go | 22 +++++++++--- 4 files changed, 55 insertions(+), 14 deletions(-) diff --git a/spindle/engines/microvm/upload_cache_http.go b/spindle/engines/microvm/upload_cache_http.go index b479616f4..a622d103e 100644 --- a/spindle/engines/microvm/upload_cache_http.go +++ b/spindle/engines/microvm/upload_cache_http.go @@ -23,7 +23,42 @@ func newHTTPUploadProxyBackend(target *url.URL, readUpstreams []CacheUpstream, l return &httpUploadBackend{handler: uploadProxyHandler(target, readUpstreams, logger)} } +func serveUploadCacheInfo(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "text/x-nix-cache-info") + if r.Method == http.MethodGet { + _, _ = io.WriteString(w, nixStoreCacheInfo) + } +} + func (b *httpUploadBackend) ServeHTTP(w http.ResponseWriter, r *http.Request) { + relPath, err := normalizeUploadCachePath(r.URL.Path) + if err != nil { + http.NotFound(w, r) + return + } + if (r.Method == http.MethodGet || r.Method == http.MethodHead) && r.URL.RawQuery == "" { + if relPath == "nix-cache-info" { + serveUploadCacheInfo(w, r) + return + } + if isNarinfoObjectPath(relPath) { + b.handler.ServeHTTP(w, r) + return + } + if isNarObjectPath(relPath) { + http.NotFound(w, r) + return + } + } + if r.Method != http.MethodPut { + w.Header().Set("Allow", http.MethodPut) + http.Error(w, "method not allowed", http.StatusMethodNotAllowed) + return + } + if r.URL.RawQuery != "" || (!isNarObjectPath(relPath) && !isNarinfoObjectPath(relPath)) { + http.NotFound(w, r) + return + } b.handler.ServeHTTP(w, r) } diff --git a/spindle/engines/microvm/upload_cache_nix_store.go b/spindle/engines/microvm/upload_cache_nix_store.go index 8ec22c47a..5dfc486dd 100644 --- a/spindle/engines/microvm/upload_cache_nix_store.go +++ b/spindle/engines/microvm/upload_cache_nix_store.go @@ -104,9 +104,6 @@ func (b *NixStoreUploadBackend) ServeHTTP(w http.ResponseWriter, r *http.Request case http.MethodPut: switch { - case relPath == "nix-cache-info": - b.putCacheInfo(w, r) - return case isNarObjectPath(relPath): b.putNar(w, r, relPath) return @@ -129,11 +126,6 @@ func (b *NixStoreUploadBackend) serveCacheInfo(w http.ResponseWriter, r *http.Re _, _ = w.Write([]byte(nixStoreCacheInfo)) } -func (b *NixStoreUploadBackend) putCacheInfo(w http.ResponseWriter, r *http.Request) { - _, _ = io.Copy(io.Discard, io.LimitReader(r.Body, int64(len(nixStoreCacheInfo))+1)) - w.WriteHeader(http.StatusOK) -} - func (b *NixStoreUploadBackend) serveNarinfo(w http.ResponseWriter, r *http.Request, relPath string) { localPath, err := b.stagingObjectPath(relPath) if err != nil { diff --git a/spindle/engines/microvm/upload_cache_nix_store_test.go b/spindle/engines/microvm/upload_cache_nix_store_test.go index bf9d4af77..b75da8682 100644 --- a/spindle/engines/microvm/upload_cache_nix_store_test.go +++ b/spindle/engines/microvm/upload_cache_nix_store_test.go @@ -119,8 +119,8 @@ func TestNixStoreBackendNixCacheInfo(t *testing.T) { rec = httptest.NewRecorder() b.ServeHTTP(rec, httptest.NewRequest(http.MethodPut, "/nix-cache-info", strings.NewReader("ignored"))) - if rec.Code != http.StatusOK { - t.Fatalf("PUT /nix-cache-info status: got %d, want 200", rec.Code) + if rec.Code != http.StatusNotFound { + t.Fatalf("PUT /nix-cache-info status: got %d, want 404", rec.Code) } } diff --git a/spindle/engines/microvm/upload_staging.go b/spindle/engines/microvm/upload_staging.go index 9d6b46f1c..e47403be6 100644 --- a/spindle/engines/microvm/upload_staging.go +++ b/spindle/engines/microvm/upload_staging.go @@ -70,13 +70,27 @@ func (s *stagingWrapper) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } + if (r.Method == http.MethodGet || r.Method == http.MethodHead) && r.URL.RawQuery == "" { + if relPath == "nix-cache-info" { + serveUploadCacheInfo(w, r) + return + } + if isNarinfoObjectPath(relPath) { + s.backend.ServeHTTP(w, r) + return + } + if isNarObjectPath(relPath) { + http.NotFound(w, r) + return + } + } if r.Method != http.MethodPut { - s.backend.ServeHTTP(w, r) + w.Header().Set("Allow", http.MethodPut) + http.Error(w, "method not allowed", http.StatusMethodNotAllowed) return } - - if relPath == "nix-cache-info" { - s.backend.ServeHTTP(w, r) + if r.URL.RawQuery != "" || (!isNarObjectPath(relPath) && !isNarinfoObjectPath(relPath)) { + http.NotFound(w, r) return } -- 2.51.2