Skip to content

chore: 의존성 업그레이드 및 보안 취약점 해소 (npm audit 38 → 2) - #47

Merged
kyj0503 merged 6 commits into
mainfrom
chore/dependency-upgrades
Jul 31, 2026
Merged

chore: 의존성 업그레이드 및 보안 취약점 해소 (npm audit 38 → 2)#47
kyj0503 merged 6 commits into
mainfrom
chore/dependency-upgrades

Conversation

@kyj0503

@kyj0503 kyj0503 commented Jul 31, 2026

Copy link
Copy Markdown
Owner

개요

의존성 점검 결과에 따라 보안 취약점을 해소하고 오래된 패키지를 정리했습니다.
npm audit 38건(critical 4 / high 26) → 2건, BE는 yfinance를 1.x로 올렸습니다.

모든 검증은 compose.dev.yaml 컨테이너 안에서 실행했습니다.

커밋

커밋 내용
chore(be) pydantic 2.13.4, pydantic-settings 2.14.2, python-dotenv 1.2.2, yfinance 1.5.2
fix(fe) 보안 패치 — jspdf 4, vitest 4, @typescript-eslint 8 + lockfile 갱신
chore(fe) 미사용 jspdf/html2canvas 제거, gitignore 정리
chore(fe) eslint 8→10, flat config 마이그레이션
fix(fe) react-router-dom 6.30.4 → 7.18.2 + 라우팅 스모크 테스트
chore(infra) Docker 실행에 필요한 환경변수 설정 문서화

판단이 필요했던 지점

1. yfinance 0.2 → 1.x 에서 백테스트 수치가 바뀌는가 → 아니오

가장 큰 리스크는 1.x에서 바뀐 auto_adjust 기본값이었습니다. 호출부
(app/utils/data_fetcher.py:121,123)가 auto_adjust=True명시적으로
전달하고 있어 영향을 받지 않습니다.

실측으로 확인했습니다. 컨테이너에서 yfinance를 0.2.65로 되돌려 동일 구간
(AAPL, 005930.KS / 2023-01-01~06-30) 종가를 대조:

  • 바 개수·날짜 완전 일치 (AAPL 123봉, 삼성전자 122봉)
  • 종가 최대 상대차 0.000034% — 부동소수점 오차 수준

2. react-router 7 업그레이드로 audit 숫자가 나빠 보임 → 실질 위험은 개선

2 moderate → 2 high로 숫자만 보면 악화지만 내용이 다릅니다.

  • 해소: Open redirect via backslash in <Link>/useNavigate (+ XSS 연계).
    이 앱은 <Link>와 클라이언트 라우팅을 쓰므로 실제 노출되던 경로
  • 신규: RSC 모드 CSRF 우회 (범위 7.12.0 - 8.2.0). 이 앱은 BrowserRouter
    선언형 SPA로 createBrowserRouter도 RSC/프레임워크 모드도 쓰지 않음 (참조 0건 확인).
    타지 않는 경로

두 권고를 모두 피하는 버전은 현재 존재하지 않습니다 (7.11 이하는 open redirect,
7.12 이상은 RSC 권고, 7.18.2가 최신). npm이 제안하는 "fix"인 7.11.0은
open redirect를 되살리는 다운그레이드입니다. 실질 위험 기준으로 7.18.2를 택했습니다.

3. eslint-plugin-react-hooks v7 의 recommended 프리셋은 v4와 동등하지 않음

v7 프리셋은 React Compiler 규칙 약 27개를 추가로 켭니다. 그대로 썼다면 lint 결과가
크게 달라졌을 것이라, rules-of-hooks(error)와 exhaustive-deps(warn) 두 개만
명시해 규칙 동등성을 유지했습니다. React Compiler 도입은 별도 판단 사안이라 제외했습니다.

유지한 제약

backtesting==0.3.3 핀과 그에 묶인 bokeh 2.4.3 / numpy<2 / pandas<3
그대로 뒀습니다 (CLAUDE.md 제약 2번). 0.6.6은 결과 수치가 달라지므로 회귀 검증이
선행되어야 합니다.

