Keys, artifacts and releases¶
The test tiers, the lint gates and the doc-tests all run against your worktree or the branch. The three checks below cover what those cannot see: a stored key that moved, a file missing from the commit, and a docs site ahead of the release.
Key-builder output is gated (#644)¶
search_key, catalog_key and sort_key produce values a consumer stores
and compares later, so a change to them is a reindex event on somebody's
production data. docs/RUST_API.md states the contract — a patch release never
changes key-builder output; a minor release may — and
tests/test_key_stability.py holds it.
If it fails, read the diff before doing anything else. It prints a per-function count and a sample of what moved:
search_key: 267 of 22878 changed (1.17%)
'подъезд'
was 'podъezd'
now 'podezd'
Then decide. If the movement is intended:
python scripts/gen_key_fixture.py # rewrite the expected values
Commit the regenerated fixture in the same change, write it up in the release's Upgrade notes, and cut that release as a minor. Regenerating to make the test go green without reading the diff is the one use the script does not have.
Review does not substitute for this. 0.14.0 moved search_key on 4.1% of a
5,030-input corpus, and the change responsible (#602) was a correctness fix whose
diff said nothing about keys.
The corpus is not reproducible and its licence is not MIT; both are recorded in
tests/fixtures/key_stability/README.md.
Does the artifact work? (#667, #669)¶
Every step above tests your worktree. It contains untracked files, generated
artefacts, a populated target/ and whatever .gitignore hides — so a file
present locally and absent from the commit is invisible to all of it. And
maturin develop produces no distributable artifact at all, so nothing before a
push touches installability.
Two checks close that, sharing one body (scripts/smoke_installed.py):
# The tracked tree — exactly what someone fetching this commit receives.
tmp=$(mktemp -d) && git archive HEAD | tar -x -C "$tmp"
python -m venv "$tmp/venv" && "$tmp/venv/bin/pip" install "$tmp"
(cd "$tmp" && "$tmp/venv/bin/python" "$OLDPWD/scripts/smoke_installed.py")
# The sdist — the artifact CI does not cover either, until #667's job runs.
maturin sdist --out "$tmp/dist"
python -m venv "$tmp/sv" && "$tmp/sv/bin/pip" install --no-binary disarm "$tmp"/dist/*.tar.gz
(cd "$tmp" && "$tmp/sv/bin/python" "$OLDPWD/scripts/smoke_installed.py")
Run them from outside the checkout, as above. A source tree on sys.path
shadows the installed package and the check passes without testing an install —
the failure it exists to find. The script says so if it happens.
These cost a full compile each, which is too slow per commit and about right per
push. .github/workflows/smoke.yml runs both in CI: the tracked-tree job on
every push to main with no paths filter, since the point is that it runs on
every commit that lands.
The docs describe main; the reader executes a tag (#641)¶
Every gate above runs against the branch. The site deploys from main on each
push, but pip install disarm gives a reader the newest tag. At the worst
point those were 68 commits apart, and docs/security/cve-validation.md named
five entry points that raised AttributeError on the release it described.
Two things now cover that gap:
- A
mkdocshook stamps every page with the commit it was built from and the published version (scripts/mkdocs_build_banner.py). Nothing to do when writing docs; it is mentioned here so nobody deletes it as decoration. - A weekly job resolves every
disarmname the docs use against the newest published wheel. Run it yourself against any build:
python scripts/check_docs_against_release.py
A red run means documented API has outrun the last release — cut one, or correct the page. It is deliberately not a pull-request gate: documentation ships with the feature it documents, so during that window the gap is correct and a PR gate would block every feature branch.
Names it cannot fix are listed in _KNOWN_GAPS, each against an open issue.
An entry may only go in with an issue number, and the script fails if a listed
name starts resolving — so the list shrinks rather than accumulating.