Bulk add/remove attributes for groups and projects
What does this MR do and why?
This MR implements the bulk editing functionality for security attributes across multiple projects and groups, addressing the requirements outlined in issue #577577 and the API design specified in issue #578000.
Key Features
- Bulk Operations: Add or remove security attributes from multiple projects and groups simultaneously
- Authorization: Proper permission checks ensure users can only modify attributes they have access to
- Performance Optimized: Uses bulk queries and background workers to handle large-scale operations efficiently
-
Group Expansion: Automatically includes all projects within specified groups using
NamespaceProjectIdsEachBatch - Batching: Processes large numbers of projects in batches (default: 50) to prevent timeouts
Implementation Details
-
GraphQL Mutation:
bulkUpdateSecurityAttributeswith support for ADD/REMOVE modes - Background Processing: Uses Sidekiq workers for asynchronous processing
- Authorization: Validates user permissions for both security attributes and target projects/groups
- Error Handling: Graceful handling of invalid GIDs, missing permissions, and processing errors
-
Reuses Existing Logic: Leverages existing
UpdateProjectAttributesServicefor consistency
Architecture
-
GraphQL Mutation (
Mutations::Security::Attributes::BulkUpdate)- Validates input arguments and authorization
- Extracts authorized attribute objects
- Delegates to service layer
-
Service Layer (
Security::Attributes::BulkUpdateService)- Optimized group expansion to projects using bulk queries
- Batches projects for processing
- Schedules async workers
-
Async Worker (
Security::Attributes::BulkUpdateWorker)- Processes individual project batches
- Reuses existing
UpdateProjectAttributesService - Handles per-project permissions and feature flags
Changelog: added EE: true
References
How to set up and validate locally
-
Enable the feature flag:
Feature.enable(:security_categories_and_attributes) -
Create test data through the UI:
- Create a group
- Inside the group above, create:
- One project (note its ID)
- One subgroup with a project inside it (note the subgroup ID)
- Go to Group → Secure → Security Configuration
- Create a security attribute in the Category: "Application"
- Get the attribute ID from console:
Security::Attribute.last.id
-
Test the GraphQL mutation:
mutation bulkUpdateSecurityAttributes { bulkUpdateSecurityAttributes(input: { items: [ "gid://gitlab/Group/176", # subgroup ID "gid://gitlab/Project/77" # project in root namespace ID ], attributes: [ "gid://gitlab/Security::Attribute/45" # attribute ID from step 2 ], mode: ADD }) { errors } } -
Verify ADD mode:
- Open each project → Secure → Security configuration → Security attributes
- Check that the attributes were assigned to both projects
-
Test REMOVE mode:
mutation bulkUpdateSecurityAttributes { bulkUpdateSecurityAttributes(input: { items: [ "gid://gitlab/Group/176", # subgroup ID "gid://gitlab/Project/77" # project in root namespace ID ], attributes: [ "gid://gitlab/Security::Attribute/45" # attribute ID from step 2 ], mode: REMOVE }) { errors } } -
Verify REMOVE mode:
- Check that the attributes were removed from both projects
Files Added
Core Implementation
-
ee/app/graphql/mutations/security/attributes/bulk_update.rb- GraphQL mutation -
ee/app/graphql/types/security/attributes/bulk_update_mode_enum.rb- Mode enum (ADD/REMOVE) -
ee/app/services/security/attributes/bulk_update_service.rb- Service layer with optimized group expansion -
ee/app/workers/security/attributes/bulk_update_worker.rb- Background worker
Tests
-
ee/spec/graphql/mutations/security/attributes/bulk_update_spec.rb- Mutation unit tests -
ee/spec/requests/api/graphql/mutations/security/attributes/bulk_update_spec.rb- GraphQL integration tests -
ee/spec/services/security/attributes/bulk_update_service_spec.rb- Service tests -
ee/spec/workers/security/attributes/bulk_update_worker_spec.rb- Worker tests
Configuration
- Updated
ee/app/graphql/ee/types/mutation_type.rb- Registered new mutation - Updated
config/sidekiq_queues.yml- Added new worker queue - Updated
ee/app/workers/all_queues.yml- Worker configuration - Updated
doc/api/graphql/reference/_index.md- Auto-generated GraphQL documentation
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.
Security
- Authorization checks implemented for both security attributes and target resources
- Input validation for all GraphQL arguments
- Proper error handling without information leakage
- Reuses existing audit logging through
UpdateProjectAttributesService
Performance
- Bulk database queries to avoid N+1 problems
- Background processing for large operations
- Batching to handle large numbers of projects
- Optimized group expansion using
NamespaceProjectIdsEachBatch - Strong memoization for expensive operations
Testing
- Unit tests for all components
- GraphQL integration tests
- Worker tests with error scenarios
- Authorization and permission tests
- Edge cases: empty inputs, invalid GIDs, mixed valid/invalid items
Edited by Nicolae Rotaru