Files
zeekay b7f9a67e2a fix: sever the ee coupling the rebase reintroduced, and boot
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.
2026-08-01 22:22:44 -07:00

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)