refactor: audit log to Postgres + split /healthz liveness from Pulp status

- audit.record_deploy 를 JSONL 파일 → Postgres deploy_audit 테이블로 (재배포 휘발 방지)
  - psycopg 지연 import, _write 는 테스트에서 monkeypatch 지점, DATABASE_URL 사용
  - 감사 기록 실패는 배포 완료를 막지 않고 UI 경고(audit_ok)
- /healthz: Pulp 무관 라이브니스 {"ok":true} (컨테이너 health check),
  Pulp 연결 배지는 /pulp-status 로 분리 (대시보드가 폴링)
- config: DATABASE_URL 추가, audit_log_path 제거

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-17 13:42:11 +09:00
parent 7ad6d65a11
commit aef4124da0
8 changed files with 95 additions and 35 deletions

View File

@@ -1,8 +1,5 @@
import json
from fastapi.testclient import TestClient
from app.config import get_settings
from app.main import app, get_pulp_client
client = TestClient(app)
@@ -141,9 +138,10 @@ def test_deploy_distribution_failure_reported():
assert "운영망 변경에 실패" in resp.text
def test_deploy_success_writes_audit_and_refreshes_list(tmp_path, monkeypatch):
monkeypatch.setenv("AUDIT_LOG_PATH", str(tmp_path / "audit.jsonl"))
get_settings.cache_clear()
def test_deploy_success_writes_audit_and_refreshes_list(monkeypatch):
# 감사 DB 쓰기는 _write 를 가로채 캡처(실 DB 불필요)
records = []
monkeypatch.setattr("app.audit._write", lambda entry: records.append(entry))
fake = _FakePulp()
_use(fake)
@@ -159,9 +157,21 @@ def test_deploy_success_writes_audit_and_refreshes_list(tmp_path, monkeypatch):
"/pulp/api/v3/publications/rpm/rpm/new/",
)
# 감사 로그: from=2, to=3, repo 이름 기록
entry = json.loads((tmp_path / "audit.jsonl").read_text(encoding="utf-8").strip())
assert entry["action"] == "deploy"
assert entry["from_version"] == 2
assert entry["to_version"] == 3
assert entry["repo_name"] == "rocky9-baseos"
# 감사 기록: from=2, to=3, repo 이름
assert len(records) == 1
assert records[0]["from_version"] == 2
assert records[0]["to_version"] == 3
assert records[0]["repo_name"] == "rocky9-baseos"
def test_deploy_succeeds_but_flags_when_audit_fails(monkeypatch):
def _boom(entry):
raise RuntimeError("DATABASE_URL 미설정")
monkeypatch.setattr("app.audit._write", _boom)
_use(_FakePulp())
resp = _post("rocky9-baseos")
# 배포는 이미 완료 → 200 이되, 감사 기록 실패를 UI 에 경고
assert resp.status_code == 200
assert "배포 완료" in resp.text
assert "감사 로그 기록 실패" in resp.text

View File

@@ -16,20 +16,27 @@ class _FakeDown:
raise httpx.ConnectError("connection refused")
def test_healthz_online():
def test_healthz_is_liveness_always_ok():
# Pulp 와 무관하게 앱 생존만 본다 → 항상 200 {"ok": true}
resp = client.get("/healthz")
assert resp.status_code == 200
assert resp.json() == {"ok": True}
def test_pulp_status_online():
app.dependency_overrides[get_pulp_client] = lambda: _FakeOnline()
try:
resp = client.get("/healthz")
resp = client.get("/pulp-status")
finally:
app.dependency_overrides.clear()
assert resp.status_code == 200
assert "연결됨" in resp.text
def test_healthz_offline_when_pulp_down():
def test_pulp_status_offline_returns_503():
app.dependency_overrides[get_pulp_client] = lambda: _FakeDown()
try:
resp = client.get("/healthz")
resp = client.get("/pulp-status")
finally:
app.dependency_overrides.clear()
assert resp.status_code == 503