fix(infra): enforce prod deployment approval gates#296
fix(infra): enforce prod deployment approval gates#296
Conversation
Manage prod deployment protections in Terraform for aws and cms environments so approval gating is codified and no longer manual in GitHub UI. Made-with: Cursor
WalkthroughThis change adds deployment protection controls to GitHub repository production environments by introducing a data source to fetch a designated reviewer and configuring deployment branch policies, approval requirements, and self-review prevention for the Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~8 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
🟨 Terraform plan (github/prod) — Changes detectedChanges: +0 ~2 -0
Run: https://github.com/JesusFilm/forge/actions/runs/22833734972 |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
infra/github/environments.tf (1)
44-58: Consistent configuration withaws_prod— consider extracting common settings.The protection settings mirror
aws_prodexactly, which is good for consistency. As the number of prod environments grows, you might extract these common settings into a local or module to reduce duplication.♻️ Optional: Extract common prod environment settings
locals { prod_env_protection = { can_admins_bypass = false prevent_self_review = true reviewer_ids = [for u in data.github_user.prod_environment_reviewer : u.id] } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@infra/github/environments.tf` around lines 44 - 58, The cms_prod Github environment resource duplicates the same protection settings used elsewhere (e.g. aws_prod); extract the shared settings into a local (or small module) and reference it from github_repository_environment.cms_prod to remove duplication: create a local like prod_env_protection containing can_admins_bypass, prevent_self_review and reviewer_ids (map reviewer data user IDs), optionally also factor out deployment_branch_policy settings, then update the cms_prod resource to read those values (use locals.prod_env_protection.can_admins_bypass, .prevent_self_review, and .reviewer_ids for the reviewers block and reference the shared deployment_branch_policy configuration) so both environments reuse the same configuration.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@infra/github/environments.tf`:
- Around line 24-26: The reviewers block currently assigns a single user
(data.github_user.prod_environment_reviewer.id) while prevent_self_review =
true, which can deadlock deployments if that user (tataihono) triggers the
change; update the environment configuration to add at least one additional
reviewer or replace the single user with a team (e.g.,
data.github_team.prod_environment_reviewers.id) so there are multiple approvers,
and reconcile this with the approval-bypass in
.github/workflows/terraform-plan.yml to avoid conflicting permissions; locate
and update the reviewers { users = [...] } block in infra/github/environments.tf
and/or add a reviewers { teams = [...] } entry to ensure a second approver
exists.
- Around line 4-6: Replace the hardcoded github_user lookup with a configurable
approach: change the data resource data.github_user.prod_environment_reviewer to
accept a variable (e.g., var.prod_reviewer_usernames) or replace it with
multiple lookups (or a github_team data resource) so reviewers are not a single
hardcoded user; update the environment reviewers block that references
prod_environment_reviewer to iterate over the variable list (or include team via
the teams attribute) and keep prevent_self_review = true; ensure you add a
corresponding variable (e.g., prod_reviewer_usernames) with a sensible default
or validation so Terraform won’t break if a username changes or a reviewer is
unavailable.
- Around line 19-22: The deployment_branch_policy sets protected_branches = true
but there is no Terraform-managed branch protection; add a
github_branch_protection resource to manage the protected branch(es) referenced
by deployment_branch_policy: create a resource "github_branch_protection" with
the repository (repo) name and the branch name(s) you want protected, configure
required_status_checks (contexts and strict), required_pull_request_reviews
(dismissal_restrictions, required_approving_review_count), enforce_admins, and
restrictions as appropriate so Terraform fully owns branch protection and
satisfies protected_branches = true. Ensure the resource name and attributes
align with the existing environment configuration and any branch names
referenced by deployment_branch_policy.
---
Nitpick comments:
In `@infra/github/environments.tf`:
- Around line 44-58: The cms_prod Github environment resource duplicates the
same protection settings used elsewhere (e.g. aws_prod); extract the shared
settings into a local (or small module) and reference it from
github_repository_environment.cms_prod to remove duplication: create a local
like prod_env_protection containing can_admins_bypass, prevent_self_review and
reviewer_ids (map reviewer data user IDs), optionally also factor out
deployment_branch_policy settings, then update the cms_prod resource to read
those values (use locals.prod_env_protection.can_admins_bypass,
.prevent_self_review, and .reviewer_ids for the reviewers block and reference
the shared deployment_branch_policy configuration) so both environments reuse
the same configuration.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 03657d58-d0d3-442e-9991-36469c6b213b
📒 Files selected for processing (1)
infra/github/environments.tf
| data "github_user" "prod_environment_reviewer" { | ||
| username = "tataihono" | ||
| } |
There was a problem hiding this comment.
Hardcoded username and single-reviewer bottleneck.
Using a single hardcoded username creates two risks:
-
Single point of failure: If "tataihono" is unavailable, no prod deployments can proceed. Combined with
prevent_self_review = true, if they trigger the deployment themselves, there's no one to approve it. -
Fragility: If the username changes or the user leaves, Terraform apply will fail.
Consider using a variable for the username and/or adding multiple reviewers (or a team via the teams attribute).
🛠️ Suggested improvement
+variable "prod_environment_reviewers" {
+ description = "GitHub usernames authorized to approve prod deployments"
+ type = list(string)
+ default = ["tataihono"]
+}
+
data "github_user" "prod_environment_reviewer" {
- username = "tataihono"
+ for_each = toset(var.prod_environment_reviewers)
+ username = each.value
}Then update the reviewers blocks:
reviewers {
- users = [data.github_user.prod_environment_reviewer.id]
+ users = [for u in data.github_user.prod_environment_reviewer : u.id]
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@infra/github/environments.tf` around lines 4 - 6, Replace the hardcoded
github_user lookup with a configurable approach: change the data resource
data.github_user.prod_environment_reviewer to accept a variable (e.g.,
var.prod_reviewer_usernames) or replace it with multiple lookups (or a
github_team data resource) so reviewers are not a single hardcoded user; update
the environment reviewers block that references prod_environment_reviewer to
iterate over the variable list (or include team via the teams attribute) and
keep prevent_self_review = true; ensure you add a corresponding variable (e.g.,
prod_reviewer_usernames) with a sensible default or validation so Terraform
won’t break if a username changes or a reviewer is unavailable.
| deployment_branch_policy { | ||
| protected_branches = true | ||
| custom_branch_policies = false | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check if branch protection resources exist elsewhere in the infra directory
echo "=== Searching for github_branch_protection resources ==="
rg -n 'github_branch_protection' infra/ || echo "No branch protection resources found in Terraform"
echo ""
echo "=== Checking repository.tf for any protection-related resources ==="
cat infra/github/repository.tfRepository: JesusFilm/forge
Length of output: 1236
protected_branches = true requires branch protection rules defined in Terraform.
The deployment_branch_policy with protected_branches = true is set in the environment configuration, but no github_branch_protection resource exists in the Terraform code. This violates the Terraform-only principle: either branch protection was configured manually (against guidelines), or it doesn't exist and the policy won't function as intended.
Add a github_branch_protection resource to infra/github/ to manage branch protection rules via Terraform.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@infra/github/environments.tf` around lines 19 - 22, The
deployment_branch_policy sets protected_branches = true but there is no
Terraform-managed branch protection; add a github_branch_protection resource to
manage the protected branch(es) referenced by deployment_branch_policy: create a
resource "github_branch_protection" with the repository (repo) name and the
branch name(s) you want protected, configure required_status_checks (contexts
and strict), required_pull_request_reviews (dismissal_restrictions,
required_approving_review_count), enforce_admins, and restrictions as
appropriate so Terraform fully owns branch protection and satisfies
protected_branches = true. Ensure the resource name and attributes align with
the existing environment configuration and any branch names referenced by
deployment_branch_policy.
| reviewers { | ||
| users = [data.github_user.prod_environment_reviewer.id] | ||
| } |
There was a problem hiding this comment.
Potential deadlock: self-review prevention with single reviewer.
With prevent_self_review = true and only one reviewer configured, if "tataihono" triggers a deployment (e.g., by pushing or merging to main), they cannot approve their own deployment request. Since there are no other reviewers, the deployment will be permanently blocked.
Additionally, the workflow in .github/workflows/terraform-plan.yml (line 29) grants "tataihono" approval bypass for PR checks, which seems inconsistent with making them the sole gatekeeper for prod deployments.
Ensure at least one additional reviewer is configured, or consider adding a team with multiple members.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@infra/github/environments.tf` around lines 24 - 26, The reviewers block
currently assigns a single user (data.github_user.prod_environment_reviewer.id)
while prevent_self_review = true, which can deadlock deployments if that user
(tataihono) triggers the change; update the environment configuration to add at
least one additional reviewer or replace the single user with a team (e.g.,
data.github_team.prod_environment_reviewers.id) so there are multiple approvers,
and reconcile this with the approval-bypass in
.github/workflows/terraform-plan.yml to avoid conflicting permissions; locate
and update the reviewers { users = [...] } block in infra/github/environments.tf
and/or add a reviewers { teams = [...] } entry to ensure a second approver
exists.
Summary
aws-prodandcms-prodGitHub environmentsinfra/github/environments.tfso prod gating is no longer manual driftContracts Changed
Regeneration Required
Validation
Resolves #67
Made with Cursor
Summary by CodeRabbit