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
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ jobs:
--ignorefile .trivyignore.yaml \
--exit-code "$code" \
--format table \
"ghcr.io/simtabi/dbpantry-${ENGINE}:${VERSION}"
"localhost/dbpantry-${ENGINE}:${VERSION}"

- name: Report unfixed findings (never fails)
if: always()
Expand All @@ -191,7 +191,7 @@ jobs:
VERSION: ${{ matrix.entry.version }}
run: |
trivy image --severity HIGH,CRITICAL --exit-code 0 --format table \
"ghcr.io/simtabi/dbpantry-${ENGINE}:${VERSION}" || true
"localhost/dbpantry-${ENGINE}:${VERSION}" || true

# ---------------------------------------------------------------------------
# When the scheduled build fails, say so where people look (design.md D-71).
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ jobs:
run: |
trivy image --severity HIGH,CRITICAL --ignore-unfixed \
--ignorefile .trivyignore.yaml --exit-code 1 --format table \
"ghcr.io/simtabi/dbpantry-${ENGINE}:${VERSION}"
"localhost/dbpantry-${ENGINE}:${VERSION}"

# ---------------------------------------------------------------------------
# Gate 2: the acceptance harness, on both architectures.
Expand Down
22 changes: 19 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ waiving them.

### Upgrade

- **Images are now named `localhost/dbpantry-*`.** Images you built before keep their old
`ghcr.io/simtabi/dbpantry-*` names, which nothing runs any more. Run `make build` once; the next
`make up` recreates the containers on the new names. Volumes and data are untouched. To build,
run and deploy under your own registry instead, export `MDB_IMAGE_PREFIX` (for example
`registry.example.com/team`) before `make build` and `make up` (design.md D-78).
- **Prod: PostgreSQL's own port stops being published.** With the prod overlay applied (see Changed), a prod
stack under `MDB_PUBLISH=direct` publishes the pooler, `pg-pooler` on `MDB_PORT_BASE + 100` (54100 by
default), and no engine port: 54000 and the other engines' ports go away. Point applications at 54100 with
Expand All @@ -29,9 +34,20 @@ waiving them.
- **Container images are no longer published.** A release publishes the GitHub release only, with
the notes and the source tarball (owner, 2026-11-13). The `ghcr.io/simtabi/dbpantry-*` images are
frozen: no new tag is pushed and nothing is deleted from ghcr.io. Build the images with
`make build`. The Kubernetes backend and the Helm chart still name `ghcr.io/simtabi` as their
registry, so push your own build there or point `global.imageRegistry` at your own registry
(design.md D-77).
`make build` (design.md D-77).
- **Images are built, run and deployed as `localhost/dbpantry-<component>:<tag>`,** and nothing
falls back to a remote registry. One default, `MDB_IMAGE_PREFIX=localhost` in
`scripts/env-lib.sh`, replaces every hard-coded registry: Compose, the generated engine and pooler
services, the patroni build, the Makefile, `scripts/{build,upgrade,verify-backups,transfer,scan}`,
the verify checks and the CI scan steps. The Helm chart's `global.imageRegistry` defaults to
`localhost`, `make up` on Kubernetes passes it the prefix the images were built under, and kind
loading follows it; `imagePullPolicy` stays `IfNotPresent`. Setting `MDB_IMAGE_PREFIX` (or
`global.imageRegistry` when installing the chart by hand) prefixes every image. The Kubernetes
guide shows `kind load docker-image`, `minikube image load` and pushing to your own registry.
Check 73 fails if any default names a remote registry or a set prefix stops reaching every image,
and check 49 now resolves every `${VAR:-default}` in an image reference. Checks 42 and 72 recognise
our images as `localhost/dbpantry-*`, and `make init-prod` resolves the caddy image the way Compose
does (`mdb_compose_ref`) before running it (design.md D-78).
- **A release runs on a pushed `vX.Y.Z` tag, or on request for a tag already on GitHub:**
`gh workflow run release.yml --repo simtabi/dbpantry -f tag=vX.Y.Z`. This replaces the dispatch
gated on `-f confirm=release-go` (D-76). Every job checks out the tag, and the first step refuses
Expand Down
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ env_project := $(call env_get,COMPOSE_PROJECT_NAME)
COMPOSE_PROJECT_NAME ?= $(or $(env_project),mdb)
export COMPOSE_PROJECT_NAME
ENV_FILE_PROD ?= .env.prod
# The prefix our images are built and run under: MDB_IMAGE_PREFIX from the
# environment, else the one default in scripts/env-lib.sh (localhost). Set but
# empty counts as unset, as it does for the scripts.
MDB_IMAGE_PREFIX := $(or $(MDB_IMAGE_PREFIX),$(shell bash -c '. scripts/env-lib.sh && mdb_image_prefix' 2>/dev/null))
# Every container call goes through scripts/runtime, which picks Docker, Podman
# or nerdctl (CONTAINER_RUNTIME=auto|docker|podman|nerdctl; design.md D-60).
RUNTIME := scripts/runtime
Expand Down Expand Up @@ -187,7 +191,7 @@ shell: ## Open the cli image (tools with no server required)
--network $(COMPOSE_PROJECT_NAME)_net \
-v "$(CURDIR)/certs:/certs:ro" \
-v "$(CURDIR)/backups:/work/backups" \
ghcr.io/simtabi/dbpantry-cli:dev
$(MDB_IMAGE_PREFIX)/dbpantry-cli:dev

