#!/usr/bin/env bash # Items 1 + 2: make the gate a REQUIRED status check and require one approval. # # RUN THIS LAST. Prerequisites, in order: # a) PR #7 (dind native sidecar) is MERGED, and # b) you have SEEN a real workflow run go green on the converted pod. # The runner Deployment is the merge gate for the whole repo. Turning on a required check # while the runner is broken means no PR can merge -- including the revert. (Recoverable: # an owner can set enable_status_check back to false. But do not rely on that.) # # Requires exactly ONE context: `gate / gate (pull_request)`. # * NOT `gate / conformance (*)` -- that job is `if: false`, and a skipped Gitea job reports # SUCCESS ("Has been skipped"). Requiring it would pass VACUOUSLY forever while nothing # ran, which under HARD RULE 4 is worse than a deadlock: a deadlock is loud. # block_admin_merge_override: true is LOAD-BEARING and was missing on the first pass. Gitea # lets repo admins override merge requirements without it, so required_approvals and the # required status check are both bypassable by exactly the account that does the merging. # Measured: PRs #5-#9 merged with ZERO approvals recorded against required_approvals: 1. # # FIELD NAMES: this Gitea (1.24.3) has NO `apply_to_admins`. Asking jq for it returns null, # which reads like "false" but means "key absent" -- enumerate real keys with `to_entries` # instead of probing names you assume exist. That mistake cost a wasted PATCH. # # * NOT the `(push)` variant -- after PR #6 there are no per-branch push runs at all, so a # PR would never produce that context. set -euo pipefail HOST=gitea.home.keithjackson.dev; OWNER=Home-Network; REPO=home-network-k3s-impl creds="$(printf 'protocol=https\nhost=%s\n\n' "$HOST" | git credential fill)" U="$(sed -n 's/^username=//p' <<<"$creds")"; P="$(sed -n 's/^password=//p' <<<"$creds")" api() { curl -sS --config <(printf 'user = "%s:%s"\n' "$U" "$P") "$@"; } echo "==> updating branch protection on main" jq -n '{ enable_push: false, enable_status_check: true, status_check_contexts: ["gate / gate (pull_request)"], required_approvals: 0, block_on_rejected_reviews: true, dismiss_stale_approvals: true, block_on_outdated_branch: false, block_admin_merge_override: true }' | api -X PATCH -H 'Content-Type: application/json' --data @- \ "https://${HOST}/api/v1/repos/${OWNER}/${REPO}/branch_protections/main" >/dev/null echo "==> verifying" api "https://${HOST}/api/v1/repos/${OWNER}/${REPO}/branches/main" \ | jq -r '{protected,user_can_push,enable_status_check,status_check_contexts,required_approvals}' cat <<'NOTE' NOTE ON required_approvals: 0 -- CHANGED FROM 1 ON 2026-10-01, and this script is the reason the change had to land here too: re-running it with 1 would silently re-impose the lock-out. The note that used to sit here called the problem and its own fix: "Gitea will not let an author approve their own PR ... if that is awkward ... set required_approvals back to 0 and rely on the status check alone." It was awkward. With jakman85 the ONLY collaborator, every PR the operator opened was unmergeable -- measured on PR #35, gate green in 1m41s, zero reviews, nothing that could ever satisfy the rule. So: 0, and the status check alone, as written. What did NOT change, deliberately: * block_admin_merge_override stays TRUE. This drops the approval COUNT; it does not hand anyone a bypass over the gate. A red gate is still unmergeable by everybody. * Architecturally/security-relevant paths are still human-reviewed -- by ci/approval-policy.sh (sensitive_paths in infra/gitea/approval-policy.json), which an administrator can waive only by posting an explicit, attributed `/approve-override ` comment. Then prove it, rather than trusting the API: git commit --allow-empty -m probe && git push origin main # EXPECT: rejected git reset --hard HEAD~1 NOTE