React 18→19, recharts 2→3, tailwindcss 3→4 도 범위에서 제외했습니다.
보안 사유가 없고 대시보드 UI 전반의 회귀 확인이 필요합니다.

검증

항목 결과
BE pytest tests/unit 141 passed
BE pytest tests/integration 16 passed
POST /api/v1/backtest 200 (AAPL 2023 상반기 +55.2%)
FE npm run test:run 99 passed / 4 failed
FE npm run type-check 통과
FE npm run build 성공
dev 서버 be 200 / fe 200
npm audit 38 → 2 (critical 4 → 0)

알려진 이슈 (이 PR 범위 밖)

  • FE 테스트 4건이 실패합니다. 이 작업 이전부터 실패하던 것으로
    portfolioCalculations.test.ts 3건, ThemeSelector.test.tsx 1건입니다.
    회귀가 아니며 순증 0입니다.
  • npm run lint가 74건(67 errors, 7 warnings)으로 실패합니다.
    기존 no-explicit-any 위반이며, eslint 6 / 8 / 10 세 조건에서 동일하게
    측정되어 이번 변경과 무관함을 확인했습니다. 별도 정리 과제입니다.
  • Playwright e2e는 컨테이너에 브라우저가 없어 실행하지 않았습니다.
    라우팅 검증은 추가한 스모크 테스트(5건)로 대체했습니다.
  • CI가 Jenkins라 이 PR에서 자동 검증이 돌지 않습니다. 위 결과는 로컬 컨테이너 실행분입니다.

🤖 Generated with Claude Code

kyj0503 and others added 6 commits August 1, 2026 02:17
- pydantic 2.11.7 → 2.13.4
- pydantic-settings 2.1.0 → 2.14.2
- python-dotenv 1.0.0 → 1.2.2
- yfinance 0.2.65 → 1.5.2

yfinance는 메이저 업그레이드지만 호출부(app/utils/data_fetcher.py)가
auto_adjust=True를 명시적으로 전달하고 있어, 1.x에서 바뀐 기본값의
영향을 받지 않는다. AAPL/005930.KS 2023-01-01~2023-06-30 구간을
0.2.65와 1.5.2로 각각 조회해 비교한 결과 바 개수·날짜 동일,
종가 최대 상대차 0.000034% (부동소수점 오차 수준)로 확인했다.

backtesting==0.3.3 핀과 그에 묶인 bokeh/numpy/pandas 제약은 유지한다.

검증: pytest tests/unit 141 passed, tests/integration 16 passed,
POST /api/v1/backtest 200 OK.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
lockfile 갱신 (package.json range 내에서 해결):
- react-router-dom → 6.30.4 (XSS via Open Redirect)
- axios → 1.19.0 (SSRF NO_PROXY 우회, 프로토타입 오염 인증 우회)
- vite → 7.3.6 (Path Traversal, server.fs.deny 우회)
- postcss → 8.5.25 (XSS, 임의 파일 읽기)
- happy-dom → 20.11.1 (cross-origin 쿠키 유출)
- 전이 의존성: ws, lodash, minimatch, brace-expansion, form-data,
  glob, rollup, tmp, js-yaml, yaml, picomatch, flatted, path-to-regexp

메이저 업그레이드 (3.x/6.x에 패치 없음):
- jspdf ^3.0.3 → ^4.2.1 (CRITICAL: LFI/Path Traversal, PDF Injection)
- vitest, @vitest/ui, @vitest/coverage-v8 ^3.2.4 → ^4.1.10
  (CRITICAL: UI 서버 구동 시 임의 파일 읽기/실행)
- @typescript-eslint/{eslint-plugin,parser} ^6.0.0 → ^8.65.0

vitest 4 대응:
- vitest.config.ts: poolOptions.forks.singleFork 제거됨
  → maxWorkers: 1 + isolate: false 로 대체
