Skip to content

fix: pin SBOM sort collation and report a missing sha256sum by name - #1296

Merged
justinjoy merged 4 commits into
mainfrom
fix/1291-1292-release-tooling
Sep 2, 2026
Merged

fix: pin SBOM sort collation and report a missing sha256sum by name#1296
justinjoy merged 4 commits into
mainfrom
fix/1291-1292-release-tooling

Conversation

@justinjoy

Copy link
Copy Markdown
Collaborator

Two independent one-issue fixes, both found while writing #750's consumer
documentation. Closes #1291 and #1292.

fix(sbom): pin sort collation so the snapshot baseline is reproducible#1291

sbom/snapshot.txt is a committed artifact, but nothing pinned the collation of
the sort producing it. Under glibc's en_US collation, leading punctuation is
ignored, so the three ./.github/workflows/*.yml entries sort among the
alphabetic names instead of before them. Regenerating on a non-C-locale machine
produced three spurious reordering hunks alongside the real dependency change —
in a gate whose whole purpose is making dependency drift reviewable.

The gate itself was never locale-broken. check-sbom-snapshot.sh re-sorts
both sides in the same process, so its verdict is order-insensitive even fully
unpinned. The defect is confined to generate-sbom.sh, whose output is
committed. The pins on the gate are defence in depth — load-bearing for the new
test, never for detection.

scripts/ci/check-sbom-snapshot-locale.sh follows the shape #886 established
for this same bug class: a pin without a regression test is a pin somebody
deletes later. It is honest about being weaker than #886's, which stubs nm and
runs the real gate — generate-sbom.sh hardcodes its output to sbom/, so
running it here would clobber the baseline. #1293 tracks the
output-directory parameter that would allow the stronger form.

Two details worth flagging for review, both found by mutation testing:

  • The guard matches \bsort\b and drops whole-line comments afterwards. An
    ^[^#]* prefix cannot cross the '^#' literal in check-sbom-snapshot.sh's
    own comment-stripping line, and so skipped the very sort it was meant to check.
  • It requires LC_ALL=C specifically. An inherited LC_ALL overrides an
    LC_COLLATE prefix, so LC_COLLATE=C is silently ineffective on exactly the
    machines this fixes — verified, and it is a correctness requirement rather than
    a style rule.

Also pins ci-pr.yml's SBOM debug path, which printed an unpinned scan directly
beneath a C-ordered baseline: two windows that disagreed only on an off-locale
runner, and only while someone was reading them to diagnose a failure.

fix(release): report a missing sha256sum by name#1292

verify-release.sh guarded b3sum, cosign and gh but invoked sha256sum
bare, so a consumer without GNU coreutils hit sha256sum: command not found on
the first verification recipe. make-tarball.sh:16-17 already guards both, so
the verifier was the one place diverging from the repo's own pattern.

This is a diagnostics fix, not a correctness or portability one. The old
behaviour was never a false pass — set -euo pipefail aborted at exit 127 — and
a macOS consumer still cannot run the script afterwards; they get a named
prerequisite error instead of an internal-looking failure.

Testing

--suite sbom goes 1 → 2. The locale guard runs in 0.05s, needs no syft, and
skips cleanly without an en_US locale or jq. Between the three review gates,
twelve mutations were run against the final tree; all are caught, and the two
whole-line-comment cases correctly pass.

The sha256sum guard was verified with a stub PATH: sha256sum is required,
exit 1, before any digest — versus command not found, exit 127, previously.

Found while doing this, filed rather than folded in

sbom/snapshot.txt is a committed artifact, but nothing pinned the
collation of the sort that produces it. Under glibc's en_US collation
leading punctuation is ignored, so the three "./.github/workflows/*.yml"
entries sort among the alphabetic names rather than before them.
Regenerating the baseline on a machine with a non-C locale therefore
produced three spurious reordering hunks alongside the real dependency
change, in a gate whose entire purpose is making dependency drift
reviewable.

The gate itself was never locale-broken: check-sbom-snapshot.sh sorts
both the current list and the baseline in the same process, so its
verdict is order-insensitive even fully unpinned. The defect is confined
to generate-sbom.sh, whose output is committed. The pins added to
check-sbom-snapshot.sh are defence in depth -- load-bearing for the new
test, never for detection.

A pin without a regression test is a pin somebody deletes later, so this
follows the shape #886 established for the same bug class: a companion
check that skips cleanly without an en_US locale. It is weaker than
#886's, which stubs nm and runs the real gate; generate-sbom.sh hardcodes
its output to sbom/, so running it here would clobber the baseline. The
script says so rather than implying otherwise, and #1293 tracks the
output-directory parameter that would allow the stronger form.

The guard matches `\bsort\b` and drops whole-line comments afterwards
rather than with an `^[^#]*` prefix -- that prefix cannot cross the '^#'
literal in check-sbom-snapshot.sh's own comment-stripping line, and so
skipped the very sort it was meant to check. It requires LC_ALL=C
specifically: an inherited LC_ALL overrides an LC_COLLATE prefix, so
LC_COLLATE=C is silently ineffective on exactly the machines this fixes.

Also pins the SBOM gate's debug path in ci-pr.yml, which printed an
unpinned scan directly beneath a C-ordered baseline -- two windows that
disagreed only on an off-locale runner, and only while someone was
reading them to work out what drifted.

Two worse instances of this class, where an unpinned sort feeds a hash
compared against a pinned or committed value, are tracked in #1294.

Refs: #1291, #1293, #1294
verify-release.sh guarded b3sum, cosign and gh but invoked sha256sum
bare, so a consumer without GNU coreutils -- stock macOS, where the
equivalent is `shasum -a 256` -- hit `sha256sum: command not found` on
the first release-verification recipe with no indication what to
install. The producer side, make-tarball.sh, already guards both, so
the verifier was the one place diverging from the repository's own
pattern.

This is a diagnostics fix, not a correctness or portability one. The old
behaviour was never a false pass: `set -euo pipefail` aborted the
command substitution at exit 127. And a macOS consumer still cannot run
the script afterwards -- they get a named prerequisite error instead of
an internal-looking failure, and docs/SIGNING.md's prerequisites table
tells them what to install.

The guard sits after argument parsing and the archive-existence check,
so a missing archive is still reported as a missing archive rather than
a missing tool, and its message matches make-tarball.sh's byte for byte.

git and gzip remain unguarded on the --tag path, which cannot succeed
until #1154 establishes the maintainer key; they belong in that change.
verify-release.sh has no automated coverage at all -- it is the only
script in this repository third parties are told to run -- which is
tracked in #1295.

Refs: #1292, #1154, #1295
Both skip branches exited 0, so meson recorded the gate as passing on a
host without en_US or without jq -- asserting nothing while reporting
success.  Same defect as #1301, introduced in a gate written to fix a
different one, and caught by that issue's shared guard only when the two
branches were merged together.
Remove the hardcoded command -v gcc prerequisite check from scripts/release/run-downstream-matrix.sh. Meson handles toolchain and compiler discovery, allowing the downstream matrix contract self-tests to execute on Windows CI and environments utilizing alternative compilers.

Safely record gcc_version in host-metadata.txt with a non-fatal fallback.
@justinjoy
justinjoy merged commit 4f2b7f0 into main Sep 2, 2026
26 checks passed
@justinjoy
justinjoy deleted the fix/1291-1292-release-tooling branch September 2, 2026 12:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant