RUNTIME BUG (caught by live smoke tests): the global auth dependency queried the request-scoped session, auto-beginning its transaction — any endpoint opening 'async with db.begin()' afterwards crashed with 'transaction already begun' (POST /materials 500). get_current_user / get_actor now resolve in a short-lived session (expire_on_commit=False keeps the context usable detached); inventory/pm scopes keep passing the request session explicitly. Smoke suites rewritten against CURRENT contracts: - assertions are behavior-based (shapes, envelopes, filters), no magic seed counts; dynamic lookups instead of hard-coded names/ids - rerun-tolerant: tolerate 409-on-create by reusing prior artifacts - aligned with current rules: revert blocked after inventory receipts (v2.6), attachments allowed in every status, termsheets optional at quote level - SMOKE_USER/SMOKE_PASSWORD env for login (default tester/123456) Verified on a fresh volume: migration + audit_log bootstrap, Casdoor seed (bcrypt), demo data, and 29+76+61 smoke checks all green.
34 lines
1.2 KiB
Python
34 lines
1.2 KiB
Python
"""Attribution for quote_events.actor — the VERIFIED user, not the raw token.
|
|
|
|
Historically this stored the bearer token string verbatim (unverifiable and
|
|
a token leak into the database). All routes that use it now sit behind the
|
|
global JWT dependency, so the token is resolved to the authenticated user
|
|
and the display name is recorded instead.
|
|
"""
|
|
from fastapi import Request
|
|
|
|
from app.auth import get_optional_user
|
|
|
|
|
|
async def get_actor(request: Request) -> str | None:
|
|
"""Resolve the caller's display name from the Casdoor Bearer token.
|
|
|
|
Uses its own session (get_optional_user default) — same reason as
|
|
get_current_user: quote routers open explicit db.begin() blocks.
|
|
"""
|
|
ctx = await get_optional_user(request)
|
|
if ctx is not None:
|
|
return ctx.display_name
|
|
# Dev-mode header fallback (only active when DEV_LOGIN_ENABLED) carries
|
|
# the name in X-User-Name / X-User-Name-B64 — keep attribution useful.
|
|
name = request.headers.get("x-user-name")
|
|
import base64
|
|
|
|
b64 = request.headers.get("x-user-name-b64")
|
|
if b64:
|
|
try:
|
|
name = base64.b64decode(b64.encode()).decode("utf-8")
|
|
except Exception:
|
|
pass
|
|
return name
|