Fix go-getter cache key conflict for HttpGetter with query parameters
Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com>
This commit is contained in:
		
							parent
							
								
									4de4c46f87
								
							
						
					
					
						commit
						2dc311027d
					
				|  | @ -242,7 +242,17 @@ func (r *Remote) Fetch(path string, cacheDirOpt ...string) (string, error) { | ||||||
| 	cacheDirPath := filepath.Join(r.Home, getterDst) | 	cacheDirPath := filepath.Join(r.Home, getterDst) | ||||||
| 	if u.Getter == "normal" { | 	if u.Getter == "normal" { | ||||||
| 		srcDir = fmt.Sprintf("%s://%s", u.Scheme, u.Host) | 		srcDir = fmt.Sprintf("%s://%s", u.Scheme, u.Host) | ||||||
| 		cacheKey = replacer.Replace(srcDir) | 		dirKey = replacer.Replace(srcDir) | ||||||
|  | 		if len(query) > 0 { | ||||||
|  | 			q := maps.Clone(query) | ||||||
|  | 			if q.Has("sshkey") { | ||||||
|  | 				q.Set("sshkey", "redacted") | ||||||
|  | 			} | ||||||
|  | 			paramsKey := strings.ReplaceAll(q.Encode(), "&", "_") | ||||||
|  | 			cacheKey = fmt.Sprintf("%s.%s", dirKey, paramsKey) | ||||||
|  | 		} else { | ||||||
|  | 			cacheKey = dirKey | ||||||
|  | 		} | ||||||
| 		cacheDirPath = filepath.Join(r.Home, cacheKey, u.Dir) | 		cacheDirPath = filepath.Join(r.Home, cacheKey, u.Dir) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -567,3 +567,119 @@ func TestRemote_Fetch(t *testing.T) { | ||||||
| 		}) | 		}) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func TestRemote_HttpUrlWithQueryParams(t *testing.T) { | ||||||
|  | 	// Test what cache paths are actually generated for HTTP URLs with query parameters
 | ||||||
|  | 	 | ||||||
|  | 	cleanfs := map[string]string{ | ||||||
|  | 		CacheDir(): "", | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	url1 := "https://gitlab.example.com/api/v4/projects/test/repository/files/values.yaml/raw?ref=commit1" | ||||||
|  | 	url2 := "https://gitlab.example.com/api/v4/projects/test/repository/files/values.yaml/raw?ref=commit2" | ||||||
|  | 	 | ||||||
|  | 	for i, url := range []string{url1, url2} { | ||||||
|  | 		t.Run(fmt.Sprintf("url%d", i+1), func(t *testing.T) { | ||||||
|  | 			testfs := testhelper.NewTestFs(cleanfs) | ||||||
|  | 			 | ||||||
|  | 			var capturedDst string | ||||||
|  | 			mockHttpGetter := &testGetter{ | ||||||
|  | 				get: func(wd, src, dst string) error { | ||||||
|  | 					capturedDst = dst | ||||||
|  | 					t.Logf("HttpGetter.Get called with dst: %s", dst) | ||||||
|  | 					t.Logf("HttpGetter.Get called with src: %s", src) | ||||||
|  | 					return nil | ||||||
|  | 				}, | ||||||
|  | 			} | ||||||
|  | 			 | ||||||
|  | 			remote := &Remote{ | ||||||
|  | 				Logger:     helmexec.NewLogger(io.Discard, "debug"), | ||||||
|  | 				Home:       CacheDir(), | ||||||
|  | 				HttpGetter: mockHttpGetter, | ||||||
|  | 				fs:         testfs.ToFileSystem(), | ||||||
|  | 			} | ||||||
|  | 			 | ||||||
|  | 			file, err := remote.Fetch(url) | ||||||
|  | 			if err != nil { | ||||||
|  | 				t.Fatalf("unexpected error: %v", err) | ||||||
|  | 			} | ||||||
|  | 			 | ||||||
|  | 			t.Logf("Fetched file path: %s", file) | ||||||
|  | 			t.Logf("Cache destination: %s", capturedDst) | ||||||
|  | 		}) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestRemote_HttpUrlQueryParamsAvoidCacheCollision(t *testing.T) { | ||||||
|  | 	// Test that URLs with different query parameters use different cache locations
 | ||||||
|  | 	// and don't have cache collisions (this was the original bug)
 | ||||||
|  | 	 | ||||||
|  | 	url1 := "https://gitlab.example.com/api/v4/projects/test/repository/files/values.yaml/raw?ref=commit1" | ||||||
|  | 	url2 := "https://gitlab.example.com/api/v4/projects/test/repository/files/values.yaml/raw?ref=commit2" | ||||||
|  | 	 | ||||||
|  | 	// First, populate cache for url1
 | ||||||
|  | 	cachefs := map[string]string{ | ||||||
|  | 		CacheDir(): "", | ||||||
|  | 		filepath.Join(CacheDir(), "https_gitlab_example_com.ref=commit1/api/v4/projects/test/repository/files/values.yaml/raw"): "content from commit1", | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	t.Run("url2 with different query params should not hit cache for url1", func(t *testing.T) { | ||||||
|  | 		testfs := testhelper.NewTestFs(cachefs) | ||||||
|  | 		 | ||||||
|  | 		httpGetCalled := false | ||||||
|  | 		mockHttpGetter := &testGetter{ | ||||||
|  | 			get: func(wd, src, dst string) error { | ||||||
|  | 				httpGetCalled = true | ||||||
|  | 				t.Logf("HttpGetter.Get called - this is expected because url2 has different query params") | ||||||
|  | 				return nil | ||||||
|  | 			}, | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		remote := &Remote{ | ||||||
|  | 			Logger:     helmexec.NewLogger(io.Discard, "debug"), | ||||||
|  | 			Home:       CacheDir(), | ||||||
|  | 			HttpGetter: mockHttpGetter, | ||||||
|  | 			fs:         testfs.ToFileSystem(), | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		_, err := remote.Fetch(url2) | ||||||
|  | 		if err != nil { | ||||||
|  | 			t.Fatalf("unexpected error: %v", err) | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		// With the fix, HttpGetter.Get should be called because url2 has different
 | ||||||
|  | 		// query parameters than url1, so they should use different cache locations
 | ||||||
|  | 		if !httpGetCalled { | ||||||
|  | 			t.Error("HttpGetter.Get should have been called for URL with different query params") | ||||||
|  | 		} | ||||||
|  | 	}) | ||||||
|  | 	 | ||||||
|  | 	t.Run("same url should hit cache", func(t *testing.T) { | ||||||
|  | 		testfs := testhelper.NewTestFs(cachefs) | ||||||
|  | 		 | ||||||
|  | 		httpGetCalled := false | ||||||
|  | 		mockHttpGetter := &testGetter{ | ||||||
|  | 			get: func(wd, src, dst string) error { | ||||||
|  | 				httpGetCalled = true | ||||||
|  | 				return nil | ||||||
|  | 			}, | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		remote := &Remote{ | ||||||
|  | 			Logger:     helmexec.NewLogger(io.Discard, "debug"), | ||||||
|  | 			Home:       CacheDir(), | ||||||
|  | 			HttpGetter: mockHttpGetter, | ||||||
|  | 			fs:         testfs.ToFileSystem(), | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		_, err := remote.Fetch(url1) | ||||||
|  | 		if err != nil { | ||||||
|  | 			t.Fatalf("unexpected error: %v", err) | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		// url1 should hit the cache since we populated it with the same URL
 | ||||||
|  | 		if httpGetCalled { | ||||||
|  | 			t.Error("HttpGetter.Get should NOT have been called for cached URL") | ||||||
|  | 		} | ||||||
|  | 	}) | ||||||
|  | } | ||||||
		Loading…
	
		Reference in New Issue