From a8b85154b88ce6507820430c1fe5d5ba02c8044d Mon Sep 17 00:00:00 2001 From: Padreug Date: Fri, 9 Oct 2026 18:45:44 +0200 Subject: [PATCH] fix(seed): branch protection honours reforge.requiredApprovers reforge-seed hardcoded approvals_whitelist_username to security-lead, so seeded stack repos ignored the module option that the working repo already respected. The package now bakes REFORGE_REQUIRED_APPROVERS in from the option (space-separated, standalone default unchanged) and the seed script builds the protection payload from it. Co-Authored-By: Claude Fable 5.1 --- modules/reforge.nix | 2 ++ packages/reforge-scripts.nix | 4 +++- scripts/reforge-seed.sh | 15 ++++++++++++--- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/modules/reforge.nix b/modules/reforge.nix index 963bb87..5026139 100644 --- a/modules/reforge.nix +++ b/modules/reforge.nix @@ -49,6 +49,8 @@ let inherit tokensDir stateDir; configDir = toString cfg.configDir; agentsDir = if cfg.agentsDir == null then null else toString cfg.agentsDir; + # Seeded stack repos get the same approver whitelist as the working repo. + requiredApprovers = cfg.requiredApprovers; refsDir = if cfg.refsDir == null then null else toString cfg.refsDir; }; diff --git a/packages/reforge-scripts.nix b/packages/reforge-scripts.nix index eb6ca8d..25d54de 100644 --- a/packages/reforge-scripts.nix +++ b/packages/reforge-scripts.nix @@ -37,6 +37,7 @@ configDir, agentsDir ? null, refsDir ? null, + requiredApprovers ? [ "security-lead" ], }: let @@ -88,6 +89,7 @@ stdenvNoCC.mkDerivation { --set-default REFORGE_CONFIG_DIR ${lib.escapeShellArg (toString configDir)} \ --set-default REFORGE_SETTINGS_DIR "$SETTINGS" \ --set-default REFORGE_AGENTS_DIR "$AGENTS" \ + --set-default REFORGE_REQUIRED_APPROVERS ${lib.escapeShellArg (lib.concatStringsSep " " requiredApprovers)} \ ${lib.optionalString ( refsDir != null ) "--set-default REFORGE_REFS_DIR ${lib.escapeShellArg (toString refsDir)}"} @@ -96,7 +98,7 @@ stdenvNoCC.mkDerivation { ''; meta = with lib; { - description = "reforge lifecycle CLI (seed/reset/compare/smoke/kickoff/role/orchestrator/fetch-targets)"; + description = "reforge lifecycle CLI (seed/reset/compare/smoke/kickoff/role/orchestrator/fetch-targets/harvest)"; mainProgram = "reforge-seed"; license = licenses.mit; }; diff --git a/scripts/reforge-seed.sh b/scripts/reforge-seed.sh index 5e2f08a..e3dc4e1 100644 --- a/scripts/reforge-seed.sh +++ b/scripts/reforge-seed.sh @@ -73,12 +73,21 @@ ensure_repo() { # name description fi } +# Approver whitelist: the module bakes reforge.requiredApprovers in as +# REFORGE_REQUIRED_APPROVERS (space-separated); the standalone default +# matches the module's default. Field name is singular (Forgejo API quirk). +APPROVERS=${REFORGE_REQUIRED_APPROVERS:-security-lead} +PROTECTION_JSON=$(jq -cn --arg a "$APPROVERS" \ + '{branch_name:"main",rule_name:"main",enable_push:false,required_approvals:1, + enable_approvals_whitelist:true, + approvals_whitelist_username:($a | split(" ") | map(select(length > 0))), + block_on_rejected_reviews:true,dismiss_stale_approvals:true}') + protect_main() { # name (same rule the module puts on the working repo) if [ "$(api GET "/repos/$ORG/$1/branch_protections/main")" = 404 ]; then - must "$(api POST "/repos/$ORG/$1/branch_protections" \ - '{"branch_name":"main","rule_name":"main","enable_push":false,"required_approvals":1,"enable_approvals_whitelist":true,"approvals_whitelist_username":["security-lead"],"block_on_rejected_reviews":true,"dismiss_stale_approvals":true}')" \ + must "$(api POST "/repos/$ORG/$1/branch_protections" "$PROTECTION_JSON")" \ "protect $ORG/$1 main" - echo " protected main" + echo " protected main (approvers: $APPROVERS)" fi }