Skip to content

ci(release): decide extras by dependence, sign the SBOM, correct the pin comment - #10

Merged
livingstaccato merged 2 commits into
mainfrom
fix/sbom-marker-extras
Aug 28, 2026
Merged

ci(release): decide extras by dependence, sign the SBOM, correct the pin comment#10
livingstaccato merged 2 commits into
mainfrom
fix/sbom-marker-extras

Conversation

@livingstaccato

@livingstaccato livingstaccato commented Aug 27, 2026

Copy link
Copy Markdown
Member

Follow-up to the release-pipeline repair, from a review of it. Five defects, each verified before anything changed.

Pin comment. The bump replaced the 40-character SHA and left the trailing # v3.0.0, three lines under a new comment block asserting "Pinned at v3.5.0 deliberately." Confirmed against the upstream tags API — 790bc6be is v3.5.0, f514d46b is v3.0.0 — so the file contradicted itself. A pin normalizer that trusts the comment rewrites the SHA back and silently reinstates the root was signed by 0/3 keys abort the bump exists to avoid.

Extras. An empty extra makes extra == "cli" false, but it makes extra in "cli" true, because "" is a substring of every string:

baz; extra == "cli"   evaluate({"extra": ""}) -> False
baz; extra in  "cli"  evaluate({"extra": ""}) -> True

An extra-gated dependency written that way is demanded, is correctly absent, and aborts the release blaming the venv — the exact false-positive class the previous fix set out to remove. Extras are now decided by whether the marker's answer depends on extra at all, which holds for every operator rather than for == alone.

Marker exceptions. Requirement(spec) was guarded; .evaluate() was not. packaging raises UndefinedComparison and UndefinedEnvironmentName at evaluate time, not parse time:

a; sys_platform ~= "1.0"  -> parses, then UndefinedComparison

That aborted with a bare traceback instead of the ::error:: annotation every other failure path here emits. Both are now caught and routed through fail().

Venv mutation. packaging was installed into the very venv the SBOM describes, after the document was written, on the argument that the ordering made it safe. Ordering keeps packaging out of the document; it does not keep the document true. Where packaging is already in the closure — verified in four of these repositories — the install silently replaces a version the document has just recorded, and a project capping packaging<26 would get that replacement with every check still green. It is now overlaid with uv run --with, which leaves the venv byte-identical while the check still sees its site-packages.

SBOM signature. The document was attached to the release but never passed to the signing step, so the one artifact these checks exist to make trustworthy shipped unauthenticated beside two signed distributions. Added to inputs on the release path only — the repair path fetches from PyPI and has no SBOM, and a glob matching nothing is fatal to that action.

Verified by building a wheel and running the script end to end in this repository: 66 dependencies, correct root purl, and the venv left byte-identical by the overlay.

…pin comment

Follow-up to the release-pipeline repair, from a review of it. Four defects,
each verified before changing anything.

Pin comment: the bump replaced the 40-character SHA and left the trailing
`# v3.0.0` sitting three lines below a new comment block asserting "Pinned at
v3.5.0 deliberately". Confirmed against the upstream tags API -- 790bc6be is
v3.5.0, f514d46b is v3.0.0 -- so the file contradicted itself. A pin
normalizer that trusts the comment rewrites the SHA back to v3.0.0 and
silently reinstates the TUF abort the bump exists to avoid.

Extras: an empty `extra` makes `extra == "cli"` false, but it makes
`extra in "cli"` *true*, because "" is a substring of every string. An
extra-gated dependency written that way would be demanded, be correctly
absent, and abort the release blaming the venv -- exactly the false-positive
class this check was fixed to remove. Extras are now decided by whether the
marker's answer depends on `extra` at all, which holds for every operator
rather than for `==` alone.

Marker exceptions: `Requirement(spec)` was guarded but `.evaluate()` was not,
and packaging raises UndefinedComparison and UndefinedEnvironmentName at
evaluate time rather than parse time. `a; sys_platform ~= "1.0"` parses
cleanly and then raises, aborting with a bare traceback instead of the
`::error::` annotation every other failure path here deliberately emits. Both
are now caught and routed through fail().

SBOM signature: the document was attached to the release but never passed to
the signing step, so the one artifact these checks exist to make trustworthy
shipped unauthenticated beside two signed distributions. It is added to
`inputs` on the release path only -- the repair path fetches from PyPI and has
no SBOM, and a glob matching nothing is fatal to that action.

Verified by building a wheel and running the script end to end: 18 components,
correct root purl, and `packaging` still absent from the document, so the
install-after-generation order still holds.
…ribed venv

The previous commit installed packaging into the very venv the SBOM describes,
after the document was written, on the argument that the ordering made it safe.
Ordering keeps packaging out of the document; it does not keep the document
true. Where packaging is already in the dependency closure -- verified in four
of these repositories -- the install silently replaces the version the document
has just recorded, and a project capping `packaging<26` would receive that
replacement with every check still green.

`uv run --with` layers the dependency onto the interpreter for the single call
that needs it. Verified: the check still sees the venv's own site-packages, and
the venv is byte-identical afterwards.
@livingstaccato
livingstaccato merged commit bfaec2e into main Aug 28, 2026
11 checks passed
@livingstaccato
livingstaccato deleted the fix/sbom-marker-extras branch August 28, 2026 04:41
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