From 05b8b448ddcb88e3927719f86f90df014dd69c9e Mon Sep 17 00:00:00 2001 From: Justin Leopard Date: Sun, 4 Oct 2026 23:09:26 -0400 Subject: [PATCH] ci: Add exact-head acceptance publisher Publish an independently reviewed PR head through a trusted manual dispatch. Keep ruleset activation separate until the publisher is merged and proven. Co-Authored-By: Codex --- .github/workflows/exact-head-acceptance.yml | 123 ++++++++++++++++++++ docs/exact-head-acceptance.md | 30 +++++ 2 files changed, 153 insertions(+) create mode 100644 .github/workflows/exact-head-acceptance.yml create mode 100644 docs/exact-head-acceptance.md diff --git a/.github/workflows/exact-head-acceptance.yml b/.github/workflows/exact-head-acceptance.yml new file mode 100644 index 0000000..2158c9b --- /dev/null +++ b/.github/workflows/exact-head-acceptance.yml @@ -0,0 +1,123 @@ +name: Exact-head acceptance +run-name: "Exact-head acceptance PR #${{ inputs.pr_number }} at ${{ inputs.head_sha }}" + +on: + workflow_dispatch: + inputs: + pr_number: + description: Open same-repository PR number targeting main + required: true + type: number + head_sha: + description: Exact 40-character PR head SHA being accepted + required: true + type: string + +permissions: {} + +concurrency: + group: exact-head-acceptance-${{ github.repository }}-${{ inputs.pr_number }} + cancel-in-progress: false + +jobs: + accept: + name: Publish exact-head acceptance + runs-on: ubuntu-latest + permissions: + checks: write + pull-requests: read + env: + GH_TOKEN: ${{ github.token }} + PR_NUMBER: ${{ inputs.pr_number }} + SUPPLIED_SHA: ${{ inputs.head_sha }} + DISPATCH_REF: ${{ github.ref }} + DISPATCH_ACTOR: ${{ github.actor }} + TRIGGERING_ACTOR: ${{ github.triggering_actor }} + TRUSTED_ACCEPTORS: JustinJLeopard + CHECK_NAME: Exact-head acceptance + DETAILS_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + steps: + - name: Validate live PR head and publish acceptance + shell: bash + run: | + set -euo pipefail + + fail() { + echo "Acceptance rejected: $1" >&2 + exit 1 + } + is_trusted() { + [[ ",$TRUSTED_ACCEPTORS," == *",$1,"* ]] + } + + is_trusted "$DISPATCH_ACTOR" || + fail "dispatcher is not allowlisted" + is_trusted "$TRIGGERING_ACTOR" || + fail "triggering actor is not allowlisted" + [[ "$DISPATCH_REF" == "refs/heads/main" ]] || + fail "workflow must be dispatched from main" + [[ "$PR_NUMBER" =~ ^[1-9][0-9]*$ ]] || + fail "PR number must be a positive integer" + [[ "$SUPPLIED_SHA" =~ ^[0-9a-f]{40}$ ]] || + fail "head SHA must be 40 lowercase hexadecimal characters" + + pr_json="$( + gh pr view "$PR_NUMBER" \ + --repo "$GITHUB_REPOSITORY" \ + --json state,isDraft,baseRefName,headRefOid,isCrossRepository + )" + if ! jq -e \ + --arg sha "$SUPPLIED_SHA" \ + ' + .state == "OPEN" and + .isDraft == false and + .baseRefName == "main" and + .isCrossRepository == false and + .headRefOid == $sha + ' <<< "$pr_json" >/dev/null; then + fail "PR must be open, non-draft, same-repository, target main, and match the supplied SHA" + fi + + external_id="pr:$PR_NUMBER:$SUPPLIED_SHA" + payload="$( + jq -n \ + --arg name "$CHECK_NAME" \ + --arg sha "$SUPPLIED_SHA" \ + --arg external_id "$external_id" \ + --arg details_url "$DETAILS_URL" \ + --arg actor "$DISPATCH_ACTOR" \ + '{ + name: $name, + head_sha: $sha, + status: "completed", + conclusion: "success", + external_id: $external_id, + details_url: $details_url, + output: { + title: "Exact PR head accepted", + summary: ("Accepted by " + $actor + ".") + } + }' + )" + check_json="$( + gh api \ + -X POST \ + -H "Accept: application/vnd.github+json" \ + "repos/$GITHUB_REPOSITORY/check-runs" \ + --input - <<< "$payload" + )" + jq -e \ + --arg name "$CHECK_NAME" \ + --arg sha "$SUPPLIED_SHA" \ + --arg external_id "$external_id" \ + ' + .name == $name and + .head_sha == $sha and + .external_id == $external_id and + .status == "completed" and + .conclusion == "success" + ' <<< "$check_json" >/dev/null || + fail "Checks API response did not preserve the exact acceptance identity" + + printf '### Exact head accepted\n\nPR #%s at %s; external ID %s.\n' \ + "$PR_NUMBER" "$SUPPLIED_SHA" "$external_id" >> "$GITHUB_STEP_SUMMARY" diff --git a/docs/exact-head-acceptance.md b/docs/exact-head-acceptance.md new file mode 100644 index 0000000..b4a56cb --- /dev/null +++ b/docs/exact-head-acceptance.md @@ -0,0 +1,30 @@ +# Exact-head acceptance + +After independent review has accepted the exact current head and required CI has +passed, an authorized maintainer publishes that decision with: + +```sh +gh workflow run exact-head-acceptance.yml --ref main \ + -f pr_number=NUMBER -f head_sha=FULL_40_CHARACTER_HEAD_SHA +``` + +Run this in the repository checkout, or add `--repo OWNER/REPO`. Verify the +workflow finishes successfully and the `Exact-head acceptance` check appears on +that exact SHA. A new commit needs a new independent review and acceptance. +Dispatch is an attestation that review has happened; it does not perform review. + +The publisher only accepts an open, non-draft, same-repository PR targeting +`main`, with the supplied SHA matching its current head. Both the dispatcher and +rerun actor must be `JustinJLeopard`; dispatch must use `main`. No PR code is +checked out or executed. Publication grants only checks-write and PR-read. + +Merge this publisher before adding `Exact-head acceptance` to repository rules. +The workflow alone does not enforce a merge gate. Activation is a separate +ruleset change after proving a missing acceptance blocks, an exact acceptance +passes, and a new head loses acceptance. Keep all other required checks intact. + +Binding a required check to the GitHub Actions app identifies the app, not this +specific workflow. Another workflow with checks-write can publish the same +check name. This publisher and an app-bound ruleset are not a universal defense +against a malicious writer changing workflows; consumers that need that threat +model must also validate trusted workflow-run provenance.