Add group REST CRUD endpoints for policy store
What does this MR do and why?
Adds group REST CRUD endpoints for the policy store, allowing group owners to manage security policies scoped to their group without requiring organization-level access.
This is MR 2 of 4 splitting the group-scoped policy store access work from !252678 (closed).
Depends on: !253003 (merged) (MR 1: Container-based authorization substrate) - now merged
Changes
API endpoints (ee/lib/api/govern/policies.rb):
GET /groups/:id/security/policy_store- List policies scoped to a groupGET /groups/:id/security/policy_store/:policy_id- Get a single policyPOST /groups/:id/security/policy_store- Create a policy scoped to a groupPATCH /groups/:id/security/policy_store/:policy_id- Update a policyDELETE /groups/:id/security/policy_store/:policy_id- Delete a policy
GPAT boundaries (config/authz/permission_groups/assignable_permissions/application_security/govern_policy/):
- Added
groupboundary tocreate.yml,read.yml,update.yml,delete.yml - Enables group-scoped granular access tokens to authorize against these endpoints
Code quality:
- Extracted
render_policy_store_error!to class-level helpers (DRY - was duplicated)
Authorization model
- Group owners can manage policies within their group
- Non-owners get 403 Forbidden
- Non-members of private groups get 404 Not Found
- Policies are scoped by
namespace_id- a group cannot see/modify organization-wide policies or other groups' policies
How to set up and validate locally
-
Enable the feature flag and experiment settings in Rails console:
Feature.enable(:security_policies_v2) ApplicationSetting.current.update!(policy_store_experiment_enabled: true) -
Enable the experiment for your group's organization and namespace:
group = Group.find_by_full_path('your-group') Organizations::OrganizationSetting.for(group.organization_id).update!(policy_store_experiment_enabled: true) NamespaceSetting.find_or_initialize_by(namespace_id: group.id).update!(policy_store_experiment_enabled: true) -
Create a personal access token with
apiscope for a group owner -
Test the endpoints:
# List policies (empty initially) curl --header "PRIVATE-TOKEN: <token>" "http://localhost:3000/api/v4/groups/<group_id>/security/policy_store" # Create a policy curl --request POST --header "PRIVATE-TOKEN: <token>" \ --header "Content-Type: application/json" \ --data '{"name": "Test policy", "trigger_type": "deployment_requested", "rules": [{"type": "custom", "value": "test"}]}' \ "http://localhost:3000/api/v4/groups/<group_id>/security/policy_store" # Get the created policy curl --header "PRIVATE-TOKEN: <token>" "http://localhost:3000/api/v4/groups/<group_id>/security/policy_store/<policy_id>" # Update the policy curl --request PATCH --header "PRIVATE-TOKEN: <token>" \ --header "Content-Type: application/json" \ --data '{"name": "Renamed policy"}' \ "http://localhost:3000/api/v4/groups/<group_id>/security/policy_store/<policy_id>" # Delete the policy curl --request DELETE --header "PRIVATE-TOKEN: <token>" \ "http://localhost:3000/api/v4/groups/<group_id>/security/policy_store/<policy_id>" -
Verify authorization by testing with a non-owner user (should get 403)
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.
References
- Work item: #627173 (closed)
- Parent MR: !252678 (closed)
- MR 1 (merged): !253003 (merged)
- Follow-up for name uniqueness scoping: #628084