Skip to content

governance / Allowlist Preflight is permanently red in 331 of 332 repos — the PAT was never distributed #656

Description

@hyperpolymath

Measured: 331 of 332 repos can never pass governance / Allowlist Preflight

governance-reusable.yml runs a Check live Actions policy step that reads the repo's live Actions permissions through gh, authenticated with secrets.HYPATIA_SCAN_PAT. Where that credential does not arrive, the step dies:

gh: To use GitHub CLI in a GitHub Actions workflow, set the GH_TOKEN environment variable.
ERROR: could not read live Actions permissions for .github/workflows
##[error]Process completed with exit code 1.

The design is deliberate, and correct — it was just never completed

The step carries this comment, and it is the right instinct:

# GitHub's job token cannot read this Administration endpoint. Keep
# this dependency explicit: missing/expired credentials must make the
# live control red rather than silently reducing it to a tree check.

Fail closed rather than quietly downgrade. But it assumes the PAT reaches every caller, and the distribution never happened.

Census — all 420 non-archived repos enumerated, then filtered

332 repos call governance-reusable.yml. Of those:

secrets: inherit HYPATIA_SCAN_PAT present repos verdict
no no 329 ❌ permanently red
no yes 2 ❌ permanently red (secret cannot reach the reusable)
yes yes 1 ✅ can pass

The one that works is standards itself.

Two independent things are missing, and both are required:

  1. secrets: inherit on the caller's job. Without it a reusable workflow receives no secrets, so even the 2 repos that hold the PAT cannot use it.
  2. The HYPATIA_SCAN_PAT secret in the repo. rsr-template-repo, for example, has zero secrets of any kind.

Why this matters beyond a red tick

governance / Allowlist Preflight is a required status check on ruleset Optimus-Branch. Wherever that ruleset applies, this single check blocks every PR on its own — regardless of the PR's merit, and regardless of every other check passing.

It also inverts the comment's own goal. A control that is red everywhere, always carries no information, gets tuned out, and is routinely bypassed with --admin — which bypasses every other rule at the same time. Failing closed and failing open converge on the same outcome when the failure is universal.

The decision

Two options, and the code shows a choice was already made — just not carried out:

(A) Complete the distribution. Add HYPATIA_SCAN_PAT to the 331 repos and secrets: inherit to their governance.yml callers. Honours the original intent. Cost: a secret in 331 repos and 331 one-line workflow edits, plus a rotation burden forever after.

(B) Make the live check conditional. Skip (not fail) when no credential is present, keep the tree check, and emit a clearly-labelled skipped conclusion. The comment above explicitly argues against this — but it was written when the assumption was that the credential would be everywhere.

(C) Split the check. Keep the tree check required; make the live check a separate, non-required context that is red only where a credential exists and the policy genuinely fails. Preserves the signal where it can be trusted without blocking the 331 where it cannot.

I would suggest (C) — it is the only option that keeps the original honesty goal intact without either a 331-repo secret distribution or a silent downgrade.

Method

Enumerate-then-filter over gh repo list hyperpolymath --limit 500 --no-archived (384 repos, plus 36 in metadatastician = 420 denominator); for each, fetch .github/workflows/governance.yml, keep those referencing governance-reusable.yml, then check for secrets: inherit and query /actions/secrets. Neither 384 nor 332 is a round number, so no page cap. The failing log was read from rsr-template-repo job 98124863115.

Not checked: whether HYPATIA_SCAN_PAT is currently valid or expired in the 3 repos that hold it; organisation- or account-level secrets that might cover repos invisibly (/user/codespaces/secrets returned 403 for this token); non-default branches.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething is broken or behaves incorrectlycicdCI/CD: workflows, actions, lockfiles, pins, runners, release gatesgovernancePolicy, rulesets, standards, compliance, and their enforcementpriority:p1High - schedule nextscope:estateAffects many or all repos across the estate

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions