From 9f8d3d3194e2e73f1b4ac4a72247028e44c3e869 Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Mon, 3 Aug 2026 13:41:23 +0100 Subject: [PATCH] fix(ci): replace `permissions: read-all` with the one scope these jobs need MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clears SonarCloud's four remaining MAJOR findings, and structurally eliminates the parse-kill that has now hit this repo twice. zig.yml e2e.yml container-build.yml install-smoke.yml permissions: read-all -> permissions: contents: read All four are read-only build/test workflows. They check out and build; nothing pushes, logs into a registry, or writes to the API — container-build.yml says so in its own header ("Build only — no push, no registry login"). `contents: read` is the whole requirement. e2e.yml's actions/upload-artifact needs no additional scope: since v4 it authenticates with the Actions runtime token, not the `permissions:` grant. WHY THIS IS MORE THAN A LINT FIX -------------------------------- These four were the only scalar `permissions:` blocks left in the repo, and the scalar form is precisely what let a text-matching sweep produce invalid YAML: permissions: read-all actions: read # mapping values are not allowed here Fixed in #64, reintroduced by #68, re-fixed in #69. In mapping form the same append is *valid* — a redundant no-op instead of a workflow-killer. Verified by replaying the actual sweep against the hardened tree: appending ` actions: read` after every `permissions:` line in all 18 workflows now leaves all 18 parsing. Before this change that same operation killed four of them. So the defence is now in two independent layers: - structural — no scalar block remains for the sweep to break here; - behavioural — .githooks/validate-workflow-yaml.sh (#69) still catches it if a scalar block is ever reintroduced, in this repo or by a template. The vulnerability Sonar flagged and the bug that broke CI had the same root cause, so one change closes both. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/container-build.yml | 7 ++++++- .github/workflows/e2e.yml | 7 ++++++- .github/workflows/install-smoke.yml | 7 ++++++- .github/workflows/zig.yml | 7 ++++++- 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/.github/workflows/container-build.yml b/.github/workflows/container-build.yml index ef425c0..fe70c51 100644 --- a/.github/workflows/container-build.yml +++ b/.github/workflows/container-build.yml @@ -29,7 +29,12 @@ on: - '.github/workflows/container-build.yml' workflow_dispatch: -permissions: read-all +# Explicit rather than `read-all`: every job here only checks out and builds. +# Naming the one scope it needs also removes the last scalar `permissions:` +# block, which is what let a text-matching sweep produce invalid YAML twice +# (fixed #64, reintroduced #68, re-fixed #69). +permissions: + contents: read concurrency: group: container-build-${{ github.ref }} diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 2c63785..621ca9d 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -25,7 +25,12 @@ on: branches: [main, master] workflow_dispatch: -permissions: read-all +# Explicit rather than `read-all`: every job here only checks out and builds. +# Naming the one scope it needs also removes the last scalar `permissions:` +# block, which is what let a text-matching sweep produce invalid YAML twice +# (fixed #64, reintroduced #68, re-fixed #69). +permissions: + contents: read concurrency: group: e2e-${{ github.ref }} diff --git a/.github/workflows/install-smoke.yml b/.github/workflows/install-smoke.yml index 8638a1d..f72f34b 100644 --- a/.github/workflows/install-smoke.yml +++ b/.github/workflows/install-smoke.yml @@ -22,7 +22,12 @@ on: branches: [main] workflow_dispatch: -permissions: read-all +# Explicit rather than `read-all`: every job here only checks out and builds. +# Naming the one scope it needs also removes the last scalar `permissions:` +# block, which is what let a text-matching sweep produce invalid YAML twice +# (fixed #64, reintroduced #68, re-fixed #69). +permissions: + contents: read concurrency: group: install-smoke-${{ github.ref }} diff --git a/.github/workflows/zig.yml b/.github/workflows/zig.yml index 0a65d9f..d59a357 100644 --- a/.github/workflows/zig.yml +++ b/.github/workflows/zig.yml @@ -23,7 +23,12 @@ on: - '.github/workflows/zig.yml' workflow_dispatch: -permissions: read-all +# Explicit rather than `read-all`: every job here only checks out and builds. +# Naming the one scope it needs also removes the last scalar `permissions:` +# block, which is what let a text-matching sweep produce invalid YAML twice +# (fixed #64, reintroduced #68, re-fixed #69). +permissions: + contents: read concurrency: group: zig-${{ github.ref }}