fix(tests): re-set RLS bypass per transaction in coverage gap tests
Security Audit / Python Dependency Audit (push) Canceled after 0s
Security Audit / Node.js Dependency Audit (push) Canceled after 0s
Security Audit / Frontend Build (tsc + vite) (push) Canceled after 0s

SET LOCAL app.bypass_rls only holds for the current transaction; a prior
commit() silently re-enabled RLS, causing db.get(User/Company, ...) to
return None on the raw db_session (no app.company_id context).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015Ahyx6D3r7G1EuAc42nezn
This commit is contained in:
2026-09-02 23:31:20 +02:00
co-authored by Claude Sonnet 5
parent dc4982bb37
commit 21b65087d3
+11 -2
View File
@@ -127,7 +127,6 @@ async def test_carryover_expiry_via_create_absence(
user_id = cov_company["user"]["id"] user_id = cov_company["user"]["id"]
year = date.today().year year = date.today().year
user = await db_session.get(User, user_id)
# Firma: Verfallsdatum in der Vergangenheit setzen (z.B. 31.01. dieses Jahr) # Firma: Verfallsdatum in der Vergangenheit setzen (z.B. 31.01. dieses Jahr)
r = await client.patch("/api/v1/companies/me", json={ r = await client.patch("/api/v1/companies/me", json={
@@ -135,9 +134,16 @@ async def test_carryover_expiry_via_create_absence(
}, headers=cov_headers) }, headers=cov_headers)
assert r.status_code == 200, r.text assert r.status_code == 200, r.text
# RLS-Bypass gilt nur innerhalb der aktuellen Transaktion (SET LOCAL) -- muss
# daher vor JEDER Query auf diesem "rohen" db_session (ohne app.company_id-
# Kontext eines eingeloggten Requests) neu gesetzt werden, siehe
# project_rls_bypass_commit_pitfall in Memory.
await db_session.execute(text("SET LOCAL app.bypass_rls = 'on'"))
user = await db_session.get(User, user_id)
assert user is not None
# VacationBalance direkt präparieren: wenig entitled, hoher (verfallener) Übertrag, # VacationBalance direkt präparieren: wenig entitled, hoher (verfallener) Übertrag,
# kaum genutzt -> ohne Verfalls-Logik würde das Konto "reichen" # kaum genutzt -> ohne Verfalls-Logik würde das Konto "reichen"
await db_session.execute(text("SET LOCAL app.bypass_rls = 'on'"))
balance = await db_session.scalar( balance = await db_session.scalar(
select(VacationBalance).where(VacationBalance.user_id == user_id, VacationBalance.year == year) select(VacationBalance).where(VacationBalance.user_id == user_id, VacationBalance.year == year)
) )
@@ -485,6 +491,9 @@ async def test_datev_holiday_takes_precedence_over_vacation(
approve = await client.post(f"/api/v1/absences/{data['id']}/approve", headers=approver_headers) approve = await client.post(f"/api/v1/absences/{data['id']}/approve", headers=approver_headers)
assert approve.status_code == 200, approve.text assert approve.status_code == 200, approve.text
# RLS-Bypass gilt nur innerhalb der aktuellen Transaktion (SET LOCAL) -- der
# vorherige Bypass ist mit dem commit() oben verfallen.
await db_session.execute(text("SET LOCAL app.bypass_rls = 'on'"))
sheet = await report_service.datev_monthly_report(company_id, user_id, 2027, 1, db_session) sheet = await report_service.datev_monthly_report(company_id, user_id, 2027, 1, db_session)
jan1_row = next(row for row in sheet.rows if row.day == 1) jan1_row = next(row for row in sheet.rows if row.day == 1)
assert jan1_row.code == "F", f"Feiertag muss Vorrang vor Urlaubs-Kürzel haben, got code={jan1_row.code!r}" assert jan1_row.code == "F", f"Feiertag muss Vorrang vor Urlaubs-Kürzel haben, got code={jan1_row.code!r}"