Release and deployment runbook
This runbook is the ordered maintainer procedure for releasing Copy GitHub Repository. It owns how an already-approved release candidate is tagged, packaged, distributed, verified, and recovered. It does not decide whether a candidate is ready; that decision is authoritative in release-readiness.md.
The supported automation is .github/workflows/release.yml. Use the workflow instead of reconstructing publication manually whenever GitHub Actions is available. publishing.md, versioning.md, release-sbom.md, and installation-security.md remain authoritative for their detailed contracts.
Three distinct deployment concerns
Do not treat these as one atomic deployment:
| Concern | Primary mechanism | Mutation/publication boundary | Independent failure/recovery? |
|---|---|---|---|
| Product release | Stable tag plus immutable release identity | Creating/reusing the approved stable tag | Yes |
| Package distribution | PowerShell Gallery and GitHub Release assets | Publish-PSResource, then gh release create |
Yes; the two channels are not atomic |
| Documentation deployment | .github/workflows/pages.yml on documentation/site changes |
GitHub Pages deployment | Yes; Pages failure does not roll back an already-published module release |
A release status must state which of these concerns completed. Never call a partially published release fully complete merely because one channel succeeded.
Canonical lifecycle
Use these lifecycle states for a normal stable release:
Planned -> Release Candidate -> Readiness Reviewed -> Approved -> Release Workflow Started -> Validated -> Artifacts Built -> Integrity Evidence Generated -> Attested -> Tag Confirmed/Created -> Published to PowerShell Gallery -> Published to GitHub Release -> Distribution Verified -> Documentation Verified -> Complete
A failure stops progression at the current state. Record the last irreversible mutation before deciding whether retry is safe.
State meanings
- Planned — version/scope work is still mutable.
- Release Candidate — one exact commit is proposed for release-specific evidence.
- Readiness Reviewed — the exact candidate has been evaluated under
release-readiness.md. - Approved — the current governance authority recorded
GOfor that exact candidate; approval does not carry to a later commit. - Release Workflow Started — the supported Release workflow is operating on the approved SHA/tag request.
- Validated — release metadata and the reusable Windows/Ubuntu/macOS Quality Gate passed for the workflow SHA.
- Artifacts Built — deterministic ZIP and validated Gallery package were produced from the same SHA.
- Integrity Evidence Generated — checksum and SPDX SBOM exist for the exact release artifact.
- Attested — required GitHub provenance/SBOM attestations completed. Independent signing remains a separate control under #80 until implemented/dispositioned.
- Tag Confirmed/Created — the stable tag resolves to the approved commit. A tag-triggered run begins with an existing tag; manual dispatch creates/reuses it only after pre-publication validation.
- Published to PowerShell Gallery — the immutable Gallery version was successfully published.
- Published to GitHub Release — the immutable GitHub Release and expected assets were created for the same stable tag.
- Distribution Verified — published identities/assets/install path were checked after publication.
- Documentation Verified — Pages health was verified when release-related documentation changed.
- Complete — all required release-specific evidence and channel results are recorded; no required publication/verification step remains unresolved.
Preconditions before starting the Release workflow
Do not begin stable publication until all applicable items below are satisfied or explicitly dispositioned by the exact-candidate readiness record:
- Exact candidate selected — record the 40-character commit SHA and intended
vMAJOR.MINOR.PATCHtag. - Release readiness is
GO— userelease-readiness.md; do not recreate its capability/blocker decision here. - Version metadata is aligned —
ModuleVersion, intended stable tag, dated changelog section, and release notes/change description agree;Unreleasedis empty at the tag boundary. - Release metadata validation passes — run
./build/Test-ReleaseReadiness.ps1 -Tag <tag> -RequireEmptyUnreleasedon the exact candidate. - Quality evidence exists — Windows, Ubuntu, and macOS Quality Gate evidence is successful for the candidate. Release workflow reruns the reusable gate and remains authoritative for the release execution.
- Applicable live E2E evidence is recorded — exact-RC live evidence required by the quality/readiness model is present; an E2E harness existing is not the same as the release candidate having been live-validated.
- Security/non-functional blockers are dispositioned — including #79, #80, and release-required items referenced by the readiness record. Open does not automatically mean blocker, but undispositioned required work prevents
GO. - Publishing environment is ready — the
powershell-galleryGitHub environment exists and providesPSGALLERY_API_KEY; any environment approval required by repository configuration is available. - No immutable-version conflict exists — the intended version must not already be published in PowerShell Gallery or as a stable GitHub Release. The workflow checks again before mutation.
- First clean same-name publication ordering is respected — if the repository itself is being converted to a clean same-name Snapshot, perform and verify that replacement first; create
v0.1.0only on the final clean replacement commit.
If any required precondition changes after approval, return to Release Candidate/Readiness Reviewed; do not reuse stale approval.
Preferred release procedure — manual workflow dispatch
Manual dispatch from main is the preferred maintainer-controlled path because the workflow can validate the current branch SHA before creating the stable tag.
- Open Actions -> Release -> Run workflow.
- Select main.
- Enter the approved stable tag, for example
v0.1.0. - Select
confirm_publish. - Start the workflow.
- Record the workflow run ID and captured
$in the release evidence record. - Verify Validate release context confirms:
- the dispatch ref is
main; - the captured SHA is still current
main; - tag/version/changelog readiness passes.
- the dispatch ref is
- Verify Validate release commit passes the reusable Windows, Ubuntu, and macOS Quality Gate on the exact workflow SHA.
- In Publish release, verify the workflow:
- reruns stable release-readiness validation;
- builds the deterministic ZIP and Gallery package;
- generates the SPDX SBOM from the completed ZIP;
- creates required build-provenance and SBOM attestations;
- confirms publishing commands exist;
- rejects duplicate Gallery/GitHub Release versions before publication;
- creates or safely reuses the annotated tag only if it resolves to the approved SHA;
- publishes the Gallery package;
- creates the GitHub Release with ZIP, checksum, and SBOM assets.
- Do not manually create a second GitHub Release or move/recreate the stable tag around the workflow.
- Continue to post-publication verification below.
Alternate tag-triggered path
Pushing an exact stable vMAJOR.MINOR.PATCH tag also starts the Release workflow. Use this path only when the tag has already been intentionally created on the exact approved candidate.
The workflow validates the tag/version metadata and Quality Gate before package publication, but the tag itself is already a public immutable release identity at workflow start. Therefore a failed tag-triggered run may require a new version/tag if the tag was wrong; do not move a published stable tag to a different commit to repair a bad release candidate.
For the initial clean same-name publication, follow the ordering in publishing.md: clean replacement first, then tag the final clean replacement commit.
What the release workflow publishes
For module version X.Y.Z, the normal GitHub Release evidence includes:
CopyGitHubRepo-X.Y.Z.zip;CopyGitHubRepo-X.Y.Z.zip.sha256;CopyGitHubRepo-X.Y.Z.spdx.json;- GitHub build-provenance attestation bound to the ZIP; and
- GitHub SBOM attestation bound to the same ZIP.
The workflow publishes the validated module package to PowerShell Gallery before creating the GitHub Release. Those operations are separate external mutations and cannot be made atomic.
Independent publisher signing is not implied by checksum/SBOM/GitHub attestations. #80 remains the authority for that separate control until implemented or explicitly dispositioned for a release.
Post-publication verification
After the workflow reports success, verify the published state rather than assuming the final API calls produced the intended consumer experience.
Tag and GitHub Release
- Confirm the stable tag resolves to the exact approved candidate SHA.
- Confirm the GitHub Release tag/title/version agree with the module version.
- Confirm the expected ZIP,
.sha256, and.spdx.jsonassets exist. - Download/verify the ZIP checksum using the documented stable verification procedure.
- Verify GitHub build-provenance and SBOM attestations against repository
infoconex/copy-github-repousing current GitHub CLI attestation verification guidance. - Confirm release notes/changelog/support/security links are correct and do not claim evidence that was not produced.
PowerShell Gallery
- Confirm
Find-PSResource CopyGitHubRepo -Version X.Y.Z -Repository PSGalleryreturns the intended immutable version. - From a clean/supported environment, install the exact version through the supported stable distribution path.
- Import the installed module in a fresh
pwsh -NoProfile -NonInteractiveprocess. - Confirm the installed manifest version is
X.Y.Zand only the documented public command surface is exported. - Exercise a safe smoke path appropriate for the release; do not perform a destructive repository migration merely to prove package import.
Stable installer/update path
- Verify
install-release.ps1 -Version X.Y.Zresolves the intended GitHub Release. - Confirm checksum validation succeeds before extraction/installer execution.
- Confirm an integrity mismatch fails closed; do not bypass checksum validation to complete the release.
Documentation site
If release-related documentation/site content changed:
- confirm the corresponding Deploy GitHub Pages run passed its Jekyll build and generated-site integrity validation;
- confirm deployment succeeded; and
- confirm the published-site smoke test succeeded.
Pages is an independent deployment. A Pages failure after module publication does not authorize altering or overwriting immutable package/release artifacts.
Failure and recovery matrix
Before retrying, determine whether the failure occurred before or after an immutable/public mutation.
| Failure | Public/immutable state | Safe normal response |
|---|---|---|
| Version/tag/manifest/changelog mismatch | None if caught by readiness validation | Fix metadata on main, create a new candidate/readiness decision, rerun. Do not tag. |
| Quality Gate failure | None for manual dispatch before tag creation | Diagnose actual failing Pester/analyzer/package evidence; fix on a new commit; repeat readiness for the new SHA. |
| Required live evidence missing/failed | None | NO-GO/PENDING; obtain valid exact-candidate evidence or explicitly disposition under readiness rules. |
| Package/artifact/SBOM/attestation failure | None for manual dispatch unless tag had already been created by another path | Fix cause on a new candidate; rerun. Never publish without required integrity evidence. |
| Publishing credential/environment approval unavailable | None if failure occurs before Gallery publication | Restore access/approval and rerun only if candidate/tag state is still valid. Never expose the key in diagnostics. |
| Existing Gallery version detected | Gallery version already exists from an earlier publication | Stop. Do not overwrite/re-publish the immutable version. Determine whether it is the intended artifact; if correction is needed, use a new version. |
| Existing GitHub Release detected | GitHub Release already exists | Stop normal publication. Do not clobber stable assets. Verify existing release; correction normally requires a new version/tag. |
| Manual tag creation fails before ref exists | No stable tag created | Resolve the GitHub/API cause; rerun only if the exact approved candidate remains current/valid. |
| Tag exists but resolves to a different commit | Stable identity conflict | Stop. Never move/reuse the tag for a different approved SHA. Use a new version/tag after review. |
| Gallery publication fails | Tag may exist for manual dispatch; Gallery version not confirmed | Determine whether Gallery actually accepted the version before retry. If absent, a reviewed rerun may reuse the exact tag only when it resolves to the approved SHA. |
| Gallery succeeds, GitHub Release fails | Gallery version is public/immutable; tag exists; GitHub Release absent | Do not republish Gallery. Preserve evidence and investigate GitHub failure. Normal workflow duplicate protection means blind rerun is not a repair mechanism; use an explicitly reviewed partial-publication recovery decision. Do not overwrite the Gallery package. |
| GitHub Release succeeds but post-publication artifact verification fails | Stable GitHub Release/public assets exist | Treat as release incident/repair condition. Do not clobber assets or move tag. Stop recommending the release as appropriate; correction normally uses a new version and the post-release process under #108 once implemented. |
| Gallery publication succeeds but clean install/import verification fails | Gallery version is public/immutable | Do not overwrite Gallery. Preserve the failing fixture/evidence; issue a corrected version if product/package defect is confirmed. |
| Documentation Pages deployment fails | Product/package release may already be complete | Fix/redeploy documentation independently. Do not mutate stable product artifacts to repair Pages. |
A retry is safe only when it cannot overwrite an immutable version, cannot associate a stable tag with a different commit, and cannot duplicate an uncertain external mutation. When external publication status is ambiguous, verify the external service first.
Partial multi-channel publication record
If one distribution channel succeeds and another fails, record at minimum:
- exact version/tag/commit;
- release workflow run ID and failed step;
- whether the stable tag exists and what commit it resolves to;
- PowerShell Gallery exact-version presence and observed package identity;
- checksum/SBOM/attestation identities already created;
- post-publication verification completed/not completed;
- current user-facing recommendation (
usable,do not use, orunder investigationas evidence supports); - recovery decision authority and rationale; and
- follow-up/incident reference when further work is required.
Do not call the release Complete until every required channel and verification state is resolved.
Manual fallback
Manual publication is a contingency, not the normal release procedure. Follow publishing.md and use the exact approved source revision plus the same local quality, release-readiness, package-validation, duplicate-version, integrity, and immutability rules.
A manual fallback must not silently omit evidence that the supported release workflow normally requires. If GitHub attestation generation is unavailable, the release-readiness authority must explicitly decide whether publication is blocked or whether a release-specific accepted limitation is defensible. Do not describe missing evidence as generated.
Documentation deployment lifecycle
GitHub Pages is deployed by .github/workflows/pages.yml when site-related paths change, and it can be dispatched manually. The workflow:
- checks out the exact workflow SHA;
- builds Jekyll content;
- runs
build/Test-GeneratedSite.ps1against_site; - uploads the Pages artifact;
- deploys it through the
github-pagesenvironment; and - smoke-tests key published routes.
Because Pages uses its own concurrency/deployment state, document/site changes can be repaired and redeployed without changing an already-published module version.
Release completion record
Before marking a stable release complete, retain or link these release-specific facts:
- version/tag and exact commit SHA;
- exact #104 go/no-go record/decision authority;
- Release workflow run ID;
- Windows/Ubuntu/macOS release Quality Gate result;
- applicable exact-candidate live E2E evidence;
- release ZIP filename/SHA-256;
- SPDX SBOM filename/identity;
- provenance/SBOM attestation verification result;
- PowerShell Gallery publication and clean-install verification;
- GitHub Release publication and asset verification;
- stable installer checksum/install verification;
- Pages deployment/smoke evidence when applicable;
- accepted limitations/residual risks; and
- final state:
Complete,Partial / recovery required, orFailed before publication.
The mutable main branch, a generic previous CI run, or the existence of a release tag alone is not sufficient release-completion evidence.
Authority and escalation
Release execution follows the current project authority in governance.md. Self-review and automation do not become independent approval evidence merely because the workflow succeeded.
Normal readiness/go-no-go remains owned by release-readiness.md. Serious post-publication security, supply-chain, artifact, credential, or distribution problems transition to the exceptional post-release incident/emergency-maintenance process tracked by #108 rather than improvising destructive repair in this runbook.
Related authorities
- Release readiness/go-no-go:
release-readiness.md - Version semantics:
versioning.md - PowerShell Gallery/release publication details:
publishing.md - Release SBOM/provenance:
release-sbom.md - Installation trust/checksum verification:
installation-security.md - Quality/live-evidence semantics:
quality-strategy.md - Project governance:
governance.md - Support lifecycle:
support-policy.md - Software assurance:
software-assurance.md