Skip to content
Merged
Show file tree
Hide file tree
Changes from 40 commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
8607271
chore(protection): retire the last exemption — the allow-list is now …
hyperpolymath Oct 24, 2026
37c45a4
docs: record the decision-layer fix everywhere a reader or agent woul…
hyperpolymath Oct 24, 2026
d9a78dd
fix(protection): the bypass removal missed three rulesets, one of the…
hyperpolymath Oct 24, 2026
da9073d
docs(ci): correct audit claims and clarify context exemption scope
coderabbitai[bot] Oct 24, 2026
8ed2f3a
Merge remote audit updates and preserve context review corrections
coderabbitai[bot] Oct 24, 2026
620060f
fix(protection): a failed read-back must not report success
hyperpolymath Oct 24, 2026
d4b3d28
fix(gate): a data-dependent rule blocks every PR and was invisible
hyperpolymath Oct 24, 2026
553bbd7
docs(gate): the failure message names both shapes of finding
hyperpolymath Oct 24, 2026
0aca273
docs(audit): the data-dependent rules are not repairable in-repo
hyperpolymath Oct 24, 2026
d49f8f7
fix(gate): a data-rule-only finding must fail strict mode
hyperpolymath Oct 24, 2026
88699f4
Update scripts/fix-required-context-name.sh
hyperpolymath Oct 25, 2026
0857173
docs(gate): clarify data-rule inspection and audit behavior
coderabbitai[bot] Oct 25, 2026
dc8caa8
fix(ci): Harden required-context audits and ruleset repair verification
coderabbitai[bot] Oct 25, 2026
477ff71
Merge remote branch updates and preserve required-context review fixes
coderabbitai[bot] Oct 25, 2026
97cd2e4
feat(ci): measure and publish real line coverage
hyperpolymath Oct 25, 2026
583101e
fix(ci): name the coverage context by slug, and publish the number
hyperpolymath Oct 25, 2026
57059c6
feat(ci): report the line counts, not just the percentage
hyperpolymath Oct 25, 2026
48fa3c9
docs(audit): correct the claim that coverage is unrepairable, with th…
hyperpolymath Oct 25, 2026
ffe1094
fix(gate): stop claiming nothing uploads while a workflow does
hyperpolymath Oct 25, 2026
faf2a1b
fix(ci): measure the commit the upload is attributed to
hyperpolymath Oct 25, 2026
64ada82
feat(gate): tell an unverified rule from an unsatisfiable one
hyperpolymath Oct 25, 2026
609deeb
Update scripts/check-required-contexts.sh
hyperpolymath Oct 25, 2026
0f433ca
Update scripts/check-required-contexts.sh
hyperpolymath Oct 25, 2026
98ebde4
fix(ci): Verify Code Quality evidence across all workflow pages
coderabbitai[bot] Oct 25, 2026
04acc6b
Merge remote head and preserve required-context evidence hardening
coderabbitai[bot] Oct 25, 2026
83afb5d
Update scripts/check-required-contexts.sh
hyperpolymath Oct 25, 2026
107d4c7
fix(ci): Match the correct GitHub Code Quality workflow path
coderabbitai[bot] Oct 25, 2026
c3e9fad
Merge commit '83afb5d2efb9b11d2b51d8d2706e2f21f34d52ca' into arena/94…
coderabbitai[bot] Oct 25, 2026
ddc6180
test(ci): Correct Code Quality workflow paths in required-context fix…
coderabbitai[bot] Oct 25, 2026
1d9ef56
Merge commit 'c3e9fad20d74964013bb91a29547a3bc60aa3579' into arena/94…
coderabbitai[bot] Oct 25, 2026
3dfb5fd
fix(gate): evidence only where a rule applies, and never a guessed br…
hyperpolymath Oct 25, 2026
b6ae8f1
fix(gate): a 404 producer and an old gh are findings about the world,…
hyperpolymath Oct 25, 2026
110b5b5
fix(ci): the transfer broke self-recognition, and a measured run is n…
hyperpolymath Oct 25, 2026
f60738c
feat(ci): wire cicd-squabbler into the gate set, propose-only
hyperpolymath Oct 25, 2026
10191dd
feat(ci): deep recon — pons gates at error, panic-attack measures hon…
hyperpolymath Oct 25, 2026
bdc5afd
fix(ci): record the squabbler pin on its containing branch
hyperpolymath Oct 25, 2026
ab87044
fix(ci): gate squabble fight on an Administration-read credential
hyperpolymath Oct 25, 2026
318fa6e
fix(ci): recognise the transferred canon by immutable identity
hyperpolymath Oct 25, 2026
c81a57e
fix(ci): report a hidden squabble gate as not evaluated
hyperpolymath Oct 25, 2026
5a5525c
fix(ci): probe squabble gate visibility before classifying
hyperpolymath Oct 25, 2026
8bc8e53
Potential fix for pull request finding
hyperpolymath Oct 25, 2026
8868d09
Update scripts/check-required-contexts.sh
hyperpolymath Oct 25, 2026
334f4be
Update Justfile
hyperpolymath Oct 25, 2026
6204ec9
Update scripts/check-required-contexts.sh
hyperpolymath Oct 25, 2026
709d120
fix(ci): Tighten coverage evidence and scanner validation
coderabbitai[bot] Oct 25, 2026
7981e33
Merge remote updates and preserve coverage evidence validation
coderabbitai[bot] Oct 25, 2026
34fb477
docs(ci): Clarify preflight and required-check audit contracts
coderabbitai[bot] Oct 25, 2026
1cf714d
Update .github/workflows/cicd-squabbler-reusable.yml
hyperpolymath Oct 25, 2026
cf1f562
Update scripts/tests/cicd-squabbler-contract-test.sh
hyperpolymath Oct 25, 2026
f061333
fix(ci): normalize coverage timestamps and resolve governance renderer
coderabbitai[bot] Oct 25, 2026
f572331
Merge branch 'main' into arena/38c7ee34-standards
hyperpolymath Oct 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions .github/code-scanning-dismissals.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@
{
"alert_number": null,
"comment": "security-events: write is the ONLY permission that can upload SARIF to code scanning; it cannot be expressed as read. The reusable this job calls declares the same permission, and GitHub rejects a run at startup when the caller grants less than the callee requests (startup_failure, zero jobs) - so downgrading this to read does not reduce privilege, it silently disables code scanning. See standards#451 and the in-file comment.",
"line": 25,
"line": 26,
"path": ".github/workflows/hypatia-scan.yml",
"reason": "won't fix",
"rule_id": "TokenPermissionsID"
},
{
"alert_number": null,
"comment": "Same structural requirement as the caller above: the scan job uploads its own SARIF, so security-events: write is the minimum this reusable can declare. Workflow-level actions/contents stay read.",
"line": 44,
"line": 62,
"path": ".github/workflows/hypatia-scan-reusable.yml",
"reason": "won't fix",
"rule_id": "TokenPermissionsID"
Expand Down Expand Up @@ -80,6 +80,22 @@
"path": ".github/workflows/fork-governance.yml",
"reason": "won't fix",
"rule_id": "TokenPermissionsID"
},
{
"alert_number": null,
"comment": "Same structural SARIF requirement as hypatia-scan.yml: this caller job grants security-events: write only so the pons job in deep-recon-reusable.yml can upload its SARIF to code scanning. A caller cannot grant less than the callee declares without startup_failure and zero jobs; workflow level remains contents: read and the panic-attack job declares contents: read only.",
"line": 36,
"path": ".github/workflows/deep-recon.yml",
"reason": "won't fix",
"rule_id": "TokenPermissionsID"
},
{
"alert_number": null,
"comment": "The pons job is the one job in this reusable that uploads SARIF, using github/codeql-action/upload-sarif, and security-events: write is the only permission spelling that can perform that upload. It is job-scoped: the reusable workflow level and the panic-attack job remain contents: read, and the scan itself still fails closed on error-severity findings or an incomplete scan.",
"line": 70,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Point the dismissal at the write permission

For this reusable, security-events: write is on line 71, while line 70 is contents: read. Because the dismissal matcher requires an exact path and line, the actual TokenPermissionsID alert will not match this entry; the newly added grounding check in scripts/tests/dismiss-code-scanning-alerts-test.sh also fails for this reason. Update this entry and its fixture to line 71.

Useful? React with 👍 / 👎.

"path": ".github/workflows/deep-recon-reusable.yml",
"reason": "won't fix",
"rule_id": "TokenPermissionsID"
}
]
}
24 changes: 24 additions & 0 deletions .github/workflows/actions.lock
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,15 @@ workflows:
- 'haskell-actions/setup@0f8e8c99d88aeb3fbfd523f1ef2c6f762d10d64d'
- 'hyperpolymath/standards@d55304a01b5260b0511aae0d14ed8b8770b00293'
- 'oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6'
'.github/workflows/cicd-squabbler-reusable.yml':
- 'actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1'
- 'hyperpolymath/cicd-squabbler@14f853fde902ab2d7631070d87a9dc9122e01013'
- 'step-security/harden-runner@ccd8616d44fd3846e67624a50d5aad6d37bf2d25'
'.github/workflows/cicd-squabbler.yml': []
'.github/workflows/code-coverage.yml':
- 'actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1'
- 'actions/upload-code-coverage@2b21a77928be8d5168c2b9581a67f2adbebacc52'
- 'dtolnay/rust-toolchain@683b588c487a69d01f6c6ddf40f036ff682cc2c8'
'.github/workflows/codeql-reusable.yml':
- 'actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1'
- 'github/codeql-action@b96794f015dfd88f77b49b1c93e0fa7110f94c63'
Expand All @@ -46,6 +55,11 @@ workflows:
'.github/workflows/deed-conformance.yml':
- 'actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1'
- 'oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6'
'.github/workflows/deep-recon-reusable.yml':
- 'actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1'
- 'actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9'
- 'github/codeql-action@b96794f015dfd88f77b49b1c93e0fa7110f94c63'
'.github/workflows/deep-recon.yml': []
'.github/workflows/dependabot-lock-regen.yml':
- 'actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1'
- 'actions/create-github-app-token@64ab729a6294000f5aa4a4bc0b73d1f32bc45510'
Expand Down Expand Up @@ -235,6 +249,11 @@ dependencies:
repo_id: 496012378
uses:
- 'actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f'
'actions/upload-code-coverage@2b21a77928be8d5168c2b9581a67f2adbebacc52':
ref: 'v1.4.4'
commit: 'sha1-2b21a77928be8d5168c2b9581a67f2adbebacc52'
owner_id: 44036562
repo_id: 1220171870
'denoland/setup-deno@22d081ff2d3a40755e97629de92e3bcbfa7cf2ed':
ref: 'v2.0.5'
commit: 'sha1-22d081ff2d3a40755e97629de92e3bcbfa7cf2ed'
Expand Down Expand Up @@ -270,6 +289,11 @@ dependencies:
commit: 'sha1-0f8e8c99d88aeb3fbfd523f1ef2c6f762d10d64d'
owner_id: 75048950
repo_id: 623796603
'hyperpolymath/cicd-squabbler@14f853fde902ab2d7631070d87a9dc9122e01013':
ref: 'main'
commit: 'sha1-14f853fde902ab2d7631070d87a9dc9122e01013'
owner_id: 6759885
repo_id: 1284026967
'hyperpolymath/standards@70019048f862250c04346f27e6ca196ff7aa187a':
ref: '70019048f862250c04346f27e6ca196ff7aa187a'
commit: 'sha1-70019048f862250c04346f27e6ca196ff7aa187a'
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/allowlist-preflight-reusable.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ jobs:

