fix(packs-lab): 일회성 토큰 jti 영속화 (SQLite) — 재시작 replay 방어 유지
인메모리 _used_jti set은 컨테이너 재시작 시 비워져 TTL 내 토큰 replay가 가능했음(webhook 배포가 잦아 실재 구멍). 영속 볼륨(PACK_BASE_DIR)의 jti_store.db에 사용 jti를 기록(PK 원자성), 만료 항목은 lazy 정리. verify_upload_token이 jti_store.consume 사용. TDD 3 + 기존 replay 테스트 보존. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
32
packs-lab/tests/test_jti_store.py
Normal file
32
packs-lab/tests/test_jti_store.py
Normal file
@@ -0,0 +1,32 @@
|
||||
"""jti_store — 영속(SQLite) 일회성 토큰 jti 저장소 단위 테스트."""
|
||||
import time
|
||||
|
||||
import pytest
|
||||
|
||||
from app import jti_store
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def _tmp_jti_db(tmp_path, monkeypatch):
|
||||
monkeypatch.setattr(jti_store, "JTI_DB_PATH", str(tmp_path / "jti.db"))
|
||||
|
||||
|
||||
def test_consume_new_jti_returns_true():
|
||||
assert jti_store.consume("new-jti", int(time.time()) + 600) is True
|
||||
|
||||
|
||||
def test_consume_duplicate_jti_returns_false():
|
||||
"""이미 사용된 jti 재consume → False (replay 차단). 파일 기반이라 재시작에도 생존."""
|
||||
exp = int(time.time()) + 600
|
||||
assert jti_store.consume("dup-jti", exp) is True
|
||||
assert jti_store.consume("dup-jti", exp) is False
|
||||
|
||||
|
||||
def test_expired_jti_cleaned_and_reusable():
|
||||
"""만료된 jti 항목은 정리되어 테이블이 무한 증식하지 않음.
|
||||
(만료 토큰 자체는 auth의 TTL 검사가 먼저 거부하므로 실사용엔 영향 없음.)"""
|
||||
past = int(time.time()) - 10
|
||||
assert jti_store.consume("exp-jti", past) is True # 만료시각으로 마킹
|
||||
future = int(time.time()) + 600
|
||||
# 다음 consume이 만료 항목을 정리 → 같은 jti 재INSERT 성공
|
||||
assert jti_store.consume("exp-jti", future) is True
|
||||
Reference in New Issue
Block a user