mirror of
https://github.com/hanzoai/insights.git
synced 2026-10-30 16:15:31 +00:00
The rebase pulled upstream files that import ee/, a tree this distribution does not carry, so `django.setup()` raised ModuleNotFoundError: No module named 'ee' before any request could be served. main had already severed this; the rebase lost the severance. Restore insights/models/ee_models.py: the four RBAC models upstream keeps under ee/, mapped managed=False onto the tables that actually exist (ee_accesscontrol, ee_dashboardprivilege, ee_role, ee_rolemembership -- verified against the live database, which has those four and no other ee_ table). 131 files repointed at it. Restore main's insights/rbac/access_control_api_mixin.py. The rebase left a fallback of `class AccessControlViewSetMixin: pass`, which drops the dangerously_get_required_scopes hook that insights/api/project.py, insights/api/team.py and products/replay_vision reach through super() -- an AttributeError on scope derivation. Enforcement itself is unaffected either way: it lives in insights/rbac/user_access_control.py, in-tree. ExplicitTeamMembership has no table in this distribution, so it cannot emit the signal the org serializer cache subscribes to; drop the registration. SyncIterableToAsync moves in-tree next to the other streaming helpers, written from the interface rather than carried over, so the MCP store proxy no longer reaches into ee/ for a generic ASGI adapter. bin/debrand renamed the hog_flow directory and the HogFlow symbol but not the module path between them, leaving `from .hog_flow.hog_flow import InsightsFlow` pointing at a path that no longer exists (33 sites). Add the missing text rule so the rename is closed, and apply it.
70 lines
2.4 KiB
Python
70 lines
2.4 KiB
Python
from rest_framework import permissions
|
|
|
|
|
|
class CanApprove(permissions.BasePermission):
|
|
"""
|
|
Checks:
|
|
1. User is in the approver set (from policy_snapshot)
|
|
2. User is not the requester (if self-approval not allowed)
|
|
"""
|
|
|
|
message = "You do not have permission to approve this change request"
|
|
|
|
def has_object_permission(self, request, view, obj):
|
|
from products.approvals.backend.models import ChangeRequestState
|
|
|
|
if obj.state != ChangeRequestState.PENDING:
|
|
self.message = "Only pending change requests can be approved"
|
|
return False
|
|
|
|
policy_snapshot = obj.policy_snapshot
|
|
allow_self_approve = policy_snapshot.get("allow_self_approve", False)
|
|
is_requester = obj.created_by == request.user
|
|
|
|
# Check self-approval first - if requester and not allowed, deny immediately
|
|
if is_requester and not allow_self_approve:
|
|
self.message = "You cannot approve your own change request"
|
|
return False
|
|
|
|
# Check if user is in explicit approver set (users/roles)
|
|
if self._user_in_approver_set(request.user, policy_snapshot, obj):
|
|
return True
|
|
|
|
self.message = "You are not in the approver set for this change request"
|
|
return False
|
|
|
|
def _user_in_approver_set(self, user, policy_snapshot: dict, change_request) -> bool:
|
|
# Check direct user IDs
|
|
if "users" in policy_snapshot and user.id in policy_snapshot["users"]:
|
|
return True
|
|
|
|
# Check role membership
|
|
approver_roles = policy_snapshot.get("roles", [])
|
|
if approver_roles:
|
|
try:
|
|
from insights.models.ee_models import RoleMembership
|
|
except ImportError:
|
|
return False
|
|
|
|
user_roles = {
|
|
str(rid)
|
|
for rid in RoleMembership.objects.filter(
|
|
user=user,
|
|
role__organization=change_request.organization,
|
|
).values_list("role_id", flat=True)
|
|
}
|
|
|
|
if user_roles & {str(r) for r in approver_roles}:
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
class CanCancel(permissions.BasePermission):
|
|
"""Only the requester can cancel their own pending change request."""
|
|
|
|
message = "You cannot cancel this change request"
|
|
|
|
def has_object_permission(self, request, view, obj):
|
|
return obj.can_be_canceled_by(request.user.id)
|