Retire the Superset reader setup and the ATOMA dashboard (PD-13)
ATOMA's users use the Petrolyst app; Superset keeps admins, editors and the app's embedded dashboards. Removed: the "ATOMA Reader" role and its rules (petrolyst_reader.py, ReaderAccessMixin, reader.css, the head template, the SQL-hiding patch), the atoma-reader mapping (it now maps to nothing in Superset), the iframe allowance for the Map tab, and the "atoma" dashboard with its Fleet/Map tab, D0 and dashboard.css. The bundle holds atoma-overview and atoma-site only (byte-identical to before); the guest role keeps the reader's 12 permissions in roles/atoma_guest.py. Brand files now name petrolyst-web. SPEC marks the retired parts as history. Checks (local): bundle checks pass; image rebuilt and healthy; import with column drift 0 and unchanged embedding ids; the production config loads with OAuth, embedding off, no reader hook; admin sees atoma-site with its tabs and filter column; the app's browser tests pass 10/10. shellcheck not run (not installed). Not deployed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
1b8e57adb4
commit
da3f803947
22 files changed
+164
-702
No files matched your search
@@ -1,23 +1,80 @@
|
||||
"""The role "ATOMA Guest": what the Petrolyst app's embedded dashboards may do (PD-12 trial).
|
||||
"""The role "ATOMA Guest": what the Petrolyst app's embedded dashboards may do (PD-12).
|
||||
|
||||
Superset gives every embedded viewer (a guest pass signed for one dashboard) the role named by
|
||||
GUEST_ROLE_NAME. That role gets the same permissions as "ATOMA Reader": reading a dashboard
|
||||
and its charts' data, nothing else. Which dashboard a guest sees comes from the pass, not from
|
||||
the role. Superset leaves the SQL out of chart-data responses for guests.
|
||||
GUEST_ROLE_NAME. Which dashboard a guest sees comes from the pass, not from the role. Superset
|
||||
leaves the SQL out of chart-data responses for guests.
|
||||
|
||||
Embedding is switched on in the local stack only (.local/fmdb-scratch, superset_config_local.py),
|
||||
so this script is not part of init.sh; run it by hand inside the Superset container:
|
||||
so this script is not part of init.sh; run it by hand inside the Superset container, once, and
|
||||
again whenever PERMISSIONS change:
|
||||
|
||||
docker exec <superset> /app/.venv/bin/python /app/petrolyst-roles/atoma_guest.py
|
||||
|
||||
Creates the role if needed and gives it exactly PERMISSIONS: missing ones are added, any other
|
||||
is removed (also one added by hand in the UI). A second run changes nothing.
|
||||
|
||||
The list was established on the local stack by reading the ATOMA dashboard as a reader (the
|
||||
former "ATOMA Reader" role, retired with PD-13): everything a dashboard asks the server for, and
|
||||
nothing more. No menu access, nothing to write, no Explore, CSV, sharing, drill or query view.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
|
||||
from atoma_reader import PERMISSIONS, sync
|
||||
|
||||
ROLE = "ATOMA Guest"
|
||||
PERMISSIONS = [
|
||||
("can_read", "Dashboard"), # the dashboard and its charts' definitions
|
||||
("can_dashboard", "Superset"), # the dashboard page
|
||||
("can_dashboard_permalink", "Superset"), # a dashboard permalink
|
||||
("can_read", "Chart"), # chart data
|
||||
("can_time_range", "Api"), # the Viewing period filter
|
||||
("can_read", "DashboardFilterStateRestApi"), # native filter state
|
||||
("can_write", "DashboardFilterStateRestApi"),
|
||||
("can_read", "DashboardPermalinkRestApi"),
|
||||
("can_read", "CurrentUserRestApi"), # who is signed in
|
||||
("can_read", "SecurityRestApi"), # the CSRF token
|
||||
("can_get", "MenuApi"),
|
||||
("can_log", "Superset"), # Superset's event log
|
||||
]
|
||||
|
||||
|
||||
def sync(name: str, permissions: list[tuple[str, str]]) -> int:
|
||||
"""Give the role `name` exactly `permissions`, creating it if needed."""
|
||||
from superset.app import create_app
|
||||
|
||||
app = create_app()
|
||||
with app.app_context():
|
||||
from superset import db, security_manager as sm
|
||||
|
||||
wanted = []
|
||||
for permission, view in permissions:
|
||||
pvm = sm.find_permission_view_menu(permission, view)
|
||||
if pvm is None:
|
||||
print(f"no permission {permission} on {view}: run `superset init` first?",
|
||||
file=sys.stderr)
|
||||
return 1
|
||||
wanted.append(pvm)
|
||||
|
||||
role = sm.find_role(name) or sm.add_role(name)
|
||||
added = [pvm for pvm in wanted if pvm not in role.permissions]
|
||||
removed = [pvm for pvm in role.permissions if pvm not in wanted]
|
||||
for pvm in added:
|
||||
sm.add_permission_role(role, pvm)
|
||||
for pvm in removed:
|
||||
sm.del_permission_role(role, pvm)
|
||||
db.session.commit()
|
||||
|
||||
print(f'role "{name}": {len(wanted)} permissions, {len(added)} added, '
|
||||
f"{len(removed)} removed")
|
||||
for pvm in removed:
|
||||
print(f" removed {pvm.permission.name} on {pvm.view_menu.name}")
|
||||
return 0
|
||||
|
||||
|
||||
def main() -> int:
|
||||
return sync(ROLE, PERMISSIONS)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(sync(ROLE, PERMISSIONS))
|
||||
sys.exit(main())
|
||||
Reference in new issue
Block a user