Loading
Paginate policy store policies GraphQL field as a connection
What does this MR do and why?
Summary
The policies field in the GraphQL API has been upgraded from returning a plain list to returning a paginated connection, allowing clients to fetch large policy sets in manageable chunks rather than all at once.
Key changes:
- Clients now navigate results using
nodesandpageInfo(withhasNextPageandendCursor) instead of receiving a flat array. - Pagination is forward-only: use
firstto set page size andafterwith the previousendCursorto advance. The page size is capped at the policy store's maximum. - Passing
idstogether with pagination arguments (firstorafter) is explicitly rejected with a clear error, since the backend returns all ID matches at once and combining them would silently drop results. - Invalid or out-of-range cursors are handled gracefully — bad cursors return an error, and cursors pointing beyond the last available page are clamped to the service maximum.
- Requesting
first: 0short-circuits immediately and returns an empty page without hitting the backend. - Tests and API documentation have been updated to reflect the new paginated shape and cover edge cases like cursor validation, page size capping, and the
ids+pagination restriction. - The frontend now reads from the connection as well: the shared query document selects
nodesandpageInfoand acceptsfirstandafter, and the list mapper and the single-policy read take their rows fromnodes. This was originally split into a stacked merge request, but thegraphql-verifyjob validates every checked-in query document against the merged schema, so the schema change and the query change have to land together.
References
- Related to https://gitlab.com/gitlab-org/gitlab/-/work_items/628956
- Plan and decision record: https://gitlab.com/gitlab-org/gitlab/-/work_items/628956#note_3830559865
- Frontend adaptation was folded in from !255618 (closed), which is now redundant
- Related to the REST pagination MR: !252366 (merged)
- Related to the MR that moved the list to GraphQL: !252319 (merged)
Screenshots or screen recordings
| Description | UI |
|---|---|
| GraphQl Result | ![]() |
How to set up and validate locally
- In a Rails console, enable the experiment:
Feature.enable(:security_policies_v2)ApplicationSetting.current.update!(policy_store_experiment_enabled: true)Organizations::Organization.find(1).update!(policy_store_experiment_enabled: true)- You must own the organization.
- Create more than 20 policies with
POST /api/v4/organizations/1/security/policy_store. - In
http://gdk.test:3000/-/graphql-explorer, run:
{
organization(id: "gid://gitlab/Organizations::Organization/1") {
policyStore {
policies(first: 5) {
nodes { id name }
pageInfo { hasNextPage endCursor }
}
}
}
}Expect 5 nodes and hasNextPage: true.
- Repeat with
after: "<endCursor>". Expect the next 5 nodes, andhasNextPage: falseon the last page. - Run
policies(ids: [1], first: 1). Expect the error "ids cannot be combined with first or after". - Open the policy store list page for the organization and confirm policies still render, then open one policy. Both read through the updated query document.
- Run
yarn jest ee/spec/frontend/policy_store. Expected result: all suites pass.
MR acceptance checklist
Evaluated against the MR acceptance checklist.
Edited by Artur Fedorov
