mirror of
https://github.com/shankar0123/certctl.git
synced 2026-06-07 12:21:31 +00:00
0161bb201c
Operator policy: docs in the public repo must help (a) a user
deploying certctl or (b) the product story. Internal engineering
process documentation belongs in cowork/ scratchpads or in git
commit history, not docs/.
Removed (docs/contributor/, 8 files, 2,323 lines):
- release-sign-off.md — internal release-day checklist
- ci-pipeline.md — what runs in CI (internal)
- ci-guards.md — what the guards are (internal)
- testing-strategy.md — internal testing strategy
- qa-test-suite.md — internal QA reference (445 lines)
- qa-prerequisites.md — internal QA setup
- gui-qa-checklist.md — manual GUI QA checklist
- test-environment.md — 1,103-line redundant with
docs/getting-started/quickstart.md +
docs/getting-started/advanced-demo.md
Removed supporting script:
- scripts/qa-doc-seed-count.sh — CI guard for the deleted
qa-test-suite.md seed-data table
Cross-reference cleanup:
- README.md: dropped the Contributor audience row + footer
pointer to docs/contributor/.
- Makefile: dropped `verify-docs` target + qa-stats comment refs.
- .github/workflows/ci.yml: dropped the QA-doc seed-count drift
CI step + dead comment refs.
- docs/reference/cli.md: repointed qa-prerequisites.md → quickstart.md.
- docs/operator/performance-baselines.md: dropped ci-pipeline.md
cross-ref.
- scripts/ci-guards/README.md: dropped the 'Guards explicitly
NOT here' section that referenced the deleted QA-doc guards.
G-3 env-docs-drift guard improvements (a real consequence: deleting
the contributor docs surfaced that some env vars only had a home
there). Refit the guard to the new doc topology:
- Defined-scan widened from `config.go + cmd/*` to all of `cmd/ +
internal/` (production code), excluding `*_test.go` — catches
service-layer env vars like CERTCTL_STEPCA_ROOT_CERT and
CERTCTL_ZEROSSL_EAB_URL that were previously invisible to the
guard.
- Docs-scan widened to include deploy/ENVIRONMENTS.md (the
canonical env-var inventory table — should have been in scope
from day one). Kept narrow to README + docs/ + deploy/helm/ +
ENVIRONMENTS.md to avoid pulling in compose/test fixtures.
- ALLOWED filter now applies to both DOCS_ONLY and CONFIG_ONLY
directions, so dynamic per-profile dispatch surfaces
(CERTCTL_SCEP_PROFILE_<NAME>_*, CERTCTL_EST_PROFILE_<NAME>_*,
CERTCTL_QA_*) don't need static doc entries.
- Added CERTCTL_SCEP_PROFILE_[A-Z_]+ and CERTCTL_EST_PROFILE_[A-Z_]+
to ALLOWED for the same reason.
deploy/ENVIRONMENTS.md: added CERTCTL_ZEROSSL_EAB_URL row — real
operator override (overrides the ZeroSSL EAB-credentials endpoint;
read at internal/connector/issuer/acme/acme.go:372) that was
defined in Go source but never documented. G-3 caught it after the
defined-scan widened.
scripts/ci-guards/S-1-hardcoded-source-counts.sh: removed dead
WORKSPACE-CHANGELOG.md allowlist entry (the file was deleted in
the prior workspace cleanup).
Verified:
All 35 scripts/ci-guards/*.sh green (FAIL=0).
No remaining references to docs/contributor/ or qa-doc-seed-count
in tracked files.
334 lines
14 KiB
Makefile
334 lines
14 KiB
Makefile
.PHONY: help build run test lint verify verify-deploy loadtest acme-cert-manager-test acme-rfc-conformance-test keycloak-integration-test okta-smoke-test benchmark-auth benchmark-auth-coldcache clean docker-up docker-down migrate-up migrate-down generate test-cover frontend-build qa-stats
|
|
|
|
# Default target - show help
|
|
help:
|
|
@echo "Certctl Development Commands"
|
|
@echo "============================="
|
|
@echo ""
|
|
@echo "Build & Run:"
|
|
@echo " make build Build server and agent binaries"
|
|
@echo " make run Run server locally (requires DB)"
|
|
@echo " make run-agent Run agent locally"
|
|
@echo ""
|
|
@echo "Testing & Quality:"
|
|
@echo " make test Run all tests"
|
|
@echo " make test-verbose Run tests with verbose output"
|
|
@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-deploy Pre-push gate: digest validity + OpenAPI parity + docker build smoke"
|
|
@echo " make loadtest k6 throughput run against postgres + certctl (NOT in verify; manual + cron only)"
|
|
@echo ""
|
|
@echo "Database:"
|
|
@echo " make migrate-up Run migrations (requires DB_URL)"
|
|
@echo " make migrate-down Rollback last migration"
|
|
@echo " make db-seed Seed database with test data"
|
|
@echo ""
|
|
@echo "Docker:"
|
|
@echo " make docker-build Build Docker images"
|
|
@echo " make docker-up Start Docker Compose stack"
|
|
@echo " make docker-down Stop Docker Compose stack"
|
|
@echo " make docker-logs View Docker logs"
|
|
@echo " make docker-clean Remove Docker resources"
|
|
@echo ""
|
|
@echo "Code Generation:"
|
|
@echo " make generate Run go generate"
|
|
@echo " make clean Clean build artifacts"
|
|
@echo ""
|
|
|
|
# Build targets
|
|
build:
|
|
@echo "Building server and agent..."
|
|
mkdir -p bin
|
|
CGO_ENABLED=0 go build -o bin/server ./cmd/server
|
|
CGO_ENABLED=0 go build -o bin/agent ./cmd/agent
|
|
@echo "Build complete: bin/server, bin/agent"
|
|
|
|
build-server:
|
|
@echo "Building server..."
|
|
mkdir -p bin
|
|
CGO_ENABLED=0 go build -o bin/server ./cmd/server
|
|
@echo "Server build complete"
|
|
|
|
build-agent:
|
|
@echo "Building agent..."
|
|
mkdir -p bin
|
|
CGO_ENABLED=0 go build -o bin/agent ./cmd/agent
|
|
@echo "Agent build complete"
|
|
|
|
# Run targets
|
|
run: build-server
|
|
@echo "Starting server (requires DATABASE_URL or DB_* env vars)..."
|
|
./bin/server
|
|
|
|
run-agent: build-agent
|
|
@echo "Starting agent (requires SERVER_URL and API_KEY env vars)..."
|
|
./bin/agent
|
|
|
|
# Testing targets
|
|
test:
|
|
@echo "Running tests..."
|
|
go test ./...
|
|
|
|
test-verbose:
|
|
@echo "Running tests with verbose output..."
|
|
go test -v ./...
|
|
|
|
test-coverage:
|
|
@echo "Running tests with coverage..."
|
|
go test -coverprofile=coverage.out ./...
|
|
go tool cover -html=coverage.out -o coverage.html
|
|
@echo "Coverage report: coverage.html"
|
|
|
|
test-cover:
|
|
@echo "Running tests with coverage..."
|
|
go test ./internal/service/... ./internal/api/handler/... ./internal/integration/... -count=1 -cover -coverprofile=coverage.out
|
|
@echo "Coverage report: coverage.out"
|
|
|
|
# Linting targets
|
|
lint:
|
|
@echo "Running golangci-lint..."
|
|
@which golangci-lint > /dev/null || (echo "Installing golangci-lint..." && go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest)
|
|
golangci-lint run ./...
|
|
|
|
fmt:
|
|
@echo "Formatting code..."
|
|
go fmt ./...
|
|
@echo "Code formatted"
|
|
|
|
vet:
|
|
@echo "Running go vet..."
|
|
go vet ./...
|
|
|
|
# verify: aggregate pre-commit gate. Mirrors what CI enforces, so
|
|
# running `make verify` locally before committing prevents the
|
|
# class of breakages that ship green-locally / red-on-CI (e.g.
|
|
# Bundle-9's ST1018 invisible-Unicode-literal hits, which `go vet`
|
|
# alone cannot catch — staticcheck under golangci-lint does).
|
|
verify:
|
|
@echo "==> fmt"
|
|
@go fmt ./... | { ! grep -q '.'; } || (echo "gofmt produced changes — commit them" && exit 1)
|
|
@echo "==> go vet ./..."
|
|
@go vet ./...
|
|
@echo "==> golangci-lint run ./... (incl. staticcheck ST*)"
|
|
@which golangci-lint > /dev/null || (echo "Installing golangci-lint..." && go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest)
|
|
@golangci-lint run ./... --timeout 5m
|
|
@echo "==> go test -short ./..."
|
|
@go test -short -count=1 ./...
|
|
@echo ""
|
|
@echo "verify: PASS — safe to commit"
|
|
|
|
# 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"
|
|
|
|
# Load-test harness — closes the #8 acquisition-readiness blocker from
|
|
# the 2026-05-01 issuer coverage audit. Boots a minimal certctl stack
|
|
# (postgres + tls-init + certctl-server) and runs k6 against the API
|
|
# tier for ~5 minutes. Exits non-zero on any threshold breach.
|
|
#
|
|
# NOT in `make verify` — load tests take minutes, not seconds, and
|
|
# don't gate per-PR signal. CI gates this behind workflow_dispatch +
|
|
# weekly cron in .github/workflows/loadtest.yml. See
|
|
# deploy/test/loadtest/README.md for thresholds, baseline, and how to
|
|
# interpret a regression.
|
|
loadtest:
|
|
@echo "==> spinning up postgres + certctl + k6 driver (this takes ~7m)"
|
|
@cd deploy/test/loadtest && docker compose up --build --abort-on-container-exit --exit-code-from k6
|
|
@echo ""
|
|
@echo "==> results landed in deploy/test/loadtest/results/"
|
|
@if [ -f deploy/test/loadtest/results/summary.txt ]; then cat deploy/test/loadtest/results/summary.txt; fi
|
|
|
|
# Auth Bundle 2 Phase 10 — Keycloak end-to-end OIDC integration test.
|
|
# Boots a Keycloak container via testcontainers-go (quay.io/keycloak:25.0),
|
|
# imports a canned realm with two groups + two users, and drives the
|
|
# full OIDC flow against the certctl service: discovery + JWKS,
|
|
# auth-code login, group-claim parsing, group-role mapping, session
|
|
# mint, and JWKS rotation.
|
|
#
|
|
# Build-tag-gated under `integration` so `make verify` (which runs
|
|
# go test -short) NEVER pulls in the 60-90s Keycloak boot. Requires a
|
|
# local Docker daemon. Skips cleanly with t.Skip() when -short is set.
|
|
keycloak-integration-test:
|
|
@echo "==> running Keycloak OIDC integration test (requires Docker)"
|
|
@go test -tags=integration -count=1 -timeout=10m \
|
|
./internal/auth/oidc/...
|
|
|
|
# Auth Bundle 2 Phase 10 — optional Okta smoke test. Gated behind TWO
|
|
# build tags (integration + okta_smoke) so it only runs when invoked
|
|
# manually against the operator's own Okta dev tenant. Requires the
|
|
# OKTA_ISSUER + OKTA_CLIENT_ID + OKTA_CLIENT_SECRET env vars; the test
|
|
# t.Skip's with a clear message when any are missing. Documented in
|
|
# internal/auth/oidc/integration_okta_smoke_test.go.
|
|
okta-smoke-test:
|
|
@echo "==> running Okta smoke test (requires OKTA_ISSUER / _CLIENT_ID / _CLIENT_SECRET env vars)"
|
|
@go test -tags='integration okta_smoke' -count=1 -timeout=2m \
|
|
./internal/auth/oidc/...
|
|
|
|
# Auth Bundle 2 Phase 14 — auth performance benchmarks. Three default-
|
|
# tag benchmarks (session steady-state + session cold-process + oidc
|
|
# steady-state) producing p50/p95/p99/max numbers per the auth-
|
|
# benchmarks.md operator-doc table.
|
|
benchmark-auth:
|
|
@echo "==> running auth performance benchmarks (session + oidc steady-state)"
|
|
@go test -bench='BenchmarkSession_|BenchmarkOIDC_SteadyState' -benchmem \
|
|
-benchtime=2000x -run='^$$' \
|
|
./internal/auth/session/ ./internal/auth/oidc/
|
|
|
|
# Auth Bundle 2 Phase 14 — OIDC cold-cache benchmark against a live
|
|
# Keycloak container (requires Docker). Build-tag-gated so the
|
|
# default-tag benchmarks above never pull in the 60-90s container
|
|
# boot. Runs the integration test FIRST to populate the
|
|
# sharedKeycloak fixture, then runs the benchmark.
|
|
benchmark-auth-coldcache:
|
|
@echo "==> running OIDC cold-cache benchmark against live Keycloak (requires Docker)"
|
|
@go test -tags integration -count=1 -timeout=10m \
|
|
-run TestKeycloakIntegration_RefreshKeysFetchesDiscoveryAndJWKS \
|
|
-bench BenchmarkOIDC_ColdCache -benchmem -benchtime=10x \
|
|
./internal/auth/oidc/
|
|
|
|
# Phase 5 — kind-driven cert-manager integration test. Requires
|
|
# `kind`, `kubectl`, `helm`, and a local Docker daemon. Sets
|
|
# KIND_AVAILABLE=1 so the test runs (it skips cleanly when unset, which
|
|
# is the CI default — kind is too heavy for per-PR CI). The test
|
|
# brings up a fresh cluster, installs cert-manager 1.15, helm-installs
|
|
# certctl-test, applies a ClusterIssuer + Certificate, and asserts the
|
|
# Secret lands.
|
|
acme-cert-manager-test:
|
|
@echo "==> running cert-manager integration test (requires kind/kubectl/helm)"
|
|
@KIND_AVAILABLE=1 go test -tags=integration -count=1 -timeout=15m \
|
|
./deploy/test/acme-integration/...
|
|
|
|
# Phase 5 — RFC 8555 conformance against `lego` driving the certctl
|
|
# server. Hermetic: brings up a single certctl-server via docker
|
|
# compose, points lego at it, runs the conformance scenarios. Skips
|
|
# when the operator hasn't built the test image (`make docker-build`
|
|
# first).
|
|
acme-rfc-conformance-test:
|
|
@echo "==> running RFC 8555 conformance via lego"
|
|
@if ! command -v lego >/dev/null 2>&1; then \
|
|
echo "lego not installed — go install github.com/go-acme/lego/v4/cmd/lego@latest"; \
|
|
exit 1; \
|
|
fi
|
|
@cd deploy/test/loadtest && docker compose up -d certctl postgres
|
|
@sleep 8
|
|
@CERTCTL_ACME_DIR=https://localhost:8443/acme/profile/prof-test/directory \
|
|
bash deploy/test/acme-integration/conformance-lego.sh
|
|
@cd deploy/test/loadtest && docker compose down
|
|
|
|
# Database targets (requires migrate tool)
|
|
migrate-up:
|
|
@echo "Running migrations..."
|
|
@which migrate > /dev/null || (echo "Installing migrate CLI..." && go install -tags 'postgres' github.com/golang-migrate/migrate/v4/cmd/migrate@latest)
|
|
migrate -path migrations -database "${DB_URL:-postgres://certctl:certctl@localhost:5432/certctl?sslmode=disable}" up
|
|
|
|
migrate-down:
|
|
@echo "Rolling back last migration..."
|
|
@which migrate > /dev/null || (echo "Installing migrate CLI..." && go install -tags 'postgres' github.com/golang-migrate/migrate/v4/cmd/migrate@latest)
|
|
migrate -path migrations -database "${DB_URL:-postgres://certctl:certctl@localhost:5432/certctl?sslmode=disable}" down 1
|
|
|
|
migrate-status:
|
|
@echo "Checking migration status..."
|
|
@which migrate > /dev/null || (echo "Installing migrate CLI..." && go install -tags 'postgres' github.com/golang-migrate/migrate/v4/cmd/migrate@latest)
|
|
migrate -path migrations -database "${DB_URL:-postgres://certctl:certctl@localhost:5432/certctl?sslmode=disable}" version
|
|
|
|
db-seed:
|
|
@echo "Seeding database with test data..."
|
|
go run ./scripts/seed/main.go
|
|
|
|
# Docker targets
|
|
docker-build:
|
|
@echo "Building Docker images..."
|
|
docker-compose -f deploy/docker-compose.yml build
|
|
|
|
docker-up:
|
|
@echo "Starting Docker Compose stack..."
|
|
docker-compose -f deploy/docker-compose.yml up -d
|
|
@echo "Stack running. Access server at http://localhost:8443"
|
|
|
|
docker-up-dev:
|
|
@echo "Starting Docker Compose stack (dev mode)..."
|
|
docker-compose -f deploy/docker-compose.yml -f deploy/docker-compose.dev.yml up -d
|
|
@echo "Stack running. PgAdmin at http://localhost:5050"
|
|
|
|
docker-down:
|
|
@echo "Stopping Docker Compose stack..."
|
|
docker-compose -f deploy/docker-compose.yml down
|
|
|
|
docker-logs:
|
|
docker-compose -f deploy/docker-compose.yml logs -f
|
|
|
|
docker-logs-server:
|
|
docker-compose -f deploy/docker-compose.yml logs -f certctl-server
|
|
|
|
docker-logs-agent:
|
|
docker-compose -f deploy/docker-compose.yml logs -f certctl-agent
|
|
|
|
docker-clean:
|
|
@echo "Removing Docker resources..."
|
|
docker-compose -f deploy/docker-compose.yml down -v
|
|
@echo "Cleaned up"
|
|
|
|
# Code generation
|
|
generate:
|
|
@echo "Running go generate..."
|
|
go generate ./...
|
|
@echo "Code generation complete"
|
|
|
|
# Frontend build
|
|
frontend-build:
|
|
@echo "Building frontend..."
|
|
cd web && npm ci && npx vite build
|
|
@echo "Frontend build complete"
|
|
|
|
# qa-stats: snapshot of the test-suite size at the current commit.
|
|
# Backend Go tests + subtests + fuzz targets + skipped sites, plus the
|
|
# seed-data counts in migrations/seed_demo.sql. Useful before a release
|
|
# to spot-check that no whole layer dropped off.
|
|
qa-stats:
|
|
@echo "=== certctl QA Suite Stats ==="
|
|
@echo "Date: $$(date +%Y-%m-%d)"
|
|
@echo "HEAD: $$(git rev-parse HEAD 2>/dev/null || echo 'not-a-git-repo')"
|
|
@echo ""
|
|
@echo "Backend test files: $$(find . -name '*_test.go' -not -path './web/*' 2>/dev/null | wc -l | tr -d ' ')"
|
|
@echo "Backend Test functions: $$(find . -name '*_test.go' -not -path './web/*' 2>/dev/null | xargs grep -c '^func Test' 2>/dev/null | awk -F: '{s+=$$2} END{print s+0}')"
|
|
@echo "Backend t.Run subtests: $$(find . -name '*_test.go' -not -path './web/*' 2>/dev/null | xargs grep -c 't\.Run(' 2>/dev/null | awk -F: '{s+=$$2} END{print s+0}')"
|
|
@echo "Frontend test files: $$(find web/src -name '*.test.ts' -o -name '*.test.tsx' 2>/dev/null | wc -l | tr -d ' ')"
|
|
@echo "Fuzz targets: $$(grep -rE 'func Fuzz[A-Z]' --include='*_test.go' . 2>/dev/null | wc -l | tr -d ' ')"
|
|
@echo "t.Skip sites: $$(grep -rE 't\.Skip(Now|f)?\(' --include='*_test.go' . 2>/dev/null | wc -l | tr -d ' ')"
|
|
@echo "qa_test.go Part_ subtests: $$(grep -cE 't\.Run\(\"Part[0-9]+_' deploy/test/qa_test.go 2>/dev/null || echo 0)"
|
|
@echo "Seed unique mc-* IDs: $$(grep -oE "mc-[a-z0-9_-]+" migrations/seed_demo.sql 2>/dev/null | sort -u | wc -l | tr -d ' ')"
|
|
@echo "Seed unique ag-* IDs: $$(grep -oE "ag-[a-z0-9_-]+" migrations/seed_demo.sql 2>/dev/null | sort -u | wc -l | tr -d ' ') (incl. agent_groups; agents-table count is 13 incl. agent-demo-1 + 3 cloud sentinels + server-scanner)"
|
|
@echo "Seed unique iss-* IDs: $$(grep -oE "iss-[a-z0-9_-]+" migrations/seed_demo.sql 2>/dev/null | sort -u | wc -l | tr -d ' ') (issuers table count is 13)"
|
|
@echo "Seed unique tgt-* IDs: $$(grep -oE "tgt-[a-z0-9_-]+" migrations/seed_demo.sql 2>/dev/null | sort -u | wc -l | tr -d ' ')"
|
|
@echo "Seed unique nst-* IDs: $$(grep -oE "nst-[a-z0-9_-]+" migrations/seed_demo.sql 2>/dev/null | sort -u | wc -l | tr -d ' ')"
|
|
|
|
# Cleanup
|
|
clean:
|
|
@echo "Cleaning build artifacts..."
|
|
rm -rf bin/ dist/ coverage.out coverage.html
|
|
go clean -testcache
|
|
cd web && rm -rf node_modules dist
|
|
@echo "Cleanup complete"
|
|
|
|
install-tools:
|
|
@echo "Installing development tools..."
|
|
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
|
|
go install -tags 'postgres' github.com/golang-migrate/migrate/v4/cmd/migrate@latest
|
|
go install github.com/cosmtrek/air@latest
|
|
@echo "Tools installed"
|