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.
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.
-
Choose the
Asia/Shanghairelease date and revision. User1for 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. -
Update the pinned WordPress base digest,
WORDPRESS_VERSION, SQLite Integration version/ref, README and Compose examples, andCHANGELOG.mdin a release pull request. Do not change an already published exact tag. -
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
-
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.
-
Merge the verified release pull request to
main. Prepare GitHub Release notes from its matching changelog section, including upgrade and compatibility notes.
Publish from the GitHub Releases page after the release pull request is merged
and main CI succeeds:
- Open Releases → Draft a new release.
- Enter
2026.09.10-r1in Choose a tag, choose Create new tag, and target the currentmainbranch. - 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-r1ghcr.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.
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.
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.
Set the exact tag once for all commands:
release=2026.09.10-r1-
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 }}'
-
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}"
-
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
publishedevent starts normal fresh publication. Record the verified digest in the post-release documentation and announcement; do not create another tag or Release. -
If the release pull request carried the
release-availability: pendingREADME 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.