"""The role "Petrolyst 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. Which dashboard and which customer's rows a guest sees come 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, once, and again whenever PERMISSIONS change: docker exec /app/.venv/bin/python /app/petrolyst-roles/petrolyst_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 ROLE = "Petrolyst 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(main())