feat: gated deploy with preview, audit log, rollback trail (stage 4)
- pulp_client: create_publication / update_distribution / wait_for_task
- GET /repos/{uuid}/deploy/confirm: 미리보기(현재→대상, 순 변화) + type-to-confirm 모달
- POST /repos/{uuid}/deploy: 검증 게이트(서버측 재확인) → publication 생성 →
distribution 교체 → 감사 로그. 2단계 실패 시 '운영망 변경 여부' 명확화
- audit.record_deploy: 누가/언제/repo/이전버전→대상버전 JSONL (롤백 추적)
- 배포 버튼은 검증 통과 + 미배포 버전만 활성, 성공 시 버전목록 OOB 갱신
- 인증은 TODO (operator placeholder, 배포 비밀번호 재확인 예정)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
37
app/audit.py
Normal file
37
app/audit.py
Normal file
@@ -0,0 +1,37 @@
|
||||
"""배포 확정 감사 로그 (스펙 §5-2).
|
||||
|
||||
누가 / 언제 / 어떤 repo 를 / 어떤 버전으로 배포했는지 append-only JSONL 로 남긴다.
|
||||
이전 버전(from_version)도 기록해 사고 시 롤백 대상을 즉시 파악할 수 있게 한다.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from datetime import datetime, timezone
|
||||
from typing import Any
|
||||
|
||||
from .config import get_settings
|
||||
|
||||
|
||||
def record_deploy(
|
||||
*,
|
||||
repo_uuid: str,
|
||||
repo_name: str,
|
||||
from_version: int | None,
|
||||
to_version: int | None,
|
||||
publication_href: str,
|
||||
operator: str = "operator", # TODO(auth): 로그인 도입 시 실제 사용자. 배포 시 비밀번호 재확인 예정.
|
||||
) -> dict[str, Any]:
|
||||
entry = {
|
||||
"ts": datetime.now(timezone.utc).isoformat(),
|
||||
"action": "deploy",
|
||||
"operator": operator,
|
||||
"repo_uuid": repo_uuid,
|
||||
"repo_name": repo_name,
|
||||
"from_version": from_version,
|
||||
"to_version": to_version,
|
||||
"publication": publication_href,
|
||||
}
|
||||
with open(get_settings().audit_log_path, "a", encoding="utf-8") as fh:
|
||||
fh.write(json.dumps(entry, ensure_ascii=False) + "\n")
|
||||
return entry
|
||||
Reference in New Issue
Block a user