From b0586d17063b571195571342887b0c2011bb760f Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Mon, 27 Jul 2026 13:56:54 +0100 Subject: [PATCH 1/4] chore(ci): grant `actions: read` across all workflows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Recovers the un-upstreamed half of local commit c655117 (2026-07-26), which never reached origin/main. `actions: read` lets a job read workflow/run metadata via the API. Several gates need it — the staleness check reads run history, and CodeQL reads workflow definitions when scanning the `actions` language. Widening a *caller* grant is always safe: the startup_failure trap is a REUSABLE requesting more than its caller grants, never the reverse. Deliberately NOT carried over from c655117: - `.github/funding.yml` — a sweeper artefact. Lowercase (GitHub reads `FUNDING.yml`), no SPDX header, and it names `metadatastician` while the real `.github/FUNDING.yml` already present names `hyperpolymath` across github/ko_fi/liberapay. Adding it would have put a second, wrong funding file in the repo. Also dropped from that local branch entirely: commit 5a5301d, which pinned github/codeql-action to 29b1f65c1f735799893313399435a59f54045865 — a SHA that DOES NOT EXIST (HTTP 404 from both the commits and git/commits endpoints). origin/main already carries a real, newer pin. Landing 5a5301d would have made CodeQL unable to resolve the action. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/TagBot.yml | 1 + .github/workflows/agda.yml | 1 + .github/workflows/boj-build.yml | 1 + .github/workflows/codeql.yml | 1 + .github/workflows/container-build.yml | 1 + .github/workflows/dependabot-automerge.yml | 1 + .github/workflows/dogfood-gate.yml | 1 + .github/workflows/e2e.yml | 1 + .github/workflows/governance.yml | 1 + .github/workflows/hypatia-scan.yml | 1 + .github/workflows/install-smoke.yml | 1 + .github/workflows/instant-sync.yml | 1 + .github/workflows/mirror.yml | 1 + .github/workflows/pages.yml | 1 + .github/workflows/push-email-notify.yml | 1 + .github/workflows/release.yml | 1 + .github/workflows/scorecard.yml | 1 + .github/workflows/secret-scanner.yml | 1 + .github/workflows/zig.yml | 1 + 19 files changed, 19 insertions(+) diff --git a/.github/workflows/TagBot.yml b/.github/workflows/TagBot.yml index dfde769..36fa2f2 100644 --- a/.github/workflows/TagBot.yml +++ b/.github/workflows/TagBot.yml @@ -26,6 +26,7 @@ on: workflow_dispatch: permissions: + actions: read contents: read jobs: diff --git a/.github/workflows/agda.yml b/.github/workflows/agda.yml index 4531d8b..ad4dbfc 100644 --- a/.github/workflows/agda.yml +++ b/.github/workflows/agda.yml @@ -22,6 +22,7 @@ on: workflow_dispatch: permissions: + actions: read contents: read concurrency: diff --git a/.github/workflows/boj-build.yml b/.github/workflows/boj-build.yml index e796d25..428759a 100644 --- a/.github/workflows/boj-build.yml +++ b/.github/workflows/boj-build.yml @@ -6,6 +6,7 @@ on: branches: [main, master] workflow_dispatch: permissions: + actions: read contents: read jobs: trigger-boj: diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index ec97ec0..19a6f2a 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -16,6 +16,7 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true permissions: + actions: read contents: read jobs: analyze: diff --git a/.github/workflows/container-build.yml b/.github/workflows/container-build.yml index ef425c0..f568eee 100644 --- a/.github/workflows/container-build.yml +++ b/.github/workflows/container-build.yml @@ -30,6 +30,7 @@ on: workflow_dispatch: permissions: read-all + actions: read concurrency: group: container-build-${{ github.ref }} diff --git a/.github/workflows/dependabot-automerge.yml b/.github/workflows/dependabot-automerge.yml index 4464081..ef4efeb 100644 --- a/.github/workflows/dependabot-automerge.yml +++ b/.github/workflows/dependabot-automerge.yml @@ -40,6 +40,7 @@ on: pull_request: types: [opened, reopened, synchronize] permissions: + actions: read contents: write # needed to enable auto-merge pull-requests: write # needed to approve # NB: keep narrow — do NOT add secrets: read or id-token: write here. diff --git a/.github/workflows/dogfood-gate.yml b/.github/workflows/dogfood-gate.yml index 8e3a6bb..04f6171 100644 --- a/.github/workflows/dogfood-gate.yml +++ b/.github/workflows/dogfood-gate.yml @@ -13,6 +13,7 @@ on: branches: [main, master] permissions: + actions: read contents: read jobs: diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 8c657aa..0698994 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -20,6 +20,7 @@ on: workflow_dispatch: permissions: read-all + actions: read concurrency: group: e2e-${{ github.ref }} diff --git a/.github/workflows/governance.yml b/.github/workflows/governance.yml index 8776de0..966a16e 100644 --- a/.github/workflows/governance.yml +++ b/.github/workflows/governance.yml @@ -9,6 +9,7 @@ on: workflow_dispatch: permissions: + actions: read contents: read jobs: diff --git a/.github/workflows/hypatia-scan.yml b/.github/workflows/hypatia-scan.yml index 5eeee3c..ae59369 100644 --- a/.github/workflows/hypatia-scan.yml +++ b/.github/workflows/hypatia-scan.yml @@ -14,6 +14,7 @@ on: # `security-events: write` to upload its SARIF, so the job below raises it # explicitly (same pattern as scorecard.yml). permissions: + actions: read contents: read security-events: write diff --git a/.github/workflows/install-smoke.yml b/.github/workflows/install-smoke.yml index 148e62e..14221e8 100644 --- a/.github/workflows/install-smoke.yml +++ b/.github/workflows/install-smoke.yml @@ -23,6 +23,7 @@ on: workflow_dispatch: permissions: read-all + actions: read concurrency: group: install-smoke-${{ github.ref }} diff --git a/.github/workflows/instant-sync.yml b/.github/workflows/instant-sync.yml index a718d56..a98e2b1 100644 --- a/.github/workflows/instant-sync.yml +++ b/.github/workflows/instant-sync.yml @@ -10,6 +10,7 @@ on: types: [published] permissions: + actions: read contents: read jobs: diff --git a/.github/workflows/mirror.yml b/.github/workflows/mirror.yml index 13ca1bd..9357e25 100644 --- a/.github/workflows/mirror.yml +++ b/.github/workflows/mirror.yml @@ -8,6 +8,7 @@ on: workflow_dispatch: permissions: + actions: read contents: read jobs: diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index b14bddd..e1f3dde 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -6,6 +6,7 @@ on: branches: [main, master] workflow_dispatch: permissions: + actions: read contents: read pages: write id-token: write diff --git a/.github/workflows/push-email-notify.yml b/.github/workflows/push-email-notify.yml index 2a95f5d..c08ea16 100644 --- a/.github/workflows/push-email-notify.yml +++ b/.github/workflows/push-email-notify.yml @@ -7,6 +7,7 @@ name: Push email notification on: push: {} permissions: + actions: read contents: read jobs: notify: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a97320e..3fa13d5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -33,6 +33,7 @@ on: type: string permissions: + actions: read contents: read jobs: diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index b97e2cb..cede40a 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -9,6 +9,7 @@ on: workflow_dispatch: permissions: + actions: read contents: read jobs: diff --git a/.github/workflows/secret-scanner.yml b/.github/workflows/secret-scanner.yml index 8262804..6d1906c 100644 --- a/.github/workflows/secret-scanner.yml +++ b/.github/workflows/secret-scanner.yml @@ -14,6 +14,7 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true permissions: + actions: read contents: read jobs: trufflehog: diff --git a/.github/workflows/zig.yml b/.github/workflows/zig.yml index 0a65d9f..9ae2c47 100644 --- a/.github/workflows/zig.yml +++ b/.github/workflows/zig.yml @@ -24,6 +24,7 @@ on: workflow_dispatch: permissions: read-all + actions: read concurrency: group: zig-${{ github.ref }} From be2f8b890264404833267acb8cefcdf3e0b03a90 Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Mon, 27 Jul 2026 13:57:37 +0100 Subject: [PATCH 2/4] docs(ci): stop asserting stale test counts in the e2e header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The header claimed "693 @test assertions, 10 Agda proofs, 8 integrations". Measured on this tree: 1129 `@test` occurrences under test/ and 3 Agda modules (Inequalities, RankIdentities, TropicalSemiring). Wrong in both directions — it undercounted the tests by 63% and overcounted the proofs 3x. Replacing it with a corrected count would be wrong again on the next commit that adds a test, so the header now describes what the job does and points at the job's own output as the authoritative source. A comment that has to be manually resynced to stay true is a comment that will drift. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/e2e.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 0698994..2fd946b 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -3,7 +3,13 @@ # # Statistikles — E2E + Aspect Tests # -# Runs the Julia test suite (693 @test assertions, 10 Agda proofs, 8 integrations). +# Runs the Julia test suite, then the Agda proof gate. +# +# Counts are deliberately NOT stated here. The previous header claimed +# "693 @test assertions, 10 Agda proofs, 8 integrations"; measured on this tree +# it is 1129 `@test` occurrences under test/ and 3 Agda modules under proofs/ — +# wrong in both directions, and wrong again on the next commit that adds a test. +# The authoritative counts are whatever this job prints when it runs. name: E2E + Aspect From 12ba5843f780f6bbda91f28aa07a5a25f3495ed7 Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Mon, 27 Jul 2026 13:58:21 +0100 Subject: [PATCH 3/4] fix(ci): don't append `actions: read` under scalar `permissions: read-all` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous commit recovered a sweep that inserted `actions: read` after every `permissions:` line. Four workflows declare permissions in the SCALAR form: permissions: read-all Hanging a mapping key under a scalar is invalid YAML, so the sweep produced: permissions: read-all actions: read # <-- "mapping values are not allowed here" Actions rejects a malformed workflow at PARSE time, which means zero jobs and NO CHECK RUN AT ALL — not a red X. `gh pr checks` shows nothing amiss while the gate silently ceases to exist. Affected: zig.yml, e2e.yml, container-build.yml, install-smoke.yml — i.e. the Zig FFI gate, the Julia test suite, the container build and the install smoke test. Four of the repo's most load-bearing gates. The insertion was redundant anyway: `read-all` already grants every read scope, including `actions: read`. The sweep matched `permissions:` as text, not as a YAML node, so it could not tell the two forms apart. Verified: all 19 workflows now parse under yaml.safe_load. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/container-build.yml | 1 - .github/workflows/e2e.yml | 1 - .github/workflows/install-smoke.yml | 1 - .github/workflows/zig.yml | 1 - 4 files changed, 4 deletions(-) diff --git a/.github/workflows/container-build.yml b/.github/workflows/container-build.yml index f568eee..ef425c0 100644 --- a/.github/workflows/container-build.yml +++ b/.github/workflows/container-build.yml @@ -30,7 +30,6 @@ on: workflow_dispatch: permissions: read-all - actions: read concurrency: group: container-build-${{ github.ref }} diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 2fd946b..3b41276 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -26,7 +26,6 @@ on: workflow_dispatch: permissions: read-all - actions: read concurrency: group: e2e-${{ github.ref }} diff --git a/.github/workflows/install-smoke.yml b/.github/workflows/install-smoke.yml index 14221e8..148e62e 100644 --- a/.github/workflows/install-smoke.yml +++ b/.github/workflows/install-smoke.yml @@ -23,7 +23,6 @@ on: workflow_dispatch: permissions: read-all - actions: read concurrency: group: install-smoke-${{ github.ref }} diff --git a/.github/workflows/zig.yml b/.github/workflows/zig.yml index 9ae2c47..0a65d9f 100644 --- a/.github/workflows/zig.yml +++ b/.github/workflows/zig.yml @@ -24,7 +24,6 @@ on: workflow_dispatch: permissions: read-all - actions: read concurrency: group: zig-${{ github.ref }} From fe01956705f982f546f9a3875450006394b6ba0d Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Mon, 27 Jul 2026 14:03:48 +0100 Subject: [PATCH 4/4] fix(ci): drop the unnecessary `actions: read` from pages.yml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The blanket sweep added `actions: read` to every workflow. pages.yml has no job that reads workflow or run metadata — it checks out, compiles Ddraig, uploads an artifact and deploys. The grant was unearned, so it goes. This also reverts pages.yml to exactly origin/main, which clears a SonarCloud Quality Gate failure ("C Security Rating on New Code"). Sonar's finding is real but PRE-EXISTING and not introduced here: pages.yml grants `pages: write` and `id-token: write` at WORKFLOW level, so the build job — which runs a compiler over checked-out sources — inherits deploy credentials it never uses. Those belong on the deploy job only. Deliberately NOT fixed in this PR. Pages deployed successfully for the first time since 2026-07-19 minutes ago (site now HTTP 200 after a long 404), and restructuring the permissions of a just-recovered deployment inside a PR whose `deploy` job cannot run is precisely the untestable change declined in #61. Filed as a follow-up instead. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/pages.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index e1f3dde..b14bddd 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -6,7 +6,6 @@ on: branches: [main, master] workflow_dispatch: permissions: - actions: read contents: read pages: write id-token: write