Add granular token authorization to Compliance & governance mutations
What does this MR do?
Adds granular (fine-grained) Personal Access Token authorization to the GraphQL mutations in Group 3 — Compliance & governance of the authorization todo list, following the GraphQL implementation guide.
For each mutation it adds an authorize_granular_token directive, the
required raw/assignable permission definitions, and a shared-example
authorization test per declared boundary. The corresponding mutation:
lines are removed from config/authz/graphql/authorization_todo.txt.
27 of the 28 group mutations are covered. BulkUpdateSecurityAttributes
is intentionally left in the todo list (see Skipped below).
Mutation → permission → boundary
| Mutation | Permission | Boundary |
|---|---|---|
| CreateComplianceFramework | create_compliance_framework |
group (namespace_path) |
| CreateComplianceFrameworkFromTemplate | create_compliance_framework |
group (namespace_path) |
| UpdateComplianceFramework | update_compliance_framework |
group (id → namespace) |
| DestroyComplianceFramework | delete_compliance_framework |
group (id → namespace) |
| CreateComplianceRequirement | create_compliance_requirement |
group (compliance_framework_id → namespace) |
| UpdateComplianceRequirement | update_compliance_requirement |
group (id → namespace) |
| DestroyComplianceRequirement | delete_compliance_requirement |
group (id → namespace) |
| CreateComplianceRequirementsControl | create_compliance_requirements_control |
group (compliance_requirement_id → namespace) |
| UpdateComplianceRequirementsControl | update_compliance_requirements_control |
group (id → namespace) |
| DestroyComplianceRequirementsControl | delete_compliance_requirements_control |
group (id → namespace) |
| LinkProjectComplianceViolationIssue | update_compliance_violations_report |
project (violation_id → project) |
| UnlinkProjectComplianceViolationIssue | update_compliance_violations_report |
project (violation_id → project) |
| UpdateProjectComplianceViolation | update_compliance_violations_report |
project (id → project) |
| ProjectSetComplianceFramework | update_compliance_framework |
project (project_id) |
| ProjectUpdateComplianceFrameworks | update_compliance_framework |
project (project_id) |
| RefreshStandardsAdherenceChecks | read_compliance_dashboard |
group (group_path) |
| SecurityAttributeCreate | create_security_attribute |
group (namespace_id) |
| SecurityAttributeUpdate | update_security_attribute |
group (id → namespace) |
| SecurityAttributeDestroy | delete_security_attribute |
group (id → namespace) |
| SecurityAttributeProjectUpdate | update_security_attribute |
project (project_id) |
| SecurityCategoryCreate | create_security_category |
group (namespace_id) |
| SecurityCategoryUpdate | update_security_category |
group (namespace_id) |
| SecurityCategoryDestroy | delete_security_category |
group (id → namespace) |
| MemberRoleDelete | delete_member_role |
group (id → namespace) + instance |
| MemberRoleUpdate | update_member_role |
group (id → namespace) + instance |
| MemberRoleToUserAssign | assign_member_role |
instance |
| GroupMembersExport | read_member |
group (group_id) |
Permissions: created vs reused
Reused (no new assignable created where possible):
read_member— reused existing raw + assignable (system_access/member/read) forGroupMembersExport.delete_member_role— reused existing raw + assignable (groups/member_role/delete).update_compliance_violations_report— raw permission already existed; bundled into a new assignable so it is grantable to granular tokens.
New raw permissions (17): create/update/delete_compliance_framework,
create/update/delete_compliance_requirement,
create/update/delete_compliance_requirements_control,
read_compliance_dashboard, create/update/delete_security_attribute,
create/update/delete_security_category, update_member_role,
assign_member_role.
New assignable permissions (10): nested resources are bundled into
their parent resource's per-verb assignable rather than standalone
assignables, following the multi-raw pattern used by
update_merge_request/create_work_item. The
create/update/delete_compliance_requirement and
..._compliance_requirements_control raws join the matching
create/update/delete_compliance_framework bundle, and
create/update/delete_security_category join
create/update/delete_security_attribute. Raw permission names and
mutation directives are unchanged — only assignable membership moved. The
resulting new assignables are create/update/delete_compliance_framework,
read_compliance_dashboard, update_compliance_violations_report,
create/update/delete_security_attribute, update_member_role, and
assign_member_role. update_compliance_framework and
update_security_attribute span group + project boundaries;
update_member_role spans group + instance; assign_member_role is
instance-only.
Judgment calls
ProjectSet/UpdateComplianceFrameworkreuseupdate_compliance_frameworkat the project boundary (assigning frameworks to a project is a framework update scoped to the project) rather than introducing a boundary-encoded permission.RefreshStandardsAdherenceChecksreusesread_compliance_dashboard, matching the mutation's existingauthorize :read_compliance_dashboardability (it recomputes data gated by dashboard read access).GroupMembersExportusesread_member(a bulk read of member data).- Member role update/delete follow the merged
MemberRoleCreatepattern (group + instance boundaries; instance-level roles resolvenamespacetoniland fall through to the standalone instance boundary).
Skipped
BulkUpdateSecurityAttributes— left in the todo list. Itsitemsargument is a mixed array ofGroupandProjectglobal IDs. The granular-tokenBoundaryExtractorresolves a single GlobalID/path perboundary_argumentand returnsnilfor array arguments, so no single boundary can be derived. Documenting rather than forcing an incorrect boundary.
How validated
bundle exec rake gitlab:permissions:validate— passes.bundle exec rake gitlab:permissions:graphql:compile_docsand...:routes:compile_docs— regenerateddoc/auth/tokens/fine_grained_access_tokens_graphql.mdand the member role description line in the REST doc; both committed.- Authorization specs run in CI (not run locally).
See the implementation guide.