Skip to content
Draft
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
8 changes: 8 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ in this repo.
- A local `trivy` scan with a stale DB misses findings: run
`trivy --download-db-only` first, and scan the **merge ref**, not just the PR
head.
- Repo-wide dependency findings belong in a dedicated `develop`-root security
owner PR. Do not mix lock repair into an unrelated product/UI PR or add dummy
source comments merely to retrigger a scanner; stack affected PRs on the
verified owner repair instead.
- The org `code_scanning` ruleset is intentionally **CodeQL-only** (multiple
code-scanning tools can't converge on one PR ref). Gating is enforced by the
Security Scan **job result**, not by that rule — do **not** add Trivy,
Expand Down Expand Up @@ -476,6 +480,10 @@ in this repo.
- Icon-only workspace controls must carry localized `aria-label` text matching
the visible app language; do not rely on the SVG icon alone for Calendar,
Tasks, drawer, modal, or toolbar actions.
- React component tests must wrap state-changing input events and asynchronous
source-registry loading in awaited `act()` before assertions or cleanup. A
passing Vitest/JUnit assertion count does not clear `not wrapped in act`
warnings; retain a runtime console-warning assertion without suppressing logs.
- Execution steps resulting in `Timeout`, `Fatal`, `Warn`, or `Denied` outputs are considered hard failures. Tests must run without these warnings to be considered passing.
- Strix success artifacts must also be scanned for `Timeout`, `Fatal`, `Warn`,
or `Denied` output before accepting clean evidence. Filter only narrowly known
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
## [Unreleased]
- 기존 보안 의존성 owner #1828의 잔여 잠금을 수선했습니다. 프런트엔드는 Vitest 계열 `4.1.11`, brace-expansion `5.0.12`, js-yaml `4.3.2`, undici `8.10.2`로 갱신하고, 별도 Strix 잠금은 aiohttp `3.14.3`, LiteLLM `1.89.7`, PyJWT `2.15.0`, urllib3 `2.8.0`으로 고정했습니다. 메일 입력 이벤트와 일정 원본 로딩을 기다리지 않던 테스트의 React act 경고도 로그 억제 없이 해결했습니다. 미패치 `braces 3.0.3` High advisory와 미실행 hosted gate가 남아 있어 배포·병합 완료로 보지 않습니다.
- Security owner 후속 수선으로 PyJWT `2.15.0`과 urllib3 `2.8.0`을 manifest·uv lock·pip hash lock에 함께 고정했습니다. 이는 exact-head Security Scan run `36804726949`가 PyJWT CVE-2026-101918과 urllib3 CVE-2026-97687/97688/97689를 검출한 뒤의 canonical-owner repair이며, unrelated consumer PR은 이 owner 계보를 ordinary merge로 소비합니다. PyJWT 2.15가 빈 JWKS fixture를 fail-closed한 Application CI 후속 실패는 빈 key set 허용으로 우회하지 않고, transport 테스트를 파싱 가능한 익명 RS256 공개키 fixture로 교정했습니다.
- Security Scan의 repo-wide Trivy 실패를 공통 `develop` 원인으로 수선했습니다. PyJWT `2.14.0`, AnyIO `4.15.1`, oauthlib `4.0.0`, Next.js/`eslint-config-next` `16.3.6`, Sharp `0.35.4`를 manifest·uv/pip hash lock·pnpm lock에 함께 고정하고, AnyIO 4.15의 deprecated alias를 제거한 Starlette `1.7.0`과 공식 TestClient 경로인 HTTPX2 `2.13.1`도 검증했습니다. optional Noema hash lock이 core lock의 HTTPX2/HTTPCore2를 구버전으로 중복 선언해 결합 설치를 깨뜨리던 후속 결함도 제거하고 두 lock의 package ownership이 겹치지 않는 실행 가능한 회귀 계약을 추가했습니다. 제품/UI PR에서 더미 주석으로 스캔을 재실행하거나 공통 잠금 수선을 섞는 대신 전용 owner PR을 사용합니다.
- 긴 이메일·첨부 본문을 의미 단위 청크로 임베딩한 뒤 기존 email/attachment 벡터 계약으로 평균화하고, 청크 요청·벡터 누적을 제한된 창으로 처리합니다. OpenAI `text-embedding-3-*`에는 저장 차원(`1536`)을 직접 요청하도록 보강했습니다. 합성 메일 fixture 5건(70청크)과 provider 요청 계약으로 1,536차원 벡터 경로를 검증했으며, 실행 시 선택한 임베딩 제공자에 본문·파싱된 첨부 텍스트를 전송할 수 있습니다. 회사 기밀 데이터는 fixture·commit·PR·log에 포함하지 않습니다.
- EmailDetail 테스트가 지원하지 않는 스레드 병합/분리 버튼을 `textContent`뿐 아니라 `aria-label`과 `title` 접근 가능 이름으로도 검출하도록 바꿔, 아이콘 전용 버튼 회귀를 놓치지 않습니다.

Expand Down
8 changes: 6 additions & 2 deletions backend/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description = "Naruon FastAPI backend"
requires-python = ">=3.12"
dependencies = [
"fastapi==0.139.0",
"starlette==1.3.1",
"starlette==1.7.0",
"uvicorn==0.51.0",
"httpx==0.28.1",
"pydantic-settings==2.14.2",
Expand Down Expand Up @@ -35,14 +35,18 @@ dependencies = [
"setuptools==83.0.0",
"wheel==0.47.0",
"websockets==16.1",
"PyJWT==2.13.0",
"PyJWT==2.15.0",
"anyio==4.15.1",
"oauthlib==4.0.0",
"urllib3==2.8.0",
"icalendar==7.2.0",
"defusedxml==0.7.1",
]

[dependency-groups]
dev = [
"coverage==7.15.1",
"httpx2==2.13.1",
"pytest==9.1.1",
"pytest-asyncio==1.4.0",
"ruff==0.15.21",
Expand Down
13 changes: 2 additions & 11 deletions backend/requirements-agent.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
# Pinned to the pydantic-ai 2.x line: services/noema_agent.py imports
# ``OpenAIChatModel`` from ``pydantic_ai.models.openai`` (renamed from
# ``OpenAIModel`` in 2.x) and constructs the model via ``OpenAIProvider``.
# Version 2.8.0 is the newest 2.x release compatible with the core
# requirements-hashes.txt pin of openai==2.44.0; 2.9.0 requires openai>=2.45.0.
# Shared packages are intentionally absent: the required combined install takes
# their exact versions and hashes from requirements-hashes.txt.
pydantic-ai-slim[openai]==2.9.0 \
--hash=sha256:11b812833eb75cfcc31c86b6e2db75e28cade6bb746844e28a40eb51b04a09d3 \
--hash=sha256:560a860cb67cf7732b16fb40e1d9205d75c02934e75e41db7ccb104ebc9ea266
Expand All @@ -24,19 +24,10 @@ genai-prices==0.0.71 \
griffelib==2.1.0 \
--hash=sha256:cc7b3d2d2865ad0b909fcc38086e3f554b5ea7acbaa7bbb7ecaa3f5dfb7d9f00
# via pydantic-ai-slim
httpcore2==2.5.0 \
--hash=sha256:5ce35188de461d31e8d000bfb8ef8bf22c6c16587a211e5571deaa5e9bdf842a
# via httpx2
httpx2==2.5.0 \
--hash=sha256:3d2d4d9cf4b61f1a1f46a95947cfdb47e80cb56a2f91c6256ac8f58e4891df41
# via genai-prices
logfire-api==4.37.0 \
--hash=sha256:1d756f8ba23aa56d438e0ba2c0f529a00fcac975b8785c561b058267f9465088
# via pydantic-graph
pydantic-graph==2.9.0 \
--hash=sha256:0ee8ad7b69d628037f3194d506b6c7099e416f25e477f9590da110cdaf48c649 \
--hash=sha256:a6d146cfd97b086e4334afc6717b2d078a3f102631cfe05e421fda2ca5a7046f
# via pydantic-ai-slim
truststore==0.10.4 \
--hash=sha256:adaeaecf1cbb5f4de3b1959b42d41f6fab57b2b1666adb59e89cb0b53361d981
# via httpcore2, httpx2
Loading
Loading