.ai/principles/distilled/permissions-rest-gpat.md
Prerequisite: If you haven't already, also read .ai/principles/distilled/permissions-fundamentals.md - it contains foundational rules that apply to all permissions work.
bin/permission command rather than creating them manually.config/authz/permissions/<resource>/<action>.yml; DO NOT add extra directories between the base path and the filename.DELETE /projects/:id/jobs/:job_id/artifacts → delete_job_artifact).read_<resource> permission for both list and show (GET) operations on the same resource.create_pipeline_schedule_variable).update_<resource> permission covering all attribute updates; DO NOT create per-attribute permissions such as update_issue_title.feature_category in the resource .metadata.yml to a valid entry from config/feature_categories.yml; look at existing endpoints in the same API file for the correct value.bundle exec rake gitlab:permissions:validate (or rely on the Lefthook pre-push hook) to catch naming and structure violations before pushing.config/authz/permission_groups/assignable_permissions/<category>/<resource>/<action>.yml; DO NOT add extra directories.permissions array already exists as a raw permission definition file before referencing it.boundaries based only on the organizational levels the bundled raw permissions actually support; DO NOT include boundaries where the permissions do not apply.project in boundaries when raw permissions cover /projects/:id/... endpoints; include group for /groups/:id/... endpoints; include user for /users/:id/... or personal-namespace operations; use instance sparingly and only for admin-facing permissions..metadata.yml only when titleization produces an incorrect display name (e.g., ci_cd → "CI/CD"); DO NOT create one when the folder name titleizes correctly..metadata.yml only when the resource name contains an acronym, brand name, or awkward pluralization; DO NOT create one when the directory name titleizes and pluralizes correctly.<actions> interpolation in a resource .metadata.yml description so the action list stays in sync automatically.rename_granular_scope_permission batched background migration, mark the old permission deprecated: true, finalize the migration in a later milestone, then delete the deprecated file using bundle exec rake gitlab:permissions:assignable:cleanup_deprecated.boundary_type between project and group is safe; changing to or from user or instance is a breaking change requiring token holders to recreate scopes.route_setting :authorization immediately before every HTTP method definition (get, post, put, delete), even when multiple endpoints share the same permission.boundary_type: :project | :group | :user | :instance for single-boundary endpoints; use the boundaries array for endpoints that support multiple boundary types.boundary option (a callable returning the boundary object) only when the boundary cannot be determined through standard parameter lookup.boundary_param when the request parameter containing the boundary identifier is not the default :id.boundaries array, include a boundary_type key in each entry and optionally a boundary_param; the system evaluates boundaries in priority order project > group > user > instance and uses the first resolvable boundary.skip_granular_token_authorization: true only for endpoints that are publicly accessible, authenticate by means other than PATs, or where authentication is optional; DO NOT use it to bypass permission checks on authenticated endpoints.config/authz/roles/public_anonymous.yml under the matching project: or group: boundary so that granular PATs without an explicit scope can access them on public resources; DO NOT add user or instance boundary permissions to this file.'authorizing granular token permissions' shared example for every endpoint, providing boundary_object, user, and request let-bindings.boundary_object to match the boundary_type: project → project, group → group, :user → :user, :instance → :instance.user is a member of the namespace (project or group) when the boundary object is a project or group.@gitlab-com/gl-security/product-security/appsec for security review before merging any new job token permission.lib/ci/job_token/policies.rb, app/validators/json_schemas/ci_job_token_policies.json, and app/assets/javascripts/token_access/constants.js.route_setting :authentication, job_token_allowed: true and route_setting :authorization, job_token_policies: <policy> to each endpoint that should accept job token authentication.:read_* policies for GET (read) operations and :admin_* policies for POST/PUT/DELETE (write/delete) operations on job token endpoints.allow_public_access_for_enabled_project_features parameter on route_setting :authorization to allow job token access based on project feature visibility, providing backward compatibility.'enforcing job token policies' shared RSpec example to test job token authorization, passing the required policy and optionally allow_public_access_for_enabled_project_features and expected_success_status.bundle exec rake ci:job_tokens:compile_docs.For the full picture, see: