Skip to content

Latest commit

 

History

History
191 lines (153 loc) · 9.07 KB

File metadata and controls

191 lines (153 loc) · 9.07 KB

Releasing

Image releases use the immutable CalVer form YYYY.MM.DD-rN, as defined in VERSIONING.md. Component versions such as WordPress 7.1.0 are recorded independently and do not determine the image tag.

Protect release tags

Configure a GitHub tag ruleset for ????.??.??-r* before publishing:

  • restrict tag creation to release maintainers;
  • block tag updates and deletion, including force pushes;

Separately protect main with required pull requests and CI checks. Configure the release Actions environment used by the manifest/signing job with required reviewers when an explicit publication approval is desired.

Repository rulesets cannot be installed by a pull request. An administrator must configure and verify this policy in Settings → Rules → Rulesets. The workflow independently requires GitHub's ref_protected signal and accepts both lightweight (commit) tags created by the Releases form and existing annotated (tag) tags. It rejects branch dispatches, tags whose target commit is not on main, and tags whose target does not match the checked-out commit. Server-side tag protection remains the authoritative control.

Prepare

  1. Choose the Asia/Shanghai release date and revision. Use r1 for the first release on a date, then increment it for every changed image artifact or evidence set. Check that the exact tag is absent from Git, Docker Hub, and GHCR.

  2. Update the pinned WordPress base digest, WORDPRESS_VERSION, SQLite Integration version/ref, README and Compose examples, and CHANGELOG.md in a release pull request. Do not change an already published exact tag.

  3. Run the local release checks:

    bash tests/test-entrypoint-reconcile.sh
    php tests/test-sqlite-local-core-update.php
    php tests/test-sqlite-select-id-key-fix.php
    php tests/test-tool-update-site-url.php
    php tests/test-tool-reset-user-password.php
    go install github.com/soulteary/ci-recipes/cmd/ci-recipes@83ccd6f83d7e7ef40f5d6faf2e11960f1de74a78
    ci-recipes docker-sqlite-wordpress validate-release 2026.09.10-r1
  4. Let pull-request CI test amd64, native arm64, and the 32-bit ARM pure-PHP fallback. Verify the local core archive and updater, SQLite CRUD, diagnostics, site URL recovery, and user password reset behavior.

  5. Merge the verified release pull request to main. Prepare GitHub Release notes from its matching changelog section, including upgrade and compatibility notes.

Publish

Publish from the GitHub Releases page after the release pull request is merged and main CI succeeds:

  1. Open Releases → Draft a new release.
  2. Enter 2026.09.10-r1 in Choose a tag, choose Create new tag, and target the current main branch.
  3. Generate and review the release notes, then select Publish release.

Publishing the GitHub Release creates a protected lightweight tag and automatically starts the image release workflow. The workflow also accepts an existing protected annotated tag. Do not start a second run while the release-triggered run is active.

For an annotated tag, create and push it first, then select that existing tag in the GitHub Releases form. A tag push alone no longer starts publication; publishing the GitHub Release is the normal automatic fresh-release trigger. Manual dispatch remains the explicit operator path described below.

The Release workflow builds each runtime platform once and publishes the same manifest digest to Docker Hub and GHCR under the immutable exact tag:

  • soulteary/sqlite-wordpress:2026.09.10-r1
  • ghcr.io/soulteary/sqlite-wordpress:2026.09.10-r1

BuildKit emits an SPDX SBOM and maximum-mode SLSA provenance for each platform. The merged index receives OCI version, source, revision, and license annotations. GitHub Actions then signs each registry's manifest digest with a keyless Sigstore identity and verifies both signatures before the release job succeeds. A registry can accept a signature referrer before making it visible to an immediate read. The workflow retries only Cosign's transient no signatures found result; identity, certificate, and other verification failures remain fail-closed.

Afterward, the serialized Promote latest workflow selects the numerically newest complete CalVer release whose two registry indexes match. It promotes both the date alias (for example 2026.08.31) and latest without rebuilding. If the newest Git tag is incomplete, promotion scans backward to the newest complete release rather than blocking all promotion.

