Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- MinerU subprocess argv 생성 시 `-`로 시작하는 option-like 인자를 거부하여 argument injection 위험을 낮춤
- API 에러 응답 생성 시 내부 예외 체인을 억제하여 의존성 오류나 내부 경로가 노출될 가능성을 줄임
- API 응답 미들웨어에 `Cache-Control: no-store, max-age=0` 헤더를 추가하여 민감한 파싱 데이터의 브라우저 및 중간 캐싱을 방지
- 중앙 `trivy-fs` 게이트가 보고한 19건의 실제 CVE를 base 브랜치(`uv.lock`)에서 제거: Pillow `>=12.3.0`(2026 이미지 디코더 CVE 배치), pypdf `>=6.14.2`(파서 DoS CVE-2026-59935/59936/59937/59938), setuptools `>=83.0.0`(CVE-2026-59890), pymdown-extensions `>=11.0.1`(b64 확장 path traversal CVE-2026-61632). pymdown 11 해석을 위해 문서 전용 `mkdocs-material`을 `>=9.7,<9.8`로 올렸고 `mkdocs build --strict`가 통과함을 확인.

### Performance
- `newsdom_api.dom_builder._html_safe_text` 함수에 early return과 타입 체크를 도입하여 불필요한 `str()` 캐스팅을 제거함으로써 처리 속도를 개선했습니다.
Expand Down
13 changes: 9 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,15 @@ sync all extras so the docs build does not drop the test toolchain
from the active environment.

The supported docs toolchain stays on the MkDocs 1.x line for now.
Keep `mkdocs<2.0` and `mkdocs-material<9.7` in place until the
upstream Material team publishes a workable migration path or this
repository validates a replacement docs stack. `uv.lock` is the source
of truth for the currently supported docs build.
Keep `mkdocs<2.0` and `mkdocs-material<9.8` in place until the
upstream Material team publishes a workable migration path off MkDocs
1.x or this repository validates a replacement docs stack. The
`mkdocs-material` floor moved to 9.7 so the transitive
`pymdown-extensions` can resolve to `>=11.0.0`, the only line that
fixes the b64-extension path-traversal (CVE-2026-61632); Material
9.6.x caps `pymdown-extensions` at `~=10.2`. `mkdocs build --strict`
is validated green on the 9.7 line. `uv.lock` is the source of truth
for the currently supported docs build.

```bash
uv sync --frozen --all-extras
Expand Down
27 changes: 24 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,13 @@ dependencies = [
"pydantic>=2.9,<3.0",
"python-multipart>=0.0.31,<1.0",
"reportlab>=4.2,<6.0",
"Pillow>=11.0,<13.0",
"pypdf>=6.13.3,<7.0",
# Pillow floor pinned to the release that clears the 2026 image-decoder
# CVE batch (CVE-2026-54058/54059/54060/55379/55380/55798/59197-59205)
# flagged by the org trivy-fs gate; Pillow decodes untrusted uploaded PDFs.
"Pillow>=12.3.0,<13.0",
# pypdf floor pinned to the release that clears the 2026 parser DoS CVE
# batch (CVE-2026-59935/59936/59937/59938); pypdf validates untrusted PDFs.
"pypdf>=6.14.2,<7.0",
]

[project.optional-dependencies]
Expand All @@ -31,13 +36,29 @@ dev = [
]
docs = [
"mkdocs>=1.6,<2.0",
"mkdocs-material>=9.6,<9.7",
# Material 9.7 line: required so the transitive pymdown-extensions can
# resolve to >=11.0.0, the only release that fixes the b64-extension path
# traversal CVE-2026-61632 (Material 9.6.x caps pymdown-extensions at
# ~=10.2). Held at <9.8 to stay on a validated docs toolchain.
"mkdocs-material>=9.7,<9.8",
]
fuzz = [
"atheris==3.0.0 ; platform_system == 'Linux' and python_version >= '3.11'",
"pyinstaller==6.21.0",
]

# Security constraints for transitive dependencies (never added as runtime
# deps, only pinned in the resolution so the trivy-fs gate stays green):
# setuptools < 83.0.0 -> CVE-2026-59890 (MEDIUM)
# pymdown-extensions < 11.0 -> CVE-2026-61632 (MEDIUM, b64 path traversal)
# pymdown-extensions is a docs-only (mkdocs-material) dependency; 11.0.1 also
# picks up the later ReDoS fix (CVE-2026-67422).
[tool.uv]
constraint-dependencies = [
"setuptools>=83.0.0",
"pymdown-extensions>=11.0.1",
]

[tool.setuptools]
package-dir = { "" = "src", "tools" = "tools"}

Expand Down
31 changes: 26 additions & 5 deletions tests/test_project_metadata.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
"""Validate package metadata, lockfile invariants, and release constraints."""

from __future__ import annotations

from pathlib import Path
import re


def _locked_package_version(name: str) -> tuple[int, ...]:
"""Return a locked package version as an integer tuple."""

text = Path("uv.lock").read_text(encoding="utf-8")
match = re.search(
rf'\[\[package\]\]\nname = "{re.escape(name)}"\nversion = "([^"]+)"',
Expand All @@ -15,6 +19,8 @@ def _locked_package_version(name: str) -> tuple[int, ...]:


def _dependencies_section(text: str) -> str:
"""Extract the top-level project dependency array from TOML source text."""

marker = "dependencies = ["
if marker not in text:
raise AssertionError("pyproject.toml is missing a project dependencies section")
Expand Down Expand Up @@ -53,6 +59,8 @@ def _dependencies_section(text: str) -> str:


def _project_version(text: str) -> str:
"""Return the version declared specifically inside the project table."""

match = re.search(
r'^\[project\]\n(?:.*\n)*?^version = "([^"]+)"',
text,
Expand Down Expand Up @@ -113,9 +121,12 @@ def test_uv_lock_tracks_project_version() -> None:
assert lock_version.group(1) == pyproject_version


def test_docs_theme_range_stays_below_warning_release():
def test_docs_theme_range_pinned_to_validated_line():
# Material 9.7 is required so pymdown-extensions can resolve to >=11.0.0,
# the only line that fixes CVE-2026-61632; `mkdocs build --strict` is
# validated green on this range. Held at <9.8 as the next validated step.
text = Path("pyproject.toml").read_text(encoding="utf-8")
assert '"mkdocs-material>=9.6,<9.7"' in text
assert '"mkdocs-material>=9.7,<9.8"' in text


def test_docs_core_range_stays_below_mkdocs_two():
Expand All @@ -128,7 +139,7 @@ def test_contributing_documents_docs_toolchain_hold():
expected_phrases = [
"MkDocs 1.x",
"mkdocs<2.0",
"mkdocs-material<9.7",
"mkdocs-material<9.8",
"uv.lock",
"migration path",
]
Expand Down Expand Up @@ -167,5 +178,15 @@ def test_uv_lock_does_not_track_external_mineru_pipeline_runtime_stack():
assert '[[package]]\nname = "torch"' not in text


def test_uv_lock_pins_pypdf_at_patched_release():
assert _locked_package_version("pypdf") >= (6, 10, 0)
def test_uv_lock_pins_all_security_remediations():
"""Prevent vulnerable dependency versions from returning on lock refresh."""

patched_floors = {
"pillow": (12, 3, 0),
"pypdf": (6, 14, 2),
"pymdown-extensions": (11, 0, 1),
"setuptools": (83, 0, 0),
}

for package_name, minimum_version in patched_floors.items():
assert _locked_package_version(package_name) >= minimum_version
Loading
Loading