Protected terraform states: REST API for protection rules
Problem Statement
As part of the Protected Terraform States epic, we are adding protection rules that control who can write to a Terraform state and from where.
This issue covers the REST API for querying and managing Terraform state protection rules. It complements the GraphQL API tracked in #594002 (closed) and provides parity for users and tooling (CLI, scripts, Terraform provider) that consume the REST API.
Proposal
Add CRUD endpoints under /projects/:id/terraform/state_protection_rules for
listing, creating, updating, and deleting Terraform state protection rules.
All endpoints are scoped to the project and require maintainer-level permissions.
List protection rules
GET /api/v4/projects/:id/terraform/state_protection_rulesReturns all protection rules for the project.
Example response:
[
{
"id": 1,
"project_id": 42,
"state_name": "production",
"minimum_access_level_for_write": "maintainer",
"allowed_from": "ci_on_protected_branch_only"
}
]Create a protection rule
POST /api/v4/projects/:id/terraform/state_protection_rules| Attribute | Type | Required | Description |
|---|---|---|---|
state_name |
string | yes | Terraform state to protect. Must be unique per project. |
minimum_access_level_for_write |
string | yes | Minimum role for write operations. One of: developer, maintainer, owner, admin. |
allowed_from |
string | no | Source restriction. One of: anywhere (default), ci_only, ci_on_protected_branch_only. |
Returns 201 Created with the created rule, or 422 Unprocessable Entity when
a rule for the same state_name already exists, or 400 Bad Request on invalid
enum values.
Update a protection rule
PATCH /api/v4/projects/:id/terraform/state_protection_rules/:terraform_state_protection_rule_id| Attribute | Type | Required | Description |
|---|---|---|---|
minimum_access_level_for_write |
string | no | Minimum role for write operations. |
allowed_from |
string | no | Source restriction. |
Supports partial updates — only provided attributes are changed. state_name
is immutable once the rule is created.
Delete a protection rule
DELETE /api/v4/projects/:id/terraform/state_protection_rules/:terraform_state_protection_rule_idReturns 204 No Content on success.
Authorization
- All endpoints require maintainer-level access (
admin_terraform_state) on the project. - Developer and below receive
403 Forbidden. - Unauthenticated requests receive
401 Unauthorized. - Follows the same
admin_terraform_statepermission as existing Terraform state endpoints.
Feature flag
Gated behind terraform_state_protection_rules (gitlab_com_derisk). When the
flag is disabled for the project, all endpoints return 404 Not Found.
Scope
In scope:
GETendpoint to list protection rules for a projectPOSTendpoint to create a rule (required:state_name,minimum_access_level_for_write; optional:allowed_from)PATCHendpoint for partial updates of an existing ruleDELETEendpoint to remove a rule- Grape entity exposing:
id,project_id,state_name,minimum_access_level_for_write,allowed_from - Request specs for all endpoints (authorized, unauthorized, invalid token, feature flag disabled)
- OpenAPI documentation generated from the Grape
descblocks
Out of scope:
- GraphQL API for rules CRUD (see #594002 (closed))
- Frontend UI (separate issue)
- Internal events / instrumentation (separate issue)
Reference
This follows the packages protection rules REST API pattern.
Reference files in the codebase:
lib/api/project_packages_protection_rules.rblib/api/entities/projects/packages/protection/rule.rbspec/requests/api/project_packages_protection_rules_spec.rbspec/support/shared_examples/requests/api/protection_rules_shared_examples.rb
Implementation checklist
- Grape entity
API::Entities::Terraform::StateProtectionRule - API class
API::Terraform::StateProtectionRulesmounted inlib/api/api.rb -
GETendpoint (list) -
POSTendpoint (create — reusesCreateRuleServicefrom the GraphQL API) -
PATCHendpoint (update — reusesUpdateRuleServicefrom the GraphQL API) -
DELETEendpoint (delete — reusesDeleteRuleServicefrom the GraphQL API) - Request specs for all endpoints (authorized, unauthorized, invalid token, feature flag disabled)
- Update OpenAPI docs (
bundle exec rake gitlab:openapi:generate)