feat(demo): scheduled demo-account reset (5c)
A security audit of every mutating endpoint found no isolation gaps — all routes scope by current_user, admin routes are gated, and the demo account is sandboxed in its own user_id space (can't reach others' data, escalate, or hit admin routes). The remaining demo concern is communal pollution of its own shared state, so add an automatic reset: a new 'demo_reset' scheduler job (admin-tunable interval, default 12h) reuses the manual reset logic, and no-ops without ever creating a demo account if none exists. Verified: a triggered run wiped the demo's video states and re-seeded its sample playlists.
This commit is contained in:
parent
7ca28189bb
commit
571f337fdf
6 changed files with 39 additions and 12 deletions
|
|
@ -56,6 +56,7 @@ JOB_INTERVALS: dict[str, int] = {
|
|||
"subscriptions": settings.subscriptions_resync_minutes,
|
||||
"playlist_sync": settings.playlist_sync_minutes,
|
||||
"maintenance": settings.maintenance_interval_minutes,
|
||||
"demo_reset": settings.demo_reset_minutes,
|
||||
}
|
||||
|
||||
# Sane bounds for an admin-set interval (minutes).
|
||||
|
|
@ -253,6 +254,20 @@ def _maintenance_job() -> None:
|
|||
_job("maintenance", work)
|
||||
|
||||
|
||||
def _demo_reset_job() -> None:
|
||||
# Auto-clean the shared demo sandbox. No-op (and never creates one) if there's no demo
|
||||
# account. Lazy import avoids a routes<->scheduler import cycle.
|
||||
def work(db):
|
||||
from app.models import User
|
||||
demo = db.query(User).filter(User.is_demo.is_(True)).one_or_none()
|
||||
if demo is None:
|
||||
return {"skipped": "no demo account"}
|
||||
from app.routes.admin import reset_demo_state
|
||||
return {"playlists_seeded": reset_demo_state(db, demo)}
|
||||
|
||||
_job("demo_reset", work)
|
||||
|
||||
|
||||
# job_id -> wrapper. The single source of truth for which jobs exist and how to run one,
|
||||
# shared by start_scheduler (recurring registration) and trigger_job (manual "run now").
|
||||
JOB_FUNCS: dict[str, Callable[[], None]] = {
|
||||
|
|
@ -264,6 +279,7 @@ JOB_FUNCS: dict[str, Callable[[], None]] = {
|
|||
"subscriptions": _subscriptions_job,
|
||||
"playlist_sync": _playlist_sync_job,
|
||||
"maintenance": _maintenance_job,
|
||||
"demo_reset": _demo_reset_job,
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue