Add delete and list queries for group secrets permissions

What does this MR do and why?

Resolves #577341 (closed)

This MR implements the GraphQL mutation for deleting group-level secrets permissions and the query for listing group-level secrets permissions. This completes the CRUD operations for group secrets permissions, allowing group owners to manage who can access and manage secrets through the GitLab UI at the group level.

Important distinction: These permissions control who can manage secrets in the GitLab UI (create, read, update, delete secrets via the web interface). This is separate from CI/CD pipeline permissions that control which jobs can use secrets during execution.

This builds on the foundation established in !213562 (merged) which implemented the update mutation for group secrets permissions.

Technical Notes

Architecture & Design Decisions

1. Delete Mutation Implementation

The delete mutation follows the same pattern as project-level secrets permissions:

GraphQL Layer

  • GroupSecretsPermissionDelete mutation accepts groupPath and principal input
  • Returns the deleted permission object and any errors
  • Gated behind the group_secrets_manager feature flag

Service Layer

  • Reuses the shared SecretsPermissionsDeleteServiceHelpers concern
  • GroupSecretsPermissions::DeleteService implements:
    • resource - returns the group
    • client - returns the group secrets manager client
    • permission_class - returns GroupSecretsPermission

Authorization

  • Requires configure_group_secrets_permission (owner-only)
  • Consistent with the update mutation authorization

2. List Query Implementation

The list query enables fetching all permissions for a group:

GraphQL Layer

  • Added secretsPermissions field to GroupType
  • Returns an array of GroupSecretsPermissionType objects
  • Gated behind the group_secrets_manager feature flag

Service Layer

  • Reuses the shared SecretsPermissionsListServiceHelpers concern
  • GroupSecretsPermissions::ListService implements:
    • resource - returns the group
    • client - returns the group secrets manager client
    • permission_class - returns GroupSecretsPermission

Authorization

  • Requires read_group_secrets_permission (available to maintainers and owners)
  • Allows maintainers to view permissions without being able to modify them

3. Code Reusability

This MR demonstrates the effectiveness of the abstraction introduced in !213562 (merged):

  • Both delete and list services leverage the shared concerns (SecretsPermissionsDeleteServiceHelpers and SecretsPermissionsListServiceHelpers)
  • Minimal code duplication between project and group implementations
  • Each service only needs to define three simple methods: resource, client, and permission_class

GraphQL Mutation

Example: Deleting a permission

mutation {
  groupSecretsPermissionDelete(input: {
    groupPath: "my-group"
    principal: {
      id: 123
      type: USER
    }
  }) {
    secretsPermission {
      group {
        id
        fullPath
      }
      principal {
        id
        type
      }
      permissions
    }
    errors
  }
}

Example: Deleting a Group principal permission (using group_path)

mutation {
  groupSecretsPermissionDelete(input: {
    groupPath: "my-group"
    principal: {
      groupPath: "my-org/sub-group"
      type: GROUP
    }
  }) {
    secretsPermission {
      group {
        id
        fullPath
      }
      principal {
        id
        type
      }
      permissions
    }
    errors
  }
}

GraphQL Query

Example: Listing all permissions for a group

query {
  group(fullPath: "my-group") {
    secretsPermissions {
      principal {
        id
        type
      }
      permissions
      grantedBy {
        id
        username
      }
      expiredAt
    }
  }
}

Feature Flag

Both the mutation and query are gated behind the existing group_secrets_manager feature flag.

Database Changes

None - permissions are stored in OpenBao, not the database.

Follow-up Work

Project Secrets Permissions Namespace Migration

Related to #582213

Currently, project-level permissions mutations, queries, and services are under the Permissions namespace. To maintain consistency with the new GroupSecretsPermissions namespace, we need to migrate them to ProjectSecretsPermissions:

  1. Backend Migration MR: Migrate existing services to ProjectSecretsPermissions namespace

    • Move SecretsManagement::Permissions::ListServiceSecretsManagement::ProjectSecretsPermissions::ListService
    • Move SecretsManagement::Permissions::DeleteServiceSecretsManagement::ProjectSecretsPermissions::DeleteService
    • Update service references
  2. GraphQL Migration MR: Create new mutations/queries under ProjectSecretsPermissions namespace

    • Add new mutations: projectSecretsPermissionUpdate, projectSecretsPermissionDelete
    • Add new queries for listing project secrets permissions
    • Introduce actions field instead of permissions: The new field will return an array of actions (read, create, update, delete) instead of a stringified array. This better describes what users are doing with secrets and avoids breaking the frontend during migration.
    • Merge create and update permissions: Since users currently need both create AND update permissions to create a secret, the frontend and backend will handle these permissions together
    • New mutations will only accept group_path for Group principals (no id fallback)
    • Keep old mutations/queries (secretsPermissionUpdate, secretsPermissionDelete) for backward compatibility
    • Mark old mutations/queries as deprecated
  3. Frontend Migration: Update frontend to use new GraphQL mutations/queries with actions field and group_path

  4. Cleanup MR: Remove deprecated mutations/queries and id parameter fallback after frontend migration is complete

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.

Edited by Erick Bajao

Merge request reports

Loading