fix(hours_payouts): RLS-Bypass-Falle bei mid-request commit
Security Audit / Python Dependency Audit (push) Has been cancelled
Security Audit / Node.js Dependency Audit (push) Has been cancelled

_build_out() lief nach db.commit() -> app.bypass_rls verfällt mit
Transaktion, Post-Commit-Reads sahen keine Zeilen mehr. _build_out()
jetzt vor commit aufgerufen (create/request/approve/reject/cancel).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LTxkZEUdfgMxZvHPiZJ8bV
This commit is contained in:
2026-08-05 18:56:55 +02:00
co-authored by Claude Sonnet 5
parent 65596e80a4
commit 803e888638
2 changed files with 62 additions and 10 deletions
+50
View File
@@ -2636,3 +2636,53 @@ Keine Commits in dieser Session.
- server-update.sh | 14 ++++++++++---- - server-update.sh | 14 ++++++++++----
--- ---
## 2026-07-10 01:54 01:55 (0m)
**Beschreibung:** Claude Code Session
**Projekt:** custom-addons
### Commits
Keine Commits in dieser Session.
### Geänderte Dateien
- DEVLOG.md | 460 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- backend/DEVLOG.md | 13 ++++
- backend/app/models/company.py | 2 +
- backend/app/models/hours_payout.py | 17 ++++-
- backend/app/routers/hours_payouts.py | 280 +++++++++++++++++++++++++++++++++++++++++++++++--------------------
- backend/app/schemas/company.py | 2 +
- backend/app/schemas/hours_payout.py | 17 +++++
- backend/migrations/versions/0042_payout_requests.py | 36 +++++++++
- backend/tests/test_hours_payouts.py | 87 +++++++++++++++++++++
- frontend/DEVLOG.md | 39 ++++++++++
- frontend/src/components/PayoutRequestCard.tsx | 150 ++++++++++++++++++++++++++++++++++++
- frontend/src/pages/AbsencesPage.tsx | 3 +
- frontend/src/pages/CompanySettingsPage.tsx | 31 +++++++-
- frontend/src/pages/HoursPayoutPage.tsx | 82 +++++++++++++++++---
- frontend/src/types/hoursPayout.ts | 7 ++
---
## 2026-08-05 18:56 18:56 (0m)
**Beschreibung:** Claude Code Session
**Projekt:** timemaster
### Commits
Keine Commits in dieser Session.
### Geänderte Dateien
- DEVLOG.md | 460 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- backend/DEVLOG.md | 13 ++++
- backend/app/models/company.py | 2 +
- backend/app/models/hours_payout.py | 17 ++++-
- backend/app/routers/hours_payouts.py | 280 +++++++++++++++++++++++++++++++++++++++++++++++--------------------
- backend/app/schemas/company.py | 2 +
- backend/app/schemas/hours_payout.py | 17 +++++
- backend/migrations/versions/0042_payout_requests.py | 36 +++++++++
- backend/tests/test_hours_payouts.py | 87 +++++++++++++++++++++
- frontend/DEVLOG.md | 39 ++++++++++
- frontend/src/components/PayoutRequestCard.tsx | 150 ++++++++++++++++++++++++++++++++++++
- frontend/src/pages/AbsencesPage.tsx | 3 +
- frontend/src/pages/CompanySettingsPage.tsx | 31 +++++++-
- frontend/src/pages/HoursPayoutPage.tsx | 82 +++++++++++++++++---
- frontend/src/types/hoursPayout.ts | 7 ++
---
+12 -10
View File
@@ -118,6 +118,7 @@ async def create_payout(
) )
db.add(payout) db.add(payout)
await db.flush() await db.flush()
await db.refresh(payout) # server_default created_at noch in-Transaktion (RLS-Kontext da)
db.add(AuditLog( db.add(AuditLog(
company_id=current_user.company_id, user_id=current_user.id, company_id=current_user.company_id, user_id=current_user.id,
@@ -128,9 +129,9 @@ async def create_payout(
}, },
ip=get_client_ip(request), ip=get_client_ip(request),
)) ))
out = await _build_out(payout, db)
await db.commit() await db.commit()
await db.refresh(payout) return out
return await _build_out(payout, db)
# ── POST /hr/payouts/request (Mitarbeiter-Selbstbedienung) ──────────────────── # ── POST /hr/payouts/request (Mitarbeiter-Selbstbedienung) ────────────────────
@@ -161,6 +162,7 @@ async def request_payout(
) )
db.add(payout) db.add(payout)
await db.flush() await db.flush()
await db.refresh(payout) # server_default created_at noch in-Transaktion (RLS-Kontext da)
db.add(AuditLog( db.add(AuditLog(
company_id=current_user.company_id, user_id=current_user.id, company_id=current_user.company_id, user_id=current_user.id,
@@ -168,9 +170,9 @@ async def request_payout(
new_value={"hours": str(hours), "note": data.note}, new_value={"hours": str(hours), "note": data.note},
ip=get_client_ip(request), ip=get_client_ip(request),
)) ))
out = await _build_out(payout, db)
await db.commit() await db.commit()
await db.refresh(payout) return out
return await _build_out(payout, db)
# ── POST /hr/payouts/{id}/approve ───────────────────────────────────────────── # ── POST /hr/payouts/{id}/approve ─────────────────────────────────────────────
@@ -202,9 +204,9 @@ async def approve_payout(
new_value={"hours": str(payout.hours), "user_id": str(payout.user_id)}, new_value={"hours": str(payout.hours), "user_id": str(payout.user_id)},
ip=get_client_ip(request), ip=get_client_ip(request),
)) ))
out = await _build_out(payout, db)
await db.commit() await db.commit()
await db.refresh(payout) return out
return await _build_out(payout, db)
# ── POST /hr/payouts/{id}/reject ────────────────────────────────────────────── # ── POST /hr/payouts/{id}/reject ──────────────────────────────────────────────
@@ -235,9 +237,9 @@ async def reject_payout(
new_value={"rejection_reason": data.rejection_reason, "user_id": str(payout.user_id)}, new_value={"rejection_reason": data.rejection_reason, "user_id": str(payout.user_id)},
ip=get_client_ip(request), ip=get_client_ip(request),
)) ))
out = await _build_out(payout, db)
await db.commit() await db.commit()
await db.refresh(payout) return out
return await _build_out(payout, db)
# ── POST /hr/payouts/{id}/cancel (Antragsteller zieht zurück) ───────────────── # ── POST /hr/payouts/{id}/cancel (Antragsteller zieht zurück) ─────────────────
@@ -264,9 +266,9 @@ async def cancel_payout(
action="hours_payout_cancelled", entity_type="hours_payout", entity_id=payout.id, action="hours_payout_cancelled", entity_type="hours_payout", entity_id=payout.id,
ip=get_client_ip(request), ip=get_client_ip(request),
)) ))
out = await _build_out(payout, db)
await db.commit() await db.commit()
await db.refresh(payout) return out
return await _build_out(payout, db)
# ── DELETE /hr/payouts/{id} ─────────────────────────────────────────────────── # ── DELETE /hr/payouts/{id} ───────────────────────────────────────────────────