Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 28 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,31 @@

## [Unreleased]

## [2026.08.30-r1] - 2026-08-30
## [2026.08.31-r2] - 2026-08-31

### Fixed

- Prepared a new immutable release revision after `2026.08.31-r1` stopped in
release preflight before any container image was built. The existing `r1`
tag and GitHub source release remain in place for audit history and are not
moved, deleted, or reused.
- Aligned the image version, validation examples, deployment examples, and
release documentation on the same `2026.08.31-r2` candidate.

### Release notes

- This revision contains the CalVer, SQLite Database Integration 3.0.1,
persistent-volume core updater, supply-chain evidence, and ARM test changes
recorded in the retained `2026.08.31-r1` source release below.

## [2026.08.31-r1] - 2026-08-31

### Release status

- The GitHub source release was created with a lightweight tag while its source
still declared `2026.08.30-r1`. The protected release workflow rejected it
during preflight and produced no container image for this exact tag. Do not
use `2026.08.31-r1` as a deployable image release.

### Added

Expand Down Expand Up @@ -82,6 +106,7 @@
- SQLite Database Integration 3.0.0 uses WAL journaling by default; keep the database, `-wal`, and `-shm` files on the same persistent volume.
- The native `wp_mysql_parser` extension is built for amd64 and arm64. Other published platforms use the integration's pure-PHP parser fallback.