- name: Stage policy tools outside the scanned tree
run: |
if [ "$GITHUB_REPOSITORY" = hyperpolymath/standards ]; then
if [ "${GITHUB_REPOSITORY_ID:-}" = "1116521501" ] || [ "$GITHUB_REPOSITORY" = hyperpolymath/standards ] || [ "$GITHUB_REPOSITORY" = metadatastician/standards ]; then
cp scripts/check-actions-policy.sh scripts/check-allowed-actions.sh "$RUNNER_TEMP/"
cp rhodium-standard-repositories/actions-allowlist/allowed-actions.json \
"$RUNNER_TEMP/allowed-actions.json"
Expand Down
281 changes: 281 additions & 0 deletions .github/workflows/cicd-squabbler-reusable.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,281 @@
# SPDX-License-Identifier: MPL-2.0
# SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell <j.d.a.jewell@open.ac.uk>
#
# cicd-squabbler-reusable.yml — run the estate's CI/CD fighter as a gate.
#
# The squabbler's one invariant is machine-checked (SPARK, in its repo):
# green ⇔ a required check actually ran and passed. It never offers a
# bypass, an admin override, or a dropped required context as a move. That
# is exactly the failure this repository paid for on 2026-10-24 (a required
# context nothing could produce, merged around with an `always` bypass), so
# the tool belongs INSIDE the gate set, not beside it.
#
# Two jobs, two different contracts:
#
# * `chains` is a HARD gate. `squabble chains` maps reusable-workflow and
# action dependencies between repositories. Exit 4 means a dependency
# cycle or a dead upstream — either makes some required check
# unproducible while the board reads green, so the job fails. Exit 2 is a
# tool failure and also fails: a gate that cannot look must not pass.
# Warnings (pin skew, diamonds) are printed and do not fail.
#
# * `fight-report` is a REPORT, deliberately. It classifies the calling
# pull request's reds (self-win | escalate | assign-owner) into the step
# summary. When it runs, it fails only when the tool itself fails
# (exit 2): "the planner proposed a move" is information for a human,
# not a verdict on the PR, and gating on it would fail every PR that is
# legitimately red for unrelated reasons — twice. It NEVER passes
# `--apply` and never writes to the repository; enacting a move is a
# follow-up commit a human (or a later, separately-reviewed
# automation) makes.
#
# Measured on this repository: `fight` reads the gate as rulesets ∪
# classic branch protection, and refuses to reason about a gate it can
# only partially see. The classic-protection endpoint is 403 to the
# built-in Actions token even though all 24 ruleset contexts are
# visible, so squabble correctly exits 2. Fight therefore runs only
# when the caller supplies the optional Administration-read credential
# declared below AND a preflight proves that credential can read the
# pull request, the branch-rules endpoint and classic protection (or a
# genuine 404 for the latter). Absent credential = the summary says
# NOT RUN, in those words. A supplied credential that cannot see the
# whole gate = NOT EVALUATED: the summary makes no claim about the PR,
# and this advisory does not redden every PR for an owner-side
# credential that needs broadening or reissuing. The pinned upstream's
# exact hidden-gate wording remains a second guard if visibility
# changes between probe and classification. Every other exit 2 fails.
#
# The squabble binary is installed by the upstream composite action pinned
# to a commit; the action itself refuses any binary whose sha256 and build
# attestation do not match its pinned release. `verify-satisfied` is NOT
# run here even when the credential is supplied: promoting that stronger
# verdict is a separate, separately-reviewed decision.
#
# Consumers pin this reusable by commit SHA like every other estate
# reusable. Keep caller grants at or above the job-level grants below, or
# GitHub rejects the run at startup with no check run at all.

