From 8ea90adcaff4dd42483ebb0b27012234cc7b41b1 Mon Sep 17 00:00:00 2001 From: codex Date: Wed, 10 Jun 2026 06:29:46 +0000 Subject: [PATCH] fix: raise git http body cap --- bot_bottle/git_http_backend.py | 4 ++-- docs/prds/0041-git-http-request-bounds.md | 8 ++++---- tests/unit/test_git_http_backend.py | 5 ++--- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/bot_bottle/git_http_backend.py b/bot_bottle/git_http_backend.py index 31d895d..1264bca 100644 --- a/bot_bottle/git_http_backend.py +++ b/bot_bottle/git_http_backend.py @@ -19,8 +19,8 @@ from urllib.parse import urlsplit DEFAULT_PORT = 9420 -# Body-size cap matching supervise_server.py's 1 MiB limit. -MAX_BODY_BYTES = 1 * 1024 * 1024 +# Bound memory use while still allowing ordinary git push packfiles. +MAX_BODY_BYTES = 100 * 1024 * 1024 class GitHttpHandler(BaseHTTPRequestHandler): diff --git a/docs/prds/0041-git-http-request-bounds.md b/docs/prds/0041-git-http-request-bounds.md index 16c5d62..0caf2e7 100644 --- a/docs/prds/0041-git-http-request-bounds.md +++ b/docs/prds/0041-git-http-request-bounds.md @@ -13,13 +13,13 @@ Add Content-Length validation and a body-size cap to `git_http_backend.py` so ma `bot_bottle/git_http_backend.py` calls `int(self.headers.get("Content-Length", 0))` without catching `ValueError`. A request with a non-numeric Content-Length raises an unhandled exception in the request handler. -The handler reads the full declared length into memory before passing the body to `git http-backend` with no upper bound. A local or compromised client can force arbitrarily high memory use. For comparison, `supervise_server.py` caps request bodies at 1 MiB. +The handler reads the full declared length into memory before passing the body to `git http-backend` with no upper bound. A local or compromised client can force arbitrarily high memory use. ## Goals / Success Criteria - A missing or non-numeric Content-Length returns HTTP 400. - A negative Content-Length returns HTTP 400. -- A body larger than the cap (1 MiB, matching `supervise_server.py`) returns HTTP 413. +- A body larger than the cap (100 MiB) returns HTTP 413. - Valid Git smart-HTTP pushes and fetches continue to work. - Unit tests cover: missing length, non-numeric length, negative length, over-cap length, and a valid push/fetch passthrough. @@ -43,12 +43,12 @@ Out of scope: ## Design -Wrap the Content-Length parse in a try/except and return 400 on `ValueError`. Add an explicit check for negative values. After parsing, compare the declared length against a module-level `MAX_BODY_BYTES` constant (default 1 MiB) and return 413 if exceeded. Read exactly `min(content_length, MAX_BODY_BYTES)` bytes. +Wrap the Content-Length parse in a try/except and return 400 on `ValueError`. Add an explicit check for negative values. After parsing, compare the declared length against a module-level `MAX_BODY_BYTES` constant (default 100 MiB) and return 413 if exceeded. Read exactly `min(content_length, MAX_BODY_BYTES)` bytes. ## Testing Strategy - Unit tests using `unittest.mock` to drive the handler with crafted headers. -- Test cases: no Content-Length header, `Content-Length: abc`, `Content-Length: -1`, `Content-Length: 2097152` (over cap), and a normal small POST body. +- Test cases: no Content-Length header, `Content-Length: abc`, `Content-Length: -1`, a declared length above `MAX_BODY_BYTES`, and a normal small POST body. Run: diff --git a/tests/unit/test_git_http_backend.py b/tests/unit/test_git_http_backend.py index ae6ddbc..99f47d2 100644 --- a/tests/unit/test_git_http_backend.py +++ b/tests/unit/test_git_http_backend.py @@ -9,7 +9,7 @@ import urllib.request from pathlib import Path from unittest import mock -from bot_bottle.git_http_backend import GitHttpHandler +from bot_bottle.git_http_backend import GitHttpHandler, MAX_BODY_BYTES class TestGitHttpBackend(unittest.TestCase): @@ -305,9 +305,8 @@ class TestContentLengthBounds(unittest.TestCase): self.assertEqual(400, status) def test_oversized_content_length_returns_413(self): - # Declare 2 MiB — over the 1 MiB cap. status = self._post("/repo.git/git-receive-pack", - content_length_header=str(2 * 1024 * 1024)) + content_length_header=str(MAX_BODY_BYTES + 1)) self.assertEqual(413, status) def test_valid_small_body_passes_through(self):