fix(security): enhance timeout configurations and body size limits fo… (#3984)

* fix(security): enhance timeout configurations and body size limits for HTTP requests

Signed-off-by: Ramkumar Chinchani <rchincha.dev@gmail.com>

* fix(tests): refactor backend result handling in proxyHTTPRequest test

Signed-off-by: Ramkumar Chinchani <rchincha.dev@gmail.com>

* fix(security): preserve ContentLength in proxied requests to prevent server hang

Signed-off-by: Ramkumar Chinchani <rchincha.dev@gmail.com>

* fix(security): preserve explicit zero-length request bodies in proxyHTTPRequest
fix(tests): add test for normalizedTimeout function to ensure default fallback

Signed-off-by: Ramkumar Chinchani <rchincha.dev@gmail.com>

* fix(security): prevent default HTTP timeout values from being set unless explicitly configured

Signed-off-by: Ramkumar Chinchani <rchincha.dev@gmail.com>

* fix(security): refactor timeout handling to use explicit checks for nil and non-positive values

Signed-off-by: Ramkumar Chinchani <rchincha.dev@gmail.com>

* fix(tests): add wait_for_event_count function to ensure expected event generation

Signed-off-by: Ramkumar Chinchani <rchincha.dev@gmail.com>

* fix(security): improve timeout handling and update error responses for large requests

Signed-off-by: Ramkumar Chinchani <rchincha.dev@gmail.com>

* fix(security): enhance HTTP timeout handling with explicit accessors and default values

Signed-off-by: Ramkumar Chinchani <rchincha.dev@gmail.com>

* fix(security): increase default API key body size and timeout values for improved performance

Signed-off-by: Ramkumar Chinchani <rchincha.dev@gmail.com>

* fix(security): unify timeout handling by replacing specific read/write timeouts with a single default timeout

Signed-off-by: Ramkumar Chinchani <rchincha.dev@gmail.com>

* fix(security): consolidate HTTP timeout accessors and enhance timeout handling

Signed-off-by: Ramkumar Chinchani <rchincha.dev@gmail.com>

* fix(security): simplify HTTP timeout accessors and set default values for read/write timeouts

Co-authored-by: Copilot <copilot@github.com>
Signed-off-by: Ramkumar Chinchani <rchincha.dev@gmail.com>

---------

Signed-off-by: Ramkumar Chinchani <rchincha.dev@gmail.com>
Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
Ramkumar Chinchani
2026-04-26 12:23:48 -07:00
committed by GitHub
parent 8282aef12b
commit 934b22d124
17 changed files with 440 additions and 56 deletions
+15
View File
@@ -33,6 +33,11 @@ import (
storageConstants "zotregistry.dev/zot/v2/pkg/storage/constants"
)
const (
defaultReadTimeout = 60 * time.Second
defaultWriteTimeout = 60 * time.Second
)
// metadataConfig reports metadata after parsing, which we use to track
// errors.
func metadataConfig(md *mapstructure.Metadata) viper.DecoderConfigOption {
@@ -1063,6 +1068,16 @@ func applyDefaultValues(config *config.Config, viperInstance *viper.Viper, logge
config.Storage.SubPaths[name] = storageConfig
}
if config.HTTP.ReadTimeout == nil {
readTimeout := defaultReadTimeout
config.HTTP.ReadTimeout = &readTimeout
}
if config.HTTP.WriteTimeout == nil {
writeTimeout := defaultWriteTimeout
config.HTTP.WriteTimeout = &writeTimeout
}
// if OpenID authentication is enabled,
// API Keys are also enabled in order to provide data path authentication
if config.HTTP.Auth != nil && config.HTTP.Auth.OpenID != nil {
+41
View File
@@ -87,6 +87,47 @@ func TestServerUsage(t *testing.T) {
})
}
func TestLoadConfigurationInjectsHTTPTimeoutDefaults(t *testing.T) {
Convey("load config sets HTTP read/write timeout defaults when not explicitly configured", t, func() {
content := `{
"storage": {"rootDirectory": "/tmp/zot"},
"http": {"address": "127.0.0.1", "port": "8080"}
}`
tmpfile := MakeTempFileWithContent(t, "zot-http-timeouts-unset.json", content)
cfg := config.New()
err := cli.LoadConfiguration(cfg, tmpfile)
So(err, ShouldBeNil)
So(cfg.HTTP.ReadTimeout, ShouldNotBeNil)
So(cfg.HTTP.WriteTimeout, ShouldNotBeNil)
So(cfg.GetHTTPReadTimeout(), ShouldEqual, 60*time.Second)
So(cfg.GetHTTPWriteTimeout(), ShouldEqual, 60*time.Second)
})
Convey("load config preserves explicit HTTP read/write timeout values", t, func() {
content := `{
"storage": {"rootDirectory": "/tmp/zot"},
"http": {
"address": "127.0.0.1",
"port": "8080",
"readTimeout": "45s",
"writeTimeout": "1m"
}
}`
tmpfile := MakeTempFileWithContent(t, "zot-http-timeouts-explicit.json", content)
cfg := config.New()
err := cli.LoadConfiguration(cfg, tmpfile)
So(err, ShouldBeNil)
So(cfg.HTTP.ReadTimeout, ShouldNotBeNil)
So(cfg.HTTP.WriteTimeout, ShouldNotBeNil)
So(cfg.GetHTTPReadTimeout(), ShouldEqual, 45*time.Second)
So(cfg.GetHTTPWriteTimeout(), ShouldEqual, time.Minute)
})
}
func TestSchema(t *testing.T) {
Convey("Test schema command", t, func(c C) {
cmd := cli.NewServerRootCmd()