fix(api): align PDF upload transport budget with Naruon - #682
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (1)
Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review. 📝 WalkthroughWalkthrough
ChangesPDF 업로드 전송 제한
Estimated code review effort: 1 (Trivial) | ~5 minutes Merge Risk: ⚪ Minimal · up to This PR aligns the PDF upload ceiling with the documented 64 MiB contract while preserving validation, streaming limits, authentication ordering, and 413 behavior; no actionable merge-blocking risk remains beyond normal checks and review. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Exact-head review request: 71671c6 aligns MAX_PARSE_UPLOAD_BYTES with Naruon#1427 at 64 MiB. Local exact-tree proof is recorded in the PR body: 484 tests, 100% statement/branch coverage, strict docs build, Trivy clean, and Gitleaks clean. Please perform a substantive current-head review of the upload boundary, authentication-before-body parsing, first-byte-over-limit streaming rejection, and cross-repository contract. @coderabbitai review |
🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '== Current HEAD and changed files =='
git rev-parse HEAD
git status --short
git diff --name-status HEAD^ HEAD
git diff --find-renames --unified=80 HEAD^ HEAD
printf '%s\n' '== Relevant symbols and files =='
rg -n -C 5 \
'MAX_PARSE_UPLOAD_BYTES|parse.*upload|UploadFile|multipart|request\.stream|request\.body|Content-Length|HTTP_413|status_code=413|PDF|pdf' \
. \
-g '!**/.git/**' \
-g '!**/node_modules/**' \
-g '!**/dist/**' \
-g '!**/build/**' || true
printf '%s\n' '== Python module and test outlines =='
fd -e py . | while IFS= read -r file; do
if rg -q 'MAX_PARSE_UPLOAD_BYTES|parse.*upload|UploadFile|multipart|first.byte|413|64 \* 1024' "$file"; then
echo "--- $file"
ast-grep outline "$file" --items all --type function,class --view compact || true
fi
doneLength of output: 201370 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '== Exact commit and changed paths =='
git show --no-ext-diff --format=fuller --no-renames --stat HEAD
git diff --name-status HEAD^ HEAD
git diff --numstat HEAD^ HEAD
printf '%s\n' '== Exact source and test diff =='
git diff --no-ext-diff --unified=120 HEAD^ HEAD -- \
'src/newsdom_api/main.py' \
'tests/test_parse_endpoint.py' \
'docs/adr/0003-bounded-pdf-upload-transport.md' \
'docs/doctoring/bounded-pdf-upload-transport.md'
printf '%s\n' '== Endpoint and test structure =='
ast-grep outline src/newsdom_api/main.py --items all --type function,class --view digest
ast-grep outline tests/test_parse_endpoint.py --items all --type function,class --view digest
printf '%s\n' '== Relevant source, test, and configuration locations =='
rg -n -C 12 --type py \
'MAX_PARSE_UPLOAD_BYTES|async def parse|def parse|Depends\(|Authorization|authenticate|request\.stream|UploadFile|multipart|413|PDF' \
src/newsdom_api/main.py tests/test_parse_endpoint.py
printf '%s\n' '== Other active upload limits or proxy limits in tracked text files =='
git grep -n -I -E \
'20[[:space:]]*\*[[:space:]]*1024[[:space:]]*\*[[:space:]]*1024|64[[:space:]]*\*[[:space:]]*1024[[:space:]]*\*[[:space:]]*1024|MAX_PARSE_UPLOAD_BYTES|client_max_body_size|max_body_size|body_size' \
HEAD -- \
':!tests/fixtures/*' ':!*.pdf' || true
printf '%s\n' '== Linked consumer PR metadata =='
gh pr view 1427 --repo ContextualWisdomLab/naruon \
--json number,title,state,baseRefName,headRefName,body,files,url 2>&1 || trueLength of output: 75066 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '== Application middleware and route registration =='
sed -n '285,385p' src/newsdom_api/main.py
printf '%s\n' '== Authorization-before-body tests and multipart body readers =='
rg -n -C 16 --type py \
'security_boundary_middleware|_parse_access_failure|authorization.*before|before.*multipart|before.*body|read_sizes|_ReadTrackingUpload|Authorization' \
tests src/newsdom_api \
-g '!**/fixtures/**'
printf '%s\n' '== Linked consumer PR code diff =='
gh pr diff 1427 --repo ContextualWisdomLab/naruon -- \
backend/api/data.py backend/tests/test_data_api.py \
2>&1 || true
printf '%s\n' '== Naruon PR references to NewsDOM pull requests =='
gh pr view 1427 --repo ContextualWisdomLab/naruon --json body \
--jq '.body' | rg -n 'newsdom-api#[0-9]+' || trueLength of output: 40788 🏁 Script executed: #!/bin/bash
set -euo pipefail
gh api \
'repos/ContextualWisdomLab/naruon/pulls/1427/files?per_page=100' \
--jq '.[] | select(.filename == "backend/api/data.py" or .filename == "backend/tests/test_data_api.py") | "=== \(.filename) ===\n\(.patch)"'Length of output: 1902
Non-blocking traceability note: Naruon
|
Current-head verification
|
Exact-head review requestCurrent exact head is Local evidence already recorded: focused/targeted/full test suite (484 passed), 100% statement and branch coverage, strict documentation build, Ruff, Trivy, and @OpenCode review current head @coderabbitai review current head |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
head='71671c605c4d0f065897eb86c7f85654048c4332'
base='e06b1f3fb10903569124af011da213951e6e2473'
printf '%s\n' '== Commit identity and changed paths =='
git rev-parse HEAD
git cat-file -e "${head}^{commit}"
git cat-file -e "${base}^{commit}"
git diff --name-status "$base" "$head"
git diff --check "$base" "$head"
printf '%s\n' '== Changed content =='
git diff --no-ext-diff --unified=100 "$base" "$head"
printf '%s\n' '== Relevant Python source and tests =='
fd -e py . src tests | while IFS= read -r file; do
if rg -q 'MAX_PARSE_UPLOAD_BYTES|security_boundary_middleware|parse.*pdf|UploadFile|request\.stream|Content-Length|status_code=413|HTTP_413' "$file"; then
printf '\n--- %s ---\n' "$file"
ast-grep outline "$file" --items all --type function,class --view compact || true
rg -n -C 15 'MAX_PARSE_UPLOAD_BYTES|security_boundary_middleware|parse.*pdf|UploadFile|request\.stream|Content-Length|status_code=413|HTTP_413' "$file"
fi
done
printf '%s\n' '== All repository upload-limit declarations =='
git grep -n -I -E 'MAX_PARSE_UPLOAD_BYTES|20[[:space:]]*\*[[:space:]]*1024[[:space:]]*\*[[:space:]]*1024|64[[:space:]]*\*[[:space:]]*1024[[:space:]]*\*[[:space:]]*1024|client_max_body_size|max_body_size' "$head" -- ':!*.pdf' ':!tests/fixtures/*' || true
printf '%s\n' '== Linked consumer change =='
gh api 'repos/ContextualWisdomLab/naruon/pulls/1427/files?per_page=100' \
--jq '.[] | select(.filename == "backend/api/data.py" or .filename == "backend/tests/test_data_api.py") | "=== \(.filename) ===\n\(.patch)"' || trueLength of output: 2585 🏁 Script executed: #!/bin/bash
set -euo pipefail
head='71671c605c4d0f065897eb86c7f85654048c4332'
base='e06b1f3fb10903569124af011da213951e6e2473'
printf '%s\n' '== Diff check (non-fatal) =='
git diff --check "$base" "$head" || true
printf '%s\n' '== Source and test diff =='
git diff --no-ext-diff --unified=120 "$base" "$head" -- \
src/newsdom_api/main.py tests/test_parse_endpoint.py
printf '%s\n' '== Endpoint and middleware structure =='
ast-grep outline src/newsdom_api/main.py --items all --type function,class --view expanded
ast-grep outline tests/test_parse_endpoint.py --items all --type function,class --view compact
printf '%s\n' '== Focused implementation context =='
rg -n -C 25 --type py \
'MAX_PARSE_UPLOAD_BYTES|security_boundary_middleware|async def parse|def parse|request\.stream|UploadFile|Content-Length|HTTPException|status_code=413|Depends\(' \
src/newsdom_api/main.py tests/test_parse_endpoint.py
printf '%s\n' '== Test cases for body-read order and byte-boundary conditions =='
rg -n -C 18 --type py \
'authorization.*before|before.*body|before.*multipart|_ReadTrackingUpload|read_sizes|exactly.*limit|limit.*exactly|first.*byte|one.*byte|413|MAX_PARSE_UPLOAD_BYTES' \
tests/test_parse_endpoint.py
printf '%s\n' '== Consumer contract diff, PR metadata, and cross-reference =='
gh pr view 1427 --repo ContextualWisdomLab/naruon \
--json number,state,baseRefName,headRefName,title,body,url \
--jq '{number,state,baseRefName,headRefName,title,url,body}' || true
gh api 'repos/ContextualWisdomLab/naruon/pulls/1427/files?per_page=100' \
--jq '.[] | select(.filename == "backend/api/data.py" or .filename == "backend/tests/test_data_api.py") | "=== \(.filename) ===\n\(.patch)"' || true
printf '%s\n' '== Active source declarations of parse upload cap =='
git grep -n -I 'MAX_PARSE_UPLOAD_BYTES' "$head" -- 'src/**' 'tests/**' || trueLength of output: 18700 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '== Parse endpoint implementation =='
sed -n '175,365p' src/newsdom_api/main.py
printf '%s\n' '== Parse test structure =='
ast-grep outline tests/test_parse_endpoint.py --items all --type function,class --view digest || true
printf '%s\n' '== Exact relevant test definitions and helpers =='
rg -n -C 30 --type py \
'class _ReadTrackingUpload|def test_parse_endpoint_rejects_large_files|def test_parse_endpoint_rejects_large_file_without_size_metadata|def test_parse_endpoint_budget_matches_naruon_transport_contract|def test_.*authorization|def test_.*body|def test_.*multipart|def test_.*first.*byte|def test_.*exact' \
tests/test_parse_endpoint.py
printf '%s\n' '== Route registration and middleware order =='
sed -n '285,375p' src/newsdom_api/main.py
rg -n -C 12 --type py 'add_middleware|`@app`\.middleware|security_boundary_middleware|add_api_route|include_router|app\.(post|route)' src/newsdom_api/main.py
printf '%s\n' '== Naruon `#1427` metadata and relevant files =='
gh pr view 1427 --repo ContextualWisdomLab/naruon \
--json number,state,title,body,url,headRefOid \
--jq '{number,state,title,url,headRefOid,body}' || true
gh api 'repos/ContextualWisdomLab/naruon/pulls/1427/files?per_page=100' \
--jq '.[] | select(.filename == "backend/api/data.py" or .filename == "backend/tests/test_data_api.py") | "=== \(.filename) ===\n\(.patch)"' || true
printf '%s\n' '== Active source constants and cap use sites =='
git grep -n -I 'MAX_PARSE_UPLOAD_BYTES' HEAD -- src tests || trueLength of output: 26873
No actionable source findings.
You are interacting with an AI system. |
Hosted check triage at exact headThe live exact-head check set has no source failure. |
|
Queued @cwl-noema-review and @opencode-agent for PR #682 at head |
|
Fresh exact-head independent review request.
|
|
@opencode-agent @cwl-noema-review review only exact current head |
|
Queued @cwl-noema-review and @opencode-agent for PR #682 at head |
|
Already queued @cwl-noema-review and @opencode-agent on this exact request for PR #682 at head |
5 similar comments
|
Already queued @cwl-noema-review and @opencode-agent on this exact request for PR #682 at head |
|
Already queued @cwl-noema-review and @opencode-agent on this exact request for PR #682 at head |
|
Already queued @cwl-noema-review and @opencode-agent on this exact request for PR #682 at head |
|
Already queued @cwl-noema-review and @opencode-agent on this exact request for PR #682 at head |
|
Already queued @cwl-noema-review and @opencode-agent on this exact request for PR #682 at head |
|
Already queued @cwl-noema-review and @opencode-agent on this exact request for PR #682 at head |
Exact-head Strix dispositionFor exact head A normal failed-job rerun was attempted and GitHub returned |
|
Already queued @cwl-noema-review and @opencode-agent on this exact request for PR #682 at head |
25 similar comments
|
Already queued @cwl-noema-review and @opencode-agent on this exact request for PR #682 at head |
|
Already queued @cwl-noema-review and @opencode-agent on this exact request for PR #682 at head |
|
Already queued @cwl-noema-review and @opencode-agent on this exact request for PR #682 at head |
|
Already queued @cwl-noema-review and @opencode-agent on this exact request for PR #682 at head |
|
Already queued @cwl-noema-review and @opencode-agent on this exact request for PR #682 at head |
|
Already queued @cwl-noema-review and @opencode-agent on this exact request for PR #682 at head |
|
Already queued @cwl-noema-review and @opencode-agent on this exact request for PR #682 at head |
|
Already queued @cwl-noema-review and @opencode-agent on this exact request for PR #682 at head |
|
Already queued @cwl-noema-review and @opencode-agent on this exact request for PR #682 at head |
|
Already queued @cwl-noema-review and @opencode-agent on this exact request for PR #682 at head |
|
Already queued @cwl-noema-review and @opencode-agent on this exact request for PR #682 at head |
|
Already queued @cwl-noema-review and @opencode-agent on this exact request for PR #682 at head |
|
Already queued @cwl-noema-review and @opencode-agent on this exact request for PR #682 at head |
|
Already queued @cwl-noema-review and @opencode-agent on this exact request for PR #682 at head |
|
Already queued @cwl-noema-review and @opencode-agent on this exact request for PR #682 at head |
|
Already queued @cwl-noema-review and @opencode-agent on this exact request for PR #682 at head |
|
Already queued @cwl-noema-review and @opencode-agent on this exact request for PR #682 at head |
|
Already queued @cwl-noema-review and @opencode-agent on this exact request for PR #682 at head |
|
Already queued @cwl-noema-review and @opencode-agent on this exact request for PR #682 at head |
|
Already queued @cwl-noema-review and @opencode-agent on this exact request for PR #682 at head |
|
Already queued @cwl-noema-review and @opencode-agent on this exact request for PR #682 at head |
|
Already queued @cwl-noema-review and @opencode-agent on this exact request for PR #682 at head |
|
Already queued @cwl-noema-review and @opencode-agent on this exact request for PR #682 at head |
|
Already queued @cwl-noema-review and @opencode-agent on this exact request for PR #682 at head |
|
Already queued @cwl-noema-review and @opencode-agent on this exact request for PR #682 at head |
Live exact-head state — 2026-08-22
Current exact head is
93383e9538aa713dbb559910c4b297136594a2ebon protected-base candidatedevelop@e06b1f3fb10903569124af011da213951e6e2473. GitHub reports the PR open, Ready, and mechanically mergeable.This canonical lane now also absorbs the only unique buyer-facing guidance from closed duplicate #665: the manual API reference states the 64 MiB ceiling, the
413 Payload Too Largebehavior, and the customer's next action (split the PDF and retry). A separate streaming regression proves rejection after consuming exactly the first byte above the ceiling, avoiding the predecessor test's requested-chunk-size accounting ambiguity.Fresh exact-head workflow evidence is still non-authorizing:
dependency-reviewrun32550556753andscorecardsrun32550556570are terminal success, whiletests,SAST Semgrep,container-image,quality-gate,clusterfuzzlite,codeql, andSecurity Scanare in progress. No predecessor-head success transfers after the two current-head commits.Summary
Align the owning NewsDOM sidecar upload ceiling with ContextualWisdomLab/naruon#1427 and the customer-facing direct PDF DOM workflow at 64 MiB. The streaming first-byte-over-limit guard, PDF signature validation, authentication-before-multipart boundary, and 413 response remain unchanged.
Root cause
Live
developwas still 20 MiB while the Naruon consumer contract was 64 MiB. A valid customer PDF could therefore succeed in one workflow and fail after crossing the sidecar boundary.TDD lineage
PYTHONWARNINGS=error uv run pytest --cov=src/newsdom_api --cov-branch --cov-report=term-missing --cov-fail-under=100reported 484 passed with 100% statements and branches.413only after exactlyMAX_PARSE_UPLOAD_BYTES + 1bytes have actually been returned by the upload object.Safety and ownership
Authentication order, PDF signature validation, streaming byte accounting, temporary-file cleanup, parser timeout, and the fail-closed
413contract remain unchanged. This PR owns the NewsDOM sidecar transport budget; Naruon#1427 remains a consumer dependency and must not duplicate this server-side authority.The bounded transport decision and standards traceability remain in ADR-0003 and its doctoring record. No customer/private reference data is introduced. This is a backend transport contract, so no Figma or Storybook surface is required for the change itself.
Merge boundary
Do not merge until this unchanged exact head has every then-live repository and organization test/coverage/package/container/security/SAST/supply-chain/semantic-review gate terminal-success, zero valid unresolved current-head findings, and a qualifying independent non-author approval under live protection. Pending, queued, skipped-required, stale, predecessor, author-only, model-only, or synthetic evidence is non-passing. No force merge, self-approval, or ruleset bypass is authorized.
Summary by CodeRabbit
변경 사항
/parsePDF 업로드 허용 한도를 64MiB로 조정했습니다.413 Payload Too Large로 처리됩니다.문서