.PHONY: new-project
new-project: ## Provision DB + roles + extensions, print the Laravel .env block
Expand Down
5 changes: 3 additions & 2 deletions compose.ha.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ x-patroni: &patroni
dockerfile: patroni/Dockerfile
args:
ENGINE_VERSION: ${MDB_PG_VERSION:-17}
image: ghcr.io/simtabi/dbpantry-patroni:${MDB_PG_VERSION:-17}
IMAGE_PREFIX: ${MDB_IMAGE_PREFIX:-localhost}
image: ${MDB_IMAGE_PREFIX:-localhost}/dbpantry-patroni:${MDB_PG_VERSION:-17}
profiles: [ha]
restart: unless-stopped
networks: [mdb]
Expand Down Expand Up @@ -210,7 +211,7 @@ services:
# ---------------------------------------------------------------------------
pgbouncer:
profiles: [ha-pooler]
image: ghcr.io/simtabi/dbpantry-pgbouncer:dev
image: ${MDB_IMAGE_PREFIX:-localhost}/dbpantry-pgbouncer:dev
restart: unless-stopped
depends_on:
haproxy: {condition: service_healthy}
Expand Down
10 changes: 7 additions & 3 deletions deploy/helm/dbpantry/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@
# engines you want and create the Secret named in global.secretName first.

global:
# Registry and repository prefix for the dbpantry images. The tag is each
# engine's version (engines.<name>.tag).
imageRegistry: ghcr.io/simtabi
# Registry and repository prefix for the dbpantry images, which are named
# <imageRegistry>/dbpantry-<engine>:<tag> (the tag is engines.<name>.tag).
# localhost is the name `make build` gives them, so a kind or minikube
# cluster runs images loaded into it (docs/guides/kubernetes.md). Set it to
# your own registry (registry.example.com/team) after pushing them there.
# No dbpantry image is published to any public registry.
imageRegistry: localhost
imagePullPolicy: IfNotPresent
imagePullSecrets: []
# "" uses the cluster's default StorageClass.
Expand Down
12 changes: 7 additions & 5 deletions design.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Everything below was verified during this session against live registries, the G
| Field | Value |
|---|---|
| Repository | `github.com/simtabi/dbpantry` (was `dbpantry-docker`, and before that `db-toolkit-docker`) |
| Images | `ghcr.io/simtabi/dbpantry-{pg,mysql,mariadb,cli}` |
| Images | `localhost/dbpantry-{pg,mysql,mariadb,cli}`, built locally (`MDB_IMAGE_PREFIX`, D-78); not published |
| Docs | [`docs/`](docs/) in this repository; no hosted site yet |
| Product page | none yet |
| Env prefix | `MDB_` |
Expand All @@ -22,9 +22,9 @@ Resolves the three-way conflict recorded in decision **D-02**.

