Skip to content

fix: bound /parse request body before multipart parsing - #787

Draft
seonghobae wants to merge 40 commits into
developfrom
jules-7450195751122755850-4248c671
Draft

fix: bound /parse request body before multipart parsing#787
seonghobae wants to merge 40 commits into
developfrom
jules-7450195751122755850-4248c671

Conversation

@seonghobae

@seonghobae seonghobae commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

현재 상태

/parse의 multipart parser 이전 request-body admission, parser 이후 form-field validation, pypdf security floor, test isolation을 한 canonical lineage에서 유지합니다. intervening descendants의 유효 test/security delta는 채택하되 generated repository doctrine과 과장된 security claim은 normal descendant로 수리합니다.

  • protected base: develop@e06b1f3fb10903569124af011da213951e6e2473
  • exact head: ebd6c71ba17151228c23d32705687097290c0c89
  • lifecycle: Draft / mechanically mergeable / exact-head hosted evidence pending
  • effective files: CHANGELOG.md, dependency doctoring, pyproject.toml, /parse source, focused parse/request-body/test-isolation/security tests, uv.lock
  • .jules/sentinel.md는 protected-base blob과 일치하므로 effective diff에서 제거된 상태를 유지합니다.

RED → GREEN → repair lineage

  • 선언된 oversized Content-Length는 body read 0회로 413, 길이가 없거나 신뢰할 수 없는 stream은 실제 누적 receive bytes로 제한하는 pre-parser RED를 /parse POST 전용 ASGI admission으로 GREEN 처리했습니다. PDF payload 20 MiB와 multipart/form framing budget 1 MiB를 분리해 총 21 MiB admission을 유지합니다.
  • language/modemax_length=50은 parser 이후 FastAPI form-value contract입니다. 이것을 multipart parser 이전 memory budget이라고 주장하지 않습니다.
  • 51-character regression은 tests/test_parse_endpoint_max_length.py에서 두 필드를 parameterize하고 HTTP 422와 FastAPI/Pydantic의 string_too_long location을 직접 고정합니다. 이 공개 validation shape를 존재하지 않는 sanitized response라고 표현하지 않습니다.
  • focused fixture는 자신이 설치한 _runtime_settings override만 복원하며 다른 fixture의 app.dependency_overrides를 지우지 않습니다. 기존 destructive-clear 회귀도 별도 test-isolation contract로 유지합니다.
  • pypdf>=6.16.2,<7.0와 lock 6.16.2를 유지합니다. 2026-09-05 재검증한 upstream advisory 기준으로 CVE-2026-84309는 6.16.0, CVE-2026-84310/CVE-2026-84311은 6.16.1에서 각각 patched이며, PyPI의 현재 latest 6.16.2는 이 floor보다 최신입니다. docs/doctoring/dependency-security-baseline.md에 CVE↔GHSA↔patched-version↔PyPI provenance를 APA-style traceability로 갱신했고, regression은 기존 CVE-2026-71852/71870과 신규 3건 모두 repository-wide suppression 대상이 아님을 고정합니다. 현재 strict PdfReader path에서 각 advisory가 반드시 reachable하다고 과장하지 않습니다.

sibling consolidation

  • #786@842e12485827c6f27a52eef997fc4e18f8865741의 유효 pypdf declaration/lock/security intent는 이 lineage에 승계했습니다. 근거 없는 upload-read chunk 성능 실험과 no-op retrigger doctrine은 승계하지 않았습니다.
  • #803@7d688fbf659a65faab8c1eb7c233243f920e29d7의 유효 delta인 language/mode max_length=50, 두 51-character 422 regressions, CHANGELOG 의미는 포함합니다. max_length 자체가 pre-parser memory exhaustion을 막는다는 global Sentinel doctrine은 결함이므로 승계하지 않습니다.
  • #774@26f99339076c3d43913f62739fe4482a6fe19224의 유효 delta도 이 exact head가 완전히 승계합니다: 동일 form bounds, 동일 focused 422 regression contract, protected-base Sentinel 복원, 더 강한 bounded pypdf>=6.16.2,<7.0 declaration/lock/doctoring, 그리고 실제 pre-parser request-body control까지 포함합니다. #774의 pypdf>=6.16.0 무상한 declaration과 stale/과장 설명은 승계 대상이 아닙니다.

