Remove Group principal from Secrets Manager permissions
What does this MR do and why?
GitLab Secrets Manager lets owners grant secrets permissions to principals: User, MemberRole, Group, Role. The Group principal is being removed. This is step 3 of that removal. Step 1 stopped honouring Group grants at login by dropping the groups JWT claim. Step 2 is the frontend MR that hides the Group tab and stops sending GROUP. This MR removes Group from the backend and the GraphQL schema.
This MR targets the step 1 branch, so its diff shows only step 3 changes. It will be retargeted to master once step 1 merges.
Where this fits
| Step | Change | MR |
|---|---|---|
| 1 | Stop sending the groups JWT claim and drop the grps line from the CEL for new namespaces. Group grants stop working. |
!254051 (merged) |
| 2 | Frontend hides the Group tab and stops sending GROUP. |
!253896 (merged) |
| 3 | Remove Group from the backend and the GraphQL schema. | !254392 (merged) |
| 4 | Delete leftover group policies in OpenBao. Existing namespaces keep the old CEL text, which is harmless with the claim gone. | Later milestone |
Merge order is 1, then 2, then 3.
Backend changes
Groupis removed fromPRINCIPAL_TYPESinSecretsManagement::BaseSecretsPermission, together with its validation and the two group lookup hooks onProjectSecretsPermissionandGroupSecretsPermission. Creating or updating a permission with type Group now fails with "must be one of: User, Role, MemberRole". Deleting one returns "Invalid principal".- The policy name helper returns nil for Group. The permission list parser skips
users/direct/group_*andapi/users/direct/group_*policies, so any policy left in OpenBao is invisible to the UI and API.
GraphQL changes
- The
GROUPvalue is removed from thePrincipalTypeenum. - The
groupPathargument is removed fromPrincipalInput, andidis now required. ThePrincipalInputValidatorand thePermissionPrincipalHelpersmutation concern are deleted. The four permission mutations no longer resolve a group path. - The
groupfield is removed from thePrincipaltype. - Descriptions no longer mention Group.
doc/api/graphql/reference/_index.mdand the introspection JSON files underpublic/-/graphql/are regenerated.
Breaking change
The permission mutations (projectSecretsPermissionUpdate, projectSecretsPermissionDelete, groupSecretsPermissionUpdate, groupSecretsPermissionDelete) are not marked experiment. Removing an enum value, an argument, and a field from them is a breaking schema change under the normal deprecation policy.
The team chose to remove rather than deprecate, for these reasons:
- Secrets Manager is still in beta.
- Group grants have granted no access since step 1 merged.
- The feature had very few users of this option, and they have been told.
- Keeping a deprecated value that returns an error for a full cycle adds confusion for little benefit.
Reviewers should weigh in if they disagree with this approach.
Behavior and compatibility
- Group policies left in OpenBao are not deleted here. They grant nothing and are not listed. A later step deletes them directly through the OpenBao API.
- The
grpsmapping in the CEL of namespaces provisioned before step 1 also stays until that cleanup. It is harmless because the claim is absent. - Self-managed instances get this on upgrade, with no opt-out.
Merge order
This MR must merge after step 1 and after the frontend MR. The frontend on master still sends GROUP and queries principal { group { ... } }. The frontend GraphQL schema lint would fail against this schema until the frontend MR lands.
Testing
The full secrets management spec tree passes locally against GDK OpenBao (2423 examples, 0 failures). A spec helper create_legacy_group_policies writes a group policy straight into OpenBao so specs can assert leftover policies are ignored. Coverage includes:
- Model: Group is rejected with a clear error, and the policy name is nil.
- Service: update rejects Group, delete rejects Group and leaves the leftover policy untouched, list skips leftover policies under both the
users/andapi/users/prefixes. - GraphQL:
GROUPis rejected by the schema, a missingidis rejected by the schema, list queries never return GROUP, anduserPermissionsreturns all false when a leftover policy exists, for both project and group. - Mount level with real JWTs: a leftover policy is denied on the project API mount (own group, project share, group to group share) and on the group API mount.
References
- Related to #623457
- Related to step 1: !254051 (merged) (drops the
groupsJWT claim) - Related to step 2: !253896 (merged) (hides the Group tab in the frontend)
Screenshots or screen recordings
No UI changes in this MR. The UI change is in the frontend MR (step 2).
How to set up and validate locally
- Have OpenBao running in GDK (
gdk status openbao) and the secrets manager enabled for a project you own. - Run the
projectSecretsPermissionUpdateGraphQL mutation withprincipal: { id: <group id>, type: GROUP }. The request is rejected by the schema because GROUP is no longer an enum value. - Run the same mutation with
principal: { type: USER }and no id. It is rejected becauseidis required. - Optional, to see a leftover policy being ignored: in a Rails console, write a policy named
users/direct/group_<group id>into the project's OpenBao namespace. The spec helpercreate_legacy_group_policiesinee/spec/support/helpers/secrets_management/gitlab_secrets_manager_helpers.rbshows the paths. Then queryprojectSecretsPermissions. The group policy is not listed, and a member of that group still cannot read secrets.
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.