Releases are built only from signed annotated vX.Y.Z tags.
Every release validates the checked-in evidence manifest structure:
python3 scripts/verify_v1_evidence.py \
.github/v1-evidence.json --check-structureFor every v1 or later release, update the manifest with public, reviewable evidence for the exact target version and run:
python3 scripts/verify_v1_evidence.py \
.github/v1-evidence.json \
--require-ready \
--release-version 1.0.0The verifier derives readiness from the evidence. Do not add a bypass, count
maintainer activity as adoption, suppress a failed gate, or move evidence dates
forward. The continuous window must end on as_of and include one public
successful-run URL for every required track on every date. DMLPact accepts only
the two-maintainer continuity mode required by its roadmap.
-
Confirm the version in
Cargo.tomland heading inCHANGELOG.mdmatch. -
Run all local checks from CONTRIBUTING.md, plus the live PostgreSQL fixture.
-
Merge through the protected
mainbranch and confirm every required check. -
Create and push a signed annotated tag:
git tag -s v0.3.0 -m "DMLPact v0.3.0" git push origin v0.3.0 -
The release workflow validates the tag signature, builds native archives, creates a CycloneDX SBOM and SHA-256 checksums, attaches attestations, and creates the GitHub release. Each archive includes a downloadable
.intoto.jsonlprovenance bundle for local verification. -
Independently download the release and verify checksums and attestations:
sha256sum --check SHA256SUMS gh attestation verify dmlpact-v0.3.0-linux-x86_64.tar.gz \ --repo yhay81/dmlpact gh attestation verify dmlpact-v0.3.0-linux-x86_64.tar.gz \ --repo yhay81/dmlpact \ --bundle dmlpact-v0.3.0-linux-x86_64.tar.gz.intoto.jsonl \ --signer-workflow yhay81/dmlpact/.github/workflows/release.yml gh attestation verify dmlpact-v0.3.0-linux-x86_64.tar.gz \ --repo yhay81/dmlpact \ --predicate-type https://cyclonedx.org/bom
-
Inspect archive contents and run
--version,capabilities,lint, and a disposable PostgreSQL plan/apply/receipt lifecycle.
The first crates.io release must be published manually because Trusted
Publishing can only be configured after the crate exists. From the exact signed
release commit, run cargo publish --dry-run --locked, review
cargo package --list --locked, then publish:
cargo publish --lockedUse a Cargo credential provider backed by the operating-system credential store. Never put a crates.io token in Git, workflow YAML, logs, or a repository-level Actions secret. If Cargo times out after upload, check the crates.io page and index before retrying; an accepted version is immutable.
After the first manual release:
- Add the crate's Trusted Publisher in crates.io, restricted to
yhay81/dmlpact, the dedicated publish workflow filename, and the protectedcrates-ioGitHub environment. - Add that workflow only after the mapping exists. Grant only
contents: readandid-token: write, pin every action to an immutable commit, exchange OIDC withrust-lang/crates-io-auth-action, and runcargo publish --locked. - Remove any temporary API token, verify registry ownership and account recovery without recording secrets, and require environment approval for every publish.
- Install the exact version from crates.io in a clean environment and repeat the PostgreSQL CLI smoke checks.
Never reuse or move a release tag. Publish a new patch release for corrections.