| Service | Image | Profile | Internal port | Host port env | Published by default |
|---|---|---|---|---|---|
| `pg` | `ghcr.io/simtabi/dbpantry-pg:<ver>` | `pg` | 5432 | `MDB_PG_HOST_PORT` | no |
| `mysql` | `ghcr.io/simtabi/dbpantry-mysql:<ver>` | `mysql` | 3306 | `MDB_MYSQL_HOST_PORT` | no |
| `mariadb` | `ghcr.io/simtabi/dbpantry-mariadb:<ver>` | `mariadb` | 3306 | `MDB_MARIADB_HOST_PORT` (3307) | no |
| `pg` | `localhost/dbpantry-pg:<ver>` | `pg` | 5432 | `MDB_PG_HOST_PORT` | no |
| `mysql` | `localhost/dbpantry-mysql:<ver>` | `mysql` | 3306 | `MDB_MYSQL_HOST_PORT` | no |
| `mariadb` | `localhost/dbpantry-mariadb:<ver>` | `mariadb` | 3306 | `MDB_MARIADB_HOST_PORT` (3307) | no |
| `adminer` | `adminer:5.4.1` | `ui` | 8080 | `MDB_ADMINER_HOST_PORT` | no (via Caddy) |
| `phpmyadmin` | `phpmyadmin:5.2.3` | `ui` | 80 | `MDB_PMA_HOST_PORT` | no (via Caddy) |
| `pgadmin` | `dpage/pgadmin4:9.9` | `ui` | 80 | `MDB_PGADMIN_HOST_PORT` | no (via Caddy) |
Expand All @@ -36,7 +36,7 @@ Resolves the three-way conflict recorded in decision **D-02**.
| `pgbouncer` | `dbpantry-pgbouncer` (built) | `prod` (required), `ha` | 6432 | `MDB_PGBOUNCER_HOST_PORT` | no |
| `etcd` | `gcr.io/etcd-development/etcd:v3.6.6` | `ha` | 2379/2380 | — | no |
| `haproxy` | `haproxy:3.2-alpine` | `ha` | 5432 w / 5433 r | `MDB_HAPROXY_*_PORT` | no |
| `cli` | `ghcr.io/simtabi/dbpantry-cli:<ver>` | on demand | — | — | no |
| `cli` | `localhost/dbpantry-cli:<ver>` | on demand | — | — | no |

The exporter rows match `docker-compose.yml` as of 2026-11-03. The compose files are the source of truth for every image here; the `etcd`, `haproxy` and `caddy` rows above still show the step 1 plan and differ from `compose.ha.yml` (`quay.io/coreos/etcd:v3.5.21`, `haproxy:3.0-alpine`) and `docker-compose.yml` (the built `dbpantry-caddy` image).

