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 GO for 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:

  1. Exact candidate selected — record the 40-character commit SHA and intended vMAJOR.MINOR.PATCH tag.
  2. Release readiness is GO — use release-readiness.md; do not recreate its capability/blocker decision here.
  3. Version metadata is alignedModuleVersion, intended stable tag, dated changelog section, and release notes/change description agree; Unreleased is empty at the tag boundary.
  4. Release metadata validation passes — run ./build/Test-ReleaseReadiness.ps1 -Tag <tag> -RequireEmptyUnreleased on the exact candidate.
  5. 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.
  6. 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.
  7. 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.
  8. Publishing environment is ready — the powershell-gallery GitHub environment exists and provides PSGALLERY_API_KEY; any environment approval required by repository configuration is available.
  9. 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.
  10. 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.0 only 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.

  1. Open Actions -> Release -> Run workflow.
  2. Select main.
  3. Enter the approved stable tag, for example v0.1.0.
  4. Select confirm_publish.
  5. Start the workflow.
  6. Record the workflow run ID and captured $ in the release evidence record.
  7. Verify Validate release context confirms:
    • the dispatch ref is main;
    • the captured SHA is still current main;
    • tag/version/changelog readiness passes.
  8. Verify Validate release commit passes the reusable Windows, Ubuntu, and macOS Quality Gate on the exact workflow SHA.
  9. 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.
  10. Do not manually create a second GitHub Release or move/recreate the stable tag around the workflow.
  11. 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.json assets exist.
  • Download/verify the ZIP checksum using the documented stable verification procedure.
  • Verify GitHub build-provenance and SBOM attestations against repository infoconex/copy-github-repo using current GitHub CLI attestation verification guidance.
  • Confirm release notes/changelog/support/security links are correct and do not claim evidence that was not produced.
  • Confirm Find-PSResource CopyGitHubRepo -Version X.Y.Z -Repository PSGallery returns 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 -NonInteractive process.
  • Confirm the installed manifest version is X.Y.Z and 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.Z resolves 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, or under investigation as 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:

  1. checks out the exact workflow SHA;
  2. builds Jekyll content;
  3. runs build/Test-GeneratedSite.ps1 against _site;
  4. uploads the Pages artifact;
  5. deploys it through the github-pages environment; and
  6. 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, or Failed 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.