Manual Release dispatch is allowed only when the selected workflow ref is a protected CalVer tag. A fresh publication requires the exact image tag to be absent from both registries. Running it from a branch fails preflight. Manual Promote latest dispatch from main can reconcile mutable aliases.

Recover from a failed preflight

Do not move, delete, or reuse a public exact CalVer tag after a failed release. A rerun uses the same source and workflow snapshot and cannot make a tag name match a different IMAGE_VERSION. Keep the failed tag and source release for audit history, correct the source version through a pull request, increment the revision, and publish a new protected tag through the GitHub Releases page. A workflow that stopped in preflight did not reach the image build or registry publication jobs.

Resume after manifest creation

If a release creates the exact manifest in both registries and then fails during evidence verification or signing, do not start another fresh run. First confirm that both indexes have the same digest and their OCI version and revision match the protected source tag. Then open Actions → Release → Run workflow, select that exact tag, enable resume_existing, and run it. Resume mode skips platform builds and manifest creation; it revalidates every platform's SBOM and provenance, signs the existing digest, and verifies the signatures.

Resume support must already exist in the workflow snapshot referenced by the tag. Earlier incomplete tags such as 2026.08.31-r2 cannot acquire this logic without moving the tag, so they remain incomplete and require a new revision. If only one registry contains the exact tag, the manifests differ, or their OCI revision does not match the tag commit, resume fails closed and a new revision is required.

The published 2026.08.31-r3 workflow snapshot includes resume support but predates the bounded signature visibility retry. If its first resume reaches Signing artifact... and then reports no signatures found, wait for the registry referrer to become visible and run the same resume again. Resume mode never rebuilds or replaces the exact manifest; an additional valid signature referrer does not change its digest.

Verify and announce

Set the exact tag once for all commands:

release=2026.09.10-r1
  1. Confirm both registries expose the same five runtime platforms, SBOM, and provenance attestations:

    docker buildx imagetools inspect "soulteary/sqlite-wordpress:${release}"
    docker buildx imagetools inspect "ghcr.io/soulteary/sqlite-wordpress:${release}"
    docker buildx imagetools inspect "soulteary/sqlite-wordpress:${release}" --format '{{ json .SBOM }}'
    docker buildx imagetools inspect "soulteary/sqlite-wordpress:${release}" --format '{{ json .Provenance }}'
  2. Verify the keyless signatures with the workflow identity and GitHub OIDC issuer:

    identity="https://github.com/soulteary/docker-sqlite-wordpress/.github/workflows/release.yaml@refs/tags/${release}"
    issuer="https://token.actions.githubusercontent.com"
    cosign verify \
      --certificate-identity "${identity}" \
      --certificate-oidc-issuer "${issuer}" \
      "soulteary/sqlite-wordpress:${release}"
    cosign verify \
      --certificate-identity "${identity}" \
      --certificate-oidc-issuer "${issuer}" \
      "ghcr.io/soulteary/sqlite-wordpress:${release}"
  3. Pull the exact tag from each registry and repeat the installation, SQLite, local core update, diagnostics, and recovery smoke tests. Verify the registry availability gate:

    ci-recipes docker-sqlite-wordpress verify-published-release "${release}"

    The GitHub Release already exists at this stage because its published event starts normal fresh publication. Record the verified digest in the post-release documentation and announcement; do not create another tag or Release.

  4. If the release pull request carried the release-availability: pending README marker and local-build Compose configuration, open a documentation follow-up that removes the marker and switches Compose to the exact published tag only after the registry availability gate confirms that the Git tag exists and Docker Hub and GHCR expose the same manifest digest.

Never force-push, delete, or retarget a published release tag. If anything in the image or its evidence must change, publish a new CalVer revision. Rerun a failed job directly when its original artifacts remain available; otherwise use the explicit resume mode only for matching complete manifests in both registries. Any conflicting or one-sided state requires a new revision.