name: CICD Squabbler (reusable)

on:
workflow_call:
inputs:
pr-number:
description: "Pull request number for the fight report; empty skips it (push/schedule runs)."
required: false
type: string
default: ""
runs-on:
description: "Runner label; the pinned squabble release is x86_64 Linux only."
required: false
type: string
default: "ubuntu-latest"
secrets:
ADMINISTRATION_READ_TOKEN:
description: "Optional fine-grained/App token with Administration:read plus pull-request, check and status read for squabble fight; absent means NOT RUN, and a credential that cannot see classic branch protection means NOT EVALUATED."
required: false

permissions:
contents: read

jobs:
chains:
name: Squabble chains (cycles and dead upstreams block)
runs-on: ${{ inputs.runs-on }}
timeout-minutes: 10
permissions:
contents: read
attestations: read
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- name: Install the pinned, attested squabble
id: squabble
uses: hyperpolymath/cicd-squabbler/.github/actions/squabble@14f853fde902ab2d7631070d87a9dc9122e01013
with:
args: ""

# Argument form is <path>=<owner/repo>: the checkout is this repo, so
# its own outbound reusable/action edges are attributed to its slug.
# No `gh:` sources and no --follow here: following into other repos
# needs their read access from this token and belongs to the weekly
# estate sweep, not a per-PR gate.
- name: Map this repository's CI dependency chains
env:
SQUABBLE_BIN: ${{ steps.squabble.outputs.path }}
REPO: ${{ github.repository }}
GH_TOKEN: ${{ github.token }}
run: |
set -uo pipefail
test -x "$SQUABBLE_BIN" || { echo "::error::squabble did not install"; exit 1; }
rc=0
"$SQUABBLE_BIN" chains ".=$REPO" | tee "$RUNNER_TEMP/chains.txt" || rc=$?
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
{
echo "### Squabble chains"
echo
echo '```'
cat "$RUNNER_TEMP/chains.txt"
echo '```'
} >> "$GITHUB_STEP_SUMMARY"
if [ "$rc" -eq 4 ]; then
echo "::error::blocking chain finding (dependency cycle or dead upstream) — see the summary"
Comment on lines +121 to +122

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Register the squabble chains job as a required check