- src/test/setup.ts: vi.fn() 화살표 함수는 new 호출 불가하므로
  IntersectionObserver/ResizeObserver 목을 class로 변경.
  happy-dom이 window.alert/confirm/prompt를 구현하지 않아
  vi.spyOn 대상이 되도록 no-op 스텁 추가.

@typescript-eslint 8 대응:
- LatestNewsSection.tsx: 미사용 catch 파라미터 제거

npm audit: 38건(critical 4/high 26) → 11건(critical 0/high 9).
남은 9건은 모두 eslint 8에서 파생되며 eslint 10 메이저가 필요해
다음 단계로 미룬다.

검증: test:run 94 passed(기존 실패 4건 동일, 회귀 없음),
type-check 통과, build 성공. lint 실패 74건은 @typescript-eslint 6에서도
동일하게 재현되는 기존 문제로 이번 변경과 무관.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
jspdf와 html2canvas는 소스 어디에서도 import되지 않는 죽은 의존성이다.
(src/, e2e/, __tests__/ 전체에서 참조 0건 — package.json에만 존재)
직전 커밋에서 jspdf를 4.2.1로 올려 CRITICAL을 해소했지만,
애초에 사용하지 않으므로 제거하는 편이 낫다. 21개 패키지가 함께 정리된다.

.gitignore에 .idea/ 와 .DS_Store 추가.

검증: test:run 94 passed(기존 실패 4건 동일), type-check 통과, build 성공.
npm audit 11건 유지(critical 0).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- eslint ^8.45.0 → ^10.8.0
- eslint-plugin-react-hooks ^4.6.0 → ^7.1.1
- eslint-plugin-react-refresh ^0.4.3 → ^0.5.3
- package.json의 eslintConfig 블록 제거 → eslint.config.js 신규 작성
- flat config에는 --ext가 없으므로 lint/lint:fix 스크립트에서 제거하고
  대상 지정은 config의 files 글롭으로 이관. dist/coverage 등은 ignores로 명시.

react-hooks v7의 recommended 프리셋은 React Compiler 규칙 약 27개를
추가로 켜기 때문에 v4와 동등하지 않다. 규칙 동등성을 유지하려고
rules-of-hooks(error)와 exhaustive-deps(warn) 두 개만 명시적으로 지정했다.

npm audit 11건(high 9, moderate 2) → 2건(moderate 2).
high 9건은 전부 eslint 8 의존 트리의 brace-expansion
GHSA-mh99-v99m-4gvg 하나에서 파생된 것으로 이번 업그레이드로 해소됐다.
남은 moderate 2건은 react-router로 6.x에 패치가 없어 7.x 업그레이드가 필요하다.

검증: lint 74 problems(67 errors, 7 warnings) — 마이그레이션 전과 정확히 동일.
검사 파일 156개, 규칙별 내역도 no-explicit-any 65 / exhaustive-deps 7 /
prefer-const 2로 일치하여 flat config가 대상을 누락하지 않음을 확인했다.
test:run 94 passed(기존 실패 4건 동일), type-check 통과, build 성공,
dev 서버 200.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
6.x에는 패치가 없는 취약점을 해소한다:
- Open redirect via backslash in <Link>/useNavigate (GHSA-wrjc-x8rr-h8h6)
- Open redirect leading to XSS (react-router-dom)
취약 범위가 6.0.0 - 7.17.0 이라 7.18 이상이 유일한 해결책이다.

미사용 @types/react-router-dom(^5.3.3) 제거 — v6부터 자체 타입을 제공한다.

앱은 BrowserRouter/Routes/Route/Navigate/Link/useLocation만 사용하는
선언형 라우팅이라 v7 breaking change에 걸리는 부분이 없어 소스 수정은 없었다.
다만 단위 테스트가 라우팅을 거의 검증하지 않아, 라우트 매칭 /
<Navigate> 리다이렉트 / <Link> 내비게이션을 확인하는 스모크 테스트를 추가했다.

