From 1daae5d70900a47c17b07f70b9700ea6c7e754b1 Mon Sep 17 00:00:00 2001 From: shankar0123 Date: Thu, 14 May 2026 15:01:38 +0000 Subject: [PATCH] =?UTF-8?q?docs(readme):=20fix=20demo=20path=20command=20?= =?UTF-8?q?=E2=80=94=20point=20at=20deploy/demo-up.sh=20wrapper?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Operator reproduction (verbatim log captured 2026-05-14): $ docker compose -f deploy/docker-compose.yml -f deploy/docker-compose.demo.yml up -d --build ... build succeeds, containers come up ... dependency failed to start: container certctl-server is unhealthy $ docker compose ... logs certctl-server | tail -1 certctl-server | Failed to load configuration: phase-2 SEC-H3 fail-closed guard (missing TS): CERTCTL_DEMO_MODE_ACK=true requires CERTCTL_DEMO_MODE_ACK_TS= set within the last 24h — refuse to start. Root cause ========== README.md L95 documented a bare `docker compose ... up` command that ignores the Phase 2 SEC-H3 fail-closed guard added in internal/config/config.go::Validate (commit 2026-05-13). The guard pairs CERTCTL_DEMO_MODE_ACK=true with a required CERTCTL_DEMO_MODE_ACK_TS= that must be within the last 24h, so a forgotten demo deploy doesn't accidentally end up serving production traffic with auth-type=none. The demo overlay (deploy/docker-compose.demo.yml) passes the timestamp through from the shell via `CERTCTL_DEMO_MODE_ACK_TS: "${CERTCTL_DEMO_MODE_ACK_TS:-}"`. The README command never exported it, so the server saw an empty value, the guard refused to boot, the healthcheck never passed, and the dependent certctl-agent container refused to start. The deploy/demo-up.sh wrapper (which already exists; it's used by CI cold-DB smoke and was added in the same SEC-H3 commit chain) mints `CERTCTL_DEMO_MODE_ACK_TS="$(date +%s)"` before exec'ing `docker compose` with the same -f flags. Drop-in replacement for the bare compose invocation. Fix === README.md "Demo path" code block now points at the wrapper script: ./deploy/demo-up.sh -d --build Plus a one-paragraph explanation of why the wrapper is the supported entry point and what the SEC-H3 timestamp gate is defending against. The bare `docker compose ... up` form is documented as failing-closed so a future operator who tries it understands the error message they see. Affected paths ============== - README.md (the Quick Start "Demo path" block; lines 92-100 before, 93-103 after this change) Out of scope (tracked separately if needed) ============================================ - The `WARN[0000] ... defaulting to a blank string` lines on docker compose stdout (POSTGRES_PASSWORD, CERTCTL_API_KEY, etc.) are red herrings — they fire on the BASE compose's env interpolation but the demo overlay immediately overrides those with hardcoded demo-safe values. They're noise; not a footgun. Leaving them alone — silencing the WARN would require either an .env shim or setting empty defaults at the base layer, both of which are worse than the current warn-but-correct behaviour. - The bare `docker compose -f base.yml up` production path (README L108) is unchanged. That path requires a real .env and will fail closed on placeholders — which is the correct behaviour. The README already documents .env setup for that path. --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c95ec89..6095e2d 100644 --- a/README.md +++ b/README.md @@ -92,10 +92,12 @@ Security: three authentication paths — API keys (SHA-256 hashed + constant-tim ```bash git clone https://github.com/certctl-io/certctl.git cd certctl -docker compose -f deploy/docker-compose.yml -f deploy/docker-compose.demo.yml up -d --build +./deploy/demo-up.sh -d --build ``` -Wait ~30 seconds, then open **https://localhost:8443** in your browser. The demo overlay flips the base into demo-mode auth (every request served as the synthetic admin actor `actor-demo-anon` — the server emits a prominent ⚠ DEMO MODE banner at boot reminding you this posture is for evaluation only) and seeds 180 days of realistic history across 13 issuers, 8 agents, managed + discovered certs, jobs, deploys, audit, and notification events. The `certctl-tls-init` init container self-signs an ECDSA-P256 cert on first boot — accept the browser warning for the demo, or feed the generated `ca.crt` to your client. +Wait ~30 seconds, then open **https://localhost:8443** in your browser. The `demo-up.sh` wrapper exports a fresh `CERTCTL_DEMO_MODE_ACK_TS=$(date +%s)` and forwards the remaining args to `docker compose -f docker-compose.yml -f docker-compose.demo.yml up`. The timestamp export is required by the Phase 2 SEC-H3 fail-closed guard in `internal/config/config.go::Validate` — demo deploys must re-ACK every 24h so a forgotten demo container never silently ends up serving production traffic with `auth-type=none`. The bare `docker compose ... up` command without the timestamp refuses to boot; the wrapper script is the supported entry point. + +The demo overlay flips the base into demo-mode auth (every request served as the synthetic admin actor `actor-demo-anon` — the server emits a prominent ⚠ DEMO MODE banner at boot reminding you this posture is for evaluation only) and seeds 180 days of realistic history across 13 issuers, 8 agents, managed + discovered certs, jobs, deploys, audit, and notification events. The `certctl-tls-init` init container self-signs an ECDSA-P256 cert on first boot — accept the browser warning for the demo, or feed the generated `ca.crt` to your client. **Production path — `.env` required, fail-closed on placeholders:**