The README's Quick Start, the qa-prerequisites contributor doc, and the
landing page (separate repo, separate commit) all shipped a copy-paste
command that produces:
service "certctl-server" has neither an image nor a build context
specified: invalid compose project
The bug landed silently with commit df4b567 (the U-3 master). Pre-U-3,
docker-compose.demo.yml was self-contained and could be invoked with a
single -f flag. U-3 deliberately reduced it to a 27-line overlay — its
only payload today is `CERTCTL_DEMO_SEED=true` on the certctl-server
service — because the demo seed now applies at boot via
postgres.RunDemoSeed, not via /docker-entrypoint-initdb.d/. The overlay
no longer carries an image: or build: of its own, so it MUST be passed
alongside the base file.
The README/qa-doc/landing-page never picked up the rename of the contract.
Every operator who copy-pasted the Quick Start since U-3 has hit the
"invalid compose project" error and bounced. The operator caught it
running the demo locally today.
This commit fixes the three certctl-repo sites:
README.md (Quick Start)
docker compose -f deploy/docker-compose.demo.yml up -d --build
→
docker compose -f deploy/docker-compose.yml -f deploy/docker-compose.demo.yml up -d --build
Plus the "drop the -f flag for clean install" prose now spells out
the correct fallback (`-f deploy/docker-compose.yml` alone).
docs/contributor/qa-prerequisites.md (Step 1)
Same single-file → two-file fix, plus an inline note explaining
why the override-only file requires the base (so the next person
who reads it understands the contract instead of re-discovering it).
deploy/ENVIRONMENTS.md (Demo Overlay → What it adds)
Replaced the stale "One line: mounts seed_demo.sql into PostgreSQL's
init directory" claim — that hasn't been true since U-3 — with the
accurate "One env var: CERTCTL_DEMO_SEED=true; server applies
seed_demo.sql at boot via postgres.RunDemoSeed" description, plus
the historical context for why the overlay can't stand alone.
The certctl.io landing page hits the same bug (line 759); fix shipping
in a separate commit in that repo.
Acceptance gate (manual):
- copy/paste the new README Quick Start command end-to-end against
a fresh clone — succeeds, dashboard at https://localhost:8443
shows the seeded demo data within ~30s.
- clean-install fallback (`docker compose -f deploy/docker-compose.yml
up -d --build`) starts a working stack with no demo data.
4.5 KiB
QA Prerequisites
Last reviewed: 2026-05-05
Operational prereqs for running release QA against certctl. Before any of the contributor-facing testing surfaces (test-environment.md, gui-qa-checklist.md, release-sign-off.md) are useful, the local stack needs to be in a known-good state.
Why manual QA on top of automated tests?
Automated tests mock dependencies and run in isolation. Manual QA validates the full integrated stack: real PostgreSQL, real HTTP, real agent binary, real file I/O, real scheduler timing. It catches issues that unit tests can't: migration ordering, Docker networking, env var parsing, browser rendering, and timing-dependent scheduler behavior.
Environment setup
Step 1: Start the full stack.
cd deploy && docker compose -f docker-compose.yml -f docker-compose.demo.yml up --build -d
This builds three containers (postgres, certctl-server, certctl-agent) and runs them on a bridge network. The --build flag ensures you're testing the current code, not a stale image. The demo overlay is an override file (no image: or build: of its own) that layers CERTCTL_DEMO_SEED=true onto the base — both files must be passed in that order or compose errors with service "certctl-server" has neither an image nor a build context specified. The seed populates the database with realistic fixtures.
Step 2: Wait for healthy state.
for i in $(seq 1 30); do
STATUS=$(docker compose ps --format json 2>/dev/null | jq -r 'select(.Health != null) | "\(.Name): \(.Health)"' 2>/dev/null)
echo "$STATUS"
echo "$STATUS" | grep -q "unhealthy\|starting" || break
sleep 2
done
Why: Docker Compose starts containers in dependency order (postgres → server → agent), but "started" doesn't mean "ready." Health checks confirm postgres accepts connections, the server responds on /health, and the agent process is running.
Step 3: Set shell variables used throughout the QA flow.
export SERVER=https://localhost:8443
export API_KEY="change-me-in-production"
export AUTH="Authorization: Bearer $API_KEY"
export CT="Content-Type: application/json"
export CACERT="--cacert ./deploy/test/certs/ca.crt"
Every curl command in QA docs uses these variables. Setting them once avoids typos and keeps the docs copy-pasteable.
Note: The default Docker Compose sets
CERTCTL_AUTH_TYPE: nonefor the demo overlay, meaning auth is disabled. Tests that exercise auth require flipping this toapi-key; instructions are in the relevant test docs.
Step 4: Build CLI and MCP server binaries on the host.
go build -o certctl-cli ./cmd/cli/...
go build -o certctl-mcp ./cmd/mcp-server/...
The CLI and MCP server are separate binaries that talk to the server over HTTP. Building them verifies the code compiles and produces the executables you'll test later.
Demo data baseline
The seed data (migrations/seed.sql + migrations/seed_demo.sql) pre-populates the database with realistic fixtures. Confirm it loaded:
curl -s $CACERT -H "$AUTH" $SERVER/api/v1/stats/summary | jq .
Expected shape:
{
"total_certificates": 15,
"active_certificates": ...,
"expiring_certificates": ...,
"expired_certificates": ...,
"pending_renewals": ...
}
Reference IDs in the demo data (used across QA docs):
| Resource | IDs | Count |
|---|---|---|
| Teams | t-platform, t-security, t-payments, t-frontend, t-data |
5 |
| Owners | o-alice, o-bob, o-carol, o-dave, o-eve |
5 |
| Policies | rp-standard, rp-urgent, rp-manual |
3 |
| Issuers | iss-local, iss-acme-le, iss-stepca, iss-digicert |
4 |
| Agents | ag-web-prod, ag-web-staging, ag-lb-prod, ag-iis-prod, ag-data-prod |
5 |
| Targets | tgt-nginx-prod, tgt-nginx-staging, tgt-f5-prod, tgt-iis-prod, tgt-nginx-data |
5 |
| Profiles | prof-standard-tls, prof-internal-mtls, prof-short-lived, prof-high-security |
4 |
| Certificates | mc-api-prod, mc-web-prod, mc-pay-prod, etc. |
15 |
| Agent Groups | ag-linux-prod, ag-linux-amd64, ag-windows, ag-datacenter-a, ag-manual |
5 |
| Network Scan Targets | nst-dc1-web, nst-dc2-apps, nst-dmz |
3 |
Once these are green
Move to the appropriate downstream surface:
test-environment.md— full local environment tutorial with real CAs (Pebble, step-ca, etc.)gui-qa-checklist.md— manual GUI test passrelease-sign-off.md— release-day checklisttesting-strategy.md— what we test in CI vs daily deep-scan vs manual QA