주의 — npm audit은 2 moderate → 2 high로 숫자가 나빠 보이지만
내용이 다르다. 7.12.0 이상에 RSC 모드 CSRF 우회 권고가 새로 붙었는데,
이 앱은 RSC/프레임워크 모드를 쓰지 않는 클라이언트 SPA라 해당 경로를
타지 않는다. 반대로 해소된 open redirect는 <Link>/useNavigate를 통해
실제로 노출되던 문제다. 현재 react-router에는 두 권고를 모두 피하는
버전이 존재하지 않는다(7.11 이하는 open redirect, 7.12 이상은 RSC 권고).
실질 위험 기준으로 7.18.2가 낫다고 판단했다.

검증: test:run 99 passed(신규 라우팅 5건 포함, 기존 실패 4건 동일),
lint 74 problems 동일, type-check 통과, build 성공, dev 서버 200.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
compose.dev.yaml로 스택을 띄우려면 저장소 루트에 .env가 필요한데
해당 샘플이 없어 처음부터 재현이 불가능했다. 두 가지 문제가 있었다.

1. mysql 서비스에 MYSQL_ROOT_PASSWORD가 없어 컨테이너가 기동하지 않고,
   MYSQL_USER/MYSQL_PASSWORD도 없어 DATABASE_USER로 지정한 계정이
   생성되지 않았다. → environment에 기본값과 함께 추가.
   .env에 MYSQL_* 키가 없어도 로컬 개발 기본값으로 동작한다.
   (.env 파일 자체는 env_file 지시자 때문에 여전히 필수)

2. 루트 .env.example 신규 작성.
   기존 backtest_be_fast/.env.example은 네이티브 실행용이라
   Docker에 필요한 MYSQL_*, VITE_API_BASE_URL, API_PROXY_TARGET,
   FASTAPI_PROXY_TARGET 키가 없었다. DATABASE_HOST가 localhost가 아닌
   서비스명 mysql이어야 한다는 점, 프록시 대상이 backtest-be-fast여야
   한다는 점을 주석으로 명시했다.

backtest_be_fast/.env.example에는 앱이 실제로 읽는 백테스팅 설정 키를
보완하고, Docker 실행 시 루트 샘플을 쓰라는 안내를 추가했다.
README의 Docker 실행 절차에도 cp .env.example .env 단계를 넣었다.

검증: .env에서 MYSQL_* 를 제거한 상태로 docker compose config 실행 시
기본값으로 해석되는 것을 확인했고, 동일한 환경변수 조합으로 mysql:8.0을
격리 기동해 appuser 접속과 schema.sql 적재(daily_prices, stock_news,
stocks)까지 확인했다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 31, 2026 17:50
@kyj0503
kyj0503 merged commit a2b640f into main Jul 31, 2026
1 check passed
@kyj0503
kyj0503 deleted the chore/dependency-upgrades branch July 31, 2026 17:50

Copilot AI 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.

Pull request overview

의존성 점검 결과를 반영해 FE/BE의 주요 패키지를 업그레이드하고, 로컬 Docker 개발 환경에서 필요한 환경변수 설정을 문서화하여 npm audit 취약점을 크게 줄이려는 PR입니다. 백테스트 플랫폼의 런타임/테스트/린트 도구체인을 최신화하면서도(특히 FE의 vitest/eslint/react-router, BE의 fastapi/pydantic/yfinance) 기존 제약(backtesting==0.3.3 등)은 유지합니다.

Changes:

  • FE: react-router-dom v7 업그레이드에 맞춰 라우팅 스모크 테스트 추가, Vitest 4 설정/해피돔 스텁 보강, ESLint 10 flat config로 마이그레이션
  • BE: FastAPI/Pydantic 및 yfinance(1.5.2) 등 핵심 의존성 업그레이드
  • Infra/Docs: compose.dev.yaml의 MySQL 기본 env 보강 및 루트 .env.example/README로 로컬 Docker 실행 절차 문서화

Reviewed changes

Copilot reviewed 11 out of 13 changed files in this pull request and generated no comments.

