This repository publishes yaml-sigil-traits as a crates.io .crate source
package. Official publications also create a version tag and a source-only
GitHub Release from the reviewed changelog. Release-plz has source-crate
publication authority only. After exact registry confirmation, a protected
GitHub App finalizer creates the annotated tag and immutable, zero-asset
Release. No release step builds or attaches binary assets. The workflow retains
no build artifacts or separately generated archives. GitHub's automatic source
archives are expected.
Cargo disables implicit binary targets, and release validation rejects an explicit binary target. Do not distribute compiled executables from this repository.
The Release proposal workflow owns the release-plz-next branch and opens or
updates its pull request against main. Release-plz analyzes Conventional
Commits and generates changelog content. The repository xtask applies the RC
policy described below. A least-privilege GitHub App creates the commit through
GitHub, so GitHub reports the commit as Verified. The commit also includes a
DCO trailer for the App bot identity.
Do not add human commits to release-plz-next. The workflow refuses to replace
the branch if it contains a commit by another identity. Review and merge the
release pull request through the normal protected-branch path. Its exact head
must pass Required CI, including all three Rust platform jobs. Merging that
pull request is the authorization signal for release-plz because
.release-plz.toml sets release_always = false and the branch uses the
release-plz- prefix.
Preserve a release pull request's individual commits when review finds them
coherent, correctly scoped, and useful to retain on main. Every retained
commit must carry its own cryptographic signature and DCO sign-off and leave
the repository in a coherent state. If the submitted sequence is noisy,
partial, or not independently meaningful, curate or squash it on the
contributor branch and re-sign the result before requesting final
authorization. Do not make the integrating repository writer repair avoidable
history problems at merge time.
Do not use GitHub's Rebase and merge option. It rewrites reviewed commits on the server and cannot preserve their signatures. Squash and merge also replaces the reviewed commits. Use it when review concludes that the submitted commit sequence is not worth retaining as-is, not as the default for coherent history. This repository disables server-side rebase merging.
Bring a human-owned branch up to date before final CI with
git rebase --gpg-sign origin/main and the approved SSH signing key. Push
rewritten history only with --force-with-lease, then request Required CI
for the new exact head SHA. Do not rewrite release-plz-next; have the
Release proposal workflow refresh that App-owned branch instead. Every
rewritten head invalidates the earlier authorization and check.
After the exact head is current, GitHub Verified, DCO-compliant, and green
under Required CI, a repository writer re-fetches origin and integrates
that immutable commit with a normal fast-forward push:
git fetch origin
expected_main="$(git rev-parse origin/main)"
expected_head="<exact-40-character-PR-head-SHA>"
git merge-base --is-ancestor "${expected_main}" "${expected_head}"
git push origin "${expected_head}:refs/heads/main"Re-check the pull request's base, head, and Required CI binding immediately
before the push. A concurrent main update makes the normal push fail closed;
rebase and re-sign the human-owned branch, or refresh the App-owned proposal,
then rerun exact-head CI. Never force-push main.
When enabled, the workflow remains a successful no-op while the GitHub App
configuration is absent. It also waits without advancing the train until the
version on main is available and non-yanked on crates.io.
The manually bounded release-pr.yml entrypoint accepts pushes to main and
writer dispatches. It calls release-proposal.yml, which is call-only and has
no public event entrypoint. After a complete official publication, the enabled
publish.yml receiver authenticates the closed, versioned
official-release-published payload before calling that same reusable
workflow. The dispatch name is unchanged; its payload is an internal
sender/receiver contract, not a public external trigger contract.
A trusted background entrypoint may create one default patch proposal when
no exact App-owned proposal exists. Once that proposal exists, background
events leave it untouched. A repository writer must dispatch Release proposal with an explicit patch, minor, or major selection to revise the
proposal. The workflow uses that dispatch input directly and does not store
release intent in pull-request text.
Proposal mutation, release intent, finalization, and notification enter
protected-automation only when they need the narrowly scoped App credential.
Official source-crate publication enters crates-io, whose configured approval
gates the OIDC-enabled publication job. Validation and readiness enter neither
environment and receive no OIDC permission.
Keep the event entrypoints release-pr.yml and publish.yml manually disabled
between bounded release operations. The reusable release-proposal.yml remains
enabled but is call-only. Check all three actual GitHub states, including
disabled workflows, with:
gh workflow list --repo NVIDIA/yaml-sigil-traits --allEnable only the workflow needed for the current operation. To create or revise
the next RC proposal from exact current main, keep publish.yml disabled and
run:
gh workflow enable release-pr.yml --repo NVIDIA/yaml-sigil-traits
gh workflow run release-pr.yml --repo NVIDIA/yaml-sigil-traits \
--ref main -f mode=next-candidate -f bump=patchReplace patch only with the reviewed minor or major intent. Stable
promotion uses mode=promote-stable and bump=patch. Wait for the selected
run to close, then disable the proposal workflow immediately:
gh workflow disable release-pr.yml --repo NVIDIA/yaml-sigil-traitsDo not rely on a push that occurred while release-pr.yml was disabled; use a
fresh explicit dispatch after enabling it. Do not enable proposal and
publication entrypoints at the same time. The later validation and publication
procedures enable only publish.yml. A successful publication keeps
publish.yml enabled until its authenticated receiver run completes; that
receiver may call the reusable proposal workflow while release-pr.yml remains
disabled.
Every proposal resolves its comparison baseline from the last official
annotated v<version> tag. The workflow confirms that the tag matches origin,
is an ancestor of current remote main, and identifies the exact non-yanked
version on crates.io. Registry prereleases that have no official tag never
become release-analysis baselines.
Important
This fallback changes proposal authorship only. It does not authorize local publication, a crates.io token, a protected-environment bypass, or binary artifacts. Official publication still uses the protected Trusted Publishing workflow.
Use this procedure when the App is unavailable or cannot safely update its
owned proposal. A repository writer may prepare the same release transaction
on a human-authored branch. Use Rust 1.95.0, cargo-binstall 1.20.1,
release-plz 0.3.160, and cargo-semver-checks 0.49.0. Create a
same-repository branch named
release-plz-manual-<target> from exact current main; do not reuse the
workflow-owned release-plz-next branch.
Before creating the manual branch, inspect any existing release-plz-next
proposal. Do not append a human commit to it or replace its App-owned head.
Finish or close that proposal and verify current main and crates.io state, or
leave it intact while using the distinctly named manual branch. Do not run the
two proposal paths concurrently.
Before either proposal mode, fetch current main and tags, verify the analyzer versions, and prepare the detached official baseline:
export RUSTUP_TOOLCHAIN=1.95.0
fetch_url="https://github.com/NVIDIA/yaml-sigil-traits"
test "$(git remote get-url origin)" = "${fetch_url}"
git fetch origin main --tags
test "$(git rev-parse HEAD)" = "$(git rev-parse origin/main)"
rustc_version="$(rustc --version)"
test "${rustc_version%% (*}" = "rustc 1.95.0"
test "$(cargo-binstall -V)" = "1.20.1"
cargo xtask release install-tools
published_version="$(cargo xtask release-version show)"
cargo xtask release verify-registry \
--check-version "${published_version}" yaml-sigil-traits
baseline_parent="$(mktemp -d)"
baseline_root="${baseline_parent}/official-release"
inventory_path="${baseline_parent}/official-tags.json"
baseline_result="${baseline_parent}/baseline-result.json"
GIT_CONFIG_COUNT=1 \
GIT_CONFIG_KEY_0=remote.origin.pushurl \
GIT_CONFIG_VALUE_0=disabled://yaml-sigil-release-proposal \
cargo xtask release baseline prepare \
--version "${published_version}" \
--head "$(git rev-parse HEAD)" \
--output "${baseline_root}" \
--result "${baseline_result}" \
--inventory-output "${inventory_path}" \
--expected-fetch-url "${fetch_url}"
registry_manifest_path="$(jq --exit-status --raw-output \
'.manifest' "${baseline_result}")"
test "$(jq --exit-status --raw-output '.inventory' "${baseline_result}")" = \
"${inventory_path}"Stop if current main, the registry record, tag type, tag target, ancestry, or remote ref differs. For the next substantive RC proposal, set the reviewed intent and run:
release_date="$(date -u +%F)"
bump="patch"
# Generate the Conventional Commit changelog and preliminary version change.
GIT_CONFIG_COUNT=1 \
GIT_CONFIG_KEY_0=remote.origin.pushurl \
GIT_CONFIG_VALUE_0=disabled://yaml-sigil-release-proposal \
release-plz update \
--config .release-plz.toml \
--registry-manifest-path "${registry_manifest_path}"
git diff --name-only -- CHANGELOG.mdThe command must list CHANGELOG.md as changed. If it does not, stop before
advancing the version: a manual proposal must not create an empty seed. Once
the expected changelog change is present, complete the candidate transaction:
target="$(cargo xtask release-version candidate \
--published "${published_version}" \
--bump "${bump}" \
--date "${release_date}" \
--release-notes)"Set bump explicitly to the reviewed patch, minor, or major version-line
advance. A patch advances the current RC on the same core, or starts the next
patch RC after a stable release. Never infer the baseline from a higher
registry prerelease.
For stable promotion, use the same baseline preparation and require its commit
to equal exact current main. Then create the manual branch and run:
release_date="$(date -u +%F)"
bump="patch"
test "$(git rev-parse "v${published_version}^{commit}")" = "$(git rev-parse HEAD)"
target="$(cargo xtask release-version promote-stable --date "${release_date}")"For either path, review the generated transaction and run:
cargo xtask release-version check
cargo xtask release-version check-compatibility \
--baseline-manifest "${registry_manifest_path}" \
--current-manifest Cargo.toml \
--package yaml-sigil-traits \
--expected-baseline-version "${published_version}" \
--expected-current-version "${target}" \
--intent "${bump}"
cargo xtask ci
cargo xtask release check-packages yaml-sigil-traits
git diff --check
git status --short
GIT_CONFIG_COUNT=1 \
GIT_CONFIG_KEY_0=remote.origin.pushurl \
GIT_CONFIG_VALUE_0=disabled://yaml-sigil-release-proposal \
cargo xtask release baseline verify \
--head "$(git rev-parse HEAD)" \
--inventory "${inventory_path}" \
--expected-fetch-url "${fetch_url}"The direct compatibility check converts the selected bump into Cargo's
pre-1.0 release type and treats every analyzer error as a failure.
Release-plz's built-in semver check is disabled so it cannot reinterpret that
result. The complete diff must contain only the intended Cargo.toml and
CHANGELOG.md changes. cargo xtask release check-packages applies the exact
Cargo metadata and library-only package gate. The related
verify-registry command preserves exit status 3 for an exact missing
version and treats yanked, malformed, or failed registry responses as errors.
Do not commit a generated Cargo.lock or package archive. Commit the complete
transaction with an SSH signature and DCO sign-off. Validate the clean exact
commit before pushing it:
cargo package
git status --shortPush the branch and open its pull request against main. The pull request
association is required for a useful release-plz dry run because
release_always = false authorizes only commits from a release-plz-* branch.
After the pull request exists, run:
# Supply the existing gh credential only for read-only forge discovery.
GIT_TOKEN="$(gh auth token)" \
release-plz release --dry-run --config .release-plz.toml
git status --shortThe process-scoped GIT_TOKEN must not be echoed, pasted, or persisted. Verify
that the dry run plans the expected crate and does not report that the current
commit is not from a release pull request. It must not publish or create tags
or GitHub Releases.
If either release-plz-next or the selected manual branch already exists,
inspect its owner, exact ref, open pull request, and commits before proceeding.
Never overwrite a foreign or unexpected branch. Resolve the collision by
finishing, closing, or deliberately renaming the human branch, then rerun all
main, tag, registry, and baseline checks. Updates to the App-owned branch use
an exact-old-SHA force-with-lease; a concurrent ref change stops the update.
Review and integrate the exact head through the ordinary protected path only
after Required CI and all three Rust platform jobs pass. If a repair is
needed, amend the signed commit while retaining one DCO trailer, force-push
with lease, and repeat the clean-commit and dry-run checks. Merging that
release-plz-* pull request is the authorization signal for the protected
official publication workflow. Do not run a local non-dry-run release command.
After the manual proposal is integrated or closed, delete only its manual
branch, confirm the exact current main and crates.io state, and dispatch a
fresh Release proposal run. Let the workflow recreate or update its own
branch from that state. Do not copy the human-authored commit onto
release-plz-next.
The default release progression is:
- a published stable
MAJOR.MINOR.PATCHstarts the next patch train asMAJOR.MINOR.(PATCH+1)-rc.1; - a published
MAJOR.MINOR.PATCH-rc.Nadvances toMAJOR.MINOR.PATCH-rc.(N+1); and - a trusted push or authenticated post-publication notification creates a default patch proposal only when the App-owned proposal does not already exist.
An empty next-version seed remains a draft pull request. A proposal with release notes is marked ready for review.
For every major, minor, or patch advance, a repository writer can
dispatch Release proposal with mode next-candidate and the intended bump.
That manual dispatch may create the proposal or replace its App-owned commit.
Later pushes and post-publication notifications do not revise an existing
proposal; another explicit writer dispatch is required to incorporate later
changes or select a different release line.
The manifest and changelog changes for an RC or stable release must be part of the release pull request. Official publication rejects a dirty source tree.
Stable promotion is an explicit review operation. First publish and verify the
RC from main. Its vMAJOR.MINOR.PATCH-rc.N tag must resolve to the exact
current main commit. Then a repository writer must manually dispatch
Release proposal with mode promote-stable. Background events cannot select
stable promotion. The workflow deterministically uses patch compatibility
intent, creates a pull request that removes the prerelease component, and
copies the reviewed RC changelog section to the stable version.
Review and merge that exact proposal before publishing the stable version. Do
not edit a contributor branch to remove rc.N, and do not promote source that
differs from the tagged RC.
Before validation or publication, confirm:
mainis the exact merged head of the intendedrelease-plz-*pull request;- the head is GitHub Verified, DCO-compliant, and green under required and platform CI;
- the crates.io Trusted Publisher matches
.github/workflows/publish.ymland thecrates-ioenvironment; - the
crates-ioenvironment requires its configured approval and has no long-lived registry token; and - repository administrators have reviewed the exact proposed release-tag creation and update/deletion rulesets and prospective immutable-Release setting, without changing them as part of workflow validation;
.github/legacy-release-inventory.jsonstill pins all four historical, mutable, zero-asset source-only Releases; and- the version, tag, and GitHub Release do not already exist, except when deliberately recovering a partial run.
Run validation from main:
gh workflow enable publish.yml --repo NVIDIA/yaml-sigil-traits
gh workflow run publish.yml --repo NVIDIA/yaml-sigil-traits \
--ref main -f operation=validateValidation compares the candidate with the detached last official tagged
source using cargo-semver-checks before it runs ordinary cargo package and a
release-plz dry run. It has no OIDC permission, uploads nothing, and does not
enter the publication environment. The readiness job also verifies the pinned
legacy Release inventory and prints a digest binding the captured release SHA,
run ID, run attempt, and required repository settings. It does not read or
change administrator-only settings.
If validation fails or publication will not begin immediately, disable
publish.yml before investigating. When an authorized publication follows the
successful validation immediately, leave it active only through that one
publication run.
Dispatch publication from main:
gh workflow run publish.yml --repo NVIDIA/yaml-sigil-traits \
--ref main -f operation=publishThe validation job runs first. The publication job starts only after
validation succeeds and the crates-io environment is approved. Only that job
receives id-token: write; it retains contents: read and
pull-requests: read. Release-plz exchanges the job identity for a short-lived
crates.io credential and publishes only the source package. It cannot create a
tag or GitHub Release.
Before approving the pending deployment, a repository administrator must run
the tracked read-only preflight from the exact current main checkout with the
four values displayed by the selected readiness run:
GH_TOKEN="$(gh auth token)" \
python3 .github/scripts/release_settings_preflight.py \
--repository NVIDIA/yaml-sigil-traits \
--release-sha <release-sha> \
--run-id <run-id> \
--run-attempt <run-attempt> \
--expected-evidence-sha256 <readiness-digest>The preflight must report repository_admin_settings=valid, reproduce the
workflow evidence digest, and bind its readback to the active exact-SHA run. It
verifies immutable Releases, the exact main and release-tag rulesets, the
Release App bypass, and absence of a required-check name collision. It performs
no mutation. Approve the crates-io deployment before the printed
approve_before_utc deadline, at most five minutes after the readback. Any run,
attempt, head, workflow, setting, or deadline change requires a fresh readback.
Approve only the pending crates-io deployment on the selected exact-SHA run.
Use gh run view <run-id> --web to open it, confirm the readiness job passed,
the run still identifies current main, and the fresh administrator readback
remains inside its deadline, then record the environment approval. An earlier
authorization or a deployment for another run is not a substitute for this
per-run gate.
Both validation and publication independently require exact current main to
be the merge result of one reviewed App proposal or the documented signed
same-repository manual fallback. Stable promotion additionally requires that
proposal's base and the release commit's sole parent be the exact tagged RC
commit, so intervening source cannot enter the stable release. Immediately
before publication, the workflow rechecks the complete official-tag inventory
and remote main. Its ephemeral release-plz configuration differs from the
reviewed configuration only by authorizing the already-checked checkout and
using a Git-invalid pull-request branch prefix, so release-plz cannot select or
check out another commit.
For the manual fallback, source authorization rechecks both the merger's and
proposal owner's current repository write permission after its final main
and pull-request reread.
The publication invocation deliberately omits release-plz's --dry-run CLI
flag. After exact registry confirmation, separate App-authenticated jobs attest
the release intent, create the annotated tag and immutable zero-asset Release,
and emit the authenticated internal notification. These jobs receive no OIDC
credential; the finalizer's App token has repository contents: write and the
notifier's separately minted token is isolated to notification.
If publication succeeds, wait for the resulting authenticated receiver run to
complete before disabling publish.yml. If the publication run fails before
notification, disable it after the failure is understood. Then confirm both
event entrypoints are disabled and the call-only reusable workflow remains
active:
gh workflow disable publish.yml --repo NVIDIA/yaml-sigil-traits
gh workflow list --repo NVIDIA/yaml-sigil-traits --allAfter a successful publication, the authenticated receiver may create the next
default proposal while release-pr.yml remains disabled. It never replaces an
existing exact App-owned proposal. Use the bounded proposal procedure later for
an explicit bump or revision; do not leave either event entrypoint enabled.
The workflow waits for crates.io to expose the expected version as non-yanked
and confirms Cargo can resolve it. The App finalizer then requires v<version>
to be an annotated tag whose object targets the captured publication commit.
The App-authored GitHub Release must be immutable, use that tag and name,
contain the exact reviewed version section from CHANGELOG.md, have the
expected prerelease state, and have no attached assets. Record the workflow
run, package, tag, Release, readback digest, and captured SHA in the workspace
release records.
The immutable-Release setting is prospective. The four historical releases in the pinned inventory remain mutable and are never rewritten; their exact tags, source archives, bodies, author, state, and zero-asset inventories are checked before every new finalization.
Never blindly retry a failed publication. Inspect crates.io, the annotated tag, and the GitHub Release first. An existing crate version cannot be overwritten, even if yanked. On a reviewed retry, the workflow distinguishes two states:
- If the exact non-yanked crate version is absent, both forge objects must also
be absent. Exact remote
mainis rechecked immediately before release-plz receives Trusted Publishing authority. - If the exact non-yanked crate version already exists, the workflow skips
release-plz and every registry mutation. It may create only a missing
annotated tag and/or missing source-only GitHub Release after independently
rechecking crates.io. Before either write, it verifies the crates.io API
checksum, downloads that exact
.crate, rejects unsafe archive entries, requires clean.cargo_vcs_info.jsonprovenance at publicationmain, and reproduces all commit-controlled source content with exact Cargo1.95.0in an ephemeral directory. The Cargo-generatedCargo.lockremains opaque; its bytes and Cargo archive metadata must match exactly, and no archive entry is excluded from the published-versus-reproduced comparison. The workflow rechecks the same non-yanked checksum after the final forge objects are present.
Recovery never moves or replaces an existing ref, edits an existing Release, deletes an object, or uploads an asset. A lightweight or wrong-target tag, a mismatched Release body or state, any attached asset, a missing or yanked crate, or a creation race fails closed for operator review. Do not replace Trusted Publishing with a long-lived token, bypass an environment, reuse a version, or attach binary assets as a recovery shortcut.