[Unreleased]: https://github.com/soulteary/docker-sqlite-wordpress/compare/2026.08.30-r1...HEAD
[2026.08.30-r1]: https://github.com/soulteary/docker-sqlite-wordpress/compare/7.1.0...2026.08.30-r1
[Unreleased]: https://github.com/soulteary/docker-sqlite-wordpress/compare/2026.08.31-r2...HEAD
[2026.08.31-r2]: https://github.com/soulteary/docker-sqlite-wordpress/compare/2026.08.31-r1...2026.08.31-r2
[2026.08.31-r1]: https://github.com/soulteary/docker-sqlite-wordpress/compare/7.1.0...2026.08.31-r1
[7.1.0]: https://github.com/soulteary/docker-sqlite-wordpress/compare/7.0.2-plugin-v3.0.0-rc.8...7.1.0
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ bash tests/test-validate-release.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
./scripts/validate-release.sh 2026.08.30-r1
./scripts/validate-release.sh 2026.08.31-r2
```

To reproduce the remaining lint and configuration checks:
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# plugin: https://github.com/WordPress/sqlite-database-integration
# The optional native Rust extension `wp_mysql_parser` accelerates the MySQL
# lexer/parser used by the SQLite driver. It requires the 3.0 monorepo layout.
ARG IMAGE_VERSION=2026.08.30-r1
ARG IMAGE_VERSION=2026.08.31-r2
ARG IMAGE_REVISION=unknown
ARG WORDPRESS_VERSION=7.1.0
ARG WORDPRESS_IMAGE=wordpress:7.1.0-php8.5-apache@sha256:6c56ffb8cc06577c604707e3164f7fe736a3db6855336804a2cd4d7c186d6502
Expand Down
46 changes: 25 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@
WordPress with SQLite, ready to use out of the box.

<!-- release-availability: pending -->
> **Release availability:** `2026.08.30-r1` is prepared but is not published yet.
> Commands below that use this exact tag become available only after the
> protected tag workflow succeeds in both registries. Until then, build the
> current repository as shown in Quick Start; the existing `latest` alias does
> not represent all features documented for current `main`.
> **Container release availability:** `2026.08.31-r2` is prepared but is not published yet
> as a verified container image. The retained
> [`2026.08.31-r1` source release](https://github.com/soulteary/docker-sqlite-wordpress/releases/tag/2026.08.31-r1)
> failed release preflight before any image was built and must not be used as a
> container release. Until the protected annotated `r2` tag succeeds in both
> registries, build the current repository as shown in Quick Start; the
> existing `latest` alias does not represent all features documented for
> current `main`.

- Based on [official image](https://hub.docker.com/_/wordpress), Easier and more sustainable solution.
- DockerHub Page: https://hub.docker.com/r/soulteary/sqlite-wordpress
Expand Down Expand Up @@ -58,7 +61,7 @@ docker exec -it <container> ls -l /var/www/html/wp-content/mu-plugins/

## Quick Start

Until `2026.08.30-r1` is published, build current `main` locally:
Until `2026.08.31-r2` is published, build current `main` locally:

```bash
docker build -t sqlite-wordpress:main .
Expand All @@ -71,11 +74,11 @@ convenience or the immutable CalVer release for reproducible deployments:
# Docker Hub: use latest
docker pull soulteary/sqlite-wordpress
# Docker Hub: use an immutable release
docker pull soulteary/sqlite-wordpress:2026.08.30-r1
docker pull soulteary/sqlite-wordpress:2026.08.31-r2
# GHCR: use latest
docker pull ghcr.io/soulteary/sqlite-wordpress:latest
# GHCR: use an immutable release
docker pull ghcr.io/soulteary/sqlite-wordpress:2026.08.30-r1
docker pull ghcr.io/soulteary/sqlite-wordpress:2026.08.31-r2
```

Launch the locally built image on port `8080`:
Expand Down Expand Up @@ -113,16 +116,17 @@ Use the quick 1-minute initial installation, enjoy.

## Image Versions and Supply-chain Evidence

Image releases use CalVer such as `2026.08.30-r1`; WordPress and SQLite
Image releases use CalVer such as `2026.08.31-r2`; WordPress and SQLite
Integration keep their own component versions. Exact `YYYY.MM.DD-rN` tags are
immutable, while the date-only tag and `latest` are verified mutable aliases.
Pin an exact tag or manifest digest in production. See
[VERSIONING.md](./VERSIONING.md) for the complete policy.

Every release includes an SPDX SBOM, maximum-mode SLSA provenance, the source
commit in OCI `org.opencontainers.image.revision`, and a keyless Sigstore
signature on each Docker Hub and GHCR manifest. Verification commands and the
expected GitHub Actions identity are documented in
Every successfully published container release includes an SPDX SBOM,
maximum-mode SLSA provenance, the source commit in OCI
`org.opencontainers.image.revision`, and a keyless Sigstore signature on each
Docker Hub and GHCR manifest. Verification commands and the expected GitHub
Actions identity are documented in
[RELEASING.md](./RELEASING.md). The repository and bundled-component license
inventory is in [LICENSES.md](./LICENSES.md).

Expand Down Expand Up @@ -218,7 +222,7 @@ chmod 600 secrets/site-url-update-token
services:

wordpress:
image: soulteary/sqlite-wordpress:2026.08.30-r1
image: soulteary/sqlite-wordpress:2026.08.31-r2
ports:
- 127.0.0.1:8080:80
environment:
Expand Down Expand Up @@ -248,7 +252,7 @@ export WORDPRESS_SITE_URL_UPDATE_PASSWORD="$(openssl rand -base64 24)"
services:

wordpress:
image: soulteary/sqlite-wordpress:2026.08.30-r1
image: soulteary/sqlite-wordpress:2026.08.31-r2
ports:
- 127.0.0.1:8080:80
environment:
Expand Down Expand Up @@ -276,7 +280,7 @@ docker run --rm -it \
--volume "$(pwd)/secrets/site-url-update-token:/run/secrets/site-url-update-token:ro" \
--env WORDPRESS_SITE_URL_UPDATE_TOOL_ENABLED=true \
--env WORDPRESS_SITE_URL_UPDATE_TOKEN_FILE=/run/secrets/site-url-update-token \
soulteary/sqlite-wordpress:2026.08.30-r1
soulteary/sqlite-wordpress:2026.08.31-r2
```

