fix(rbac): close critical auth gaps — full RBAC audit remediation

CRITICAL — unauthenticated endpoints (CWE-306):
- agent_superset.py: 10 SQL/dashboard/dataset proxy endpoints → plugin:superset_proxy:EXECUTE
- agent_superset_explore.py: 10 database explore endpoints → plugin:superset_proxy:READ
- clean_release.py / clean_release_v2.py: router-level deny-by-default → clean_release:MANAGE
- settings.py: PUT/DELETE/test environment → admin:settings:WRITE/READ
- tasks.py: log/stats/sources/export → tasks:READ

HIGH — authorization gaps (CWE-285, CWE-613):
- require_api_key_or_jwt: add token blacklist + is_active + is_admin flag checks
- get_current_user: add is_active check
- WebSocket: add _authorize_websocket() RBAC helper, permission-gate all 6 WS endpoints
- agent_conversations: add Depends(get_current_user) to save endpoint + router-level guard
- legacy validation redirect: add validation.task:VIEW guard

MEDIUM — consistency & architecture:
- admin.py: fix permission parsing split(':',1) → rsplit(':',1)
- app.py lifespan: sync RBAC permission catalog at startup
- schemas/auth.py: add is_admin to RoleSchema (with BeforeValidator), RoleCreate, RoleUpdate
- models/auth.py: add is_admin support in create_role/update_role handlers
- permissions.ts: expand KNOWN_ACTIONS (VIEW/CREATE/EDIT/MANAGE/APPROVE/PREVIEW/LAUNCH/LAUNCH_PROD)
- permissions.ts: isAdminUser checks is_admin flag from /auth/me
- Navbar.svelte: replace exact role name check with hasPermission()
- admin/+page.svelte, admin/settings/llm/+page.svelte: add ProtectedRoute guards

TESTS:
- test_dependencies_unit.py: fix 5 tests for new is_token_blacklisted + is_admin checks
- test_api_key_auth.py: fix test_jwt_precedence for is_token_blacklisted mock
- permissions.test.ts: update non-KNOWN_ACTION test to use unknown suffix 'xyz'

VERIFIED: 230 backend tests pass, 3257 frontend tests pass, index rebuilt (7373 contracts, 3832 edges)
This commit is contained in:
2026-07-23 12:38:19 +03:00
parent e62735cc06
commit cd4b91daa5
19 changed files with 222 additions and 40 deletions

View File

@@ -15,7 +15,7 @@
# @TEST_EDGE: jwt_precedence -> JWT takes precedence over API key
from datetime import UTC, datetime, timedelta
import pytest
from unittest.mock import AsyncMock, MagicMock
from unittest.mock import AsyncMock, MagicMock, patch
from fastapi import HTTPException
from fastapi.testclient import TestClient
@@ -459,6 +459,7 @@ class TestRequireApiKeyOrJwt:
# Create a JWT user with Admin role (full access)
role = Role(name="Admin", description="Admin role")
role.is_admin = True
mock_db.add(role)
mock_db.commit()
@@ -485,14 +486,15 @@ class TestRequireApiKeyOrJwt:
app.dependency_overrides[get_auth_db] = _get_auth_db_override
# Send request with BOTH X-API-Key and Authorization: Bearer
response = client.post(
self.API_START_URL,
json=self.START_PAYLOAD,
headers={
"X-API-Key": raw_key,
"Authorization": f"Bearer {token}",
},
)
with patch('src.dependencies.is_token_blacklisted', return_value=False):
response = client.post(
self.API_START_URL,
json=self.START_PAYLOAD,
headers={
"X-API-Key": raw_key,
"Authorization": f"Bearer {token}",
},
)
assert response.status_code == 202
data = response.json()
assert "task_id" in data