diff --git a/pkg/apk/apk/cache.go b/pkg/apk/apk/cache.go index 78ce1097a..1d28e666e 100644 --- a/pkg/apk/apk/cache.go +++ b/pkg/apk/apk/cache.go @@ -492,16 +492,16 @@ func cachePathFromURL(root string, u url.URL) (string, error) { u2.ForceQuery = false u2.RawFragment = "" u2.RawQuery = "" - filename := filepath.Base(u2.Path) - archDir := filepath.Dir(u2.Path) - dir := filepath.Base(archDir) - repoDir := filepath.Dir(archDir) - // include the hostname - u2.Path = repoDir - - // url encode it so it can be a single directory - repoDir = url.QueryEscape(u2.String()) - cacheFile := filepath.Join(root, repoDir, dir, filename) + + // Use the full path as the cache structure to handle both top-level and nested files uniformly + cachePath := strings.TrimPrefix(filepath.Clean(u2.Path), "/") + baseURL := u2 + baseURL.Path = "" + + // url encode the base URL so it can be a single directory + baseDir := url.QueryEscape(baseURL.String()) + cacheFile := filepath.Join(root, baseDir, cachePath) + // validate it is within root cacheFile = filepath.Clean(cacheFile) cleanroot := filepath.Clean(root) diff --git a/pkg/apk/apk/implementation_test.go b/pkg/apk/apk/implementation_test.go index 163098b9d..dfdd184c4 100644 --- a/pkg/apk/apk/implementation_test.go +++ b/pkg/apk/apk/implementation_test.go @@ -715,7 +715,10 @@ func TestFetchPackage(t *testing.T) { tmpDir := t.TempDir() a := prepLayout(t, tmpDir) // fill the cache - repoDir := filepath.Join(tmpDir, url.QueryEscape(testAlpineRepos), testArch) + // New cache structure uses full path: https%3A%2F%2Fhost/path/to/arch/file + repoURL, _ := url.Parse(testAlpineRepos) + baseDir := url.QueryEscape(repoURL.Scheme + "://" + repoURL.Host) + repoDir := filepath.Join(tmpDir, baseDir, strings.TrimPrefix(repoURL.Path, "/"), testArch) err := os.MkdirAll(repoDir, 0o755) require.NoError(t, err, "unable to mkdir cache") @@ -757,7 +760,9 @@ func TestFetchPackage(t *testing.T) { tmpDir := t.TempDir() a := prepLayout(t, tmpDir) // fill the cache - repoDir := filepath.Join(tmpDir, url.QueryEscape(testAlpineRepos), testArch) + repoURL, _ := url.Parse(testAlpineRepos) + baseDir := url.QueryEscape(repoURL.Scheme + "://" + repoURL.Host) + repoDir := filepath.Join(tmpDir, baseDir, strings.TrimPrefix(repoURL.Path, "/"), testArch) err := os.MkdirAll(repoDir, 0o755) require.NoError(t, err, "unable to mkdir cache") @@ -785,7 +790,9 @@ func TestFetchPackage(t *testing.T) { tmpDir := t.TempDir() a := prepLayout(t, tmpDir) // fill the cache - repoDir := filepath.Join(tmpDir, url.QueryEscape(testAlpineRepos), testArch) + repoURL, _ := url.Parse(testAlpineRepos) + baseDir := url.QueryEscape(repoURL.Scheme + "://" + repoURL.Host) + repoDir := filepath.Join(tmpDir, baseDir, strings.TrimPrefix(repoURL.Path, "/"), testArch) err := os.MkdirAll(repoDir, 0o755) require.NoError(t, err, "unable to mkdir cache") @@ -815,7 +822,9 @@ func TestFetchPackage(t *testing.T) { tmpDir := t.TempDir() a := prepLayout(t, tmpDir) // fill the cache - repoDir := filepath.Join(tmpDir, url.QueryEscape(testAlpineRepos), testArch) + repoURL, _ := url.Parse(testAlpineRepos) + baseDir := url.QueryEscape(repoURL.Scheme + "://" + repoURL.Host) + repoDir := filepath.Join(tmpDir, baseDir, strings.TrimPrefix(repoURL.Path, "/"), testArch) err := os.MkdirAll(repoDir, 0o755) require.NoError(t, err, "unable to mkdir cache") diff --git a/pkg/apk/apk/repo_test.go b/pkg/apk/apk/repo_test.go index 7dae913cc..eb0fc109f 100644 --- a/pkg/apk/apk/repo_test.go +++ b/pkg/apk/apk/repo_test.go @@ -178,7 +178,9 @@ func TestGetRepositoryIndexes(t *testing.T) { tmpDir := t.TempDir() a := prepLayout(t, tmpDir, []string{testAlpineRepos}) // fill the cache - repoDir := filepath.Join(tmpDir, url.QueryEscape(testAlpineRepos), testArch) + repoURL, _ := url.Parse(testAlpineRepos) + baseDir := url.QueryEscape(repoURL.Scheme + "://" + repoURL.Host) + repoDir := filepath.Join(tmpDir, baseDir, strings.TrimPrefix(repoURL.Path, "/"), testArch) a.SetClient(&http.Client{ Transport: &testLocalTransport{