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: bulkUpdateSecurityAttributes with 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 UpdateProjectAttributesService for consistency

Architecture

  1. GraphQL Mutation (Mutations::Security::Attributes::BulkUpdate)
    • Validates input arguments and authorization
    • Extracts authorized attribute objects
    • Delegates to service layer
  2. Service Layer (Security::Attributes::BulkUpdateService)
    • Optimized group expansion to projects using bulk queries
    • Batches projects for processing
    • Schedules async workers
  3. Async Worker (Security::Attributes::BulkUpdateWorker)
    • Processes individual project batches
    • Reuses existing UpdateProjectAttributesService
    • Handles per-project permissions and feature flags

Changelog: added EE: true

References

issue #577577

How to set up and validate locally

  1. Enable the feature flag:

    Feature.enable(:security_categories_and_attributes)
  2. 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
  3. 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
      }
    }
  4. Verify ADD mode:

    • Open each project → Secure → Security configuration → Security attributes
    • Check that the attributes were assigned to both projects
  5. 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
      }
    }
  6. 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

Merge request reports

Loading