Secrets permissions graphql improvements
What does this MR do and why?
Resolves #582213
This MR introduces significant improvements to the secrets permissions GraphQL API by:
-
Introducing
actionsfield to replacepermissions- better semantic clarity and type safety -
Merging
createandupdateinto singleWRITEaction - simplifies the permission model since both are required to create secrets, and "write" is more intuitive for users -
Creating new project secrets permissions endpoints under
ProjectSecretsPermissionsnamespace for consistency withGroupSecretsPermissions -
Renaming payload keys from
secret_permissiontosecrets_permission(plural) for consistency - Maintaining backward compatibility with old endpoints during migration period
Important: 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.
Technical Notes
Architecture & Design Decisions
1. Actions vs Permissions
Why "actions" instead of "permissions"?
- More descriptive of what users are actually doing with secrets (read, write, delete)
- Avoids redundancy with the entity name (
SecretsPermission.permissionsis confusing) - Better semantic clarity for API consumers
- Enables use of GraphQL enum for type safety
Old behavior:
- Field name:
permissions - Type:
String(stringified array like"create,read,update,delete") - Values:
['create', 'update', 'read', 'delete'](four separate permissions)
New behavior:
- Field name:
actions - Type:
[SecretsManagementAction!]!(GraphQL enum array) - Values:
[READ, WRITE, DELETE](three actions,WRITEcombines create+update)
2. Merging Create and Update into WRITE Action
Problem: Users currently need BOTH create AND update permissions to create a secret, which is unintuitive.
Solution: Merge them into a single WRITE action that grants both create and update capabilities. The name "WRITE" is more intuitive for users as it clearly indicates the ability to create and modify secrets.
Implementation:
-
Model layer:
BaseSecretsPermissionnow usesactionsattribute instead ofpermissions -
Conversion methods:
-
to_capabilities: ConvertsWRITEaction →['create', 'update']capabilities for OpenBao -
set_actions_from_capabilities: Converts['create', 'update']capabilities →WRITEaction
-
-
Internal handling: OpenBao still uses separate
createandupdatecapabilities, but the API surface uses the simplerWRITEaction
3. New Project Secrets Permissions Endpoints
Created new mutations and queries under ProjectSecretsPermissions namespace:
New Mutations:
-
projectSecretsPermissionUpdate- Usesactionsfield, acceptsgroup_pathfor Group principals -
projectSecretsPermissionDelete- UsessecretsPermissionresponse key (plural)
New Query:
-
projectSecretsPermissions- Returns array ofProjectSecretsPermissionTypewithactionsfield
New Types:
-
ProjectSecretsPermissionType- Usesactionsfield fromSecretsPermissionInterface -
SecretsManagementActionenum -READ,WRITE,DELETE
4. Backward Compatibility
Old endpoints remain functional during migration:
-
secretsPermissionUpdateandsecretsPermissionDeletemutations still work - Old mutations accept
permissionsparameter and convert toactionsinternally - Old
SecretPermissionTypeoverridesactionsfield to provide backward-compatiblepermissionsfield (stringified) - Conversion logic:
WRITEaction expands back to['create', 'update']for old API
Migration path:
- This MR: New endpoints available, old endpoints still work
- Frontend migration: Update to use new endpoints
- Future cleanup MR: Remove old endpoints after frontend migration
5. Payload Key Consistency
Changed: secret_permission → secrets_permission (plural, emphasis on "secrets")
This applies to all new mutations:
groupSecretsPermissionUpdate.secretsPermissiongroupSecretsPermissionDelete.secretsPermissionprojectSecretsPermissionUpdate.secretsPermissionprojectSecretsPermissionDelete.secretsPermission
Old mutations keep secret_permission for backward compatibility.
6. Shared Helper for Principal Resolution
Created Helpers::PermissionPrincipalHelpers concern to share resolve_principal_id logic between group and project mutations. This handles the group_path → id conversion for Group principals.
Files Changed
New GraphQL Files:
-
ee/app/graphql/mutations/secrets_management/project_secrets_permissions/update.rb- New update mutation -
ee/app/graphql/mutations/secrets_management/project_secrets_permissions/delete.rb- New delete mutation -
ee/app/graphql/resolvers/secrets_management/project_secrets_permissions_resolver.rb- New list resolver -
ee/app/graphql/types/secrets_management/permissions/action_enum.rb- Actions enum -
ee/app/graphql/types/secrets_management/project_secrets_permission_type.rb- New type withactions -
ee/app/graphql/mutations/secrets_management/helpers/permission_principal_helpers.rb- Shared principal resolution
Updated GraphQL Files:
-
ee/app/graphql/types/secrets_management/secrets_permission_interface.rb- Changedpermissionstoactions -
ee/app/graphql/types/secrets_management/permissions/secret_permission_type.rb- Added backward-compatiblepermissionsfield -
ee/app/graphql/mutations/secrets_management/group_secrets_permissions/update.rb- Usesactions, shared principal helper -
ee/app/graphql/mutations/secrets_management/group_secrets_permissions/delete.rb- Updated payload key -
ee/app/graphql/mutations/secrets_management/permissions/update.rb- Convertspermissionstoactions -
ee/app/graphql/mutations/secrets_management/permissions/delete.rb- Updated payload key
Model Changes:
-
ee/app/models/secrets_management/base_secrets_permission.rb- Changedpermissionstoactions, added conversion methods
Service Changes:
-
ee/app/services/concerns/secrets_management/secrets_permissions/update_service_helpers.rb- Usesactions -
ee/app/services/concerns/secrets_management/secrets_permissions/delete_service_helpers.rb- Updated method signature -
ee/app/services/concerns/secrets_management/secrets_permissions/list_service_helpers.rb- Converts capabilities to actions
GraphQL Examples
New Project Secrets Permission Endpoints
Update Permission (New)
mutation {
projectSecretsPermissionUpdate(input: {
projectPath: "my-org/my-project"
principal: {
groupPath: "my-org/sub-group" # For Group principals
type: GROUP
}
actions: [READ, WRITE, DELETE] # Note: WRITE replaces create+update
expiredAt: "2025-12-31"
}) {
secretsPermission { # Note: plural "secrets"
project {
fullPath
}
principal {
id
type
}
actions # Returns: ["read", "write", "delete"]
grantedBy {
username
}
expiredAt
}
errors
}
}
Delete Permission (New)
mutation {
projectSecretsPermissionDelete(input: {
projectPath: "my-org/my-project"
principal: {
id: 123
type: USER
}
}) {
secretsPermission { # Note: plural "secrets"
principal {
id
type
}
}
errors
}
}
List Permissions (New)
query {
projectSecretsPermissions(projectPath: "my-org/my-project") {
nodes {
principal {
id
type
}
actions # Returns: ["read", "write", "delete"]
grantedBy {
username
}
expiredAt
}
}
}
Old Endpoints (Backward Compatible)
The old secretsPermissionUpdate and secretsPermissionDelete mutations still work:
mutation {
secretsPermissionUpdate(input: {
projectPath: "my-org/my-project"
principal: { id: 123, type: USER }
permissions: ["read", "create", "update", "delete"] # Old format still accepted
}) {
secretPermission { # Old response key (singular)
permissions # Returns stringified: "create,delete,read,update"
}
}
}
Feature Flags
- Group permissions: Gated behind
group_secrets_managerfeature flag - Project permissions: Gated behind
secrets_managerfeature flag
Database Changes
None - permissions are stored in OpenBao, not the database.
Migration Strategy
-
This MR: New endpoints available with
actionsfield, old endpoints remain functional - Frontend migration (#582687): Update UI to use new endpoints
- Future cleanup MR: Remove old endpoints after frontend migration complete
Dependencies
Depends on:
- !214500 (merged) - Add delete and list queries for group secrets permissions (merged)
Enables:
- #582687 - Frontend: migrate to new secrets permissions endpoints
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.