mirror of
https://github.com/ansible/awx.git
synced 2026-10-31 06:26:15 -02:30
AAP-96178: Fix unified_jobs pagination count to respect RBAC filtering (#16751)
* AAP-96178: Fix unified_jobs pagination count to respect RBAC filtering Non-admin users saw the unfiltered table-wide count instead of the count matching their RBAC-visible results. Use the same primary-key subquery approach already proven on the /api/v2/jobs/ endpoint. * AAP-96178: Add docstrings and mixed-role count test for UnifiedJobPaginator Clarify the PK subquery approach with expanded docstring and inline comments per review feedback. Add a functional test verifying that a user with a mix of JT and inventory roles sees a count matching exactly their permitted results. * AAP-96178: Add deduplication test for multiple RBAC access routes Verify that a job reachable through three overlapping permission paths (direct JT role, org audit role, and team JT role) appears exactly once in both results and count. Assisted-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+11
-3
@@ -16,7 +16,7 @@ from django.utils.translation import gettext_lazy as _
|
||||
from ansible_base.rest_filters.rest_framework.field_lookup_backend import (
|
||||
FieldLookupBackend,
|
||||
)
|
||||
from awx.main.models import ActivityStream, UnifiedJob
|
||||
from awx.main.models import ActivityStream
|
||||
|
||||
|
||||
class DisabledPaginator(DjangoPaginator):
|
||||
@@ -38,11 +38,19 @@ class ActivityStreamPaginator(DjangoPaginator):
|
||||
|
||||
|
||||
class UnifiedJobPaginator(DjangoPaginator):
|
||||
"""Use unfiltered table count for unified job pagination."""
|
||||
"""Count only the unified jobs the requesting user can see.
|
||||
|
||||
Uses a PK subquery so the database can index-scan the RBAC-filtered
|
||||
primary keys instead of counting the full UNION queryset directly.
|
||||
Same approach as JobPaginator.
|
||||
"""
|
||||
|
||||
@cached_property
|
||||
def count(self):
|
||||
return UnifiedJob.objects.count()
|
||||
# Collect PKs from the RBAC-filtered queryset (stripping ORDER BY for efficiency),
|
||||
# then COUNT against the base table using an index-only scan on the PK.
|
||||
visible_pks = self.object_list.order_by().values("pk")
|
||||
return self.object_list.model.objects.filter(pk__in=visible_pks).count()
|
||||
|
||||
|
||||
class JobPaginator(DjangoPaginator):
|
||||
|
||||
Reference in New Issue
Block a user