Wave 2: Epics: Enable granular PATs for Epics REST endpoints
## Summary
Implement granular Personal Access Token (PAT) permissions for Epics REST API endpoints, following GitLab's authorization conventions.
## Endpoints Modified
- `GET /groups/:id/epics` → `read_epic`
- `GET /groups/:id/-/epics` → `read_epic`
- `GET /groups/:id/epics/:epic_iid` → `read_epic`
- `GET /groups/:id/-/epics/:epic_iid` → `read_epic`
- `POST /groups/:id/epics` → `create_epic`
- `POST /groups/:id/-/epics` → `create_epic`
- `PUT /groups/:id/epics/:epic_iid` → `update_epic`
- `PUT /groups/:id/-/epics/:epic_iid` → `update_epic`
- `DELETE /groups/:id/epics/:epic_iid` → `delete_epic`
- `DELETE /groups/:id/-/epics/:epic_iid` → `delete_epic`
## Permissions Created
- `read_epic` – Grants the ability to read epics
- `create_epic` – Grants the ability to create epics
- `update_epic` – Grants the ability to update epics
- `delete_epic` – Grants the ability to delete epics
### Files Created
- `config/authz/permissions/epic/read.yml`
- `config/authz/permissions/epic/create.yml`
- `config/authz/permissions/epic/update.yml`
- `config/authz/permissions/epic/delete.yml`
- `config/authz/permissions/epic/_metadata.yml`
## Permission Groups Created
- `read_epic` – Grants the ability to read epics
- `create_epic` – Grants the ability to create epics
- `update_epic` – Grants the ability to update epics
- `delete_epic` – Grants the ability to delete epics
### Files Created
- `config/authz/permission_groups/assignable_permissions/epic/read.yml`
- `config/authz/permission_groups/assignable_permissions/epic/create.yml`
- `config/authz/permission_groups/assignable_permissions/epic/update.yml`
- `config/authz/permission_groups/assignable_permissions/epic/delete.yml`
## Requirements
### API Analysis
Analyze the relevant API file under `lib/api/` and:
- Identify all REST API endpoints (GET, POST, PUT, DELETE)
- List each endpoint with its HTTP method and route pattern
- Note the `feature_category` defined in the file
- Determine the boundary type for each endpoint based on route patterns:
- `/projects/:id/...` → project boundary
- `/groups/:id/...` → group boundary
- `/users/:id/...` → user boundary
- No prefix → instance boundary
### Permission Design
For each endpoint, define permissions using the following conventions:
**Naming Pattern:** `action_resource(_subresource)`
- Use singular form (e.g. `read_job`, not `read_jobs`)
- Preferred actions: `create`, `read`, `update`, `delete`, `push`, `download`
- Avoid: `admin_*`, `manage_*`, `access_*`
**Permission Granularity Rules:**
- List and Show operations → single `read_resource` permission
- Nested resources → include parent in the name (e.g. `create_pipeline_schedule_variable`)
- Special actions → unique permissions (e.g. `cancel_job`, `retry_job`, `download_artifact`)
- Attribute updates → single `update_resource` permission (do not create attribute-specific permissions)
### Permission YAML File
```yaml
---
name: <permission_name>
description: Grants the ability to <action description>
boundaries:
- <boundary_type> # project, group, user, or instance
```
### Permission Group YAML File
```yaml
---
name: <permission_name>
description: Grants the ability to <action description>
boundaries:
- <boundary_type> # project, group, user, or instance
permissions:
- <permission_name>
```
### Add Authorization Decorators
Add the route_setting :authorization decorator immediately before each route definition in the API file:
```ruby
route_setting :authorization, permissions: :<permission_name>, boundary_type: :<boundary_type>
get ':id/resource' do
# endpoint implementation
end
```
### Add Test Coverage
In the corresponding spec file under spec/requests/api/, add the following for each endpoint:
```ruby
it_behaves_like 'authorizing granular token permissions', :<permission_name> do
let(:boundary_object) { <boundary_object> } # project, group, user, or nil for instance
let(:user) { <user_variable> }
let(:request) do
<http_method> api(\"<endpoint_path>\", personal_access_token: pat), params: <params_hash_if_needed>
end
end
```
task