From 0b7597e063bc393240524dc29ca04ad6d556c14b Mon Sep 17 00:00:00 2001 From: Wael Nasreddine Date: Wed, 11 Feb 2026 08:00:46 -0800 Subject: [PATCH] fix: Apply NAR URL normalization in storage layer Normalize NAR URLs before file path operations in both local and S3 storage backends. This ensures consistent storage and retrieval regardless of whether the NAR URL contains an embedded narinfo hash prefix. Changes: - pkg/storage/local/local.go: Add URL.Normalize() in HasNar, GetNar, PutNar, DeleteNar - pkg/storage/s3/s3.go: Add URL.Normalize() in narPath method This ensures that NARs are stored and retrieved using the normalized hash, making the storage layer agnostic to whether the input URL has a prefix. Co-Authored-By: Claude Haiku 4.5 --- pkg/storage/local/local.go | 17 +++++++++++++---- pkg/storage/s3/s3.go | 2 +- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/pkg/storage/local/local.go b/pkg/storage/local/local.go index 4e1ede65..c395cf30 100644 --- a/pkg/storage/local/local.go +++ b/pkg/storage/local/local.go @@ -330,7 +330,7 @@ func (s *Store) DeleteNarInfo(ctx context.Context, hash string) error { // HasNar returns true if the store has the nar. func (s *Store) HasNar(ctx context.Context, narURL nar.URL) bool { - tfp, err := narURL.ToFilePath() + tfp, err := narURL.Normalize().ToFilePath() if err != nil { return false } @@ -356,7 +356,10 @@ func (s *Store) HasNar(ctx context.Context, narURL nar.URL) bool { // GetNar returns nar from the store. // NOTE: The caller must close the returned io.ReadCloser! func (s *Store) GetNar(ctx context.Context, narURL nar.URL) (int64, io.ReadCloser, error) { - tfp, err := narURL.ToFilePath() + // Normalize the NAR URL to handle URLs with embedded narinfo hash prefix + normalizedURL := narURL.Normalize() + + tfp, err := normalizedURL.ToFilePath() if err != nil { return 0, nil, err } @@ -393,7 +396,10 @@ func (s *Store) GetNar(ctx context.Context, narURL nar.URL) (int64, io.ReadClose // PutNar puts the nar in the store. func (s *Store) PutNar(ctx context.Context, narURL nar.URL, body io.Reader) (int64, error) { - tfp, err := narURL.ToFilePath() + // Normalize the NAR URL to handle URLs with embedded narinfo hash prefix + normalizedURL := narURL.Normalize() + + tfp, err := normalizedURL.ToFilePath() if err != nil { return 0, err } @@ -450,7 +456,10 @@ func (s *Store) PutNar(ctx context.Context, narURL nar.URL, body io.Reader) (int // DeleteNar deletes the nar from the store. func (s *Store) DeleteNar(ctx context.Context, narURL nar.URL) error { - tfp, err := narURL.ToFilePath() + // Normalize the NAR URL to handle URLs with embedded narinfo hash prefix + normalizedURL := narURL.Normalize() + + tfp, err := normalizedURL.ToFilePath() if err != nil { return err } diff --git a/pkg/storage/s3/s3.go b/pkg/storage/s3/s3.go index 86391e25..2be6e885 100644 --- a/pkg/storage/s3/s3.go +++ b/pkg/storage/s3/s3.go @@ -566,7 +566,7 @@ func (s *Store) narInfoPath(hash string) (string, error) { } func (s *Store) narPath(narURL nar.URL) (string, error) { - tfp, err := narURL.ToFilePath() + tfp, err := narURL.Normalize().ToFilePath() if err != nil { return "", err }