173 lines
6.8 KiB
Python
173 lines
6.8 KiB
Python
"""
|
|
Unit tests for RBAC bootstrap initialization.
|
|
Tests that bootstrap creates correct rules and initial data.
|
|
"""
|
|
|
|
import pytest
|
|
from unittest.mock import Mock, MagicMock, patch
|
|
from modules.interfaces.interfaceBootstrap import (
|
|
initBootstrap,
|
|
initRootMandate,
|
|
initAdminUser,
|
|
initEventUser,
|
|
initRbacRules,
|
|
createDefaultRoleRules,
|
|
createTableSpecificRules
|
|
)
|
|
from modules.datamodels.datamodelUam import UserInDB, Mandate, AuthAuthority
|
|
from modules.datamodels.datamodelRbac import AccessRule, AccessRuleContext
|
|
from modules.datamodels.datamodelUam import AccessLevel
|
|
|
|
|
|
class TestRbacBootstrap:
|
|
"""Test RBAC bootstrap initialization."""
|
|
|
|
def testInitRootMandateCreatesIfNotExists(self):
|
|
"""Test that initRootMandate creates mandate if it doesn't exist."""
|
|
db = Mock()
|
|
db.getRecordset = Mock(return_value=[]) # No existing mandates
|
|
db.recordCreate = Mock(return_value={"id": "mandate1", "name": "Root"})
|
|
|
|
mandateId = initRootMandate(db)
|
|
|
|
assert mandateId == "mandate1"
|
|
db.recordCreate.assert_called_once()
|
|
callArgs = db.recordCreate.call_args
|
|
assert isinstance(callArgs[0][1], Mandate)
|
|
assert callArgs[0][1].name == "Root"
|
|
|
|
def testInitRootMandateReturnsExisting(self):
|
|
"""Test that initRootMandate returns existing mandate ID."""
|
|
db = Mock()
|
|
db.getRecordset = Mock(return_value=[{"id": "existing_mandate"}])
|
|
|
|
mandateId = initRootMandate(db)
|
|
|
|
assert mandateId == "existing_mandate"
|
|
db.recordCreate.assert_not_called()
|
|
|
|
def testInitAdminUserCreatesWithSysadminRole(self):
|
|
"""Test that initAdminUser creates user with sysadmin role."""
|
|
db = Mock()
|
|
db.getRecordset = Mock(return_value=[]) # No existing users
|
|
db.recordCreate = Mock(return_value={"id": "admin1", "username": "admin"})
|
|
|
|
with patch('modules.interfaces.interfaceBootstrap._getPasswordHash', return_value="hashed"):
|
|
userId = initAdminUser(db, "mandate1")
|
|
|
|
assert userId == "admin1"
|
|
db.recordCreate.assert_called_once()
|
|
callArgs = db.recordCreate.call_args
|
|
user = callArgs[0][1]
|
|
assert isinstance(user, UserInDB)
|
|
assert user.username == "admin"
|
|
assert "sysadmin" in user.roleLabels
|
|
|
|
def testInitEventUserCreatesWithSysadminRole(self):
|
|
"""Test that initEventUser creates user with sysadmin role."""
|
|
db = Mock()
|
|
db.getRecordset = Mock(return_value=[]) # No existing users
|
|
db.recordCreate = Mock(return_value={"id": "event1", "username": "event"})
|
|
|
|
with patch('modules.interfaces.interfaceBootstrap._getPasswordHash', return_value="hashed"):
|
|
userId = initEventUser(db, "mandate1")
|
|
|
|
assert userId == "event1"
|
|
db.recordCreate.assert_called_once()
|
|
callArgs = db.recordCreate.call_args
|
|
user = callArgs[0][1]
|
|
assert isinstance(user, UserInDB)
|
|
assert user.username == "event"
|
|
assert "sysadmin" in user.roleLabels
|
|
|
|
def testCreateDefaultRoleRules(self):
|
|
"""Test that createDefaultRoleRules creates correct default rules."""
|
|
db = Mock()
|
|
db.recordCreate = Mock()
|
|
|
|
createDefaultRoleRules(db)
|
|
|
|
# Should create 4 default rules (sysadmin, admin, user, viewer)
|
|
assert db.recordCreate.call_count == 4
|
|
|
|
# Check sysadmin rule
|
|
sysadminCall = [call for call in db.recordCreate.call_args_list
|
|
if call[0][1].roleLabel == "sysadmin"][0]
|
|
sysadminRule = sysadminCall[0][1]
|
|
assert sysadminRule.context == AccessRuleContext.DATA
|
|
assert sysadminRule.item is None
|
|
assert sysadminRule.view == True
|
|
assert sysadminRule.read == AccessLevel.ALL
|
|
assert sysadminRule.create == AccessLevel.ALL
|
|
|
|
# Check user rule
|
|
userCall = [call for call in db.recordCreate.call_args_list
|
|
if call[0][1].roleLabel == "user"][0]
|
|
userRule = userCall[0][1]
|
|
assert userRule.read == AccessLevel.MY
|
|
assert userRule.create == AccessLevel.MY
|
|
|
|
def testCreateTableSpecificRules(self):
|
|
"""Test that createTableSpecificRules creates table-specific rules."""
|
|
db = Mock()
|
|
db.recordCreate = Mock()
|
|
|
|
createTableSpecificRules(db)
|
|
|
|
# Should create multiple rules for different tables
|
|
assert db.recordCreate.call_count > 0
|
|
|
|
# Check that Mandate table rules are created
|
|
mandateCalls = [call for call in db.recordCreate.call_args_list
|
|
if call[0][1].item == "Mandate"]
|
|
assert len(mandateCalls) > 0
|
|
|
|
# Check sysadmin rule for Mandate
|
|
sysadminMandateCall = [call for call in mandateCalls
|
|
if call[0][1].roleLabel == "sysadmin"][0]
|
|
sysadminRule = sysadminMandateCall[0][1]
|
|
assert sysadminRule.view == True
|
|
assert sysadminRule.read == AccessLevel.ALL
|
|
|
|
# Check that other roles have view=False for Mandate
|
|
otherMandateCalls = [call for call in mandateCalls
|
|
if call[0][1].roleLabel != "sysadmin"]
|
|
for call in otherMandateCalls:
|
|
rule = call[0][1]
|
|
assert rule.view == False
|
|
|
|
def testInitRbacRulesSkipsIfExists(self):
|
|
"""Test that initRbacRules skips default rule creation if rules already exist, but adds missing table-specific rules."""
|
|
db = Mock()
|
|
# Mock existing rules - include rules for ChatWorkflow and Prompt to prevent adding missing rules
|
|
# Need rules for all required roles to fully prevent creation
|
|
existingRules = []
|
|
for table in ["ChatWorkflow", "Prompt"]:
|
|
for role in ["sysadmin", "admin", "user", "viewer"]:
|
|
existingRules.append({
|
|
"id": f"rule_{table}_{role}",
|
|
"item": table,
|
|
"context": AccessRuleContext.DATA.value,
|
|
"roleLabel": role
|
|
})
|
|
db.getRecordset = Mock(return_value=existingRules)
|
|
db.recordCreate = Mock()
|
|
|
|
initRbacRules(db)
|
|
|
|
# Should not create new rules since all required tables already have rules for all roles
|
|
db.recordCreate.assert_not_called()
|
|
|
|
def testInitRbacRulesCreatesIfNotExists(self):
|
|
"""Test that initRbacRules creates rules if they don't exist."""
|
|
db = Mock()
|
|
db.getRecordset = Mock(side_effect=[
|
|
[], # No existing rules
|
|
[] # After creating default rules
|
|
])
|
|
db.recordCreate = Mock()
|
|
|
|
initRbacRules(db)
|
|
|
|
# Should create rules
|
|
assert db.recordCreate.call_count > 0
|