fix: Logging regression for manifest HEAD requests (#4756)

This commit is contained in:
Milos Gajdos
2026-01-06 09:03:21 -08:00
committed by GitHub
4 changed files with 106 additions and 1 deletions

View File

@@ -34,6 +34,7 @@ import (
"github.com/opencontainers/go-digest"
"github.com/opencontainers/image-spec/specs-go"
v1 "github.com/opencontainers/image-spec/specs-go/v1"
hookstest "github.com/sirupsen/logrus/hooks/test"
)
var headerConfig = http.Header{
@@ -1709,7 +1710,10 @@ func testManifestAPISchema2(t *testing.T, env *testEnv, imageName reference.Name
// ------------------
// Fetch by tag name
// HEAD requests should not contain a body
// HEAD requests should emit a logging entry and not contain a body
hook := hookstest.NewGlobal()
defer hook.Reset()
headReq, err := http.NewRequest(http.MethodHead, manifestURL, nil)
if err != nil {
t.Fatalf("Error constructing request: %s", err)
@@ -1726,6 +1730,14 @@ func testManifestAPISchema2(t *testing.T, env *testEnv, imageName reference.Name
"ETag": []string{fmt.Sprintf(`"%s"`, dgst)},
})
lastMsg := hook.LastEntry()
if v := lastMsg.Data["http.request.method"]; v != http.MethodHead {
t.Errorf("expected http.request.method to be %q, got %q", http.MethodHead, v)
}
if v := lastMsg.Data["http.response.status"]; v != http.StatusOK {
t.Errorf("expected http.response.status to be %d, got %d", http.StatusOK, v)
}
headBody, err := io.ReadAll(headResp.Body)
if err != nil {
t.Fatalf("reading body for head manifest: %v", err)

View File

@@ -217,6 +217,7 @@ func (imh *manifestHandler) GetManifest(w http.ResponseWriter, r *http.Request)
w.Header().Set("Etag", fmt.Sprintf(`"%s"`, imh.Digest))
if r.Method == http.MethodHead {
w.WriteHeader(http.StatusOK)
return
}

91
vendor/github.com/sirupsen/logrus/hooks/test/test.go generated vendored Normal file
View File

@@ -0,0 +1,91 @@
// The Test package is used for testing logrus.
// It provides a simple hooks which register logged messages.
package test
import (
"io/ioutil"
"sync"
"github.com/sirupsen/logrus"
)
// Hook is a hook designed for dealing with logs in test scenarios.
type Hook struct {
// Entries is an array of all entries that have been received by this hook.
// For safe access, use the AllEntries() method, rather than reading this
// value directly.
Entries []logrus.Entry
mu sync.RWMutex
}
// NewGlobal installs a test hook for the global logger.
func NewGlobal() *Hook {
hook := new(Hook)
logrus.AddHook(hook)
return hook
}
// NewLocal installs a test hook for a given local logger.
func NewLocal(logger *logrus.Logger) *Hook {
hook := new(Hook)
logger.AddHook(hook)
return hook
}
// NewNullLogger creates a discarding logger and installs the test hook.
func NewNullLogger() (*logrus.Logger, *Hook) {
logger := logrus.New()
logger.Out = ioutil.Discard
return logger, NewLocal(logger)
}
func (t *Hook) Fire(e *logrus.Entry) error {
t.mu.Lock()
defer t.mu.Unlock()
t.Entries = append(t.Entries, *e)
return nil
}
func (t *Hook) Levels() []logrus.Level {
return logrus.AllLevels
}
// LastEntry returns the last entry that was logged or nil.
func (t *Hook) LastEntry() *logrus.Entry {
t.mu.RLock()
defer t.mu.RUnlock()
i := len(t.Entries) - 1
if i < 0 {
return nil
}
return &t.Entries[i]
}
// AllEntries returns all entries that were logged.
func (t *Hook) AllEntries() []*logrus.Entry {
t.mu.RLock()
defer t.mu.RUnlock()
// Make a copy so the returned value won't race with future log requests
entries := make([]*logrus.Entry, len(t.Entries))
for i := 0; i < len(t.Entries); i++ {
// Make a copy, for safety
entries[i] = &t.Entries[i]
}
return entries
}
// Reset removes all Entries from this test hook.
func (t *Hook) Reset() {
t.mu.Lock()
defer t.mu.Unlock()
t.Entries = make([]logrus.Entry, 0)
}

1
vendor/modules.txt vendored
View File

@@ -442,6 +442,7 @@ github.com/redis/go-redis/v9/internal/util
# github.com/sirupsen/logrus v1.9.3
## explicit; go 1.13
github.com/sirupsen/logrus
github.com/sirupsen/logrus/hooks/test
# github.com/spf13/cobra v1.8.0
## explicit; go 1.15
github.com/spf13/cobra