When squabble chains exits 4 for a dependency cycle or dead upstream, this step makes the workflow red, but that red does not block merging: a repo-wide search finds no registration of cicd-squabbler.yml or its squabble / Squabble chains (cycles and dead upstreams block) context in config/rulesets/gates.json or another checked-in ruleset source, while the committed audit still describes the existing 21 required contexts. Add the hard chains context to the required gate (while leaving the fight-report job advisory), otherwise the workflow's stated hard-gate invariant is unenforced.

Useful? React with 👍 / 👎.

exit 1
fi
if [ "$rc" -ne 0 ]; then
echo "::error::squabble chains failed to run (exit $rc) — a gate that cannot look does not pass"
exit 1
fi

fight-report:
name: Squabble fight report (advisory)
if: inputs.pr-number != ''
runs-on: ${{ inputs.runs-on }}
timeout-minutes: 10
permissions:
contents: read
pull-requests: read
attestations: read
steps:
# This is the only job in the reusable that touches a caller secret.
# Harden it first (Hypatia RE001 / ruling D131) so outbound egress is
# audited from the first credential-bearing request onward.
- name: Harden runner (egress audit)
uses: step-security/harden-runner@ccd8616d44fd3846e67624a50d5aad6d37bf2d25 # v2.22.1
with:
egress-policy: audit

