Add group secret create mutation

What does this MR do and why?

This MR implements the GraphQL mutation for creating group-level secrets, building on the service layer foundation from !218785 (merged). This is MR 2 in the implementation sequence, focusing on the API layer.

What this adds:

  • Mutations::SecretsManagement::GroupSecrets::Create - GraphQL mutation for creating group secrets
  • Request specs for the create mutation
  • Integration with the GroupSecrets::CreateService from !218785 (merged)
  • Proper authorization checks using GroupSecretPolicy
  • Error handling and validation feedback

Key implementation details:

GraphQL Mutation

The mutation accepts the following arguments:

  • groupPath (required) - Full path to the group (e.g., gitlab-org/subgroup)
  • name (required) - Secret name (alphanumeric + underscores only)
  • secret (required) - Secret value (max 10k bytes)
  • environment (required) - Environment scope (e.g., production, * for all)
  • protected (required) - Boolean flag for protected branch restriction
  • description (optional) - Human-readable description

Returns:

  • groupSecret - The created secret object with metadata
  • errors - Array of validation/authorization errors

Authorization

  • Requires write_secret permission on the group
  • Uses GroupSecretPolicy which delegates to group permissions
  • Returns proper error messages for unauthorized access

Scoping Behavior

Group secrets use environment + protected for access control:

  • environment: 'production', protected: true → Only accessible from protected branches in production
  • environment: '*', protected: false → Accessible from any branch in any environment
  • environment: 'staging', protected: false → Accessible from any branch in staging

This differs from project secrets which use environment + branch scoping.

Error Handling

The mutation handles:

  • Validation errors - Invalid name format, missing required fields, value too large
  • Authorization errors - User lacks permission to create secrets
  • Duplicate errors - Secret with same name already exists
  • OpenBao errors - Connection issues, policy creation failures

Example Usage

mutation {
  groupSecretCreate(input: {
    groupPath: "gitlab-org/my-group"
    name: "DATABASE_PASSWORD"
    secret: "super-secret-value"
    environment: "production"
    protected: true
    description: "Production database credentials"
  }) {
    groupSecret {
      name
      description
      environment
      protected
      metadataVersion
    }
    errors
  }
}

Integration with Service Layer

The mutation delegates to GroupSecrets::CreateService which:

  1. Validates the secret attributes
  2. Writes the secret value to OpenBao
  3. Creates/updates OpenBao policies for CI access
  4. Tracks creation lifecycle (started_at, completed_at)
  5. Returns the secret with metadata_version for optimistic locking

Testing

Comprehensive request specs cover:

  • Successful secret creation
  • Authorization checks (owner, maintainer, developer, guest)
  • Validation errors (invalid name, missing fields, value too large)
  • Duplicate secret handling
  • Policy creation for different environment/protected combinations
  • Internal event tracking

Related to #577342

This is MR 2 based on !218365 (comment 3004462962)

Dependencies:

  • !218785 (merged) - Implement create/update services for group secret (merged)

Next steps:

  • MR 3: Add groupSecretUpdate mutation
  • MR 4: Add groupSecretDelete mutation
  • MR 5: Add group secrets list query
Edited by Erick Bajao

Merge request reports

Loading