File size: 2,152 Bytes
b65ef75
 
 
 
 
 
 
 
 
 
 
 
 
adf80ee
b65ef75
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
from __future__ import annotations

from typing import Optional, Set

# Role hierarchy used across MCP server and FastAPI routes
VALID_ROLES = ("viewer", "editor", "admin", "owner")
ROLE_ORDER = {role: idx for idx, role in enumerate(VALID_ROLES)}

# Permission matrix defining which roles can perform which enterprise actions
PERMISSIONS: dict[str, Set[str]] = {
    "manage_rules": {"owner", "admin"},
    "ingest_documents": {"owner", "admin", "editor"},
    "delete_documents": {"owner", "admin"},
    "view_analytics": {"viewer", "editor", "admin", "owner"},  # All roles can view analytics
}

# Mapping of MCP tool names to enterprise actions
TOOL_PERMISSION_MAP: dict[str, str] = {
    "admin.addRule": "manage_rules",
    "admin.deleteRule": "manage_rules",
    "rag.ingest": "ingest_documents",
    "rag.delete": "delete_documents",
}


def normalize_role(raw_value: Optional[str]) -> str:
    """
    Normalize an inbound role string. Defaults to 'viewer' when undefined or invalid.
    """
    if not raw_value:
        return "viewer"
    value = raw_value.strip().lower()
    if value not in VALID_ROLES:
        return "viewer"
    return value


def allowed_roles_for(action: str) -> Set[str]:
    """
    Return the set of roles that can execute the given action.
    If the action is unknown, all roles are allowed.
    """
    return PERMISSIONS.get(action, set(VALID_ROLES))


def role_allows(role: str, action: str) -> bool:
    """
    Check whether the supplied role has permission for the action.
    Unknown actions default to allow-all to avoid accidental lockouts.
    """
    allowed = allowed_roles_for(action)
    return role in allowed if allowed else True


def describe_allowed_roles(action: str) -> str:
    """
    Return a human-friendly description of which roles are allowed for an action.
    """
    allowed = sorted(allowed_roles_for(action), key=lambda r: ROLE_ORDER.get(r, 0))
    return ", ".join(allowed)


def get_required_action_for_tool(tool_name: str) -> Optional[str]:
    """
    Look up the enterprise action that applies to a tool name, if any.
    """
    return TOOL_PERMISSION_MAP.get(tool_name)