jogosultsági szintek RBAC beállítva tesztelve

This commit is contained in:
Roo
2026-06-25 20:41:49 +00:00
parent 52011606ff
commit 36109fc722
242 changed files with 8672 additions and 2237 deletions

View File

@@ -0,0 +1,385 @@
# /opt/docker/dev/service_finder/backend/app/scripts/seed_rbac.py
"""
RBAC Phase 1: Seed script for database-driven Role-Based Access Control.
This script initializes the database with:
- 6 system roles (SUPERADMIN, ADMIN, MODERATOR, SALES_REP, SERVICE_MGR, USER)
- 28 permission codes across 8 domains
- Role-permission mappings according to the audit proposal matrix
- User migration: maps existing UserRole enum values to new role_id FK
Usage:
docker exec sf_api python -m app.scripts.seed_rbac
"""
import asyncio
import logging
from sqlalchemy import select, text, update
from app.db.session import AsyncSessionLocal
from app.models.system.rbac import SystemRole, SystemPermission, SystemRolePermission
from app.models.identity.identity import User, UserRole
logging.basicConfig(level=logging.INFO, format='%(asctime)s [%(levelname)s]: %(message)s')
logger = logging.getLogger("Seed-RBAC")
# ──────────────────────────────────────────────
# STEP A: 6 System Roles
# ──────────────────────────────────────────────
ROLES = [
{"name": "SUPERADMIN", "description": "Platform super administrator with full system access", "rank": 100, "is_system": True},
{"name": "ADMIN", "description": "Platform administrator with elevated management privileges", "rank": 80, "is_system": True},
{"name": "MODERATOR", "description": "Content moderator with limited administrative access", "rank": 60, "is_system": True},
{"name": "SALES_REP", "description": "Sales representative with fleet creation privileges", "rank": 40, "is_system": True},
{"name": "SERVICE_MGR", "description": "Service manager with organization-level access", "rank": 20, "is_system": True},
{"name": "USER", "description": "Regular platform user with basic access", "rank": 0, "is_system": True},
]
# ──────────────────────────────────────────────
# STEP B: 28 Permission Codes
# ──────────────────────────────────────────────
PERMISSIONS = [
# fleet domain (6 permissions)
{"code": "fleet:view", "domain": "fleet", "action": "view", "description": "View fleet/vehicle data"},
{"code": "fleet:create", "domain": "fleet", "action": "create", "description": "Create new fleet/vehicle entries"},
{"code": "fleet:edit", "domain": "fleet", "action": "edit", "description": "Edit existing fleet/vehicle data"},
{"code": "fleet:delete", "domain": "fleet", "action": "delete", "description": "Delete fleet/vehicle entries"},
{"code": "fleet:approve", "domain": "fleet", "action": "approve","description": "Approve fleet/vehicle submissions"},
# user domain (5 permissions)
{"code": "user:view", "domain": "user", "action": "view", "description": "View user profiles and data"},
{"code": "user:create", "domain": "user", "action": "create", "description": "Create new user accounts"},
{"code": "user:edit", "domain": "user", "action": "edit", "description": "Edit user profiles and data"},
{"code": "user:delete", "domain": "user", "action": "delete", "description": "Delete user accounts"},
{"code": "user:manage-roles", "domain": "user", "action": "manage-roles","description": "Manage user role assignments"},
# finance domain (4 permissions)
{"code": "finance:view", "domain": "finance", "action": "view", "description": "View financial data and transactions"},
{"code": "finance:edit", "domain": "finance", "action": "edit", "description": "Edit financial records"},
{"code": "finance:approve", "domain": "finance", "action": "approve", "description": "Approve financial transactions"},
{"code": "finance:refund", "domain": "finance", "action": "refund", "description": "Process refunds"},
# system domain (3 permissions)
{"code": "system:view", "domain": "system", "action": "view", "description": "View system configuration"},
{"code": "system:edit", "domain": "system", "action": "edit", "description": "Edit system configuration"},
{"code": "system:manage", "domain": "system", "action": "manage", "description": "Full system management access"},
# org domain (4 permissions)
{"code": "org:view", "domain": "org", "action": "view", "description": "View organization data"},
{"code": "org:edit", "domain": "org", "action": "edit", "description": "Edit organization data"},
{"code": "org:delete", "domain": "org", "action": "delete", "description": "Delete organizations"},
{"code": "org:manage-members", "domain": "org", "action": "manage-members","description": "Manage organization members"},
# reports domain (3 permissions)
{"code": "reports:view", "domain": "reports", "action": "view", "description": "View reports"},
{"code": "reports:export", "domain": "reports", "action": "export", "description": "Export reports"},
{"code": "reports:manage", "domain": "reports", "action": "manage", "description": "Manage report configurations"},
# audit domain (2 permissions)
{"code": "audit:view", "domain": "audit", "action": "view", "description": "View audit logs"},
{"code": "audit:export", "domain": "audit", "action": "export", "description": "Export audit logs"},
# settings domain (2 permissions)
{"code": "settings:view", "domain": "settings", "action": "view", "description": "View system settings"},
{"code": "settings:edit", "domain": "settings", "action": "edit", "description": "Edit system settings"},
]
# ──────────────────────────────────────────────
# STEP C: Role-Permission Mapping Matrix
# Format: { "role_name": {"permission_code": True/False} }
# True = granted, False = denied (explicit)
# ──────────────────────────────────────────────
ROLE_PERMISSION_MATRIX = {
"SUPERADMIN": {
# fleet - all granted
"fleet:view": True, "fleet:create": True, "fleet:edit": True,
"fleet:delete": True, "fleet:approve": True,
# user - all granted
"user:view": True, "user:create": True, "user:edit": True,
"user:delete": True, "user:manage-roles": True,
# finance - all granted
"finance:view": True, "finance:edit": True,
"finance:approve": True, "finance:refund": True,
# system - all granted
"system:view": True, "system:edit": True, "system:manage": True,
# org - all granted
"org:view": True, "org:edit": True, "org:delete": True, "org:manage-members": True,
# reports - all granted
"reports:view": True, "reports:export": True, "reports:manage": True,
# audit - all granted
"audit:view": True, "audit:export": True,
# settings - all granted
"settings:view": True, "settings:edit": True,
},
"ADMIN": {
# fleet
"fleet:view": True, "fleet:create": True, "fleet:edit": True,
"fleet:delete": False, "fleet:approve": True,
# user
"user:view": True, "user:create": True, "user:edit": True,
"user:delete": False, "user:manage-roles": False,
# finance
"finance:view": True, "finance:edit": True,
"finance:approve": False, "finance:refund": False,
# system
"system:view": True, "system:edit": True, "system:manage": False,
# org
"org:view": True, "org:edit": True, "org:delete": False, "org:manage-members": True,
# reports
"reports:view": True, "reports:export": True, "reports:manage": False,
# audit
"audit:view": False, "audit:export": False,
# settings
"settings:view": True, "settings:edit": True,
},
"MODERATOR": {
# fleet
"fleet:view": True, "fleet:create": False, "fleet:edit": False,
"fleet:delete": False, "fleet:approve": False,
# user
"user:view": True, "user:create": False, "user:edit": False,
"user:delete": False, "user:manage-roles": False,
# finance
"finance:view": True, "finance:edit": False,
"finance:approve": False, "finance:refund": False,
# system
"system:view": True, "system:edit": False, "system:manage": False,
# org
"org:view": True, "org:edit": False, "org:delete": False, "org:manage-members": False,
# reports
"reports:view": True, "reports:export": True, "reports:manage": False,
# audit
"audit:view": False, "audit:export": False,
# settings
"settings:view": False, "settings:edit": False,
},
"SALES_REP": {
# fleet
"fleet:view": True, "fleet:create": True, "fleet:edit": False,
"fleet:delete": False, "fleet:approve": False,
# user
"user:view": False, "user:create": False, "user:edit": False,
"user:delete": False, "user:manage-roles": False,
# finance
"finance:view": False, "finance:edit": False,
"finance:approve": False, "finance:refund": False,
# system
"system:view": False, "system:edit": False, "system:manage": False,
# org
"org:view": True, "org:edit": False, "org:delete": False, "org:manage-members": False,
# reports
"reports:view": True, "reports:export": False, "reports:manage": False,
# audit
"audit:view": False, "audit:export": False,
# settings
"settings:view": False, "settings:edit": False,
},
"SERVICE_MGR": {
# fleet
"fleet:view": True, "fleet:create": False, "fleet:edit": False,
"fleet:delete": False, "fleet:approve": False,
# user
"user:view": False, "user:create": False, "user:edit": False,
"user:delete": False, "user:manage-roles": False,
# finance
"finance:view": False, "finance:edit": False,
"finance:approve": False, "finance:refund": False,
# system
"system:view": False, "system:edit": False, "system:manage": False,
# org
"org:view": True, "org:edit": False, "org:delete": False, "org:manage-members": False,
# reports
"reports:view": True, "reports:export": False, "reports:manage": False,
# audit
"audit:view": False, "audit:export": False,
# settings
"settings:view": False, "settings:edit": False,
},
"USER": {
# fleet
"fleet:view": True, "fleet:create": False, "fleet:edit": False,
"fleet:delete": False, "fleet:approve": False,
# user
"user:view": False, "user:create": False, "user:edit": False,
"user:delete": False, "user:manage-roles": False,
# finance
"finance:view": False, "finance:edit": False,
"finance:approve": False, "finance:refund": False,
# system
"system:view": False, "system:edit": False, "system:manage": False,
# org
"org:view": False, "org:edit": False, "org:delete": False, "org:manage-members": False,
# reports
"reports:view": False, "reports:export": False, "reports:manage": False,
# audit
"audit:view": False, "audit:export": False,
# settings
"settings:view": False, "settings:edit": False,
},
}
# Map UserRole enum values to role names
USERROLE_TO_ROLE_NAME = {
UserRole.SUPERADMIN: "SUPERADMIN",
UserRole.ADMIN: "ADMIN",
UserRole.MODERATOR: "MODERATOR",
UserRole.SALES_REP: "SALES_REP",
UserRole.SERVICE_MGR: "SERVICE_MGR",
UserRole.USER: "USER",
}
async def seed_rbac():
"""Main seed function: creates roles, permissions, mappings, and migrates users."""
async with AsyncSessionLocal() as db:
try:
# ── STEP A: Insert Roles ──
logger.info("=" * 60)
logger.info("STEP A: Inserting 6 system roles...")
role_map = {} # name -> id
for role_data in ROLES:
existing = await db.execute(
select(SystemRole).where(SystemRole.name == role_data["name"])
)
role = existing.scalar_one_or_none()
if role:
logger.info(f" ⏭️ Role '{role_data['name']}' already exists (id={role.id}), updating...")
role.description = role_data["description"]
role.rank = role_data["rank"]
role.is_system = role_data["is_system"]
else:
role = SystemRole(**role_data)
db.add(role)
await db.flush()
logger.info(f" ✅ Created role '{role_data['name']}' (id={role.id})")
role_map[role_data["name"]] = role.id
await db.commit()
logger.info(f" ✅ Roles committed. {len(role_map)} roles in role_map.")
# ── STEP B: Insert Permissions ──
logger.info("=" * 60)
logger.info("STEP B: Inserting 28 permission codes...")
perm_map = {} # code -> id
for perm_data in PERMISSIONS:
existing = await db.execute(
select(SystemPermission).where(SystemPermission.code == perm_data["code"])
)
perm = existing.scalar_one_or_none()
if perm:
logger.info(f" ⏭️ Permission '{perm_data['code']}' already exists (id={perm.id}), updating...")
perm.domain = perm_data["domain"]
perm.action = perm_data["action"]
perm.description = perm_data["description"]
else:
perm = SystemPermission(**perm_data)
db.add(perm)
await db.flush()
logger.info(f" ✅ Created permission '{perm_data['code']}' (id={perm.id})")
perm_map[perm_data["code"]] = perm.id
await db.commit()
logger.info(f" ✅ Permissions committed. {len(perm_map)} permissions in perm_map.")
# ── STEP C: Insert Role-Permission Mappings ──
logger.info("=" * 60)
logger.info("STEP C: Inserting role-permission mappings...")
mapping_count = 0
for role_name, perms in ROLE_PERMISSION_MATRIX.items():
role_id = role_map.get(role_name)
if not role_id:
logger.warning(f" ⚠️ Role '{role_name}' not found in role_map, skipping!")
continue
for perm_code, granted in perms.items():
perm_id = perm_map.get(perm_code)
if not perm_id:
logger.warning(f" ⚠️ Permission '{perm_code}' not found in perm_map, skipping!")
continue
# Check if mapping already exists
existing = await db.execute(
select(SystemRolePermission).where(
SystemRolePermission.role_id == role_id,
SystemRolePermission.permission_id == perm_id,
)
)
rp = existing.scalar_one_or_none()
if rp:
if rp.granted != granted:
rp.granted = granted
logger.info(f" 🔄 Updated mapping: {role_name} -> {perm_code} (granted={granted})")
else:
rp = SystemRolePermission(
role_id=role_id,
permission_id=perm_id,
granted=granted,
)
db.add(rp)
mapping_count += 1
await db.commit()
logger.info(f"{mapping_count} new role-permission mappings created.")
# ── STEP D: Migrate Existing Users ──
logger.info("=" * 60)
logger.info("STEP D: Migrating existing users to role_id...")
# Get all users that don't have role_id set yet
result = await db.execute(
select(User).where(User.role_id.is_(None))
)
users_to_migrate = result.scalars().all()
migrated_count = 0
skipped_count = 0
for user in users_to_migrate:
role_name = USERROLE_TO_ROLE_NAME.get(user.role)
if not role_name:
logger.warning(f" ⚠️ User {user.id} has unknown role '{user.role}', skipping...")
skipped_count += 1
continue
role_id = role_map.get(role_name)
if not role_id:
logger.warning(f" ⚠️ Role '{role_name}' not found for user {user.id}, skipping...")
skipped_count += 1
continue
user.role_id = role_id
migrated_count += 1
await db.commit()
logger.info(f" ✅ Users migrated: {migrated_count} updated, {skipped_count} skipped.")
# ── FINAL REPORT ──
logger.info("=" * 60)
logger.info("📊 RBAC SEED SUMMARY")
logger.info(f" Roles: {len(role_map)}")
logger.info(f" Permissions: {len(perm_map)}")
# Count total role_permissions
rp_result = await db.execute(select(SystemRolePermission))
total_rp = len(rp_result.scalars().all())
logger.info(f" Role-Permission Mappings: {total_rp}")
# Count users with role_id
user_result = await db.execute(
select(User).where(User.role_id.isnot(None))
)
users_with_role = len(user_result.scalars().all())
logger.info(f" Users with role_id assigned: {users_with_role}")
logger.info("=" * 60)
logger.info("✅ RBAC Phase 1 seeding completed successfully!")
except Exception as e:
await db.rollback()
logger.error(f"❌ RBAC seeding failed: {e}")
raise
async def main():
logger.info("🚀 Starting RBAC Phase 1 seed...")
await seed_rbac()
if __name__ == "__main__":
asyncio.run(main())

View File

@@ -94,7 +94,7 @@ async def seed_params():
# --- 4. FINANCE (Költségek és Devizák) ---
{"key": "finance_default_currency", "value": "HUF", "category": "finance", "description": "Helyi alap deviza", "scope_level": "global"},
{"key": "finance_base_currency", "value": "EUR", "category": "finance", "description": "Központi elszámoló deviza (Statisztikákhoz)", "scope_level": "global"},
{"key": "org_naming_template", "value": "{last_name} Flotta", "category": "system", "description": "Szervezet név sablon", "scope_level": "global"},
{"key": "org_naming_template", "value": "{last_name} {first_name} - Privát Garázs (#{user_id})", "category": "system", "description": "Szervezet név sablon (Privát Garázs)", "scope_level": "global"},
# --- 5. DOCUMENT & OCR (Robot 1 vezérlése) ---
{