feat(phase-4): Task 1 — audit log backfill in auth.py and documents.py (D-13)

- Add write_audit_log import to auth.py and documents.py
- auth.py: login success (auth.login), login failure (auth.login_failed, no PII),
  logout (auth.logout), logout-all (auth.sign_out_all), change-password
  (auth.password_changed), TOTP enable (auth.totp_enrolled), TOTP disable
  (auth.totp_revoked), backup code used (auth.backup_code_used)
- documents.py: upload confirm (document.uploaded, size+backend only),
  document delete (document.deleted, size only — no filename/extracted_text)
- Add request: Request param to change_password, disable_totp, confirm_upload, delete_document
This commit is contained in:
curo1305
2026-05-25 21:48:15 +02:00
parent 2a0df32e92
commit e451b16f8f
2 changed files with 128 additions and 0 deletions
+32
View File
@@ -30,6 +30,7 @@ from db.models import Document, Quota, Share, User
from deps.auth import get_regular_user
from deps.db import get_db
from services import classifier, storage
from services.audit import write_audit_log
from storage import get_storage_backend
from tasks.document_tasks import extract_and_classify
@@ -95,6 +96,7 @@ async def request_upload_url(
@router.post("/{doc_id}/confirm")
async def confirm_upload(
doc_id: str,
request: Request,
session: AsyncSession = Depends(get_db),
current_user: User = Depends(get_regular_user),
):
@@ -173,6 +175,17 @@ async def confirm_upload(
used_bytes = row.used_bytes
doc.status = "uploaded"
# D-13: document uploaded event — size_bytes + storage_backend only, NO filename, NO extracted_text (T-04-07-02)
_ip = request.headers.get("X-Forwarded-For") or (request.client.host if request.client else None)
await write_audit_log(
session,
event_type="document.uploaded",
user_id=current_user.id,
actor_id=current_user.id,
resource_id=doc.id,
ip_address=_ip,
metadata_={"size_bytes": size, "storage_backend": "minio"},
)
await session.commit()
extract_and_classify.delay(str(doc.id))
@@ -340,6 +353,7 @@ async def get_document(
@router.delete("/{doc_id}")
async def delete_document(
doc_id: str,
request: Request,
session: AsyncSession = Depends(get_db),
current_user: User = Depends(get_regular_user),
):
@@ -360,9 +374,27 @@ async def delete_document(
if doc is None or doc.user_id != current_user.id:
raise HTTPException(404, "Document not found")
# Capture audit metadata before delete removes the row
_doc_size = doc.size_bytes
_doc_id = doc.id
_ip = request.headers.get("X-Forwarded-For") or (request.client.host if request.client else None)
ok = await storage.delete_document(session, doc_id)
if not ok:
raise HTTPException(404, "Document not found")
# D-13: document deleted event — written AFTER successful delete, size_bytes only (T-04-07-02)
await write_audit_log(
session,
event_type="document.deleted",
user_id=current_user.id,
actor_id=current_user.id,
resource_id=_doc_id,
ip_address=_ip,
metadata_={"size_bytes": _doc_size},
)
await session.commit()
return {"success": True}