"""Seed the asset_global_admin role (全局资产管理员). Revision ID: 275 Revises: 274 Create Date: 2026-06-11 Background ---------- ``asset_admin`` is auto-derived from ``asset_office_admins`` and its write authority is region-scoped: an office admin may only mutate assets whose resolved office is in their managed set. User direction 2026-06-11: add a **global asset admin** who — like global_admin — can operate assets in EVERY office, but without any authority outside the asset domain. Semantics (see ``app/core/rbac.py`` docstring on ``ASSET_GLOBAL_ADMIN_ROLE``): * Manually granted / revoked on the RBAC page (unlike asset_admin, which rejects manual grants). * Holders are co-granted ``asset_admin`` by the office-admin derivation + daily reconciler, so every existing entry gate and frontend surface works unchanged. * All office-region gates short-circuit via ``rbac.has_global_asset_scope`` for holders. Migration steps --------------- 1. INSERT ``asset_global_admin`` into ``auth_roles`` if missing. Idempotent: re-runs are a no-op. Downgrade removes the role row (assignments first — no FK cascade guarantee across MySQL/TiDB configs). """ from __future__ import annotations import sqlalchemy as sa from alembic import op revision = "275" down_revision = "274" branch_labels = None depends_on = None def upgrade() -> None: bind = op.get_bind() exists = bind.execute(sa.text( "SELECT 1 FROM auth_roles WHERE name = 'asset_global_admin' LIMIT 1" )).first() if exists is None: # Dashed UUID — must match SQLAlchemy GUID's bind format. See # migration 092's docstring for the FK error this avoids. bind.execute(sa.text( "INSERT INTO auth_roles (id, name, description, is_system) " "VALUES (UUID(), 'asset_global_admin', " "'Global asset admin (asset-domain write authority over " "every office; manually granted)', 1)" )) def downgrade() -> None: bind = op.get_bind() bind.execute(sa.text( "DELETE FROM auth_user_roles WHERE role_id IN (" " SELECT id FROM auth_roles WHERE name = 'asset_global_admin'" ")" )) bind.execute(sa.text( "DELETE FROM auth_roles WHERE name = 'asset_global_admin'" ))