mirror of
https://github.com/shankar0123/certctl.git
synced 2026-06-07 16:31:33 +00:00
072e2af198
Fourth latent bug surfaced by the Auditable Codebase Bundle's cold-DB compose smoke. CI run on master tip5b151e74fails with: certctl-postgres | FATAL: password authentication failed for user "certctl" (SQLSTATE 28P01 — invalid_password) after every other auth gate has been satisfied. The earlier closures (6d0f774DEMO_MODE_ACK,910097emigration 000043 idempotency,58b1441bootstrap-token interpolation) all hold; this one is a different interpolation gap. Root cause: the base compose at deploy/docker-compose.yml:177 builds the certctl-server's database URL via compose-level interpolation: CERTCTL_DATABASE_URL: ${CERTCTL_DATABASE_URL:-postgres://certctl:${POSTGRES_PASSWORD}@postgres:5432/certctl?sslmode=disable} The inner ${POSTGRES_PASSWORD} reads the SHELL environment, not the postgres service's environment: block. The demo overlay sets POSTGRES_PASSWORD: certctl on the postgres service (which feeds postgres's initdb only — that's why the database is seeded with password 'certctl'), but never exports it as a compose-level shell var. In a zero-env-var CI run the shell var is blank, so the generated URL is: postgres://certctl:@postgres:5432/certctl?sslmode=disable ^ empty password while postgres rejects with SCRAM mismatch because its pg_authid holds the hash of 'certctl'. Pre-CI, this gap was masked because every developer running the demo locally had POSTGRES_PASSWORD=certctl in their shell or deploy/.env from earlier sessions; the cold-DB smoke is the first zero-env-var consumer of this overlay. Fix: pin CERTCTL_DATABASE_URL with the literal demo password in the demo overlay's certctl-server environment block. The base compose's ${CERTCTL_DATABASE_URL:-...} default is overlay-overridable, so this literal is overlay-scoped — production deploys that supply their own CERTCTL_DATABASE_URL still win. The overlay was always claimed self-sufficient by its docstring ('Supplies the change-me-... placeholder values for POSTGRES_PASSWORD, CERTCTL_API_KEY, CERTCTL_CONFIG_ENCRYPTION_KEY, and CERTCTL_AGENT_ID so the demo runs without a deploy/.env file') — this commit makes the database URL actually match that claim. Same pattern as the58b1441BOOTSTRAP_TOKEN fix: when compose-level interpolation reads from the shell, the overlay's environment: block alone is not enough; the variable that references it must also be pinned explicitly. Verified: YAML parse clean (python3 yaml.safe_load). All 35 scripts/ci-guards/*.sh green, including complete-path-config-coverage.sh (CERTCTL_DATABASE_URL has a non-config consumer in deploy/), G-3-env-docs-drift, B2-compose-base-no-demo-env, S-1-hardcoded-source-counts.
105 lines
5.4 KiB
YAML
105 lines
5.4 KiB
YAML
# =============================================================================
|
|
# certctl DEMO overlay — Bundle 2 (2026-05-12)
|
|
# =============================================================================
|
|
#
|
|
# Layered on top of the production-shaped base (docker-compose.yml) to give
|
|
# operators a one-command, zero-config demo path:
|
|
#
|
|
# docker compose -f deploy/docker-compose.yml \
|
|
# -f deploy/docker-compose.demo.yml up -d --build
|
|
#
|
|
# What this overlay does:
|
|
#
|
|
# 1. Flips CERTCTL_AUTH_TYPE=none + CERTCTL_DEMO_MODE_ACK=true. Every
|
|
# request is served as the synthetic admin actor `actor-demo-anon`;
|
|
# the server emits a prominent ⚠ DEMO MODE WARN banner at boot with
|
|
# a production-promotion checklist (cmd/server/main.go::emitDemoBanner).
|
|
#
|
|
# 2. Flips CERTCTL_KEYGEN_MODE=server (the demo issues + holds the key on
|
|
# the server to keep the dashboard populated; production deploys must
|
|
# use the default `agent` mode where keys never leave the agent box).
|
|
#
|
|
# 3. Flips CERTCTL_DEMO_SEED=true. The server applies migrations/seed_demo.sql
|
|
# at boot via postgres.RunDemoSeed AFTER baseline migrations + seed.sql,
|
|
# pre-seeding 180 days of simulated history across 13 issuers + 8 agents.
|
|
#
|
|
# 4. Supplies the change-me-... placeholder values for POSTGRES_PASSWORD,
|
|
# CERTCTL_API_KEY, CERTCTL_CONFIG_ENCRYPTION_KEY, and CERTCTL_AGENT_ID
|
|
# so the demo runs without a deploy/.env file. The Bundle 2 fail-closed
|
|
# Validate() rejects these placeholders outside demo mode, so this only
|
|
# works alongside DEMO_MODE_ACK=true.
|
|
#
|
|
# U-3 history: pre-U-3 this overlay mounted seed_demo.sql into postgres
|
|
# `/docker-entrypoint-initdb.d/`. That worked only because the production
|
|
# stack also mounted the migrations there. Once U-3 dropped the production
|
|
# initdb mounts (single source of truth: server runs RunMigrations + RunSeed
|
|
# at boot), the demo seed could no longer be applied at initdb time — the
|
|
# tables it references wouldn't exist yet. Post-U-3 the overlay just sets
|
|
# CERTCTL_DEMO_SEED=true; the server applies seed_demo.sql at boot via
|
|
# postgres.RunDemoSeed AFTER baseline migrations + seed.sql.
|
|
#
|
|
# Bundle 2 history: pre-Bundle-2 the base compose IS this demo path; this
|
|
# overlay was a single-flag thin shim. Bundle 2 split the demo env vars
|
|
# out of the base so `docker compose -f deploy/docker-compose.yml up`
|
|
# (no overlay) boots production-shaped — which is what every operator
|
|
# reading the README quickstart line "drop the demo overlay for a clean
|
|
# install" expected. The overlay carries the full demo posture now.
|
|
#
|
|
# To start fresh (wipe previous data):
|
|
# docker compose -f deploy/docker-compose.yml \
|
|
# -f deploy/docker-compose.demo.yml down -v
|
|
# docker compose -f deploy/docker-compose.yml \
|
|
# -f deploy/docker-compose.demo.yml up -d --build
|
|
|
|
services:
|
|
postgres:
|
|
# Fixed weak password is intentional for the no-setup demo path.
|
|
# See docker-compose.yml for the production override pattern.
|
|
environment:
|
|
POSTGRES_PASSWORD: certctl
|
|
|
|
certctl-server:
|
|
environment:
|
|
# Demo-mode auth: every request served as the synthetic
|
|
# `actor-demo-anon` admin. The server's HIGH-12 startup guard
|
|
# requires DEMO_MODE_ACK=true to allow this combination on a
|
|
# non-loopback bind; the boot-time WARN banner (cmd/server/main.go)
|
|
# reminds the operator on every start.
|
|
CERTCTL_AUTH_TYPE: none
|
|
CERTCTL_DEMO_MODE_ACK: "true"
|
|
# Server-side keygen so the demo can populate the dashboard with
|
|
# full lifecycle history. Production deploys leave this at the
|
|
# code default `agent` (CertctlAgent generates ECDSA P-256 keys
|
|
# locally and submits CSRs only).
|
|
CERTCTL_KEYGEN_MODE: server
|
|
# Demo creds — the Bundle 2 fail-closed Validate() rejects these
|
|
# sentinels outside demo mode, but DEMO_MODE_ACK=true unlocks them.
|
|
CERTCTL_CONFIG_ENCRYPTION_KEY: change-me-32-char-encryption-key
|
|
CERTCTL_AUTH_SECRET: change-me-in-production
|
|
# Cold-DB smoke fix (2026-05-13): the base compose builds the
|
|
# database URL via compose-level `${POSTGRES_PASSWORD}` interpolation
|
|
# (deploy/docker-compose.yml line ~177), which reads the SHELL env —
|
|
# NOT the postgres service's `environment:` block above (that one
|
|
# feeds the postgres container's initdb only). In a zero-env-var
|
|
# CI run the shell var is blank, producing
|
|
# `postgres://certctl:@postgres:5432/...` and a SCRAM rejection
|
|
# against a database that initdb seeded with password `certctl`.
|
|
# Pinning the full URL here closes the gap: the demo overlay is
|
|
# now fully self-sufficient (matches the file's docstring claim)
|
|
# and the cold-DB smoke passes against a fresh GitHub-runner clone
|
|
# with no .env file or exported shell vars. Production deploys
|
|
# override CERTCTL_DATABASE_URL via the base compose's
|
|
# `${CERTCTL_DATABASE_URL:-...}` default, so this literal is
|
|
# overlay-scoped and never leaks into a production posture.
|
|
CERTCTL_DATABASE_URL: postgres://certctl:certctl@postgres:5432/certctl?sslmode=disable
|
|
# 180-day simulated history seed applied at boot.
|
|
CERTCTL_DEMO_SEED: "true"
|
|
|
|
certctl-agent:
|
|
environment:
|
|
# Pre-seeded by migrations/seed_demo.sql; the bundled agent
|
|
# connects with these creds and the demo-mode synthetic admin
|
|
# accepts every request regardless of API key.
|
|
CERTCTL_API_KEY: change-me-in-production
|
|
CERTCTL_AGENT_ID: agent-demo-1
|