Expand Down Expand Up @@ -492,6 +492,8 @@ Relied on: pgBouncer configuration reference (<https://www.pgbouncer.org/config.

**D-77: a release publishes the GitHub release only, on a pushed version tag or on request; images stop.** Supersedes D-76's trigger and D-56's image publishing, and nothing else in them. The owner decided on 2026-11-13 that every Go repository ships on its GitHub release only, with no container registry among the channels, and answered "Yes, stop images" for dbpantry. `release.yml` loses its publish and manifest jobs: the registry login, the per-architecture push, the SBOM and provenance attested to the registry, the multi-architecture manifest and its provenance, and the `packages: write` they needed. Nothing is deleted from ghcr.io, and measured that day no dbpantry package existed there, so no consumer could have pulled one. The scan and verify gates stay: the images are still the product, every user builds them with `make build`, and a release still refuses a tag whose images do not build or carry a fixable finding. The GitHub release now needs scan and verify instead of the manifest job. The triggers become the org's pair: a pushed `v[0-9]+.[0-9]+.[0-9]+` tag, and `workflow_dispatch` with a required `tag` input (`gh workflow run release.yml --repo simtabi/dbpantry -f tag=vX.Y.Z`), replacing `confirm=release-go`. The tag is `inputs.tag || github.ref_name`; the first step refuses anything but a `vX.Y.Z[-pre]` tag that exists on GitHub, the next step still refuses a pre-release, and every job checks out `refs/tags/<tag>`, because a dispatch's `GITHUB_SHA` is its branch's head, not the tag's commit: the tag-on-`main` check now tests `HEAD` after that checkout. No pre-release tag filter is declared, since dbpantry refuses pre-releases. dbpantry builds no release binaries, so it keeps its own jobs rather than calling `simtabi/.github`'s shared `go-release.yml`, which runs GoReleaser. The Kubernetes backend (`scripts/backends/kubernetes.sh`) and the Helm chart (`global.imageRegistry: ghcr.io/simtabi`) still name the frozen registry; changing them is a separate decision. The guard is `src/internal/release`'s `TestReleaseRunsOnAVersionTagOrOnRequest`, which fails on any other trigger, a branch or non-version tag filter, a missing or optional `tag` input, a first step that is not the refusal, a checkout of anything but the tag, a job that does not need the gating job, or any image publish (registry login or push, `buildx --push`, `imagetools create`, `push-to-registry: true`, a `docker/` publish action, `packages: write`); `TestReleasePolicyRejectsAWrongRelease` proves each can fail, and that a local build and scan passes.

**D-78: our images are named localhost/dbpantry-*, from one default, and nothing names a remote registry.** Follows D-77. With images no longer published, `ghcr.io/simtabi/dbpantry-*` stayed the name every image was built, run and deployed under: `scripts/build` defaulted `MDB_IMAGE_PREFIX` to it, Compose, the generated engine services, the pooler descriptor, the patroni Dockerfile, the Makefile, five scripts, six checks and both workflows wrote it out, the Helm chart's `global.imageRegistry` defaulted to it, and the Kubernetes backend loaded it into kind. A cluster without an image therefore pulled from a registry that holds nothing. The owner chose `localhost/` (2026-11-13) over an unqualified `dbpantry/<component>`, which check 49 refuses because Podman will not resolve a short name (D-60) and which Docker would expand to Docker Hub on a pull; `localhost` is fully qualified, is the prefix Podman gives local builds, never reaches a remote registry, and loads into kind and minikube as it is. The default is written once, `MDB_IMAGE_PREFIX_DEFAULT=localhost` in `scripts/env-lib.sh`, with `mdb_image_prefix`, `mdb_image` and `mdb_image_ref` (which moves a descriptor's `localhost/dbpantry-pgbouncer:dev` to the prefix in force); the Makefile reads it from there. Files that cannot read it repeat it: Compose as `${MDB_IMAGE_PREFIX:-localhost}`, the patroni Dockerfile's `ARG IMAGE_PREFIX`, the chart's `global.imageRegistry`, the pooler descriptor, and the CI scan steps, which build with the default. `MDB_IMAGE_PREFIX` stays an environment variable, as before, not a `.env` setting. On Kubernetes, `scripts/helm-values` renders `global.imageRegistry` from it and `_mdb_k8s_local_images` reads that back, so kind loads exactly the names the chart runs; `imagePullPolicy` stays `IfNotPresent`. Check 49's Compose parser resolved only a leading `${VAR:-default}`, which misread a prefixed reference as `localhost}/...`; it now resolves every one, innermost first, and still counts 55 references. Check 73 holds every default to `localhost`, fails on a dotted registry before `dbpantry-` in any tracked file but prose, limits `ghcr.io/simtabi` to nine files that describe the frozen images or their history (each at its measured count), and proves that a set prefix reaches `mdb_image`, the pooler, `make shell`, helm-values, kind loading and the rendered chart. Images built before keep their old names: `make build` once, and the next `make up` recreates the containers; volumes are untouched. The first CI run of this change failed four checks, each a reader of the old name the literal search missed: check 42 allowlisted our images as `ghcr\.io/simtabi/[a-z-]+` and check 72 recognised them by the same regex, so both now name `localhost/dbpantry-*` (72 under the prefix in force); `scripts/init` passed the caddy service's raw `image:` line to `run`, which is now Compose syntax, so it resolves it with `mdb_compose_ref` and `make init-prod` (check 26) works again; and check 73 itself listed one image in CI because `make verify` exports `COMPOSE_PROFILES`, which `helm-values` ranks above the `MDB_PROFILES` the check set. Check 73 now sets both, counts the escaped spelling too, and fails on any script that runs a Compose `image:` line without `mdb_compose_ref`. A check run directly is not the check `make verify` runs: reproduce through `make verify CHECKS=`.

