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,144 @@
#!/usr/bin/env python3
"""
🔧 P0 EXECUTION - Fix Phantom Permissions
Inserts 8 orphaned permission codes into system.permissions and maps them
to SUPERADMIN (role_id=1) and ADMIN (role_id=2) with granted=True.
The 8 missing codes:
- dual-control:request (security)
- dual-control:approve (security)
- dual-control:view (security)
- services:manage (service)
- subscription:manage (subscription)
- user:manage (user)
- moderation:manage (moderation)
- gamification:manage (gamification)
Run: docker compose exec sf_api python3 /app/backend/scripts/fix_phantom_permissions.py
"""
import asyncio
import logging
import os
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy import text, select
from sqlalchemy.orm import sessionmaker
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
DATABASE_URL = os.getenv(
"DATABASE_URL",
"postgresql+asyncpg://sf_user:sf_password@postgres:5432/service_finder",
)
# ── The 8 orphaned permissions ──
PHANTOM_PERMISSIONS = [
{"code": "dual-control:request", "domain": "security", "action": "request"},
{"code": "dual-control:approve", "domain": "security", "action": "approve"},
{"code": "dual-control:view", "domain": "security", "action": "view"},
{"code": "services:manage", "domain": "service", "action": "manage"},
{"code": "subscription:manage", "domain": "subscription", "action": "manage"},
{"code": "user:manage", "domain": "user", "action": "manage"},
{"code": "moderation:manage", "domain": "moderation", "action": "manage"},
{"code": "gamification:manage", "domain": "gamification", "action": "manage"},
]
# Target roles: SUPERADMIN=1, ADMIN=2
TARGET_ROLE_IDS = [1, 2]
async def main():
engine = create_async_engine(DATABASE_URL, echo=False)
async_session_factory = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
async with async_session_factory() as session:
# ── Step 1: Fetch existing permission codes ──
result = await session.execute(text("SELECT code FROM system.permissions"))
existing_codes = {row[0] for row in result.all()}
logger.info(f"Existing permission codes ({len(existing_codes)}): {sorted(existing_codes)}")
# ── Step 2: Insert missing permissions ──
inserted_ids = {} # code -> id
for perm in PHANTOM_PERMISSIONS:
if perm["code"] in existing_codes:
logger.info(f" ⏭️ Already exists: {perm['code']}")
# Fetch its id
row = (await session.execute(
text("SELECT id FROM system.permissions WHERE code = :code"),
{"code": perm["code"]},
)).scalar_one_or_none()
if row:
inserted_ids[perm["code"]] = row
continue
logger.info(f" Inserting: {perm['code']} (domain={perm['domain']})")
row = (await session.execute(
text("""
INSERT INTO system.permissions (code, domain, action, description, is_system)
VALUES (:code, :domain, :action, :description, TRUE)
RETURNING id
"""),
{
"code": perm["code"],
"domain": perm["domain"],
"action": perm["action"],
"description": f"Auto-inserted by P0 fix: {perm['code']}",
},
)).scalar_one()
inserted_ids[perm["code"]] = row
await session.commit()
logger.info(f"✅ Permission insertion complete. {len(inserted_ids)} codes tracked.")
# ── Step 3: Fetch existing role_permission pairs ──
result = await session.execute(
text("SELECT role_id, permission_id FROM system.role_permissions WHERE granted = TRUE")
)
existing_pairs = {(row[0], row[1]) for row in result.all()}
logger.info(f"Existing role_permission pairs: {len(existing_pairs)}")
# ── Step 4: Insert missing role_permission mappings ──
inserted_count = 0
for code, perm_id in inserted_ids.items():
for role_id in TARGET_ROLE_IDS:
if (role_id, perm_id) in existing_pairs:
logger.info(f" ⏭️ Already mapped: role_id={role_id} -> {code}")
continue
logger.info(f" Mapping: role_id={role_id} -> {code} (perm_id={perm_id})")
await session.execute(
text("""
INSERT INTO system.role_permissions (role_id, permission_id, granted)
VALUES (:role_id, :perm_id, TRUE)
"""),
{"role_id": role_id, "perm_id": perm_id},
)
inserted_count += 1
await session.commit()
logger.info(f"✅ Role-permission mapping complete. {inserted_count} new mappings inserted.")
# ── Step 5: Verify ──
logger.info("\n🔍 VERIFICATION:")
result = await session.execute(
text("""
SELECT p.code, r.name, rp.granted
FROM system.role_permissions rp
JOIN system.permissions p ON p.id = rp.permission_id
JOIN system.roles r ON r.id = rp.role_id
WHERE p.code IN :codes
ORDER BY p.code, r.name
"""),
{"codes": tuple(perm["code"] for perm in PHANTOM_PERMISSIONS)},
)
for row in result.all():
logger.info(f" {row[0]} | role={row[1]} | granted={row[2]}")
await engine.dispose()
logger.info("\n🎉 Done. All 8 phantom permissions have been inserted and mapped.")
if __name__ == "__main__":
asyncio.run(main())