Skip to content

The rig-backup image (rig-gitops#897, P3)

The Dell's backup CronJobs dump Postgres, encrypt each dump to an age recipient and upload the ciphertext to R2 (plan: rig-gitops#897). This image holds the tools for that and nothing else. Nothing references it yet; P5 does.

  • Dockerfile: deploy/backup-image/Dockerfile
  • Workflow: .github/workflows/publish-backup-image.yml
  • Security review: claude-3 docs/ai-tooling-registry/backup/2026-10-03-security-review-rig-backup-age-jq-curl.md. Its conditions on how each tool may be called bind the scripts (P4), not just this image.

What is in it

Component Pin Source
Base docker.io/pgvector/pgvector:0.8.7-pg16-trixie@sha256:40d828eda66737aaacb934387a337babf1455ebd56e9bdd13fc08e211257c972 Docker Hub, by index digest. PostgreSQL 16.15 on Debian trixie
age age=1.2.1-1+b5 Debian trixie
jq jq=1.7.1-6+deb13u4, libjq1 at the same version Debian trixie-security
curl curl=8.14.1-2+deb13u5, libcurl4t64 at the same version Debian trixie
ca-certificates ca-certificates=20250419 Debian trixie. The base purges it, and curl needs it for TLS
openssl openssl=3.5.7-1~deb13u3, libssl3t64 at the same version Debian trixie-security (DSA-6531-1). Already in the base through postgresql-common → ssl-cert, but unpinned; pinned for the openssl review's condition 6.1.1 (P3b), since it signs backup runs (P6)

apt-get install --no-install-recommends adds those and their dependencies only. The build fails if any age-plugin-* file exists, and prints every installed package with its version.

  • User: 999:999, the base's postgres user.
  • HOME=/nonexistent: jq imports ~/.jq on every run, and curl, psql and libpq read ~/.curlrc, ~/.psqlrc and ~/.pgpass. None can exist.
  • Nothing phones home. No health check, no telemetry and no baked-in URL. The only network access is apt at build.
  • No script. ENTRYPOINT is /usr/local/bin/rig-backup.sh, which P4 writes and P5 mounts from a ConfigMap, so a script fix needs no rebuild. Until then the container fails to start; it never runs docker-entrypoint.sh or the server.

Why PostgreSQL 16. pg_dump must be at least the server's major version. The rig's server is pgvector/pgvector:pg16@sha256:7d400e34…, PostgreSQL 16.13 (deploy/k8s/postgres.yaml:42, deployment). The backup base is a different, reviewed digest of the same family: 16.15, the same major. The review doesn't cover the server's digest, so this image doesn't use it. Re-pinning the server to another major means re-pinning this base.

Publishing

Event What happens
Pull request touching deploy/backup-image/** or the workflow Build, smoke test, package list. No push
Push to main (same paths), or manual dispatch on main The same, then push ghcr.io/dashecorp/rig-backup:sha-<40-hex commit> and record the digest in the run summary
  • Tags: only sha-<full commit SHA>, never latest. Manifests reference the image by tag and digest.
  • Actions: actions/checkout, docker/login-action and docker/build-push-action, the three this repo already uses, each pinned to the commit its current major tag points to. Permissions are contents: read and packages: write, with GITHUB_TOKEN for GHCR.
  • Smoke test: runs age --version, jq --version, curl -q --version and pg_dump --version in the built image, with the network off and the entrypoint overridden, and fails unless each shows the pinned upstream version. Debian's jq 1.7.1 prints jq-1.7, so it also checks every apt pin's exact Debian version with dpkg-query.
  • Package list: the run summary lists every package the image adds to the base. The review needs that list on the image PR: anything outside curl's dependency closure plus jq, libjq1, libonig5, age, ca-certificates and openssl is a finding.

Known gaps

  • No provenance or SBOM attestation. Both need an attestation-capable builder (docker/setup-buildx-action, and BuildKit's SBOM scanner image), which have no security review. The build sets provenance: false and sbom: false so the default docker driver works. Attestation tooling gets its own review in a follow-up issue.
  • The base digest was read from the Docker Hub API in the review, not checked against the registry.

Bumping a pin

Every pin is a row in the security review. A bump needs a new or updated registry entry in claude-3 first, then a PR here that changes the Dockerfile only.

Change What it needs
New Debian revision of the same upstream version (+deb13uN, +bN) Row update after reading its changelog and any DSA. Debian keeps only the current version per suite, so the old pin stops resolving and the build fails: that failure is the trigger
New upstream version of age, jq or curl A new security review
Base digest Row update with the same check: layers 1 to 14 equal to the official postgres:16.x-trixie of that version, the rest equal to pgvector's Dockerfile at the tag, PG_MAJOR equal to the server's major. At least monthly, and on any DSA for a package in the image

After the bump merges, take the new digest from the run summary and update the manifests that pin it.