mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-09-30 11:12:35 +02:00
Three issues from the post-merge audit of the unified-dispatch PR, all
pre-existed on dev but became more impactful once every print routes
through the queue:
1. Start/Stop ownership gates. /queue/{id}/stop required QUEUE_UPDATE_ALL
(admin-only) -- operators saw the Stop button in the queue UI but got
403 on click. /queue/{id}/start required QUEUE_UPDATE_OWN with no
ownership check -- _OWN holders could start anyone's queue items via
direct API. Both routes now use require_ownership_permission, mirroring
/cancel. Stop is strict (rejects unowned items for _OWN); start preserves
#1670's VP-import flow where _OWN can start NULL-owner items and claim
ownership at click-time. Frontend QueuePage Start/Stop buttons flip
from printers:control to canModify('queue', 'update', created_by_id).
2. TOCTOU race on insert_position. Concurrent ASAP inserts to the same
scope both computed MAX(position) from before the other committed; in
an empty scope, both inserted at position=1 (duplicate). Wraps the
read+update in a transaction-scoped Postgres pg_advisory_xact_lock
keyed on the printer_id. Different printers don't contend. SQLite
serializes writes implicitly so the path is no-op there. Dialect is
checked against the live session binding, not the is_sqlite() helper,
because the test fixture overrides get_db to SQLite while
settings.database_url still points at Postgres.
3. /reorder duplicate-position validator. POST /queue/reorder set position
from the payload in a loop with no uniqueness validation -- a buggy
drag-drop client could leave the queue with ambiguous ordering (the
scheduler's ORDER BY (printer_id, position) ties break by row order).
New model_validator on PrintQueueReorder rejects duplicates at the
schema layer with 422 + "Duplicate positions in reorder request: [N, ...]".