Migrate policy store createPolicy to the GraphQL mutation
What does this MR do and why?
Summary
Policy creation has been migrated from a direct REST API call to a GraphQL mutation (governPolicyCreate). Previously, creating a policy sent an HTTP POST request to the organization's policy store endpoint; now it sends a GraphQL mutation instead, which is more consistent with how the rest of the application communicates with the backend.
As part of this change, a new custom error class (PolicyStoreMutationError) was introduced to cleanly represent validation failures returned by the GraphQL mutation (e.g., duplicate names or invalid rules). This allows the error-handling logic to treat GraphQL validation errors the same way it previously treated REST API 400 errors, so users still see meaningful error messages when something goes wrong.
The old REST-based createPolicyStorePolicy method has been removed from the API layer since it is no longer needed. Tests have been updated throughout to reflect the new GraphQL-based flow and the new error type.
Closes https://gitlab.com/gitlab-org/gitlab/-/issues/617791
References
- Approved plan: https://gitlab.com/gitlab-org/gitlab/-/issues/617791#note_3739595318
- Parent epic: https://gitlab.com/groups/gitlab-org/-/epics/22542
- Backend mutation:
ee/app/graphql/mutations/govern/policy_create.rb
Screenshots or screen recordings
No UI changes — behavior-preserving transport migration.
How to set up and validate locally
The feature is an experiment, gated by the security_policies_v2 feature flag (instance-level), the policy_store_experiment_enabled application setting, and an Ultimate license.
- In rails console:
Feature.enable(:security_policies_v2)andApplicationSetting.current.update!(policy_store_experiment_enabled: true)(Ultimate license required). - Visit a group's Secure > Policies policy store list and create a new policy through the wizard (name, trigger, at least one rule), then Save.
- Expected: the browser's network tab shows a
governPolicyCreaterequest to/api/graphql(no POST to/api/v4/organizations/.../security/policy_store), and the editor returns to the list with a "Policy ... was created." confirmation. - Create another policy with the same name. Expected: an inline "A policy with this name already exists." error on the name field, no page alert.
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist.
Verification
Jest: Test Suites: 30 passed, 30 total · Tests: 494 passed, 494 total (full policy_store + api_spec run).
Adversarial review verdict: pass with findings (all findings addressed or recorded as follow-ups):
- Post-create redirect to the new policy's detail view is a possible follow-up now that the mutation returns the id.
- The wizard's
canSavegating is what keeps the mutation's non-null arguments satisfied. - The REST create endpoint now has no frontend caller and is removed with the update/delete migrations.