Files
cleveragents-core/robot/helper_permission_system.py
Luis Mendes 64af753aab
CI / benchmark-publish (pull_request) Has been skipped
CI / lint (pull_request) Successful in 15s
CI / build (pull_request) Successful in 17s
CI / quality (pull_request) Successful in 19s
CI / security (pull_request) Successful in 32s
CI / typecheck (pull_request) Successful in 36s
CI / integration_tests (pull_request) Successful in 2m40s
CI / unit_tests (pull_request) Successful in 11m42s
CI / docker (pull_request) Successful in 40s
CI / benchmark-regression (pull_request) Successful in 21m35s
CI / coverage (pull_request) Successful in 45m10s
CI / lint (push) Successful in 12s
CI / quality (push) Successful in 18s
CI / build (push) Successful in 23s
CI / security (push) Successful in 32s
CI / typecheck (push) Successful in 57s
CI / benchmark-regression (push) Has been skipped
CI / integration_tests (push) Successful in 2m43s
CI / unit_tests (push) Successful in 12m13s
CI / benchmark-publish (push) Successful in 12m19s
CI / docker (push) Successful in 1m2s
CI / coverage (push) Successful in 1h26m6s
feat(security): add permission system
Implemented namespace/project/plan/skill permission model with role
bindings (owner/admin/editor/viewer) and default deny policy. Added
enforcement hooks at CLI/service boundaries that are server-only; local
mode returns permissive defaults. Includes role enums, permission check
service, role matrix documentation.

Includes Behave BDD scenarios, Robot integration tests, ASV benchmarks,
and reference documentation.

ISSUES CLOSED: #344
2026-02-28 20:21:18 +00:00

114 lines
3.2 KiB
Python

"""Robot Framework helper for permission system integration tests.
Exposes keyword functions that exercise the permission domain model
and PermissionService from Python so Robot tests can validate
behaviour without importing modules directly in Robot syntax.
"""
from __future__ import annotations
import os
import sys
# Ensure the src directory is on the path for imports
_src = os.path.join(os.path.dirname(__file__), "..", "src")
if _src not in sys.path:
sys.path.insert(0, _src)
from cleveragents.application.services.permission_service import ( # noqa: E402
PermissionService,
)
from cleveragents.domain.models.core.permission import ( # noqa: E402
DEFAULT_LOCAL_ROLE_MAPPING,
ROLE_PERMISSIONS,
PermissionAction,
PermissionRole,
PermissionScope,
RoleBinding,
)
_SERVER_MODE_ENV = "CLEVERAGENTS_SERVER_MODE"
def get_permission_roles() -> list[str]:
"""Return all PermissionRole values."""
return [r.value for r in PermissionRole]
def get_permission_scopes() -> list[str]:
"""Return all PermissionScope values."""
return [s.value for s in PermissionScope]
def get_permission_actions() -> list[str]:
"""Return all PermissionAction values."""
return [a.value for a in PermissionAction]
def check_permission_local_mode(
principal: str, action: str, scope: str, scope_id: str
) -> bool:
"""Run a permission check in local mode and return the result."""
os.environ.pop(_SERVER_MODE_ENV, None)
svc = PermissionService()
check = svc.check_permission(
principal=principal,
action=PermissionAction(action),
scope=PermissionScope(scope),
scope_id=scope_id,
)
return check.result
def check_permission_server_no_bindings(
principal: str, action: str, scope: str, scope_id: str
) -> bool:
"""Run a permission check in server mode with no bindings."""
os.environ[_SERVER_MODE_ENV] = "true"
svc = PermissionService()
check = svc.check_permission(
principal=principal,
action=PermissionAction(action),
scope=PermissionScope(scope),
scope_id=scope_id,
)
os.environ.pop(_SERVER_MODE_ENV, None)
return check.result
def check_permission_server_with_binding(
principal: str,
role: str,
action: str,
scope: str,
scope_id: str,
) -> bool:
"""Run a permission check in server mode with a specific binding."""
os.environ[_SERVER_MODE_ENV] = "true"
binding = RoleBinding(
principal=principal,
role=PermissionRole(role),
scope=PermissionScope(scope),
scope_id=scope_id,
)
svc = PermissionService(bindings=[binding])
check = svc.check_permission(
principal=principal,
action=PermissionAction(action),
scope=PermissionScope(scope),
scope_id=scope_id,
)
os.environ.pop(_SERVER_MODE_ENV, None)
return check.result
def get_role_action_count(role: str) -> int:
"""Return the number of allowed actions for a given role."""
perm_role = PermissionRole(role)
return len(ROLE_PERMISSIONS[perm_role])
def get_default_local_role() -> str:
"""Return the default local role for the wildcard principal."""
return str(DEFAULT_LOCAL_ROLE_MAPPING["*"])