RunWhen-maintained Spilo PostgreSQL + Patroni container images — built and published to GitHub Container Registry (GHCR) with automated vulnerability scanning.
The upstream zalando/spilo project does not publish regular Docker image releases. This fork:
- Builds independently from upstream master to resolve CVEs on our schedule
- Publishes container images to GHCR (amd64 by default; arm64 available via workflow input)
- Scans every build with Trivy (CRITICAL + HIGH severity)
- Auto-updates dependencies via Renovatebot
- Supports PostgreSQL 16, 17, 18 (matching upstream)
| PostgreSQL | Image | Status |
|---|---|---|
| 18 | ghcr.io/runwhen-contrib/spilo-18 |
Active |
| 17 | ghcr.io/runwhen-contrib/spilo-17 |
Active |
| 16 | ghcr.io/runwhen-contrib/spilo-16 |
Active |
Tags: {git-sha} (immutable) plus latest (rolling). Examples: spilo-18:8a3f2c1b, spilo-18:latest.
# Pull the latest PostgreSQL 18 image
docker pull ghcr.io/runwhen-contrib/spilo-18:latest
# Run a single-node Patroni cluster
docker run -d --name spilo \
-e SCOPE=test \
-e PGVERSION=18 \
ghcr.io/runwhen-contrib/spilo-18:latest# Clone
git clone git@github.com:runwhen-contrib/spilo.git
cd spilo
# Build with default PostgreSQL 18
docker build \
--build-arg PGVERSION=18 \
--build-arg DEMO=false \
--build-arg COMPRESS=false \
-t spilo:local \
postgres-appliance/
# Or use a different version
docker build --build-arg PGVERSION=17 -t spilo-17:local postgres-appliance/SPILO_TEST_IMAGE=spilo:local bash postgres-appliance/tests/test_spilo.sh| Workflow | Trigger | What It Does |
|---|---|---|
build-push.yaml |
Push to main, tag push, manual |
Build → test → push to GHCR → scan (amd64 by default; multiarch input for arm64) |
pr-build.yaml |
PR opened against main |
Trivy fs scan → build → integration test |
trivy-scheduled.yaml |
Weekly (Mondays), manual | Scan all published PG version images |
renovate.yml |
Daily, manual | Auto-update dependencies |
sync-upstream.yaml |
Daily, manual | Bump submodule → open PR with upstream commit log |
Renovatebot tracks:
- PostgreSQL version in Dockerfile
- Patroni version (PyPI)
- wal-g version (GitHub releases)
- PostGIS, bg_mon, pg_auth_mon, pg_mon, plprofiler, pg_profile, pam_oauth2
- Base image (Ubuntu)
- GitHub Actions versions in workflows
Minor/patch updates auto-merge after 3 days. Major updates require manual approval.
Trivy scans run on:
- Every PR (filesystem scan of
postgres-appliance/) - Every push to main/tag (image scan after build)
- Weekly scheduled scan of all published images
- Results uploaded to GitHub Security tab as SARIF
Known false positives are tracked in .trivyignore.
Upstream source lives in postgres-appliance/. We track zalando/spilo:master via a daily sync workflow that opens PRs showing exactly what changed.
We modify build scripts directly to resolve CVEs — bumping pinned component versions, updating base images, and patching dependencies without waiting for upstream releases.
| Capability | How |
|---|---|
| Fix wal-g CVE | Edit ENV WALG_VERSION=v3.1.0 in Dockerfile |
| Update base image | Edit ARG BASE_IMAGE=ubuntu:24.04 |
| Patch an extension | Edit commit ref ENV or modify build script |
| Adopt upstream fixes | Merge the daily sync PR (or cherry-pick commits) |
sync-upstream.yaml opens a PR when upstream has new commits:
- Detects new commits on
zalando/spilo:master - Creates a merge branch with upstream changes
- Opens a PR showing the diff in
postgres-appliance/ - CI runs build → test on the PR
git fetch upstream
git merge upstream/master
# Only possible conflict: README.md → keep our version
git push origin main- Review
postgres-appliance/diffs for CVE fixes and breaking changes - If Dockerfile build args/ENVs changed, update
renovate.json - CI passes (build workflow runs on the sync PR)
- Merge the PR, or cherry-pick specific commits
- Build and push images if CVE fixes were included
Apache 2.0 — see upstream zalando/spilo LICENSE.