mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-10-05 21:51:23 +02:00
fix(permissions): self-heal Administrators to ALL_PERMISSIONS on upgrade + Pipelines runs dashboard polish
Administrators system group sync - Fresh installs already bootstrap with ALL_PERMISSIONS, so they always have every permission. Upgrades previously only got what one-off backfill blocks in seed_default_groups() explicitly listed (library:purge, archives:purge, the OWN/ALL read-flag block, orca_cloud:auth, pipelines:*). Any Permission enum member added without a matching block silently stayed missing on existing admin rows. The most recent gap was printer_sensor_history:read (Sensor History charts returned 403 for upgraded admins). - seed_default_groups() now syncs Administrators to ALL_PERMISSIONS on every startup: append every Permission value that isn't already on the row. Additive only -- hand-added custom permissions are preserved. - The pure-admin one-off backfills (library:purge / archives:purge block, the OWN/ALL + orca_cloud:auth + legacy-read-flag block, the Administrators branch of the pipeline backfill) are retired since the sync subsumes them. Non-admin backfills (Operators / Viewers OWN-tier reads, Operators orca_cloud:auth, pipelines for non-admin groups, makerworld:*, clear_plate cross-group adders) are untouched. - Tests: test_administrators_printer_sensor_history_read_backfilled (regression for the reported gap), test_administrators_sync_covers_every_current_permission (generic invariant -- any future new permission lands on admin without needing a one-off test), test_administrators_sync_is_additive_only (custom permissions preserved). 12/12 backfill-migration + 102/102 broader permission tests green; ruff clean. Pipelines runs dashboard - PipelineRunsPage.tsx: the Pipeline / Status / Target filter row's three native <select> elements are replaced with a bambu-themed FilterDropdown (button trigger, floating menu, optgroup-style headers for the Target picker, hover + selected states with a check mark, closes on outside click and Escape). Same value/onChange contract -- visual only. - SlicerPipelinesPanel.tsx: wrap list?.pipelines ?? [] in useMemo so the reference is stable when the data is stable. Fixes the react-hooks/exhaustive-deps warning where the inline fallback returned a fresh empty array every render, invalidating both downstream useMemo caches (target-options + filtered-pipelines list).
This commit is contained in:
@@ -3345,7 +3345,7 @@ async def seed_default_groups():
|
||||
|
||||
from sqlalchemy import select
|
||||
|
||||
from backend.app.core.permissions import DEFAULT_GROUPS
|
||||
from backend.app.core.permissions import ALL_PERMISSIONS, DEFAULT_GROUPS
|
||||
from backend.app.models.group import Group
|
||||
from backend.app.models.user import User
|
||||
|
||||
@@ -3498,63 +3498,31 @@ async def seed_default_groups():
|
||||
group.permissions = perms
|
||||
await session.commit()
|
||||
|
||||
# Backfill library:purge + archives:purge for the Administrators group
|
||||
# on existing installs. Both permissions were added after Administrators
|
||||
# was first seeded, so upgrading users miss them even though the default
|
||||
# config (ALL_PERMISSIONS) includes them for fresh installs.
|
||||
# Backfill: sync the Administrators system group to ALL_PERMISSIONS.
|
||||
# Administrators' contract is full access to every feature — fresh
|
||||
# installs get that via DEFAULT_GROUPS["Administrators"]["permissions"]
|
||||
# = ALL_PERMISSIONS. Upgrading installs would otherwise stay frozen at
|
||||
# whatever permission set existed when they were first seeded, so a
|
||||
# newly-added Permission enum member silently leaves admins gated out
|
||||
# of the feature it controls.
|
||||
#
|
||||
# Generalises the previous one-off admin backfills (library:purge,
|
||||
# archives:purge, the OWN/ALL read-flag set + legacy read flags,
|
||||
# orca_cloud:auth, printer_sensor_history:read, …): every current
|
||||
# Permission enum value is appended to the admin group if missing.
|
||||
# Additive only — never removes a permission an operator added by
|
||||
# hand. Run AFTER the legacy-rename migration above so the renamed
|
||||
# OWN/ALL variants land in the group before the sync sees them.
|
||||
result = await session.execute(select(Group).where(Group.name == "Administrators"))
|
||||
admin_group = result.scalar_one_or_none()
|
||||
if admin_group and admin_group.permissions is not None:
|
||||
perms = list(admin_group.permissions)
|
||||
added = False
|
||||
for new_perm in ("library:purge", "archives:purge"):
|
||||
for new_perm in ALL_PERMISSIONS:
|
||||
if new_perm not in perms:
|
||||
perms.append(new_perm)
|
||||
added = True
|
||||
logger.info("Added %s to Administrators group (backfill)", new_perm)
|
||||
if added:
|
||||
admin_group.permissions = perms
|
||||
await session.commit()
|
||||
|
||||
# Backfill the read flag set for the Administrators group on existing
|
||||
# installs (maziggy/bambuddy-security #2). Two layers:
|
||||
#
|
||||
# (a) New OWN/ALL splits — `archives:read_own` etc. Fresh installs get
|
||||
# these via ALL_PERMISSIONS; upgrades need the explicit backfill
|
||||
# so admin's permission set matches a fresh install's.
|
||||
#
|
||||
# (b) Legacy `archives:read` / `library:read` / `queue:read`. The
|
||||
# frontend still gates download / preview UI on these LEGACY
|
||||
# strings (see ArchivesPage / FileManagerPage), so admin needs
|
||||
# them retained even though the new API uses the OWN/ALL split.
|
||||
# The PERMISSION_MIGRATION_ALL map deliberately doesn't rename
|
||||
# read flags for admin — this backfill ensures they're present
|
||||
# even if they were stripped by hand or by an older migration.
|
||||
#
|
||||
# Also includes orca_cloud:auth for parity with fresh-install
|
||||
# behaviour (ALL_PERMISSIONS covers it; backfill makes sure an
|
||||
# admin role that's been customised since seed still has it).
|
||||
result = await session.execute(select(Group).where(Group.name == "Administrators"))
|
||||
admin_group = result.scalar_one_or_none()
|
||||
if admin_group and admin_group.permissions is not None:
|
||||
perms = list(admin_group.permissions)
|
||||
added = False
|
||||
for new_perm in (
|
||||
"archives:read",
|
||||
"archives:read_own",
|
||||
"archives:read_all",
|
||||
"library:read",
|
||||
"library:read_own",
|
||||
"library:read_all",
|
||||
"queue:read",
|
||||
"queue:read_own",
|
||||
"queue:read_all",
|
||||
"orca_cloud:auth",
|
||||
):
|
||||
if new_perm not in perms:
|
||||
perms.append(new_perm)
|
||||
added = True
|
||||
logger.info("Added %s to Administrators group (backfill)", new_perm)
|
||||
logger.info("Added %s to Administrators group (ALL_PERMISSIONS sync)", new_perm)
|
||||
if added:
|
||||
admin_group.permissions = perms
|
||||
await session.commit()
|
||||
@@ -3613,25 +3581,18 @@ async def seed_default_groups():
|
||||
group.permissions = perms
|
||||
await session.commit()
|
||||
|
||||
# Backfill pipeline permissions (#1425). Pipelines were added after
|
||||
# initial seeding, so existing groups need them appended:
|
||||
# - Administrators: all three (matches fresh-install ALL_PERMISSIONS)
|
||||
# Backfill pipeline permissions (#1425) for non-admin groups.
|
||||
# Administrators is handled by the ALL_PERMISSIONS sync above.
|
||||
# - Operators: all three (matches fresh-install DEFAULT_GROUPS)
|
||||
# - Viewers + any group with library:read_own or settings:read:
|
||||
# - Any other group with library:read_own or settings:read:
|
||||
# pipelines:read only
|
||||
result = await session.execute(select(Group))
|
||||
for group in result.scalars().all():
|
||||
if not group.permissions:
|
||||
if not group.permissions or group.name == "Administrators":
|
||||
continue
|
||||
perms = list(group.permissions)
|
||||
changed = False
|
||||
if group.name == "Administrators":
|
||||
for new_perm in ("pipelines:read", "pipelines:write", "pipelines:run"):
|
||||
if new_perm not in perms:
|
||||
perms.append(new_perm)
|
||||
changed = True
|
||||
logger.info("Added %s to Administrators group (backfill)", new_perm)
|
||||
elif group.name == "Operators":
|
||||
if group.name == "Operators":
|
||||
for new_perm in ("pipelines:read", "pipelines:write", "pipelines:run"):
|
||||
if new_perm not in perms:
|
||||
perms.append(new_perm)
|
||||
|
||||
Reference in New Issue
Block a user