Commercial GA is a release-batch gate, not one more ordinary CI job. It verifies immutable artifacts from a controlled release workflow and never rebuilds packages from product source on the spot.
Inputs required before dispatch
| Input | Provider | Purpose |
|---|---|---|
| Release run id and artifact name | Release workflow | Locate the immutable candidate |
| Full 40-character commit | Release owner/automation | Bind source and provenance |
| Authenticated HTTPS feed | Package platform | Real customer restore endpoint |
| Short-lived read-only credential | Identity/secret platform | Least-privilege feed access |
| Signer fingerprints | Security/release team | Constrain trusted signers |
| Vulnerability threshold | Security governance | Define the blocking line |
| Third-party license policy | Legal/OSS governance | Define license acceptance |
| External Consumer artifact | Release workflow | Repository-external consumption target |
Artifact contract
At minimum, the candidate contains:
packages/ signed immutable nupkg filesconsumer/ one external .slnx and its projectsprovenance.json packages, hashes, commit, signers, evidence indexSBOM / policy evidencePublished versions are immutable. Fixes require a new version and new provenance.
Verification order
Check external prerequisites → validate artifact layout → validate provenance schema and release commit → validate package set, versions, and SHA-256 → dotnet nuget verify --all → validate signers, SBOM, vulnerabilities, and license policy → external Consumer empty-cache restore/build/test/publishOrder matters. Once a hash or commit is inconsistent, the batch identity is not trustworthy and later consumption results cannot repair it.
Why fail-closed is mandatory
These shortcuts create false evidence and are prohibited:
- replacing an unavailable feed with a local folder;
- repacking current source after an artifact download failure;
- skipping signatures when no signer is configured;
- warning-only behavior for missing SBOM or policy evidence;
- substituting a product-repository solution for the external Consumer.
Run and diagnose
Check prerequisite variables first:
scripts/build/verify-commercial-ga.sh --check-prerequisitesMissing values are listed and return failure. The GitHub Actions Commercial GA workflow then injects artifact paths and runs complete verification.
| Output | Meaning | Owner |
|---|---|---|
external prerequisite unavailable | Release infrastructure input is missing | Release/platform team |
| provenance schema/hash mismatch | Artifact and index disagree | Release workflow owner |
| signer mismatch | Signer is outside the trusted set | Security/release team |
| policy evidence failed | Vulnerability or license policy rejected | Security/OSS governance |
| Consumer restore/build failure | Feed, closure, or template regression | Framework/package owners |
Exact environment variables
--check-prerequisites verifies only that variables are non-empty. Full execution validates schema, hashes, signatures, policies, and Consumer behavior.
| Variable | Content |
|---|---|
BITZORCAS_COMMERCIAL_FEED_URL | HTTPS feed without embedded credentials, query, or fragment |
BITZORCAS_RELEASE_PACKAGES_DIR | Release artifact packages/ directory |
BITZORCAS_RELEASE_PROVENANCE_PATH | Path to provenance.json |
BITZORCAS_RELEASE_GIT_COMMIT | Controlled 40-character release commit |
BITZORCAS_TRUSTED_SIGNER_FINGERPRINTS | Non-empty SHA-256 signer fingerprint set |
BITZORCAS_VULNERABILITY_THRESHOLD | Threshold matching provenance and scan evidence |
BITZORCAS_THIRD_PARTY_LICENSE_POLICY | Policy identifier/threshold matching evidence |
BITZORCAS_APPROVED_LICENSE_EXPRESSIONS | Allow-listed SPDX expressions for third-party licenses |
BITZORCAS_RELEASE_CONSUMER_SOLUTION | The sole .slnx, outside the vendor repository |
BITZORCAS_RELEASE_PUBLISH_PROJECTS | Publish projects joined by platform path separator |
NuGetPackageSourceCredentials_BitzOrcasCommercial | Short-lived NuGet feed credential |
# Report presence only; never echo secret values.for name in \ BITZORCAS_COMMERCIAL_FEED_URL \ BITZORCAS_RELEASE_PACKAGES_DIR \ BITZORCAS_RELEASE_PROVENANCE_PATH \ BITZORCAS_RELEASE_GIT_COMMIT \ BITZORCAS_TRUSTED_SIGNER_FINGERPRINTS \ BITZORCAS_VULNERABILITY_THRESHOLD \ BITZORCAS_THIRD_PARTY_LICENSE_POLICY \ BITZORCAS_RELEASE_CONSUMER_SOLUTION \ BITZORCAS_RELEASE_PUBLISH_PROJECTS \ NuGetPackageSourceCredentials_BitzOrcasCommercialdo # Expand the variable name indirectly and print presence only. test -n "${!name:-}" && printf '%s=present\n' "$name" || printf '%s=missing\n' "$name"doneDo not persist these values in repository scripts or shared shell history. The formal workflow derives them from GitHub Variables, Secrets, downloaded artifact paths, and controlled inputs.
Provenance and package identity checks
The verifier:
- validates structure against
0012-commercial-release-provenance.schema.json; - matches provenance commit to the controlled workflow commit;
- requires provenance signers to equal the controlled fingerprint set;
- requires physical nupkg, provenance, and commercial catalog packageId sets to be identical;
- validates per-file SHA-256 (nupkgs additionally carry SHA-512 aligned with the NuGet global-packages representation), nuspec id/version, and dependencies;
- rejects source, PDB, Source Link, machine paths, and credential markers;
- requires SBOM coverage for released identities and package dependencies;
- rejects unresolved findings and expired exemptions.
Different hashes for one packageId/version violate immutability. Missing and extra packages both fail; this is exact-set validation, not “contains at least the catalog packages.”
External Consumer verification
GA writes a temporary NuGet.Config with <clear /> and Package Source Mapping, forces BitzOrcas.* to the formal feed, and isolates package, HTTP, plugin, and CLI-home caches.
It runs dotnet nuget verify --all with trusted fingerprints for every package, then restores, Release-builds, Release-tests the external Solution, and publishes every declared project. Commands kill their process group after a 15-minute timeout; failed output is redacted before reporting.
Current GA publish does not force PublishTrimmed=true. Trimming depends on external project settings. A Profile claiming trim safety must set that property in the release Consumer and add an explicit assertion.
workflow_dispatch operation
The formal GitHub Actions workflow accepts three manual inputs: release run id, artifact name, and full release commit. It checks out verifier code at that commit, then downloads the candidate from the selected run.
The downloaded artifact must contain exactly one top-level Consumer .slnx and at least one .csproj; otherwise it fails with external prerequisite unavailable: release Consumer artifact layout. Never rewrite $GITHUB_ENV to point at a vendor-repository Solution.
After the gate passes
A passing GA gate permits entry into the cutover window. The runbook must still verify configuration, readiness, License state, observability, database compatibility, and rollback conditions while retaining the previous version during the observation period.
Governance manifests
The GA gate and runtime enforcement draw on a set of reviewable governance manifests maintained in the source repository at docs/architecture/00-governance/manifests/. They are the machine-readable source of truth for production readiness, not documentation prose.
| Manifest | Scope |
|---|---|
0001-module-governance-legacy-ledger.json | legacy module-root ratchet |
0002-production-adapter-readiness.json | adapter readiness guard |
0003-operations-runtime-surface.json | operations runtime visibility surface |
0004-template-upgrade-map.json | template version upgrade map |
0005-test-drift-ledger.json | test-drift classifications |
0006-persistence-surface-classification.json | entity/persistence surface classification |
0008-error-catalog.json | strong-typed error catalog (1,968 codes — measure with `jq ‘.entries |
0009-error-catalog-legacy-baseline.json | legacy two-segment error-code baseline |
0010-commercial-package-catalog.json | commercial package / profile / license catalog |
0011-profile-package-closure.json | profile package closure + runnable combinations |
0012-commercial-release-provenance.schema.json | release provenance schema (referenced above) |
0013-runtime-license-policy-catalog.json | shared runtime license policies + static combination boundary |
(Numbering jumps 0006 → 0008; there is no 0007.) The full governance narrative and the gates these manifests back are documented in the Governance section.
GA completion checklist
- workflow inputs bind a trusted release run and 40-character commit;
- downloaded artifact exactly matches provenance and physical package sets;
- every nupkg hash, identity, content, and signer passes;
- SBOM covers release identities and transitive package dependencies;
- vulnerability and third-party license policies pass with no expired exemption;
- external Consumer restores from the formal HTTPS feed with empty caches;
- Consumer Release build, test, and every selected publish pass;
- Runtime License, migration, readiness, monitoring, and rollback runbook pass in target environment;
- release record preserves workflow run, artifact, provenance, policy evidence, and approvers;
- the previous version and rollback path remain during observation.
If any item is absent, the state is “GA incomplete” or “external prerequisite unavailable,” never “partially passed GA.”