guardia-itsm/routers/audit.py
DESKTOP-TKLFCPRython bc85c5228a feat(itsm): Jira-like ITSM 시스템 구현
- FastAPI + SQLAlchemy(aiosqlite) 기반 SR 상태 머신
  (RECEIVED → PARSED → PENDING_APPROVAL → APPROVED → IN_PROGRESS
   → PENDING_PM_VALIDATION → COMPLETED / FAILED_ROLLBACK)
- PM 승인 워크플로우 (ApprovalFlow 테이블)
- SHA-256 해시 체인 감사 로그 (위변조 방지)
- AES-256-GCM 서버 자격증명 암호화 (IP/PW API 미노출)
- CMDB: 기관(MOF/MOIS/MSS) + 서버 정보 관리
- 더미 데이터 자동 시딩 (6개 SR, 3개 기관, 6개 서버)
- Dark-theme SPA: 대시보드 / 칸반 보드 / SR 목록 / 감사 로그 / CMDB

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 19:31:09 +09:00

56 lines
1.6 KiB
Python

"""Audit log endpoints with hash-chain verification."""
import hashlib
import json
from typing import List, Optional
from fastapi import APIRouter, Depends, Query
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from database import get_db
from models import AuditLog, AuditLogOut
router = APIRouter(prefix="/api/audit", tags=["audit"])
@router.get("", response_model=List[AuditLogOut])
async def list_audit_logs(
sr_id: Optional[str] = Query(None),
skip: int = 0,
limit: int = 100,
db: AsyncSession = Depends(get_db),
):
q = select(AuditLog).order_by(AuditLog.created_at.desc())
if sr_id:
q = q.where(AuditLog.sr_id == sr_id)
q = q.offset(skip).limit(limit)
result = await db.execute(q)
return result.scalars().all()
@router.get("/verify")
async def verify_chain(db: AsyncSession = Depends(get_db)):
"""Verify SHA-256 hash chain integrity."""
result = await db.execute(select(AuditLog).order_by(AuditLog.id))
logs = result.scalars().all()
broken_at: Optional[int] = None
for log in logs:
payload = json.dumps(
{"prev": log.prev_hash or "", "actor": log.actor or "",
"action": log.action,
"detail": log.detail or "",
"ts": log.created_at.isoformat() if log.created_at else ""},
ensure_ascii=False, sort_keys=True
)
expected = hashlib.sha256(payload.encode()).hexdigest()
if expected != log.log_hash:
broken_at = log.id
break
return {
"total": len(logs),
"intact": broken_at is None,
"broken_at_id": broken_at,
}