For PASSWORD, export a fresh value and pass only the variable name so the shell
Expand All @@ -290,7 +294,7 @@ docker run --rm -it \
--volume "$(pwd)/wordpress:/var/www/html" \
--env WORDPRESS_SITE_URL_UPDATE_TOOL_ENABLED=true \
--env WORDPRESS_SITE_URL_UPDATE_PASSWORD \
soulteary/sqlite-wordpress:2026.08.30-r1
soulteary/sqlite-wordpress:2026.08.31-r2
```

After the update, stop this temporary container and start the normal deployment
Expand Down Expand Up @@ -429,7 +433,7 @@ docker run --rm --user 0:0 \
--mount type=bind,source="$(pwd)/wordpress",target=/source,readonly \
--mount type=bind,source="$(pwd)/backups",target=/backup \
--env "BACKUP_NAME=${backup_name}" \
soulteary/sqlite-wordpress:2026.08.30-r1 \
soulteary/sqlite-wordpress:2026.08.31-r2 \
-Eeuo pipefail -c '
[[ -n "${BACKUP_NAME}" && "${BACKUP_NAME}" != */* ]]
archive="/backup/${BACKUP_NAME}"
Expand Down Expand Up @@ -464,7 +468,7 @@ docker run --rm --user 0:0 \
--mount "type=volume,source=${wordpress_volume},target=/source,readonly" \
--mount type=bind,source="$(pwd)/backups",target=/backup \
--env "BACKUP_NAME=${backup_name}" \
soulteary/sqlite-wordpress:2026.08.30-r1 \
soulteary/sqlite-wordpress:2026.08.31-r2 \
-Eeuo pipefail -c '
[[ -n "${BACKUP_NAME}" && "${BACKUP_NAME}" != */* ]]
archive="/backup/${BACKUP_NAME}"
Expand Down Expand Up @@ -497,7 +501,7 @@ docker run --rm --user 0:0 \
--mount type=bind,source="$(pwd)/wordpress",target=/source \
--mount type=bind,source="$(pwd)/backups",target=/backup,readonly \
--env "BACKUP_NAME=${backup_name}" \
soulteary/sqlite-wordpress:2026.08.30-r1 \
soulteary/sqlite-wordpress:2026.08.31-r2 \
-Eeuo pipefail -c '
[[ -n "${BACKUP_NAME}" && "${BACKUP_NAME}" != */* ]]
archive="/backup/${BACKUP_NAME}"
Expand Down Expand Up @@ -535,7 +539,7 @@ docker run --rm --user 0:0 \
--mount "type=volume,source=${wordpress_volume},target=/source" \
--mount type=bind,source="$(pwd)/backups",target=/backup,readonly \
--env "BACKUP_NAME=${backup_name}" \
soulteary/sqlite-wordpress:2026.08.30-r1 \
soulteary/sqlite-wordpress:2026.08.31-r2 \
-Eeuo pipefail -c '
[[ -n "${BACKUP_NAME}" && "${BACKUP_NAME}" != */* ]]
archive="/backup/${BACKUP_NAME}"
Expand Down
31 changes: 22 additions & 9 deletions RELEASING.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@ authoritative control.

## Prepare

1. Choose the UTC release date and revision. Use `r1` for the first release on
a date, then increment it for every changed image artifact or evidence set.
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
Expand All @@ -38,7 +39,7 @@ authoritative control.
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
./scripts/validate-release.sh 2026.08.30-r1
./scripts/validate-release.sh 2026.08.31-r2
```

4. Let pull-request CI test amd64, native arm64, and the 32-bit ARM pure-PHP
Expand All @@ -56,15 +57,17 @@ Do not let the GitHub Release form create a lightweight tag.
```bash
git switch main
git pull --ff-only
git tag -a 2026.08.30-r1 -m "Release 2026.08.30-r1"
git push origin refs/tags/2026.08.30-r1
release=2026.08.31-r2
git tag -a "${release}" -m "Release ${release}"
test "$(git cat-file -t "refs/tags/${release}")" = tag
git push origin "refs/tags/${release}"
```

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.08.30-r1`
- `ghcr.io/soulteary/sqlite-wordpress:2026.08.30-r1`
- `soulteary/sqlite-wordpress:2026.08.31-r2`
- `ghcr.io/soulteary/sqlite-wordpress:2026.08.31-r2`

BuildKit emits an SPDX SBOM and maximum-mode SLSA provenance for each platform.
The merged index receives OCI version, source, revision, and license
Expand All @@ -74,20 +77,30 @@ succeeds.

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.30`) and `latest` without rebuilding.
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 an
unpublished annotated CalVer tag. 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 cannot turn a lightweight tag into an annotated tag or make a tag name
match a different `IMAGE_VERSION`. Keep the failed tag and source release for
audit history, correct the ruleset and source version through a pull request,
increment the revision, and publish a new annotated protected tag. A workflow
that stopped in preflight did not reach the image build or registry publication
jobs.

## Verify and announce

Set the exact tag once for all commands:

```bash
release=2026.08.30-r1
release=2026.08.31-r2
```