Show a summary per file
File Description
README.md Docker 실행 시 루트 .env 준비 절차를 명시해 로컬 실행 가이드 보강
compose.dev.yaml MySQL 컨테이너가 .env 일부 키 누락 시에도 기동 가능하도록 기본값 추가
backtest_fe/vitest.config.ts Vitest 4 변경사항 반영(poolOptions 제거) 및 단일 워커/비격리 실행 설정
backtest_fe/src/test/setup.ts happy-dom 환경에서 alert/confirm/prompt 및 Observer 모킹을 Vitest 4에 맞게 보강
backtest_fe/src/features/backtest/components/results/LatestNewsSection.tsx 불필요한 catch (error) 바인딩 제거로 코드 정리
backtest_fe/src/tests/routing.test.tsx react-router-dom v7 마이그레이션 안전장치로 라우팅 스모크 테스트 신규 추가
backtest_fe/package.json FE 의존성 업그레이드(react-router-dom/vitest/eslint/@typescript-eslint 등) 및 미사용 패키지 제거
backtest_fe/eslint.config.js ESLint 10 flat config 도입 및 기존 규칙 동등성 유지(react-hooks는 명시 규칙)
backtest_be_fast/requirements.txt BE 의존성 업그레이드(FastAPI/Pydantic/yfinance 등), backtesting==0.3.3 핀 유지
backtest_be_fast/.env.example 도커/네이티브 환경변수 샘플 사용처를 명확히 하는 주석 보강
.gitignore IDE(macOS/IntelliJ) 산출물 무시 규칙 추가
.env.example compose.dev.yaml 구동을 위한 루트 .env 샘플 신규 추가

kyj0503 added a commit that referenced this pull request Aug 2, 2026
#47·#48·#49로 스택과 검증 체계가 바뀌었는데 문서가 따라가지 못했다.
실측한 값으로만 갱신했고, 문서에 적은 명령·경로·수치는 모두 실행해
존재를 확인했다.

## 사실과 달랐던 것

- backtest_fe/README.md: React 18 표기(실제 19), 테스트 13파일/98건
  (실제 16/113), 커버리지 17.13%(실제 21.81%), 존재하지 않는
  src/components/ 디렉터리 설명, shared 파일 수 불일치,
  끊긴 링크 4개(TEST.md 등 모두 부재)
- backtest_fe/docs/testing/execution.md: 설정 파일을 vite.config.ts로
  안내(실제 vitest.config.ts), 환경을 jsdom으로 안내(실제 happy-dom)
- backtest_be_fast/tests/README.md: 총 68건(실제 141건)
- UNIT_TEST_QUICK_REFERENCE.md: 파일별 개수 3건 불일치,
  하드코딩된 타인 절대경로(/home/coontec/...), venv 기반 실행 안내,
  실제와 다른 CI 예시(GitHub Actions/venv)
- TEST_COVERAGE_SUMMARY.md: 파일별 개수 3건 불일치, venv 실행 안내
  (합계 59건은 이 문서가 다루는 4개 모듈 기준으로 지금도 정확해 유지)
- README.md(루트): backtest_fe/__tests__/ 구조(이제 src 안으로 이동),
  스택 버전 미표기

## 새로 담은 것

- CI Quality Gate의 존재와 재현 방법(docker build --target test)
- 게이트가 배포는 막지만 병합은 막지 않는다는 점(브랜치 보호 미사용)
- type-check와 type-check:test의 분리 이유
- lint 경고 상한 3이 래칫이라는 점과 목표
- Tailwind 4 제약(설정이 index.css, @theme에 색상 리터럴 금지,
  .app-container)
- vitest isolate:false 금지 이유
- FE build의 NODE_ENV=production 고정 이유
- VITE_API_BASE_URL을 비워야 하는 계약
- build:analyze가 현재 실질적으로 build와 동일하다는 주의

CLAUDE.md와 .github/copilot-instructions.md에는 위 제약들을 에이전트가
반복해서 밟지 않도록 명시했다.

BE 문서 2건은 편집 과정에서 CRLF가 LF로 바뀌어 원래 개행으로 되돌렸다.
코드 변경은 없다(마크다운만).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.

2 participants