fix(master): drop registry response bodies from poll errors (#9)

This commit is contained in:
2026-10-13 08:26:29 +02:00
parent 92e7646221
commit f169eddc4c
2 changed files with 65 additions and 1 deletions
+33
View File
@@ -249,3 +249,36 @@ func TestMissingDigestHeaderDoesNotFallBackToDownload(t *testing.T) {
assert.Error(t, err)
assert.Equal(t, []string{http.MethodHead}, methods)
}
// ggcr copies up to 64 KiB of the registry's response into its errors. The
// registry host comes from an image name, so that text must not reach the
// stored poll error.
func TestRegistryErrorBodyDoesNotLeak(t *testing.T) {
dockerConfig(t, "")
tests := []struct {
name string
body string
want string
}{
{"raw body", "internal-secret-body", "registry answered 400 Bad Request"},
{"structured errors", `{"errors":[{"code":"MANIFEST_UNKNOWN","message":"internal-secret-body","detail":"internal-secret-body"},{"code":"internal-secret-body"}]}`,
"registry answered 400 Bad Request (MANIFEST_UNKNOWN)"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// HEAD answers carry no body, so the leak is in the GET /v2/ ping.
w.WriteHeader(http.StatusBadRequest)
_, _ = w.Write([]byte(tt.body))
}))
t.Cleanup(srv.Close)
host := strings.TrimPrefix(srv.URL, "http://")
_, err := New("test").Digest(context.Background(), host+"/a/b:1")
require.Error(t, err)
assert.NotContains(t, err.Error(), "internal-secret-body")
assert.Equal(t, "lookup "+host+"/a/b:1: "+tt.want, strings.Replace(err.Error(), "index.docker.io/", "", 1))
})
}
}