This repository declares its release contract in
base_manifest.yaml. It is consumed by Base's guarded
release commands and is the source of truth for the version file, changelog,
GitHub Release, and Homebrew handoff.
The repository release line and its temporary publication gates are defined in
the versioning policy. Always enter the release workflow
through scripts/release; do not invoke
basectl release directly. The repository guard validates the candidate before
delegating safe operations to Base's generic release machinery.
The shared provider, platform, license, and release-artifact rules are
summarized in the Base ecosystem platform, license, and release
policy.
-
Create or choose a release issue and set its repository Project metadata.
-
Create a release-preparation branch and dedicated worktree from
origin/main. -
Prepare the release metadata in the release-preparation branch. Move the relevant
Unreleasedentries inCHANGELOG.mdinto a dated release section. UpdateVERSION, the top release row inREADME.md, the current-release commit pin inREADME.md,docs/versioning-policy.md, anddocs/v2/quickstart.md, and theversion=line inlib/bash/base-bash-libs.releaseto the same version. Keep the pin's tag, full commit, and release-asset wording aligned with the release being prepared, and update the documentation-contract expectation in the same pull request. Leave that checked-in metadata'scommit=unknownanddirty_state=unknownplaceholders intact: the release artifact builder writes the final commit identity into its private staged copy. Ordinary pull requests do not changeVERSIONor the embedded release version. -
Validate the candidate and perform a candidate rehearsal before merging the preparation pull request. The rehearsal is intentionally bound to the clean preparation-branch commit, not to a tag that does not exist yet:
candidate_commit="$(git rev-parse HEAD)" scripts/release-artifact build --version X.Y.Z --commit "$candidate_commit" \ --output /private/tmp/base-bash-libs-X.Y.Z scripts/release-artifact verify /private/tmp/base-bash-libs-X.Y.Z \ --commit "$candidate_commit"
Run the full validation before opening the pull request:
./tests/validate.sh git diff --check
-
Open and merge the reviewed release-preparation pull request. Then sync a clean local
maincheckout and capture the merge commit that will be the immutable source for the release:git fetch origin main git checkout --detach origin/main release_commit="$(git rev-parse HEAD)" scripts/release refs --version X.Y.Z scripts/release-artifact build --version X.Y.Z --commit "$release_commit" \ --output /private/tmp/base-bash-libs-X.Y.Z-final scripts/release-artifact verify /private/tmp/base-bash-libs-X.Y.Z-final \ --commit "$release_commit"
The final asset is built from the real merged commit while the tag is still absent. Do not invent a tag or use a future tag SHA:
scripts/release refsis the read-only guard that confirms the name is available, and publication creates the immutable annotated tag only after the final checks pass.The output contains a deterministic archive, an SPDX 2.3 SBOM, a reproducibility/provenance statement, and a checksum manifest. The archive embeds
lib/bash/base-bash-libs.releasewith the exact release version, tag commit,dirty_state=clean, andprovenance=release-artifact; this metadata is generated in the artifact rather than committed with a self-referential commit hash. Offline verification requires exactly one same-version archive, SBOM, provenance statement, and checksum manifest. The checksum manifest must cover every mandatory asset exactly once, while the provenance subject, SBOM namespace/package, and embedded metadata must agree on the archive digest, version, and full source commit. Treat any missing, duplicate, traversal-bearing, or inconsistent record as a failed release gate; do not choose one asset from an ambiguous directory. Archive file and directory timestamps are normalized in UTC, path ordering uses theClocale, and archive creation supports GNU tar and bsdtar only; other tar implementations fail closed rather than claiming reproducibility. Generate the repository component row for the ecosystem BOM from the same immutable merged commit:scripts/release-bom-row --version X.Y.Z --commit "$release_commit" \ --platform macos-14 --platform ubuntu-24.04 \ --evidence run://base-bash-libs/validation \ --output /private/tmp/base-bash-libs-X.Y.Z-row.jsonThe release-invariant stage derives two API references from the checked-out release contract. It validates the candidate tree at
HEADagainst the published compatibility baseline fromfirst-party-cutover.yaml, including whenVERSIONhas advanced for release preparation. Both references and provenance are printed in diagnostics.BASE_BASH_LIBS_COMPATIBILITY_REFremains available for explicit audited fixture overrides, but is not needed for the documented local or CI command. -
Inspect the release from the merged repository root:
scripts/release check --version X.Y.Z --manifest base_manifest.yaml \ --bom /private/tmp/base-ecosystem-X.Y.Z.json scripts/release plan --version X.Y.Z --manifest base_manifest.yaml scripts/release notes --version X.Y.Z --manifest base_manifest.yaml scripts/release publish --version X.Y.Z --manifest base_manifest.yaml \ --bom /private/tmp/base-ecosystem-X.Y.Z.json --dry-run
The
refspreflight is mandatory before any real publication attempt. It fails closed if the candidate tag exists locally or onorigin, or if either side cannot be inspected. -
Publish only after the readiness checks pass. Use
--yesonly from a trusted non-interactive release shell:scripts/release publish --version X.Y.Z --manifest base_manifest.yaml \ --bom /private/tmp/base-ecosystem-X.Y.Z.json --yes
-
Verify the annotated
vX.Y.Ztag and the GitHub Release forbasefoundry/base-bash-libs. Then perform the remote completion check from a clean checkout:scripts/release-artifact verify-remote --version X.Y.Z --commit "$release_commit" \ --output /private/tmp/base-bash-libs-X.Y.Z-remoteThis check reads the published release, rejects draft or mismatched tags, requires all four canonical assets, downloads them into private staging, and runs the same offline verifier against the expected commit. A missing or partial upload fails closed and leaves no verification directory, so a retry cannot accidentally consume a partial asset set.
The SPDX 2.3 SBOM format is versioned with the release: releases before v2.2.0
retain their published SHA256-only file records, while v2.2.0 and later include
both SHA256 and the SHA1 checksum required by SPDX 2.3 file records. The Linux
and macOS validation jobs independently parse and semantically validate each
candidate SBOM with spdx-tools==0.8.5; macOS also exercises the shasum -a 1
checksum path. Both jobs check a parseable negative fixture that must produce
exactly one semantic error, specifically the missing SHA1 checksum. This
validation does not rewrite or replace any already-published release asset;
corrected SBOMs are produced only for a future authorized release.
The release contract requires the tap-owned formula
basefoundry/base/base-bash-libs in basefoundry/homebrew-base.
After the GitHub Release and its verified canonical source asset exist:
-
Create a tap release branch and update
Formula/base-bash-libs.rbto the uploaded canonical archive URL, version, SHA256, and version assertions in the formula test. Do not use GitHub's automaticarchive/refs/tags/...URL for v2. Read back the exact release asset and checksum before opening the tap pull request. -
Validate the formula from the tap checkout:
brew install --build-from-source Formula/base-bash-libs.rb brew test basefoundry/base/base-bash-libs brew audit --new --formula Formula/base-bash-libs.rb -
Publish any tap bottle artifacts required by the tap policy, then open and merge the tap pull request.
-
Smoke-test a consumer install and verify that
BASE_BASH_LIBS_VERSIONand thebase-bashlauncher report the new version.
Base pins this repository by full commit SHA in its GitHub Actions workflows. After the release, update the Base pin to the release commit, run Base's source-checkout and integration tests, and record the dependency update in the Base changelog when it is user-visible or release-relevant.
Record the library release URL, asset checksums and provenance, Homebrew tap pull request, and Base dependency pull request on the release issue. Remove the release worktree and merged branches when safe. Do not publish a release while the worktree is dirty, the version metadata disagrees, the changelog section is missing, the repository release guard blocks the candidate, or a declared downstream handoff has not been completed or explicitly deferred.