Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -215,9 +215,11 @@ jobs:
# first step in the flow that judges a published artifact, and it needs all
# three to exist.
#
# It gates nothing -- by the time it runs, every version number is spent. Its
# value is that it reports within minutes of the publish rather than whenever
# somebody next installs.
# It gates none of the publishes -- by the time it runs, every version number
# is spent. `alias` below is the one thing it does gate, and the comment there
# says why that is the right exception: moving a tag is reversible where a
# publish is not. Otherwise its value is that it reports within minutes of the
# publish rather than whenever somebody next installs.
smoke:
needs: [binaries, pypi, crates]
permissions:
Expand Down
20 changes: 13 additions & 7 deletions .github/workflows/smoke.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,18 @@ name: Smoke
# crates.io, downloads the released binaries, and runs the CLI tier against all
# three.
#
# It cannot gate anything, and is not built to. A version does not exist until
# It cannot gate a publish, and is not built to. A version does not exist until
# it is published and publication is irreversible, so any test of a registry
# necessarily runs after the only decision it could have informed. The remedy
# for a red run is to yank and publish again, and a yank hides a version from
# resolvers rather than removing it. Built for how quickly it reports, not for
# what it prevents.
#
# The release flow's `alias` job is the one caller that waits on this, and it is
# not a counter-example: moving `v0` is reversible and is a recommendation
# rather than an artifact, so a red run here leaving the alias on the previous
# release is the safe direction. Nothing irreversible is behind this workflow.
#
# Reusable so the release flow and the schedule run the same steps: a smoke
# procedure kept in two files is one that eventually tests two different things.
# The publishing jobs must not follow it here. A trusted publisher matches on
Expand Down Expand Up @@ -92,12 +97,13 @@ jobs:
echo "tag=${tag}" >>"${GITHUB_OUTPUT}"
echo "version=${version}" >>"${GITHUB_OUTPUT}"

# This ref, so the harness is the current one. `RUST_BINARY` and
# `REQUIRE_INSTALLED_PACKAGE` are what point the tier at an installed
# artifact, and a tag published before they existed carries a harness that
# ignores them: the first run of this workflow checked out `v0.0.1` and
# quietly tested the checkout instead. Full depth, because the next step
# needs a tag that a shallow fetch would not carry.
# This ref, so the harness is the current one. `RUST_BINARY`,
# `REQUIRE_RUST_BINARY` and `REQUIRE_INSTALLED_PACKAGE` are what point the
# tier at an installed artifact, and a tag published before they existed
# carries a harness that ignores them: the first run of this workflow
# checked out `v0.0.1` and quietly tested the checkout instead. Full
# depth, because the next step needs a tag that a shallow fetch would not
# carry.
- uses: actions/checkout@v7
with:
fetch-depth: 0
Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ One tool, two implementations, one specification. The reasoning behind the corpu

**Three invocation channels share the CLI and nothing else:** the four hook ids, the composite action in `action.yml`, and the two commands, one per implementation. The ids are not served from here — this repository carries no `.pre-commit-hooks.yaml`, and the two mirrors hold two ids each — so the `hook` job in CI generates them and resolves each id from the tree a consumer clones. A green test suite says nothing about whether a manifest resolves or the action runs, which is why CI carries `hook` and `action` jobs at all. It also explains why exclusion belongs to the tool — `.unwrapignore` and `--exclude` reach all three, while `pre-commit`'s own `exclude:` key reaches one.

**Nothing but `smoke.yml` tests what a registry serves.** Every other job builds the thing it tests, so a wheel missing a module, or a crate that will not compile from its own package, would publish green. That workflow installs from PyPI and from crates.io, checks the released binaries against `SHA256SUMS`, and runs the CLI tier against all three; the release flow calls it after every publish and a weekly schedule calls it again. It gates nothing, because by the time it runs the version number is spent. Its two footholds in the harness are `RUST_BINARY` and `REQUIRE_INSTALLED_PACKAGE`, and it takes the harness from the ref it runs on while taking the corpus from the tag — the switches may postdate a tag, and the specification a version was published against may not be replaced by a later one.
**Nothing but `smoke.yml` tests what a registry serves.** Every other job builds the thing it tests, so a wheel missing a module, or a crate that will not compile from its own package, would publish green. That workflow installs from PyPI and from crates.io, checks the released binaries against `SHA256SUMS`, and runs the CLI tier against all three; the release flow calls it after every publish and a weekly schedule calls it again. It gates none of the publishes, because by the time it runs the version number is spent; the release flow's `alias` job does wait on it, so a red run leaves `v0` on the previous release, which is the safe direction for a tag that is a recommendation rather than an artifact. Its three footholds in the harness are `RUST_BINARY`, `REQUIRE_RUST_BINARY` and `REQUIRE_INSTALLED_PACKAGE`, and it takes the harness from the ref it runs on while taking the corpus from the tag — the switches may postdate a tag, and the specification a version was published against may not be replaced by a later one.

**The fork-safe pair cannot be exercised from this repository.** `unwrap-propose.yml` and `unwrap-comment.yml` are reusable workflows a consumer calls, and the second is triggered by `workflow_run`, which fires only for a copy of the calling workflow already on a repository's default branch. No job here can reach it and no branch can either, so its verification is a live pull request in a throwaway repository wired to both halves. Two invariants hold the design up, and a change that breaks either is a security regression rather than a bug: the comment half checks out nothing and runs nothing from the pull request, and it refuses an artifact whose pull request number is not the one the producing run's own head repository, branch and commit belong to. Both are stated for a consumer in [SECURITY.md](SECURITY.md), so a change to either has to move that file with it. Everything underneath the pair -- the transform, the version resolution, the checksum -- is the action, which `action` in CI does cover.

Expand Down
Loading