Release Process
Each release candidate must be built from a reviewed commit in protected CI. Before publication:
-
Create both ignored operator denylists described below and run
scripts/verify-public-export.sh --releasefrom a clean commit, then runscripts/verify-release-artifacts.sh; retain the public-export manifest, generated package artifacts, CycloneDX SBOM, andqualification/adapter-qualification.jsonas build evidence. -
Review dependency, secret, and release-ownership scan results, the SBOM and third-party notices, package metadata, adapter qualification matrix, and clean consumer validation for .NET, JavaScript, Python, and Go.
-
Record contract additions, behavior changes, qualification changes, migrations, and known limits in the release notes. Package availability or an advertised capability must not be presented as
live_qualifiedwithout a current live receipt in the release artifact. The canonical .NET MCP host additionally requires a passing frozen2026-07-28requirements receipt, two-process round-robin/failover/recovery evidence, and the production-container MCP receipt whose loaded image config digest matches the retained attested OCI archive. The execution-smoke worker requires the equivalent packaged-container receipt. Both loaded images must also pass the release workflow’s pinned Trivy HIGH/CRITICAL vulnerability and embedded-secret gate, with the JSON results retained alongside the receipts. The official runner’s extension and pending scenarios remain visible evidence but are not part of the frozen conformance score. For the pinned alpha.11 runner, the eight failing task diagnostics are generic core-schema rejections of the task extension envelope after their functional checks pass; the ninth is an unimplemented pending JSON-Schema diagnostic fixture. Do not authorize publication ofvyral-runtimewhile its MCP evidence remains the explicitly selected-scenario preview gate; it must first pass the same frozen requirements profile or be deliberately excluded from that release. -
Publish packages only through a trusted-publishing or OIDC-backed registry configuration. Do not place long-lived registry tokens in the repository or workflow files.
-
Attach provenance/attestations and SBOMs to the published release; publish container images with build provenance and SBOM attestations enabled.
-
Before any visibility change, scan every reachable Git ref as well as the current tree. Create an ignored, one-pattern-per-line
.release-history-denylistcontaining the private vocabulary that must never become public, then run:Terminal window VYRAL_PUBLIC_HISTORY_DENYLIST_FILE=.release-history-denylist \scripts/scan-release-history.shAn ignore rule only protects future untracked files. If this gate finds a credential-shaped historical blob or a denylisted identifier in prior content, a commit message, or a path, rewrite or split the public history and re-run the gate; do not publish the denylist or the matching value. Prefer a fresh public repository for a formerly private history, or obtain the hosting provider’s confirmation that rewritten objects have been purged. A force-push alone does not prove old objects are no longer retrievable before visibility changes.
-
Before every release, create an ignored
.release-ownership-denylistcontaining sibling repository names, consumer deployment identities, and private defaults known to the release operator, one regular expression per line. Run the current-tree ownership gate without publishing the policy:Terminal window VYRAL_RELEASE_OWNERSHIP_DENYLIST_FILE=.release-ownership-denylist \scripts/scan-release-ownership.shBoth private operator denylists are also applied to the one-commit public tree by
scripts/verify-public-export.sh --release; release mode refuses a dirty tree or a missing policy. The export is selected from the Git index by an explicit path allowlist, rejects generated/private artifacts, and must reproduce byte-for-byte across two independent builds. Use--allow-dirtyonly to rehearse local changes; release evidence must come from the default clean-tree mode.The always-on CI gate catches developer-local absolute paths and concrete cloud identities. The operator policy is still required because private vocabulary cannot be inferred safely from public source.
The version lines and maturity promises are defined in the stability policy and enforced by
scripts/verify-version-policy.py. Source versions do not prove registry publication.
Before the first public release, the repository owner must also configure the hosted controls that cannot be represented in source: protected release branches, required release-integrity, dependency-review, and CodeQL checks, Dependency Graph/Dependabot alerts, secret scanning with push protection, private vulnerability reporting, and registry trusted publishing. These controls are operational prerequisites, not claims made by a local build. Audit the currently configured GitHub subset without mutating repository settings:
python3 scripts/audit-github-launch-controls.py \ --output artifacts/qualification/github-launch-controls.jsonUse --allow-incomplete only to capture a pre-launch gap report; it does not
turn pending or plan-unavailable controls into passing evidence. Registry
trusted publishers and release-environment approvals remain explicit operator
checks because GitHub repository APIs cannot prove their external registry state.
The release is incomplete if any artifact lacks its license, source repository metadata, README, or matching symbol package. For a security-sensitive correction, follow SECURITY.md and publish an explicit remediation note.
Canonical source: docs/maintainers/releasing.md at cb04cf7
