Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
78 changes: 60 additions & 18 deletions .github/affirmation-trusted/README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,69 @@ commit-signing public key:
* fetched 2026-10-28 from `gh api users/web-flow/gpg_keys`
(the entry with `key_id` `B5690EEEBB952194`)

`github-web-flow-previous.gpg` is the expired key it replaced
(`5DE3E0509C47EA3CF04A42D34AEE18F83AFDEB23`), kept so historical commits can
still be classified.

== Why it exists

The Affirmation Document Gate (`hyperpolymath/cicd-suite`
`actions/affirmation-check`, run from `main-estate-audit.yml`) classifies the
signature on the commit that last changed `AFFIRMATION.adoc`. The copy of the
web-flow key vendored inside that action is GitHub's *previous* key
The Affirmation Document Gate (`actions/affirmation-check`) attempts to classify
the signature on the commit that last changed `AFFIRMATION.adoc`, using the
available Git history. The copy of the web-flow key vendored inside that action
is GitHub's *previous* key
(`5DE3E0509C47EA3CF04A42D34AEE18F83AFDEB23`, expired 2024-01-16) — the action's
own fingerprint allowlist names the new key, but the new key is not in its
keyring. Every GitHub-signed commit (web merges, squash landings, and the
test-merge commit a shallow PR checkout consists of) therefore classified as
`E` ("cannot be checked"), which the gate treats as "bad, revoked, or failed
verification" and fails on. That was the `estate-audit` failure on PR #102.

The workflow now runs `.github/affirmation-trusted/check.sh`, vendored from
`cicd-suite@bf7dd95cf49733019343ff485c2f45c6b261839c` with a local repair:
`E` accompanied by GnuPG's `NO_PUBKEY` is a notice; bad, revoked, and other failed
keyring. A GitHub-signed commit whose key the keyring lacks (web merges, squash
landings, and the test-merge commit a shallow PR checkout consists of)
classifies as `E` ("cannot be checked"), which the action treats as "bad,
revoked, or failed verification" and fails on. That was the `estate-audit`
failure on PR #102.

`check.sh` in this directory is that action's script vendored from
`cicd-suite@bf7dd95cf49733019343ff485c2f45c6b261839c` with a local repair: `E`
accompanied by GnuPG's `NO_PUBKEY` is a notice; bad, revoked, and other failed
verifications still fail. The local script imports both the current and
historical vendored GitHub keys and rejects them unless their primary
fingerprints match the two pinned above. This is a contained workaround, not
the durable trust boundary: gate code in a pull-request checkout is necessarily
reviewed code, whereas the root fix belongs in `cicd-suite`, whose pinned
external action can then be restored. If GitHub rotates the web-flow key
again, re-fetch it the same way and update the fingerprint above in the same
commit.
fingerprints match the two pinned above.

== Current status (2026-11-09)

`main-estate-audit.yml` is now a thin caller of the suite's shared reusable
workflow, so the gate that runs on this repository is *upstream's*
`actions/affirmation-check` at the suite's own pin — not the local script. The
local script is no longer wired into CI.

