diff --git a/modules/github/repository/main.tf b/modules/github/repository/main.tf index a3b2b9f..7483297 100644 --- a/modules/github/repository/main.tf +++ b/modules/github/repository/main.tf @@ -102,6 +102,69 @@ resource "github_repository_ruleset" "default_branch" { } +# Additional named rulesets for non-default branches (e.g., develop). +resource "github_repository_ruleset" "additional" { + for_each = var.config.additional_rulesets + + name = each.key + repository = github_repository.this.name + target = "branch" + enforcement = "active" + + conditions { + ref_name { + include = [each.value.branch_pattern] + exclude = [] + } + } + + rules { + deletion = true + non_fast_forward = true + + dynamic "required_status_checks" { + for_each = length(each.value.required_status_checks) > 0 ? [1] : [] + content { + strict_required_status_checks_policy = false + + dynamic "required_check" { + for_each = each.value.required_status_checks + content { + context = required_check.value + integration_id = 0 + } + } + } + } + + dynamic "pull_request" { + for_each = each.value.require_pr_reviews ? [1] : [] + content { + required_approving_review_count = 0 + dismiss_stale_reviews_on_push = false + require_code_owner_review = false + require_last_push_approval = false + required_review_thread_resolution = false + } + } + } + + bypass_actors { + actor_id = 5 # Admin repository role + actor_type = "RepositoryRole" + bypass_mode = "always" + } + + dynamic "bypass_actors" { + for_each = each.value.bypass_actors + content { + actor_id = bypass_actors.value.actor_id + actor_type = bypass_actors.value.actor_type + bypass_mode = bypass_actors.value.bypass_mode + } + } +} + # Deployment environments with optional wait timers and branch policies. # Used for staging/production gates and environment-scoped secrets/variables. resource "github_repository_environment" "this" { diff --git a/modules/github/repository/variables.tf b/modules/github/repository/variables.tf index 45adb87..ceefe17 100644 --- a/modules/github/repository/variables.tf +++ b/modules/github/repository/variables.tf @@ -54,6 +54,19 @@ variable "config" { })), []) }) + # Additional named rulesets targeting specific branches (e.g., develop). + # Key = ruleset name, value = ruleset config. + additional_rulesets = optional(map(object({ + branch_pattern = string + required_status_checks = optional(list(string), []) + require_pr_reviews = optional(bool, false) + bypass_actors = optional(list(object({ + actor_id = number + actor_type = string + bypass_mode = string + })), []) + })), {}) + # GitHub Environments for deployment gates. # Useful for staging/production promotion with wait timers. environments = optional(map(object({ diff --git a/terraform/github/locals.tf b/terraform/github/locals.tf index ded849f..d03d1ee 100644 --- a/terraform/github/locals.tf +++ b/terraform/github/locals.tf @@ -242,9 +242,40 @@ locals { archived = false branch_protection = { - enabled = true - required_status_checks = ["Commitlint", "CI"] - require_pr_reviews = false + enabled = true + # Real check names from ci.yml ("Typecheck · Lint · Test · Build"), + # e2e.yml ("E2E (chromium/firefox/webkit)"), and GitHub's built-in + # dependency-review action ("Dependency review"). + # Previous value "CI" was a placeholder that never matched any check. + required_status_checks = [ + "Typecheck · Lint · Test · Build", + "Commitlint", + "E2E (chromium)", + "E2E (firefox)", + "E2E (webkit)", + "Dependency review", + ] + require_pr_reviews = false + # Allow github-actions[bot] (changesets) to push version-bump commits to main. + bypass_actors = [ + { actor_id = 15368, actor_type = "Integration", bypass_mode = "always" } + ] + } + + additional_rulesets = { + protect-develop = { + branch_pattern = "refs/heads/develop" + # CI only — no E2E or Dependency Review (too slow for integration branch). + required_status_checks = [ + "Typecheck · Lint · Test · Build", + "Commitlint", + ] + require_pr_reviews = false + bypass_actors = [ + # github-actions[bot] — Renovate automerge pushes directly to develop. + { actor_id = 15368, actor_type = "Integration", bypass_mode = "always" } + ] + } } allow_auto_merge = true