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
+18 -6
View File
@@ -82,12 +82,18 @@ type ImageTrust struct {
// @Param requestBody body string true "Public key content"
// @Success 200 {string} string "ok"
// @Failure 400 {string} string "bad request"
// @Failure 413 {string} string "request entity too large"
// @Failure 500 {string} string "internal server error"
func (trust *ImageTrust) HandleCosignPublicKeyUpload(response http.ResponseWriter, request *http.Request) {
body, err := io.ReadAll(request.Body)
body, err := io.ReadAll(http.MaxBytesReader(response, request.Body, constants.MaxImageTrustBodySize))
if err != nil {
trust.Log.Error().Err(err).Str("component", "image-trust").Msg("failed to read cosign key body")
response.WriteHeader(http.StatusInternalServerError)
var mbe *http.MaxBytesError
if errors.As(err, &mbe) {
response.WriteHeader(http.StatusRequestEntityTooLarge)
} else {
trust.Log.Error().Err(err).Str("component", "image-trust").Msg("failed to read cosign key body")
response.WriteHeader(http.StatusInternalServerError)
}
return
}
@@ -117,6 +123,7 @@ func (trust *ImageTrust) HandleCosignPublicKeyUpload(response http.ResponseWrite
// @Param requestBody body string true "Certificate content"
// @Success 200 {string} string "ok"
// @Failure 400 {string} string "bad request"
// @Failure 413 {string} string "request entity too large"
// @Failure 500 {string} string "internal server error"
func (trust *ImageTrust) HandleNotationCertificateUpload(response http.ResponseWriter, request *http.Request) {
var truststoreType string
@@ -127,10 +134,15 @@ func (trust *ImageTrust) HandleNotationCertificateUpload(response http.ResponseW
truststoreType = "ca" // default value of "truststoreType" query param
}
body, err := io.ReadAll(request.Body)
body, err := io.ReadAll(http.MaxBytesReader(response, request.Body, constants.MaxImageTrustBodySize))
if err != nil {
trust.Log.Error().Err(err).Str("component", "image-trust").Msg("failed to read notation certificate body")
response.WriteHeader(http.StatusInternalServerError)
var mbe *http.MaxBytesError
if errors.As(err, &mbe) {
response.WriteHeader(http.StatusRequestEntityTooLarge)
} else {
trust.Log.Error().Err(err).Str("component", "image-trust").Msg("failed to read notation certificate body")
response.WriteHeader(http.StatusInternalServerError)
}
return
}
+33 -2
View File
@@ -3,6 +3,7 @@
package extensions_test
import (
"bytes"
"context"
"encoding/json"
"errors"
@@ -56,7 +57,8 @@ func TestSignatureHandlers(t *testing.T) {
}
Convey("Test error handling when Cosign handler reads the request body", t, func() {
request, _ := http.NewRequestWithContext(context.TODO(), http.MethodPost, "baseURL", errReader(0))
request, err := http.NewRequestWithContext(context.TODO(), http.MethodPost, "http://example.com", errReader(0))
So(err, ShouldBeNil)
response := httptest.NewRecorder()
trust.HandleCosignPublicKeyUpload(response, request)
@@ -67,7 +69,8 @@ func TestSignatureHandlers(t *testing.T) {
})
Convey("Test error handling when Notation handler reads the request body", t, func() {
request, _ := http.NewRequestWithContext(context.TODO(), http.MethodPost, "baseURL", errReader(0))
request, err := http.NewRequestWithContext(context.TODO(), http.MethodPost, "http://example.com", errReader(0))
So(err, ShouldBeNil)
query := request.URL.Query()
request.URL.RawQuery = query.Encode()
@@ -78,6 +81,34 @@ func TestSignatureHandlers(t *testing.T) {
defer resp.Body.Close()
So(resp.StatusCode, ShouldEqual, http.StatusInternalServerError)
})
Convey("Test cosign upload body over max size returns 413", t, func() {
overSizedBody := make([]byte, constants.MaxImageTrustBodySize+1)
request, err := http.NewRequestWithContext(context.TODO(), http.MethodPost,
"http://example.com", bytes.NewReader(overSizedBody))
So(err, ShouldBeNil)
response := httptest.NewRecorder()
trust.HandleCosignPublicKeyUpload(response, request)
resp := response.Result()
defer resp.Body.Close()
So(resp.StatusCode, ShouldEqual, http.StatusRequestEntityTooLarge)
})
Convey("Test notation upload body over max size returns 413", t, func() {
overSizedBody := make([]byte, constants.MaxImageTrustBodySize+1)
request, err := http.NewRequestWithContext(context.TODO(), http.MethodPost,
"http://example.com", bytes.NewReader(overSizedBody))
So(err, ShouldBeNil)
response := httptest.NewRecorder()
trust.HandleNotationCertificateUpload(response, request)
resp := response.Result()
defer resp.Body.Close()
So(resp.StatusCode, ShouldEqual, http.StatusRequestEntityTooLarge)
})
}
func TestSignaturesAllowedMethodsHeader(t *testing.T) {