That gate checks out at depth 1, so the commit whose signature it classifies is
the *checkout boundary*. On a pull request that is the test-merge commit; on a
push it is the branch tip. Neither is necessarily the commit that last changed
`AFFIRMATION.adoc`. The gate emits a notice naming the boundary commit. Even
when that commit's signature verifies, CI may not have checked the signature
on the commit that last changed `AFFIRMATION.adoc`. A passing gate can also
report that the boundary commit's signature could not be verified.
Measured on this repository 2026-11-09: the gate passes in both shapes
(`estate-audit / governance` on PR run 42605863386; a depth-1 push-shape run
over the GitHub-signed landing commit `c0eb4f1` exited 0 with "verified with a
trusted key: GitHub <noreply@github.com>"), and it classifies the boundary
commit in both.

The local script is kept because:

* it is the reference implementation of the fix the upstream action still
needs. Re-checked 2026-11-09: the suite's vendored `github-web-flow.gpg` is
byte-identical to `github-web-flow-previous.gpg` here — its only key is the
2017 primary `5DE3E050…`, not the 2024 key `968479A1…` that signed this
repository's recent landings. Upstream's verification of those landings
therefore depends on resolving a key that is not in the file it ships (it
succeeded on the runner, which has network), which is precisely the fragile
path the local repair hardens: it ships both keys and turns a `NO_PUBKEY`
into a notice instead of a failure;
* `tests/workflows/review_regressions_test.sh` exercises it, so the repair
cannot rot silently;
* if the shared gate ever starts failing on a key it cannot classify, this
script is the local oracle to diagnose it — run
`bash .github/affirmation-trusted/check.sh` from the repository root.

This was always a contained workaround, not the durable trust boundary: gate
code in a pull-request checkout is necessarily reviewed code, and the root fix
belongs upstream. If GitHub rotates the web-flow key again, re-fetch it the
same way and update the fingerprint above in the same commit.
4 changes: 1 addition & 3 deletions .github/workflows/actions.lock
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,7 @@ workflows:
- 'step-security/harden-runner@1d88384fd173af6ecb012dfd0264a306b711241a'
'.github/workflows/label-triage.yml': []
'.github/workflows/labels.yml': []
'.github/workflows/main-estate-audit.yml':
- 'actions/checkout@v7.0.1'
- 'hyperpolymath/cicd-suite@bf7dd95cf49733019343ff485c2f45c6b261839c'
'.github/workflows/main-estate-audit.yml': []
'.github/workflows/mirror.yml': []
'.github/workflows/openssf-compliance.yml':
- 'actions/checkout@v7.0.1'
Expand Down
178 changes: 53 additions & 125 deletions .github/workflows/main-estate-audit.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,55 @@
# This workflow is managed by gh actions-lock.
# SPDX-License-Identifier: MPL-2.0
# This workflow is managed by gh actions-lock.
#
# Central Estate CI/CD Audit — a THIN CALLER of the shared estate audit.
#
# This file used to be an expanded copy of the audit: one job of 26 steps, each
# a direct `uses:` of a hyperpolymath/cicd-suite composite. A copy freezes the
# repository at whatever suite commit its actions.lock happened to hold, so
# upstream fixes never arrive, and it had drifted four ways:
#
# * It still ran `prat-check` and `semantic-audit-check`, which upstream
# removed as stubs that passed unconditionally (README, known defect 5:
# a green tick that credited assurance nothing checked).
# * It still ran `contractile-validation-check` and `proof-runner-check`,
# removed upstream for pass-on-absence (known defect 7): each printed
# "passed" when the tool it exists to run was absent — the normal case on
# a hosted runner — so they could only ever certify scans that never ran.
# * One job stopped at its first failing gate, so a single red hid the other
# 25 and every failure read "estate-audit: failing after 8s" with no gate
# named. The shared workflow reports five component checks (governance,
# hygiene, manifests, languages, advisory), each gate its own step, and
# keeps running the remaining gates after one fails.
# * Every step named `hyperpolymath/cicd-suite`, the suite's PRE-RENAME
# coordinate. Measured on this branch (runs 42603702962 / 42603704212,
# 2026-11-09): a reusable-workflow call under the old name starts with ZERO
# jobs and reports only "failure", while the same pin under the canonical
# name starts all five component checks. Resolving the old coordinate via
# the API still succeeds because REST follows the transfer redirect — the
# redirect is exactly what made the failure invisible. This repository's
# own workflow-linter re-resolution step flags it 24 times.
#
# So the audit is called, not copied:
#
# * Pin is a full branch-reachable commit SHA on the suite's default branch
# (2026-11-09 main). Never `@main` or a tag: the account enforces
# sha_pinning_required, and a branch ref would change the gates in every
# consuming repository at once. Never a blob SHA.
# * Caller job id stays `estate-audit`, and the workflow name is unchanged,
# so the required context keeps the prefix it had. The component checks
# report as `estate-audit / governance`, `estate-audit / hygiene`,
# `estate-audit / manifests`, `estate-audit / languages`,
# `estate-audit / advisory`.
# * DE-ONBOARDED from actions.lock: this file's entry lists no step-level
# action refs (the reusable call is a job-level `uses:`, which
# gh actions-lock does not track). An onboarded cross-repo reusable call
# under sha_pinning_required is the zero-job startup failure measured
# above. Regenerate the lock with `gh actions-lock` — do not hand-edit it.
#
# The Affirmation Document Gate now comes from the shared workflow. This
# repository's local repair (.github/affirmation-trusted/) remains the
# reference implementation for the upstream defect it documents; see that
# directory's README.

name: Central Estate CI/CD Audit

Expand All @@ -9,132 +59,10 @@ on:
pull_request:
branches: [ "main" ]

# Least privilege: every gate below is a read-only check over the tree.
# Least privilege: the called workflow only reads this repository's tree.
permissions:
contents: read

jobs:
estate-audit:
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
# fetch-depth: 0 is load-bearing for the Affirmation Document Gate: it
# classifies the signature on the commit that last changed
# AFFIRMATION.adoc. In the default depth-1 checkout that "commit" is
# the shallow boundary (on a PR, GitHub's test-merge commit), so the
# gate graded a checkout artefact, not the affirming commit. The local
# check treats unavailable public keys as notices and still rejects bad
# signatures; the current GitHub key is in .github/affirmation-trusted/.
- uses: actions/checkout@v7.0.1
with:
fetch-depth: 0
persist-credentials: false

- name: Required Files Gate
if: ${{ !cancelled() }}
uses: hyperpolymath/cicd-suite/actions/required-files-check@bf7dd95cf49733019343ff485c2f45c6b261839c

- name: Code Hygiene Gate
if: ${{ !cancelled() }}
uses: hyperpolymath/cicd-suite/actions/code-hygiene-check@bf7dd95cf49733019343ff485c2f45c6b261839c

- name: Manifest Validation Gate
if: ${{ !cancelled() }}
uses: hyperpolymath/cicd-suite/actions/manifest-check@bf7dd95cf49733019343ff485c2f45c6b261839c

- name: Idris2 ABI Purity Gate
if: ${{ !cancelled() }}
uses: hyperpolymath/cicd-suite/actions/idris2-abi-check@bf7dd95cf49733019343ff485c2f45c6b261839c

- name: Zig UnifiedApiAdapter API Gate
if: ${{ !cancelled() }}
uses: hyperpolymath/cicd-suite/actions/zig-unified-api-adapter-check@bf7dd95cf49733019343ff485c2f45c6b261839c

- name: Contractile Validation Gate
if: ${{ !cancelled() }}
uses: hyperpolymath/cicd-suite/actions/contractile-validation-check@bf7dd95cf49733019343ff485c2f45c6b261839c

- name: Recipes Set Validation Gate
if: ${{ !cancelled() }}
uses: hyperpolymath/cicd-suite/actions/recipes-set-check@bf7dd95cf49733019343ff485c2f45c6b261839c

- name: Affirmation Document Gate
if: ${{ !cancelled() }}
run: bash .github/affirmation-trusted/check.sh

- name: Academic Referencing Gate
if: ${{ !cancelled() }}
uses: hyperpolymath/cicd-suite/actions/referencing-check@bf7dd95cf49733019343ff485c2f45c6b261839c

- name: Semantic Audit Gate
if: ${{ !cancelled() }}
uses: hyperpolymath/cicd-suite/actions/semantic-audit-check@bf7dd95cf49733019343ff485c2f45c6b261839c

- name: SPDX License Gate
if: ${{ !cancelled() }}
uses: hyperpolymath/cicd-suite/actions/spdx-license-check@bf7dd95cf49733019343ff485c2f45c6b261839c

- name: Proof Runner Gate
if: ${{ !cancelled() }}
uses: hyperpolymath/cicd-suite/actions/proof-runner-check@bf7dd95cf49733019343ff485c2f45c6b261839c

- name: PRAT Testing Gate
if: ${{ !cancelled() }}
uses: hyperpolymath/cicd-suite/actions/prat-check@bf7dd95cf49733019343ff485c2f45c6b261839c

# No "Panic Attack & Pons" step here (removed 2026-10-28): the
# cicd-suite custom-tools-check composite prints "validation passed"
# when neither tool is on PATH — which is always — so it certified
# scans that never ran. panic-attack and pons-asinorum evidence is
# produced exactly once per trigger by the standards Hypatia lane
# (fork-governance.yml on PRs, hypatia-scan.yml on push/schedule)
# as verdict-grid rows with status envelopes; a presence proxy in
# this audit would only be a second, weaker claim to reconcile.

- name: WWW & Well-Known Compliance Gate
if: ${{ !cancelled() }}
uses: hyperpolymath/cicd-suite/actions/www-compliance-check@bf7dd95cf49733019343ff485c2f45c6b261839c

- name: BoJ Cartridge Validation Gate
if: ${{ !cancelled() }}
uses: hyperpolymath/cicd-suite/actions/boj-cartridge-check@bf7dd95cf49733019343ff485c2f45c6b261839c

- name: Formatting Validation Gate
if: ${{ !cancelled() }}
uses: hyperpolymath/cicd-suite/actions/formatting-check@bf7dd95cf49733019343ff485c2f45c6b261839c

- name: Accreditations & Badges Gate
if: ${{ !cancelled() }}
uses: hyperpolymath/cicd-suite/actions/badges-check@bf7dd95cf49733019343ff485c2f45c6b261839c

- name: Metrics Extraction Gate
if: ${{ !cancelled() }}
uses: hyperpolymath/cicd-suite/actions/metrics-check@bf7dd95cf49733019343ff485c2f45c6b261839c

- name: Linguist & Banned Languages Gate
if: ${{ !cancelled() }}
uses: hyperpolymath/cicd-suite/actions/linguist-check@bf7dd95cf49733019343ff485c2f45c6b261839c

- name: Test & Benchmarks Dashboard Gate
if: ${{ !cancelled() }}
uses: hyperpolymath/cicd-suite/actions/tests-benches-check@bf7dd95cf49733019343ff485c2f45c6b261839c

- name: Hosting & Site Status Gate
if: ${{ !cancelled() }}
uses: hyperpolymath/cicd-suite/actions/hosting-check@bf7dd95cf49733019343ff485c2f45c6b261839c

- name: Git-Sea Analytics Gate
if: ${{ !cancelled() }}
uses: hyperpolymath/cicd-suite/actions/gitsea-check@bf7dd95cf49733019343ff485c2f45c6b261839c

- name: Trust & Humans Validation Gate
if: ${{ !cancelled() }}
uses: hyperpolymath/cicd-suite/actions/trust-humans-check@bf7dd95cf49733019343ff485c2f45c6b261839c

- name: Are We UnAPI Gate (Secret Scanning)
if: ${{ !cancelled() }}
uses: hyperpolymath/cicd-suite/actions/secrets-check@bf7dd95cf49733019343ff485c2f45c6b261839c

- name: Reasonably Good Token Validation Gate
if: ${{ !cancelled() }}
uses: hyperpolymath/cicd-suite/actions/vaulted-tokens-check@bf7dd95cf49733019343ff485c2f45c6b261839c
uses: hyperpolymath/proven-cicd-and-workflows/.github/workflows/main-estate-audit.yml@3120495390635096552935d904652789253938e8 # suite main, 2026-11-09
Loading