mirror of
https://github.com/shankar0123/certctl.git
synced 2026-06-07 20:11:31 +00:00
25996f86fa
Phase 2 SEC-H3 (commit 69a2b5c) added a fail-closed requirement: when
CERTCTL_DEMO_MODE_ACK=true, the server refuses to start unless
CERTCTL_DEMO_MODE_ACK_TS=<unix-epoch> is set and within the last 24h.
The demo overlay (docker-compose.demo.yml) sets DEMO_MODE_ACK=true
but didn't supply the paired TS, so:
Failed to load configuration: phase-2 SEC-H3 fail-closed guard
(missing TS): CERTCTL_DEMO_MODE_ACK=true requires
CERTCTL_DEMO_MODE_ACK_TS=<unix-epoch> set within the last 24h —
refuse to start.
This bricks the cold-DB compose smoke job, the README quickstart
(`docker compose -f .yml -f demo.yml up`), and every operator using
the demo overlay locally — symptom: certctl-server container restart
loop with the SEC-H3 message above.
Fix is three-piece:
1. deploy/docker-compose.demo.yml passes the TS through from the
shell env via `CERTCTL_DEMO_MODE_ACK_TS: "${CERTCTL_DEMO_MODE_ACK_TS:-}"`.
The overlay can't hardcode the value (it would rot the next day)
and SEC-H3 is designed to refresh on every up.
2. deploy/demo-up.sh — new helper that mints
`CERTCTL_DEMO_MODE_ACK_TS=$(date +%s)` and forwards args to
`docker compose up`. The SEC-H3 error message points operators
at it. Replaces the bare `docker compose -f ... up` invocation
in the overlay's docstring + README quickstart references.
3. .github/workflows/ci.yml cold-db-compose-smoke job exports a fresh
TS before the initial up-d AND re-emits it into /tmp/_smoke.env so
the force-recreate at step 4 inherits the value (--env-file replaces
the shell-env source for compose-file interpolation, so omitting the
re-emission would re-trip the guard).
Other CI compose surfaces verified clean:
- docker-compose.test.yml uses auth=api-key (not demo-mode); not
affected.
- security-deep-scan.yml uses the base compose without the demo
overlay; not affected.
Verified locally: YAML parses, bash syntax check passes on demo-up.sh,
overlay's docstring + the SEC-H3 error message now agree on the helper
script's existence.
126 lines
6.6 KiB
YAML
126 lines
6.6 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:
|
|
#
|
|
# deploy/demo-up.sh -d --build
|
|
#
|
|
# (which forwards args to `docker compose up` after exporting the fresh
|
|
# CERTCTL_DEMO_MODE_ACK_TS that Phase 2 SEC-H3 requires). Equivalent
|
|
# manual invocation:
|
|
#
|
|
# CERTCTL_DEMO_MODE_ACK_TS=$(date +%s) 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).
|
|
# Phase 2 SEC-H3 (2026-05-13) pairs DEMO_MODE_ACK with a required
|
|
# DEMO_MODE_ACK_TS within the last 24h. The overlay reads
|
|
# ${CERTCTL_DEMO_MODE_ACK_TS:-} from the shell — use deploy/demo-up.sh
|
|
# (which exports a fresh TS) instead of bare `docker compose up`.
|
|
#
|
|
# 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
|
|
# deploy/demo-up.sh -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"
|
|
# Phase 2 SEC-H3 (2026-05-13): DEMO_MODE_ACK=true requires a fresh
|
|
# DEMO_MODE_ACK_TS within the last 24h. The overlay can't hardcode
|
|
# a timestamp (it would rot the next day), so we passthrough from
|
|
# the shell. Operators set this via:
|
|
# CERTCTL_DEMO_MODE_ACK_TS=$(date +%s) docker compose \
|
|
# -f docker-compose.yml -f docker-compose.demo.yml up -d
|
|
# The cold-DB smoke + any helper script (deploy/demo-up.sh, when
|
|
# it lands) export this before invoking compose. Empty value
|
|
# fails the SEC-H3 guard with a clear operator-facing error
|
|
# message pointing at this line.
|
|
CERTCTL_DEMO_MODE_ACK_TS: "${CERTCTL_DEMO_MODE_ACK_TS:-}"
|
|
# 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
|