Authz Redaction Service for Knowledge Graph
What does this MR do and why?
This MR introduces Authz::RedactionService, a new service that performs batch authorization checks for resources.
This service is the foundation for Layer 3: Final Redaction Layer in the Knowledge Graph Security Architecture.
This code isn't used anywhere yet, it is a prerequisite before introducing the endpoint.
References
- This MR is one of a few MRs as a part of Knowledge Graph AuthZ Rails Redaction Endpoint (#583850)
- Knowledge Graph Rails Integration Epic
Problem this is solving
The Knowledge Graph service queries ClickHouse for GitLab data (issues, merge requests, vulnerabilities, etc.) that has been pre-filtered using traversal IDs. However, traversal ID filtering provides only coarse-grained authorization at the group/project level. It cannot account for:
- Confidential issues - Only visible to project members and issue participants
- Runtime checks - SAML group links, IP restrictions
- Custom roles - Fine-grained permissions beyond Reporter+ access
- Other resource-specific visibility - Feature access levels, banned/blocked users
Rails is the authoritative source for all authorization decisions via Ability.allowed?. Any service that returns search or discovery results must perform final redaction using Rails authorization.
Solution
Authz::RedactionService provides a generic, reusable service for batch authorization checks that:
- Accepts a user and a hash of resources grouped by type (e.g.,
{ 'issues' => [1, 2, 3], 'merge_requests' => [4, 5] }) - Batch loads resources with association preloading to prevent N+1 queries
- Performs authorization checks using
Ability.allowed?withDeclarativePolicy.user_scopeoptimization - Returns authorization results as a hash mapping resource IDs to boolean values
Important Notes
- Does not include all items: This MR will not include every item we plan to index, only a subset. Future items will be added in subsequent MRs.
- Assumes authenticated user: The service does NOT validate user state (blocked, deactivated, etc.). The caller (API endpoint) is responsible for authentication and user validation. Marks it clearly as so.
-
Follows SearchService pattern: Uses the same
visible_result?pattern as SearchService to ensure consistent authorization behavior. - Accepts optional logger: For audit logging of redacted results (to be used by the API endpoint).
How to set up and validate locally
There are many ways that this service could filter out data but here is one example
- Create a confidential issue
- Create a non-confidential issue
- Add a guest user to the issue's parent project (guests cannot read confidental issues)
- Call the service for the guest user
service = Authz::RedactionService.new(
user: guest_user,
resources_by_type: {
'issues' => [$CONFIDENTIAL_ISSUE_ID, $NON_CONFIDENTIAL_ISSUE_ID]
}
)
result = service.execute
# => {
# 'issues' => { CONFIDENTIAL_ISSUE_ID => false, NON_CONFIDENTIAL_ISSUE_ID => true }
# }