- 01-02-SUMMARY.md: plan completion summary with deviations - STATE.md: advanced plan position, added decisions, updated metrics - ROADMAP.md: phase 01 marked complete (2/2 plans) - REQUIREMENTS.md: DATA-03 and DATA-04 marked complete
128 lines
5.4 KiB
Markdown
128 lines
5.4 KiB
Markdown
---
|
|
phase: 01-data-integrity
|
|
plan: 02
|
|
subsystem: api
|
|
tags: [go, http, security, testing, maxbytesreader, body-size-limit]
|
|
|
|
# Dependency graph
|
|
requires:
|
|
- phase: 01-data-integrity plan 01
|
|
provides: UPSERT fix and FK enforcement already applied; test file structure established
|
|
|
|
provides:
|
|
- HTTP 413 response for oversized request bodies (>1MB) on WebhookHandler, TagsHandler POST, TagAssignmentHandler PUT/DELETE
|
|
- maxBodyBytes constant (1 << 20) and MaxBytesReader + errors.As pattern
|
|
- t.Fatalf at all 6 test setup call sites (no more silent test pass-on-setup-failure)
|
|
- 3 new oversized-body tests proving DATA-03 fixed
|
|
|
|
affects:
|
|
- phase-02 (database refactor — handlers are now correct and hardened, test suite is reliable)
|
|
- any future handler additions that accept a body (pattern established)
|
|
|
|
# Tech tracking
|
|
tech-stack:
|
|
added: []
|
|
patterns:
|
|
- "MaxBytesReader + errors.As(*http.MaxBytesError) pattern for request body size limiting in handlers"
|
|
- "JSON-prefix oversized body test: use valid JSON opening so decoder reads past limit before MaxBytesReader triggers"
|
|
|
|
key-files:
|
|
created: []
|
|
modified:
|
|
- pkg/diunwebhook/diunwebhook.go
|
|
- pkg/diunwebhook/diunwebhook_test.go
|
|
|
|
key-decisions:
|
|
- "Use MaxBytesReader wrapping r.Body before each JSON decode; distinguish 413 from 400 via errors.As on *http.MaxBytesError"
|
|
- "Oversized body test bodies must use valid JSON prefix (e.g. {\"image\":\") + padding — all-x bodies trigger JSON parse error before MaxBytesReader limit is reached"
|
|
|
|
patterns-established:
|
|
- "MaxBytesReader body guard pattern: r.Body = http.MaxBytesReader(w, r.Body, maxBodyBytes) before decode, errors.As for 413 vs 400"
|
|
- "Test setup errors must use t.Fatalf, never silent return"
|
|
|
|
requirements-completed:
|
|
- DATA-03
|
|
- DATA-04
|
|
|
|
# Metrics
|
|
duration: 7min
|
|
completed: 2026-03-23
|
|
---
|
|
|
|
# Phase 01 Plan 02: Body Size Limits and Test Setup Hardening Summary
|
|
|
|
**Request body size limits (1MB cap, HTTP 413) added to four handler paths; six silent test-setup returns replaced with t.Fatalf to surface setup failures in CI**
|
|
|
|
## Performance
|
|
|
|
- **Duration:** 7 min
|
|
- **Started:** 2026-03-23T20:17:30Z
|
|
- **Completed:** 2026-03-23T20:24:37Z
|
|
- **Tasks:** 2
|
|
- **Files modified:** 2
|
|
|
|
## Accomplishments
|
|
|
|
- Added `maxBodyBytes` constant and `errors` import to `diunwebhook.go`; applied `http.MaxBytesReader` + `errors.As(*http.MaxBytesError)` guard before JSON decode in WebhookHandler, TagsHandler POST, TagAssignmentHandler PUT and DELETE — returns HTTP 413 on body > 1MB
|
|
- Replaced 6 silent `if err != nil { return }` test setup patterns with `t.Fatalf(...)` so failing setup always fails the test, not silently passes
|
|
- Added 3 new oversized-body tests (TestWebhookHandler_OversizedBody, TestTagsHandler_OversizedBody, TestTagAssignmentHandler_OversizedBody); all pass with 413
|
|
|
|
## Task Commits
|
|
|
|
Each task was committed atomically:
|
|
|
|
1. **RED: add failing 413 tests** - `311e91d` (test)
|
|
2. **Task 1: MaxBytesReader in handlers + GREEN test fix** - `98dfd76` (feat)
|
|
3. **Task 2: Replace silent returns with t.Fatalf** - `7bdfc5f` (fix)
|
|
|
|
**Plan metadata:** (docs commit — see below)
|
|
|
|
_Note: TDD task 1 has a RED commit followed by a combined feat commit covering the implementation and the test body correction._
|
|
|
|
## Files Created/Modified
|
|
|
|
- `pkg/diunwebhook/diunwebhook.go` — added `errors` import, `maxBodyBytes` constant, MaxBytesReader guards in 4 handler paths
|
|
- `pkg/diunwebhook/diunwebhook_test.go` — 3 new oversized-body tests; 6 t.Fatalf replacements
|
|
|
|
## Decisions Made
|
|
|
|
- `http.MaxBytesReader` is applied per-handler (not via middleware) to match the existing no-middleware architecture
|
|
- Body limit set at 1MB (`1 << 20`) matching the plan spec
|
|
- Oversized body test bodies use a valid JSON prefix (`{"image":"` + padding) rather than all-`x` bytes — the JSON decoder reads only 1 byte of invalid content before failing, so all-`x` never triggers MaxBytesReader; a JSON string value causes the decoder to read the full field before the limit fires
|
|
|
|
## Deviations from Plan
|
|
|
|
### Auto-fixed Issues
|
|
|
|
**1. [Rule 1 - Bug] Oversized body tests used all-x bytes; fixed to use valid JSON prefix**
|
|
- **Found during:** Task 1 GREEN phase
|
|
- **Issue:** Test body `make([]byte, 1<<20+1)` filled with `'x'` causes JSON decoder to fail at byte 1 with "invalid character" — MaxBytesReader never triggers because the read count never reaches the limit
|
|
- **Fix:** Changed test bodies to `{"image":"` (or `{"name":"`) + `bytes.Repeat([]byte("x"), 1<<20+1)` so the decoder reads past 1MB before encountering an unterminated string
|
|
- **Files modified:** pkg/diunwebhook/diunwebhook_test.go
|
|
- **Verification:** All 3 oversized-body tests now pass with HTTP 413
|
|
- **Committed in:** 98dfd76 (Task 1 feat commit)
|
|
|
|
---
|
|
|
|
**Total deviations:** 1 auto-fixed (Rule 1 - test bug)
|
|
**Impact on plan:** The fix is necessary for tests to validate what they claim. No scope creep; the handler implementation is exactly as specified.
|
|
|
|
## Issues Encountered
|
|
|
|
None beyond the test body deviation documented above.
|
|
|
|
## User Setup Required
|
|
|
|
None - no external service configuration required.
|
|
|
|
## Next Phase Readiness
|
|
|
|
- DATA-03 and DATA-04 fixed; all Phase 01 plans complete
|
|
- Full test suite passes with 0 failures
|
|
- Handler hardening pattern (MaxBytesReader + errors.As) established for future handlers
|
|
- Ready to transition to Phase 02 (database refactor / PostgreSQL support)
|
|
|
|
---
|
|
*Phase: 01-data-integrity*
|
|
*Completed: 2026-03-23*
|