diff --git a/Makefile b/Makefile index b6d10b3..247a339 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: help build run test lint verify clean docker-up docker-down migrate-up migrate-down generate test-cover frontend-build qa-stats +.PHONY: help build run test lint verify verify-docs verify-deploy clean docker-up docker-down migrate-up migrate-down generate test-cover frontend-build qa-stats # Default target - show help help: @@ -16,6 +16,8 @@ help: @echo " make lint Run linter (golangci-lint)" @echo " make fmt Format code with gofmt" @echo " make verify Pre-commit gate: fmt + vet + lint + test (CI-parity)" + @echo " make verify-docs Pre-tag gate: QA-doc drift checks (operator-facing docs)" + @echo " make verify-deploy Pre-push gate: digest validity + OpenAPI parity + docker build smoke" @echo "" @echo "Database:" @echo " make migrate-up Run migrations (requires DB_URL)" @@ -116,6 +118,38 @@ verify: @echo "" @echo "verify: PASS — safe to commit" +# verify-docs: pre-tag gate. Runs the QA-doc Part-count + seed-count +# drift guards that ci-pipeline-cleanup Phase 11 / frozen decision 0.13 +# moved out of CI (was per-push blocking; now operator-runs pre-tag). +# These guards protect docs/qa-test-guide.md headlines from drifting +# vs the underlying source-of-truth (testing-guide Part count, seed +# row count). Operator-facing docs only — not product-affecting. +verify-docs: + @echo "==> QA-doc Part-count drift" + @bash scripts/qa-doc-part-count.sh + @echo "==> QA-doc seed-count drift" + @bash scripts/qa-doc-seed-count.sh + @echo "" + @echo "verify-docs: PASS — safe to tag" + +# verify-deploy: optional pre-push gate. Runs the digest-validity check, +# the OpenAPI ↔ handler parity check, and a Docker build smoke for the +# production images (server + agent only — fast subset for local; CI +# builds all 4 Dockerfiles per ci-pipeline-cleanup Phase 8 / frozen +# decision 0.10). +# +# Per ci-pipeline-cleanup bundle Phase 11 / frozen decision 0.13. +verify-deploy: + @echo "==> Digest validity" + @bash scripts/ci-guards/digest-validity.sh + @echo "==> OpenAPI ↔ handler parity" + @bash scripts/ci-guards/openapi-handler-parity.sh + @echo "==> Docker build smoke (server + agent — fast subset)" + @docker build -f Dockerfile -t certctl:verify . + @docker build -f Dockerfile.agent -t certctl-agent:verify . + @echo "" + @echo "verify-deploy: PASS — safe to push" + # Database targets (requires migrate tool) migrate-up: @echo "Running migrations..." diff --git a/scripts/qa-doc-part-count.sh b/scripts/qa-doc-part-count.sh new file mode 100755 index 0000000..b659a8e --- /dev/null +++ b/scripts/qa-doc-part-count.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +# scripts/qa-doc-part-count.sh +# +# Bundle P / Strengthening #6 — QA-doc Part-count drift guard. +# Forces every PR that adds a Part to docs/testing-guide.md to keep +# docs/qa-test-guide.md headline in sync. +# +# Per ci-pipeline-cleanup bundle Phase 11 / frozen decision 0.13: +# moved out of CI (was in ci.yml) — operator runs via 'make verify-docs' +# pre-tag. Protects docs-the-operator-reads, not anything the product +# depends on; CI-blocking on every push was overkill. + +set -e +DOC_PARTS=$(grep -oE '49 of [0-9]+ Parts' docs/qa-test-guide.md | grep -oE '[0-9]+' | tail -1) +GUIDE_PARTS=$(grep -cE '^## Part [0-9]+:' docs/testing-guide.md) +if [ -z "$DOC_PARTS" ]; then + echo "::error::Could not extract Part count from docs/qa-test-guide.md headline." + echo " Expected pattern: '49 of Parts'" + exit 1 +fi +if [ "$DOC_PARTS" != "$GUIDE_PARTS" ]; then + echo "::error::DRIFT — qa-test-guide.md headline claims $DOC_PARTS Parts; testing-guide.md has $GUIDE_PARTS Parts." + echo " Update docs/qa-test-guide.md to match. Bundle I patched this once;" + echo " Bundle P added this guard so the drift cannot recur silently." + exit 1 +fi +echo "qa-doc-part-count: clean ($DOC_PARTS == $GUIDE_PARTS)." diff --git a/scripts/qa-doc-seed-count.sh b/scripts/qa-doc-seed-count.sh new file mode 100755 index 0000000..04d364b --- /dev/null +++ b/scripts/qa-doc-seed-count.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +# scripts/qa-doc-seed-count.sh +# +# Bundle P / Strengthening #6 — QA-doc seed-count drift guard. +# Forces every PR that adds a seed row to migrations/seed_demo.sql +# to keep docs/qa-test-guide.md::Seed Data Reference in sync. +# +# Per ci-pipeline-cleanup bundle Phase 11 / frozen decision 0.13: +# moved out of CI (was in ci.yml) — operator runs via 'make verify-docs' +# pre-tag. + +set -e +# Seed-cert count: agnostic to documented header format. The current +# documented count lives in `### Certificates (32 total in ...` — +# extract the first integer in that header. +DOC_CERTS=$(grep -oE '### Certificates \([0-9]+' docs/qa-test-guide.md | grep -oE '[0-9]+' | head -1) +# Authoritative count: unique mc-* IDs in seed_demo.sql. +SEED_CERTS=$(grep -oE 'mc-[a-z0-9_-]+' migrations/seed_demo.sql | sort -u | wc -l | tr -d ' ') +if [ -z "$DOC_CERTS" ]; then + echo "::warning::Could not extract documented cert count from docs/qa-test-guide.md." + echo " Skipping cert-count drift check (header format may have changed)." +elif [ "$DOC_CERTS" != "$SEED_CERTS" ]; then + echo "::error::DRIFT — qa-test-guide.md says $DOC_CERTS certs; seed_demo.sql has $SEED_CERTS unique mc-* IDs." + echo " Update docs/qa-test-guide.md::Seed Data Reference to match." + exit 1 +fi +# Issuers: seed-table count vs doc claim. +DOC_ISS=$(grep -oE '### Issuers \([0-9]+' docs/qa-test-guide.md | grep -oE '[0-9]+' | head -1) +# Authoritative: unique iss-* IDs (close enough proxy; the issuers +# table count IS the unique-ID count for this prefix). +SEED_ISS=$(grep -oE 'iss-[a-z0-9_-]+' migrations/seed_demo.sql | sort -u | wc -l | tr -d ' ') +if [ -z "$DOC_ISS" ]; then + echo "::warning::Could not extract documented issuer count." +elif [ "$DOC_ISS" != "$SEED_ISS" ] && [ "$((SEED_ISS - DOC_ISS))" -gt 5 ]; then + # Allow up to 5pp slack — iss-* IDs appear in audit_events and + # other reference tables that aren't issuer-table rows. Drift + # only flags when the spread grows large. + echo "::error::DRIFT — qa-test-guide.md says $DOC_ISS issuers; seed_demo.sql has $SEED_ISS unique iss-* IDs (spread > 5)." + exit 1 +fi +echo "qa-doc-seed-count: clean."