From 52033a6290139f4a98470652eadfb7b2d493068e Mon Sep 17 00:00:00 2001 From: "didericis (claude)" Date: Tue, 2 Jun 2026 10:28:19 -0400 Subject: [PATCH] docs: add PRD 0041 --- docs/prds/0041-git-http-request-bounds.md | 74 +++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 docs/prds/0041-git-http-request-bounds.md diff --git a/docs/prds/0041-git-http-request-bounds.md b/docs/prds/0041-git-http-request-bounds.md new file mode 100644 index 0000000..34696fa --- /dev/null +++ b/docs/prds/0041-git-http-request-bounds.md @@ -0,0 +1,74 @@ +# PRD 0041: Git HTTP Request Bounds + +- **Status:** Draft +- **Author:** didericis-codex +- **Created:** 2026-06-02 +- **Issue:** #138 + +## Summary + +Add Content-Length validation and a body-size cap to `git_http_backend.py` so +malformed or oversized smart-HTTP requests fail cleanly rather than crashing +the handler or exhausting memory. + +## Problem + +`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. + +## 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. +- 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. + +## Non-goals + +- No changes to git-gate authentication or route logic. +- No changes to `supervise_server.py`. +- No streaming / chunked-transfer-encoding support. +- No TLS changes. + +## Scope + +In scope: + +- `bot_bottle/git_http_backend.py` request parsing and body reading. +- Unit tests in `tests/unit/test_git_http_backend.py`. + +Out of scope: + +- Integration tests that drive a real Git client through the handler. + +## 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. + +## 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. + +Run: + +- `python3 -m unittest tests.unit.test_git_http_backend` +- `python3 -m unittest discover -s tests/unit` + +## Open Questions + +None.