Promotion boundary

모든 source/doc/test 변경은 predecessor CI evidence를 무효화합니다. 새 exact head의 required tests/security/code-scanning/review evidence가 terminal GREEN이고 unresolved thread가 없으며 independent current-head review가 성립하기 전에는 Ready/merge-ready로 올리지 않습니다. Self-approval, administrator bypass, gate weakening, no-op retrigger, force push, destructive rebase는 사용하지 않습니다.

@google-labs-jules

Copy link
Copy Markdown

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@coderabbitai

coderabbitai Bot commented Sep 2, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

This report is out of date. Scroll down for Devin Review's latest report on this PR.

Devin Review found 3 potential issues.

Devin Review

Comment thread CHANGELOG.md Outdated
Comment thread tests/test_parse_endpoint.py Outdated
Comment thread src/newsdom_api/main.py

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

Devin Review

Comment thread pyproject.toml
@seonghobae
seonghobae marked this pull request as draft September 3, 2026 10:38
@seonghobae seonghobae changed the title 🛡️ Sentinel: FastAPI 폼 필드 입력 제한 추가로 메모리 고갈 취약점 완화 fix: bound /parse request body before multipart parsing Sep 3, 2026

Copy link
Copy Markdown
Collaborator Author

@claude Fresh test-isolation RED is now on exact head cbfd7b87515ac828b40515c552a3454abc5f673e: tests/test_test_isolation_contract.py rejects app.dependency_overrides.clear() in tests/test_parse_endpoint.py because that test does not own overrides installed by other fixtures.

Minimal GREEN on a normal descendant:

  • in test_parse_form_field_max_length_exceeded, replace the direct app.dependency_overrides[_runtime_settings] = ... mutation with monkeypatch.setitem(app.dependency_overrides, _runtime_settings, ...), so pytest restores either the prior _runtime_settings override or absence automatically;
  • remove the broad finally: app.dependency_overrides.clear() cleanup;
  • retain the existing _parse_access_failure monkeypatch and both language/mode 51-character assertions;
  • run the new isolation contract plus tests/test_parse_endpoint.py and request-body limiter regressions.

Do not clear or replace the whole override mapping, and do not create a source-neutral retrigger. If the branch advances, read/adopt the intervening delta and continue non-force.

@google-labs-jules

Copy link
Copy Markdown

@claude Fresh test-isolation RED is now on exact head cbfd7b87515ac828b40515c552a3454abc5f673e: tests/test_test_isolation_contract.py rejects app.dependency_overrides.clear() in tests/test_parse_endpoint.py because that test does not own overrides installed by other fixtures.

Minimal GREEN on a normal descendant:

  • in test_parse_form_field_max_length_exceeded, replace the direct app.dependency_overrides[_runtime_settings] = ... mutation with monkeypatch.setitem(app.dependency_overrides, _runtime_settings, ...), so pytest restores either the prior _runtime_settings override or absence automatically;
  • remove the broad finally: app.dependency_overrides.clear() cleanup;
  • retain the existing _parse_access_failure monkeypatch and both language/mode 51-character assertions;
  • run the new isolation contract plus tests/test_parse_endpoint.py and request-body limiter regressions.

Do not clear or replace the whole override mapping, and do not create a source-neutral retrigger. If the branch advances, read/adopt the intervening delta and continue non-force.

Acknowledged. test_parse_form_field_max_length_exceeded 테스트 함수에서 직접 app.dependency_overrides를 덮어쓰지 않고 monkeypatch.setitem()을 사용하여 격리를 보장하도록 수정했습니다. 또한 요청 본문 길이를 제한하는 RequestBodyLimitMiddleware가 누락된 coverage(100% 달성)를 해결할 수 있도록 test_request_body_limit.py에 추가 테스트(test_request_body_limit_allows_short_body, test_request_body_limit_allows_short_body_other_event, test_request_body_limit_invalid_content_length)를 작성했습니다. 최종 100% 커버리지 GREEN 확인 후 제출합니다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant