From 75605903f10ecffa0b42bcb50ab8d5ff6fcec843 Mon Sep 17 00:00:00 2001 From: Ivan Vydrin Date: Thu, 6 Aug 2026 12:29:59 +0300 Subject: [PATCH] Attest and checksum what actually ships Verifying the published 0.1.0 release, rather than the build output, falsified both commands SECURITY.md tells an adopter to run. gh attestation verify on a downloaded release binary exits 1. The attestation named only the .nupkg files as subjects, so the three downloadable zips were never attested -- and those zips are what a person without the .NET SDK actually downloads. sha256sum -c SHA256SUMS.txt fails four of its seven entries. The file was generated across the whole build directory, so it listed the .nupkg and .snupkg files, which go to NuGet and are never attached to the release. Both now cover what ships: the zips are attestation subjects alongside the packages, and the checksum file is generated over the release assets only. The cause is worth recording because it is the same mistake this project keeps writing about. The verification instructions were checked -- against the rehearsal artifacts directory, which contains the packages. Both commands passed there and failed in reality. Testing in the wrong environment is indistinguishable from not testing, right up until someone follows the documentation. 0.1.0 is published and immutable, so SECURITY.md now says which release each command applies to and gives the form that does work today: sha256sum -c --ignore-missing SHA256SUMS.txt, confirmed against the real 0.1.0 assets, reports OK for all three binaries. --- .github/workflows/release.yml | 13 +++++++++++-- CHANGELOG.md | 18 ++++++++++++++++++ SECURITY.md | 17 +++++++++++++---- 3 files changed, 42 insertions(+), 6 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 043e2c6..f258cb8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -92,8 +92,12 @@ jobs: ( cd "publish/$rid" && zip -qr "../../artifacts/lakespeak-${{ steps.version.outputs.version }}-$rid.zip" . ) done + # Only over what actually reaches the release. Running this across the whole build directory + # put the .nupkg and .snupkg files in the list, and those go to NuGet rather than to the + # release - so `sha256sum -c SHA256SUMS.txt` failed on four of seven entries for anyone who + # downloaded the release and followed SECURITY.md. Shipped that way in 0.1.0. - name: Checksums - run: cd artifacts && sha256sum * > SHA256SUMS.txt && cat SHA256SUMS.txt + run: cd artifacts && sha256sum *.zip > SHA256SUMS.txt && cat SHA256SUMS.txt # An SBOM is the vendor list an adopter's SOC 2 vendor-risk review asks # for. Generated from the restored graph, not hand-maintained. @@ -103,10 +107,15 @@ jobs: export PATH="$PATH:$HOME/.dotnet/tools" dotnet CycloneDX LakeSpeak.slnx -o artifacts --json --filename sbom.json + # The zips are attested as well as the packages. Attesting only the .nupkg files left the + # three downloadable binaries unattested, so `gh attestation verify` on a downloaded release + # binary failed - which is precisely the command SECURITY.md tells an adopter to run. - uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4.1.1 id: attest with: - subject-path: 'artifacts/*.nupkg' + subject-path: | + artifacts/*.nupkg + artifacts/*.zip # The attestation is reachable through GitHub's Attestations API, but the bundle also has to # land on the release itself: tooling that verifies a downloaded artifact offline has no API diff --git a/CHANGELOG.md b/CHANGELOG.md index 5fa0e2a..a26d762 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,24 @@ Notable changes, newest first. This project follows [semantic versioning](https: the caveat that `0.x` minor versions may break the API — that is what `0.x` means, and it is stated here rather than left to be discovered. +## Unreleased + +### Fixed + +- **Release binaries are now attested.** The provenance attestation covered only the `.nupkg` + files, so `gh attestation verify` on a downloaded release binary failed — the exact command + `SECURITY.md` tells an adopter to run. The zips are now attestation subjects too. +- **`SHA256SUMS.txt` now lists only what is actually on the release.** It was generated across the + whole build directory, so it included the four `.nupkg`/`.snupkg` files that go to NuGet rather + than to the release; `sha256sum -c` therefore failed on four of seven entries for anyone who + downloaded 0.1.0. + + Both were found by verifying the published 0.1.0 release rather than the build output. The + verification instructions had been checked against a rehearsal artifacts directory, which + contains the packages — so both commands passed there and failed in reality. `SECURITY.md` now + states what applies to 0.1.0 and what changes from 0.1.1, including the + `sha256sum -c --ignore-missing` form that does work on 0.1.0. + ## 0.1.0 — 2026-08-06 Results come back whole, the documentation's own claims are under test, and the one image that was diff --git a/SECURITY.md b/SECURITY.md index c8a20b7..19a0291 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -94,13 +94,16 @@ Checking it takes one command and needs only the [GitHub CLI](https://cli.github.com): ```bash -gh attestation verify lakespeak-0.1.0-linux-x64.zip --repo ivanvyd/LakeSpeak.NET +gh attestation verify LakeSpeak.Cli.0.1.0.nupkg --repo ivanvyd/LakeSpeak.NET ``` -The same works on a package: +> **Applies from 0.1.1.** In `0.1.0` the attestation covers only the two `.nupkg` files, so running +> the same command against a downloaded release binary fails. That was a packaging mistake, not a +> tampered file: the binaries were built by the same workflow run, and their digests are in that +> release's `SHA256SUMS.txt`. From 0.1.1 the release binaries are attested too: ```bash -gh attestation verify LakeSpeak.Cli.0.1.0.nupkg --repo ivanvyd/LakeSpeak.NET +gh attestation verify lakespeak-0.1.1-linux-x64.zip --repo ivanvyd/LakeSpeak.NET ``` A passing check tells you the file was built by `.github/workflows/release.yml` in this @@ -116,12 +119,18 @@ started by someone holding only the GitHub account. You can check any release ta git -c gpg.ssh.allowedSignersFile=.github/allowed_signers verify-tag v0.1.0 ``` -To check the binaries against their published digests instead: +To check the binaries against their published digests instead, from the directory you downloaded +them into: ```bash sha256sum -c SHA256SUMS.txt ``` +> **Also applies from 0.1.1.** `0.1.0`'s `SHA256SUMS.txt` additionally lists the four `.nupkg` and +> `.snupkg` files, which are published to NuGet rather than attached to the release — so that +> command reports four missing files there. The three entries for the release binaries are correct +> and can be checked individually with `sha256sum -c --ignore-missing SHA256SUMS.txt`. + `sbom.json` on each release is a CycloneDX bill of materials, which is usually what a security review asks for before any of the above.