1. Confirm both registries expose the same five runtime platforms, SBOM, and
Expand Down
20 changes: 10 additions & 10 deletions VERSIONING.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,24 @@ Immutable releases use:
YYYY.MM.DD-rN
```

- `YYYY.MM.DD` is the release date in UTC.
- `YYYY.MM.DD` is the project release date in `Asia/Shanghai` (UTC+08:00).
- `rN` is a positive revision beginning at `r1`.
- Leading zeroes are required for month and day.
- The date must be a real calendar date.

Examples:

```text
2026.08.30-r1
2026.08.30-r2
2026.08.31-r1
2026.08.31-r2
2026.09.04-r1
```

Use another revision on the same UTC date whenever any published image content
or release evidence changes, including a WordPress or plugin update, a base
image rebuild, project code, labels, SBOM/provenance, or a packaging fix. Start
at `r1` again on a new date. Documentation-only changes do not require an image
release.
Use another revision on the same project release date whenever any published
image content or release evidence changes, including a WordPress or plugin
update, a base image rebuild, project code, labels, SBOM/provenance, or a
packaging fix. Start at `r1` again on a new date. Documentation-only changes do
not require an image release.

The release date identifies when the artifact is prepared for publication; it
does not claim that every bundled component was released on that date. Publish
Expand All @@ -41,8 +41,8 @@ late fixes under their actual release date, and never reuse or move a tag.

| Tag | Example | Mutability | Intended use |
| --- | --- | --- | --- |
| Exact release | `2026.08.30-r1` | Immutable | Deployments, rollback, audit, and signatures |
| Date alias | `2026.08.30` | Mutable within that date | Follow the newest revision published for one date |
| Exact release | `2026.08.31-r2` | Immutable | Deployments, rollback, audit, and signatures |
| Date alias | `2026.08.31` | Mutable within that date | Follow the newest revision published for one date |
| Rolling alias | `latest` | Mutable | Follow the newest complete release |

Production deployments should pin an exact release tag, or preferably its
Expand Down
2 changes: 1 addition & 1 deletion scripts/validate-release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ set -euo pipefail

release_version="${1:-}"
if [[ ! "${release_version}" =~ ^[0-9]{4}\.(0[1-9]|1[0-2])\.(0[1-9]|[12][0-9]|3[01])-r[1-9][0-9]*$ ]]; then
echo "release version must use YYYY.MM.DD-rN CalVer (for example, 2026.08.30-r1)" >&2
echo "release version must use YYYY.MM.DD-rN CalVer (for example, 2026.08.31-r2)" >&2
exit 1
fi

Expand Down
6 changes: 3 additions & 3 deletions tests/test-validate-release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -32,20 +32,20 @@ pinned_digest="${wordpress_image##*@}"
PATH="${fake_bin}:${PATH}" \
FAKE_EXPECTED_REF="${base_image}" \
FAKE_MANIFEST_DIGEST="${pinned_digest}" \
./scripts/validate-release.sh 2026.08.30-r1 --verify-upstream >/dev/null
./scripts/validate-release.sh 2026.08.31-r2 --verify-upstream >/dev/null

mismatch_digest="sha256:0000000000000000000000000000000000000000000000000000000000000000"
if PATH="${fake_bin}:${PATH}" \
FAKE_EXPECTED_REF="${base_image}" \
FAKE_MANIFEST_DIGEST="${mismatch_digest}" \
./scripts/validate-release.sh 2026.08.30-r1 --verify-upstream \
./scripts/validate-release.sh 2026.08.31-r2 --verify-upstream \
>/dev/null 2>"${fake_bin}/mismatch.log"; then
echo "digest mismatch unexpectedly passed" >&2
exit 1
fi
grep -Fq "not pinned digest ${pinned_digest}" "${fake_bin}/mismatch.log"

for invalid_version in 7.1.0 2026.8.30-r1 2026.02.30-r1 2026.08.30-r0; do
for invalid_version in 7.1.0 2026.8.31-r1 2026.02.30-r1 2026.08.31-r0; do
if ./scripts/validate-release.sh "${invalid_version}" >/dev/null 2>"${fake_bin}/invalid.log"; then
echo "invalid release version unexpectedly passed: ${invalid_version}" >&2
exit 1
Expand Down