Add GraphQL catalog queries for the policy store
What does this MR do and why?
This change adds a new Policy Store feature to GitLab's GraphQL API (introduced as an experimental feature in GitLab 19.4). It exposes a catalog of available building blocks — actions, rules, and triggers — that users can reference when creating security policies.
The catalog is accessible via both Groups and Organizations through a new policyStore field, but only when the policy store experiment is enabled (controlled by a feature flag at the group or instance level). If the experiment isn't active, the field returns null.
The change includes the necessary API type definitions, a resolver that checks whether the feature is enabled before returning data, and full test coverage for the new fields and their behavior.
Related to https://gitlab.com/gitlab-org/gitlab/-/work_items/613019.
References
- Issue (confidential): https://gitlab.com/gitlab-org/gitlab/-/work_items/613019
- Epic: https://gitlab.com/groups/gitlab-org/-/epics/22027
- REST endpoints this mirrors: !249148 (merged)
- Published spec (members only): https://security-policies-knowledge-d7e8b2.gitlab.io/epics/22027-cd-deployment-policies/specs/613019-graphql-policy-store-api/
- Delivery evidence (members only): https://security-policies-knowledge-d7e8b2.gitlab.io/epics/22027-cd-deployment-policies/evidence/613019-delivery/
Verification
- Type specs:
ee/spec/graphql/types/govern/policy_store_{trigger,rule,action,}type_spec.rb; request specee/spec/requests/api/graphql/govern/policy_store_catalogs_spec.rbcovers both parents and every gating axis separately (flag, instance setting, license, group opt-in, non-root group) — judged by CI. bundle exec rake gitlab:permissions:validate→GraphQL permissions are valid; RuboCop clean; pre-push hooksgraphql_introspection_check,permissions-verify, andgraphql_docspassed.- The catalog types override
def idbecauseBaseObject#idbuilds a GlobalID that plain hashes lack. - Adversarial review verdict on the initial (root-level) shape, verbatim: pass with findings; the follow-up commit moved the fields onto
Group/Organizationto fix the under-gating described above. Accepted findings: plain lists rather than connections, andStringcatalog ids rather than an enum (the catalog is data and will come from a remote store service later).
Screenshots or screen recordings
| Description | UI |
|---|---|
| New queries | ![]() |
How to set up and validate locally
-
In
rails console, activate the experiment (Ultimate license required):Feature.enable(:security_policies_v2) Gitlab::CurrentSettings.update!(policy_store_experiment_enabled: true) -
Validate the organization catalogs in GraphiQL (
/-/graphql-explorer):{ organization(id: "gid://gitlab/Organizations::Organization/1") { policyStore { triggers { id name } rules { id name } actions { id name } } } } -
For the group catalogs, also opt a root group in:
Group.find_by_full_path('gitlab-org').namespace_settings.update!(policy_store_experiment_enabled: true)then query:
{ group(fullPath: "gitlab-org") { policyStore { triggers { id name } rules { id name } actions { id name } } } } -
Expect the static catalogs: the
deployment_requestedtrigger;custom,calendar, andenvironmentrules;blockandrequire_approvalactions. -
Expect
policyStoreto returnnullwhen the feature flag or instance setting is off, on non-root groups, and on root groups that have not opted in.
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist.
