Add a create mutation to the policy store GraphQL API

What does this MR do and why?

This merge request adds a new GraphQL API operation (GovernPolicyCreate) that allows users to create security policies in the policy store for an organization. The feature is introduced as an experimental capability (GitLab 19.4) and requires the user to be an organization owner with appropriate permissions.

The operation accepts policy details such as name, description, trigger type, rules, actions, enforcement mode, and scope, then saves the policy to the policy store. It includes proper error handling: access is silently blocked for unauthorized users or when the feature is disabled, validation errors are returned as user-facing messages, and unexpected internal failures are logged and surfaced as a generic error message. Tests cover successful creation, invalid inputs, permission checks, and feature flag/license gating.

References

Screenshots or screen recordings

No UI changes.

How to set up and validate locally

  1. In a rails console, enable the feature flag: Feature.enable(:security_policies_v2)
  2. Enable the experiment setting: Gitlab::CurrentSettings.current_application_settings.update!(policy_store_experiment_enabled: true)
  3. Ensure the instance/group has an Ultimate license.
  4. Sign in as an organization owner (or admin) and open GraphiQL at /-/graphql-explorer.
  5. Run:
mutation {
  governPolicyCreate(input: {
    organizationId: "gid://gitlab/Organizations::Organization/1",
    name: "Block deploys to production",
    triggerType: "deployment_requested",
    rules: [{ type: "environment", value: { names: ["production"] } }],
    actions: [{ type: "block" }]
  }) {
    policy {
      id
      name
      triggerType
    }
    errors
  }
}

Expect:

{
  "data": {
    "governPolicyCreate": {
      "policy": {
        "id": 1,
        "name": "Block deploys to production",
        "triggerType": "deployment_requested"
      },
      "errors": []
    }
  }
}
  1. Confirm it's listed, via the policies field added in MR 250240:
query {
  organization(id: "gid://gitlab/Organizations::Organization/1") {
    policyStore {
      policies {
        id
        name
      }
    }
  }
}

Specs: ee/spec/requests/api/graphql/mutations/govern/policy_create_spec.rb (happy path, empty rules rejection, store validation failure, conflicting policy_scope+scope_rego, unmapped-reason tracking, non-owner/outside-user denial, flag/setting/license off → resource-not-available, granular-token shared example) and ee/spec/graphql/mutations/govern/policy_create_spec.rb (schema assertions). Local result: 19 examples, 0 failures, 1 pending (granular-token shared example's built-in skip for instance boundaries). Rubocop clean.

rake gitlab:graphql:update_all, rake gitlab:permissions:graphql:compile_docs, rake gitlab:permissions:routes:compile_docs, and rake gitlab:permissions:validate were run and are green; generated docs and introspection schema changes are committed.

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist.

Edited by Artur Fedorov

Merge request reports

Loading
Loading