# Do not equate "a secret string exists" with "fight can inspect":
# the estate PAT measured on this PR is present but cannot read the
# Administration endpoint. Probe exactly the read surfaces squabble
# needs for its gate (PR/base, branch rules, classic protection). A
# classic-protection 404 is visible evidence of no classic gate; any
# other classic failure means the gate is only partially visible.
- name: Probe whether fight can inspect the full gate
id: fight-credential
env:
GH_TOKEN: ${{ secrets.ADMINISTRATION_READ_TOKEN }}
REPO: ${{ github.repository }}
PR_NUMBER: ${{ inputs.pr-number }}
run: |
set -uo pipefail
not_evaluated() {
reason="$1"
echo "available=false" >> "$GITHUB_OUTPUT"
echo "::notice title=Squabble fight not evaluated::${reason}. This advisory makes no claim about this pull request's reds. The hard chains gate still ran."
{
echo "### Squabble fight report — NOT EVALUATED"
echo
echo "${reason}."
echo "squabble fight reads rulesets and classic branch protection as one gate and refuses to reason about a partially visible gate. This advisory therefore makes no claim about this pull request's reds. Broaden or reissue the Administration-read credential to enable classification. The separate hard \`squabble chains\` gate remains enforced."
} >> "$GITHUB_STEP_SUMMARY"
exit 0
}
Comment thread
hyperpolymath marked this conversation as resolved.
Resolved
case "$PR_NUMBER" in
''|*[!0-9]*) echo "::error::pr-number must be a number, got '$PR_NUMBER'"; exit 1 ;;
esac
if [ -z "$GH_TOKEN" ]; then
echo "available=false" >> "$GITHUB_OUTPUT"
echo "::notice title=Squabble fight not run::No Administration-read credential was supplied, so the advisory fight report did not inspect this pull request. The hard chains gate still ran."
{
echo "### Squabble fight report — NOT RUN"
echo
echo "No \`ADMINISTRATION_READ_TOKEN\` was supplied by the caller."
echo "squabble fight reads rulesets and classic branch protection as one gate, and the built-in Actions token cannot read the classic-protection endpoint. This advisory job therefore makes no claim about this pull request's reds. The separate hard \`squabble chains\` gate remains enforced."
} >> "$GITHUB_STEP_SUMMARY"
exit 0
fi
probe_err="$RUNNER_TEMP/fight-probe.err"
pr_json="$(gh pr view "$PR_NUMBER" --repo "$REPO" --json baseRefName 2>"$probe_err")" \
|| not_evaluated "The supplied credential could not read this pull request"
base_ref="$(printf '%s' "$pr_json" | jq -er '.baseRefName | select(type == "string" and length > 0)')" \
|| { echo "::error::gh pr view returned no usable base branch for the fight preflight"; exit 1; }
encoded_base_ref="$(printf '%s' "$base_ref" | jq -Rr '@uri')"
gh api "repos/$REPO/rules/branches/$encoded_base_ref" >/dev/null 2>"$probe_err" \
|| not_evaluated "The supplied credential could not read this pull request's branch rules"
if gh api "repos/$REPO/branches/$encoded_base_ref/protection" >/dev/null 2>"$probe_err"; then
:
elif grep -Eq 'HTTP 404|Branch not protected' "$probe_err"; then
:
else
not_evaluated "The supplied credential could not read classic branch protection"
fi
echo "available=true" >> "$GITHUB_OUTPUT"

- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
if: steps.fight-credential.outputs.available == 'true'
with:
persist-credentials: false

- name: Install the pinned, attested squabble
id: squabble
if: steps.fight-credential.outputs.available == 'true'
uses: hyperpolymath/cicd-squabbler/.github/actions/squabble@14f853fde902ab2d7631070d87a9dc9122e01013
with:
args: ""

# Propose-only: no --apply, ever, from CI. Exit 3 ("no gate on the
# base branch") is a reportable finding printed below, not a tool
# failure. Exit 2 is normally a tool failure and fails the job,
# because a silently broken advisor would be indistinguishable from
# "nothing to fight". The sole exception is the pinned upstream's
# exact hidden-classic-protection wording: that is positive evidence
# the supplied credential could not see the whole gate, so the
# advisory reports NOT EVALUATED instead of pretending to classify.
# The wording is version-specific; if a future pin changes it, the
# generic exit-2 branch below turns red until this contract is
# updated — failing closed, not silently downgrading real breakage.
- name: Classify this pull request's reds
if: steps.fight-credential.outputs.available == 'true'
env:
SQUABBLE_BIN: ${{ steps.squabble.outputs.path }}
REPO: ${{ github.repository }}
PR_NUMBER: ${{ inputs.pr-number }}
GH_TOKEN: ${{ secrets.ADMINISTRATION_READ_TOKEN }}
run: |
set -uo pipefail
test -x "$SQUABBLE_BIN" || { echo "::error::squabble did not install"; exit 1; }
case "$PR_NUMBER" in
''|*[!0-9]*) echo "::error::pr-number must be a number, got '$PR_NUMBER'"; exit 1 ;;
esac
rc=0
"$SQUABBLE_BIN" fight "$REPO" "$PR_NUMBER" --repo-root . > "$RUNNER_TEMP/fight.txt" 2>&1 || rc=$?
gate_hidden=false
if [ "$rc" -eq 2 ] && grep -Fq "classic branch protection on this branch is not visible to this token" "$RUNNER_TEMP/fight.txt"; then
gate_hidden=true
fi
{
if [ "$gate_hidden" = "true" ]; then
echo "### Squabble fight report — NOT EVALUATED"
else
echo "### Squabble fight report (propose-only)"
fi
echo
echo '```'
cat "$RUNNER_TEMP/fight.txt"
echo '```'
echo
if [ "$gate_hidden" = "true" ]; then
echo "Exit 2 — classic branch protection is not visible to the supplied credential, so squabble refused to reason about a partially visible gate. This advisory makes no claim about this pull request's reds, and no move was applied."
else
echo "Exit $rc. No move was applied; squabble in CI proposes, humans enact."
fi
} >> "$GITHUB_STEP_SUMMARY"
cat "$RUNNER_TEMP/fight.txt"
if [ "$gate_hidden" = "true" ]; then
echo "::notice title=Squabble fight not evaluated::The supplied credential cannot read classic branch protection, so this advisory makes no claim about this pull request's reds. Broaden the Administration-read credential to enable classification. The hard chains gate still ran."
exit 0
fi
if [ "$rc" -eq 2 ]; then
echo "::error::squabble fight failed to run — the report above is a failure, not an all-clear"
exit 1
fi
if [ "$rc" -eq 3 ]; then
echo "::warning::squabble found no required_status_checks gate on the base branch — nothing to triage"
exit 0
fi
if [ "$rc" -ne 0 ]; then
echo "::error::squabble fight exited $rc (unclassified) — treated as a tool failure"
exit 1
fi
Loading
Loading