## 8. arm64 deliverability

**Nothing in the spec is undeliverable on arm64.** The named unknown anticipated gaps that do not exist:
Expand Down
8 changes: 4 additions & 4 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ services:
build:
context: ./images
dockerfile: caddy/Dockerfile
image: ghcr.io/simtabi/dbpantry-caddy:dev
image: ${MDB_IMAGE_PREFIX:-localhost}/dbpantry-caddy:dev
restart: unless-stopped
<<: *hardening
# Binding 80/443 needs this one capability back; everything else stays
Expand Down Expand Up @@ -159,7 +159,7 @@ services:
# ---------------------------------------------------------------------------
backup-pg:
profiles: [backup]
image: ghcr.io/simtabi/dbpantry-pg:${MDB_PG_VERSION:-17}
image: ${MDB_IMAGE_PREFIX:-localhost}/dbpantry-pg:${MDB_PG_VERSION:-17}
restart: unless-stopped
<<: *hardening
entrypoint: ["/mdb/scripts/backup", "--engine", "pg", "--schedule"]
Expand Down Expand Up @@ -213,7 +213,7 @@ services:

backup-mysql:
profiles: [backup]
image: ghcr.io/simtabi/dbpantry-mysql:${MDB_MYSQL_VERSION:-8.4}
image: ${MDB_IMAGE_PREFIX:-localhost}/dbpantry-mysql:${MDB_MYSQL_VERSION:-8.4}
restart: unless-stopped
<<: *hardening
entrypoint: ["/mdb/scripts/backup", "--engine", "mysql", "--schedule"]
Expand Down Expand Up @@ -266,7 +266,7 @@ services:

backup-mariadb:
profiles: [backup]
image: ghcr.io/simtabi/dbpantry-mariadb:${MDB_MARIADB_VERSION:-11.8}
image: ${MDB_IMAGE_PREFIX:-localhost}/dbpantry-mariadb:${MDB_MARIADB_VERSION:-11.8}
restart: unless-stopped
<<: *hardening
entrypoint: ["/mdb/scripts/backup", "--engine", "mariadb", "--schedule"]
Expand Down
2 changes: 1 addition & 1 deletion docs/guides/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ MDB_ENGINE_DUMP_GLOBALS='pg_dumpall --globals-only'
MDB_ENGINE_RESTORE='pg_restore --no-owner'

MDB_ENGINE_POOLING=external
MDB_ENGINE_POOLER_IMAGE=ghcr.io/simtabi/dbpantry-pgbouncer:dev
MDB_ENGINE_POOLER_IMAGE=localhost/dbpantry-pgbouncer:dev
MDB_ENGINE_POOLING_REQUIRED_IN_PROD=true

MDB_ENGINE_LICENSE=PostgreSQL
Expand Down
Loading
Loading