|
| 1 | +// SPDX-License-Identifier: CC-BY-SA-4.0 |
| 2 | +// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) |
| 3 | + |
| 4 | += Central Reusable actions/cache SHA Corruption — 2026-06-21 |
| 5 | +:toc: |
| 6 | +:toclevels: 2 |
| 7 | +:source-highlighter: rouge |
| 8 | +:icons: font |
| 9 | + |
| 10 | +Companion machine-readable manifest: `audit-hypatia-cache-sha-corruption-2026-06-21.a2ml`. |
| 11 | +Sibling to `audit-hypatia-pin-orphan-2026-05-27.adoc` — a *different* SHA-pin |
| 12 | +failure class on the same two reusables (that one was the orphaned |
| 13 | +`@<standards-sha>` reference to the reusable; this one is a corrupt |
| 14 | +third-party action SHA *inside* the reusable). |
| 15 | + |
| 16 | +== Summary |
| 17 | + |
| 18 | +From 2026-06-20/21 the estate-wide `scan / Hypatia Neurosymbolic Analysis` |
| 19 | +job failed at the *"Prepare all required actions"* stage — before any scan |
| 20 | +step ran — with: |
| 21 | + |
| 22 | +---- |
| 23 | +Unable to resolve action `actions/cache@d4373f267a887d77f9eb0683a479ec60b1fe5b2b` |
| 24 | +(unable to find version d4373f267a887d77f9eb0683a479ec60b1fe5b2b) |
| 25 | +---- |
| 26 | + |
| 27 | +The corrupt SHA was **not** present in any consumer workflow. It was pinned |
| 28 | +once, centrally, in the two reusable workflows that every estate repo calls: |
| 29 | + |
| 30 | +* `.github/workflows/hypatia-scan-reusable.yml` |
| 31 | +* `.github/workflows/governance-reusable.yml` |
| 32 | + |
| 33 | +Observed failing on `nextgen-databases#41`, `KnotTheory.jl#29`, |
| 34 | +`nextgen-typing#67` (and, per PR #394, `wokelangiser`). |
| 35 | + |
| 36 | +== Root cause |
| 37 | + |
| 38 | +`d4373f267a887d77f9eb0683a479ec60b1fe5b2b` does not correspond to any |
| 39 | +`actions/cache` ref. It is a corruption of v4.2.2's real commit |
| 40 | +`d4323d4df104b026a6aa633fdb11d772146be0bf` — the version comment read |
| 41 | +`# v4.2.0`, but the hash matched neither v4.2.0 nor v4.2.2. GitHub Actions |
| 42 | +resolves a `uses:` SHA as a commit; an unknown SHA fails the whole job at |
| 43 | +parse stage, so no consumer scan ever started. |
| 44 | + |
| 45 | +== Verification |
| 46 | + |
| 47 | +Upstream resolution via `git ls-remote https://github.com/actions/cache`: |
| 48 | + |
| 49 | +[cols="2,3,1", options="header"] |
| 50 | +|=== |
| 51 | +| SHA | Upstream ref | Resolves? |
| 52 | + |
| 53 | +| `d4373f26…` (the corrupt pin) | (none) | ✗ bogus |
| 54 | +| `d4323d4d…` (v4.2.2 — the likely typo source) | `refs/tags/v4.2.2` | ✓ |
| 55 | +| `1bd1e32a…` (the repair pin) | `refs/tags/v4.2.0` | ✓ |
| 56 | +| `0057852b…` (estate "most common") | `refs/tags/v4` + `v4.3.0` | ✓ |
| 57 | +| `27d5ce7f…` (estate, used across hypatia) | `main` + `v5` + `v5.0.5` | ✓ |
| 58 | +|=== |
| 59 | + |
| 60 | +`git grep d4373f267a887d77f9eb0683a479ec60b1fe5b2b` across standards and |
| 61 | +hypatia → zero matches after the fix. |
| 62 | + |
| 63 | +== Fix — standards#394 (merged 2026-06-21T10:52Z, commit `d72fe5a`) |
| 64 | + |
| 65 | +Both reusables re-pinned, preserving the documented version: |
| 66 | + |
| 67 | +[source,diff] |
| 68 | +---- |
| 69 | +- uses: actions/cache@d4373f267a887d77f9eb0683a479ec60b1fe5b2b # v4.2.0 |
| 70 | ++ uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 |
| 71 | +---- |
| 72 | + |
| 73 | +`1bd1e32a…` is the genuine immutable `v4.2.0` commit, so the `# v4.2.0` |
| 74 | +comment is now accurate. This is a surgical hash repair, not a version bump |
| 75 | +to the moving `v4` tag. |
| 76 | + |
| 77 | +== Propagation caveat — necessary but not yet sufficient |
| 78 | + |
| 79 | +Consumers do **not** pin these reusables to `@main`. They pin a specific |
| 80 | +`standards` commit SHA, e.g.: |
| 81 | + |
| 82 | +---- |
| 83 | +uses: hyperpolymath/standards/.github/workflows/hypatia-scan-reusable.yml@5eb28d7d… (hypatia itself) |
| 84 | +uses: hyperpolymath/standards/.github/workflows/governance-reusable.yml@861b5e91… (most consumers) |
| 85 | +---- |
| 86 | + |
| 87 | +Because the repair landed as a *new* `standards` HEAD (`d72fe5a`), every |
| 88 | +consumer still pinned at a pre-#394 SHA keeps dereferencing the broken cache |
| 89 | +pin until it is re-enrolled to a post-#394 SHA. This is exactly what |
| 90 | +`scripts/check-workflow-staleness.sh` reports — it fails any consumer whose |
| 91 | +pinned SHA != current standards HEAD ("Workflow pins Hypatia reusable before |
| 92 | +cache/baseline-delay fix. Refresh to current standards SHA."). |
| 93 | + |
| 94 | +Therefore the post-#394 `governance / Check Workflow Staleness` red is |
| 95 | +**expected drift**, not a new defect: it is the signal that the estate |
| 96 | +re-enrollment pass (gitbot-fleet `enroll-repos`, repinning consumers to |
| 97 | +`d72fe5a` or later) is still pending. Re-enrollment is the propagation |
| 98 | +mechanism; until it runs, an affected consumer sees both the cache failure |
| 99 | +(if its pinned SHA predates #394) and the staleness failure. |
| 100 | + |
| 101 | +== Companion findings — out of scope (central), recorded for the backlog |
| 102 | + |
| 103 | +These surfaced on `nextgen-databases` alongside the central failure. They are |
| 104 | +**repo-internal**, pre-existing, and not addressed by #394: |
| 105 | + |
| 106 | +. *K9 pedigree validation.* `verisimdb/connectors/test-infra/deploy.k9.ncl` |
| 107 | + fails "Pedigree block missing 'name'". In `k9-svc/pedigree.ncl`, |
| 108 | + `Metadata.name | String` is the only metadata field with no `default`, so |
| 109 | + it is mandatory. Fix: add `metadata.name`; per the canonical |
| 110 | + `k9-svc/pandoc/container/deploy.k9.ncl` sample, ideally also |
| 111 | + `metadata.version` + `validation.pedigree_version` and a leash level — |
| 112 | + `trust_level`/`security_level` ∈ `'Kennel | 'Yard | 'Hunt` (a |
| 113 | + shell-running `deploy.k9.ncl` is `'Hunt`). |
| 114 | +. *Trusted-base reduction policy.* The `governance / trusted-base` job (per |
| 115 | + `docs/TRUSTED-BASE-REDUCTION-POLICY.adoc` + `scripts/check-trusted-base.sh`) |
| 116 | + is red: a soundness-relevant escape hatch in a proof-bearing file in |
| 117 | + `nextgen-databases` is undocumented. Disposition is per-repo — discharge, |
| 118 | + budget (`// TRUSTED:`), axiom (`// AXIOM:`), or a dated debt entry in that |
| 119 | + repo's `docs/proof-debt.md`. |
| 120 | + |
| 121 | +== What this audit does NOT discharge |
| 122 | + |
| 123 | +* The consumer re-enrollment pass (gitbot-fleet `enroll-repos` → repin |
| 124 | + consumers to `d72fe5a`+). Out of scope for standards + hypatia; tracked on |
| 125 | + hypatia#464. |
| 126 | +* The two `nextgen-databases` repo-internal findings above. Out of scope |
| 127 | + (that repo); flagged for its maintainers via hypatia#464 / nextgen-typing#69. |
| 128 | + |
| 129 | +== Cross-references |
| 130 | + |
| 131 | +* Fix PR: `hyperpolymath/standards#394` (merged 2026-06-21). |
| 132 | +* Estate CI-health umbrella: `hyperpolymath/hypatia#464`. |
| 133 | +* "Out of scope — central" list: `hyperpolymath/nextgen-typing#69`. |
| 134 | +* Sibling SHA-pin audit: `audit-hypatia-pin-orphan-2026-05-27.adoc`. |
0 commit comments