Ctrl K
ComunidadGuías…

Makefile

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
.PHONY: test-store test-routes test-docs test-doc-links test-doc-versions test-doc-checks test-comparison-sources test-docs-live test-evaluation test-recovery compatibility agent-lifecycle agent-compatibility live-notifications live-oidc live-ct live-kubernetes live-eab live-acme live-winacme all build build-core test test-frontend test-coverage lint routes \
        dev dev-certs generate-kek run-core run-gateway-selfsigned run-gateway-acme run-gateway-vault run-frontend \
        clean help

# ── Variables ────────────────────────────────────────────
GO   := go
BIN  := bin
PKI  := .certpilot/pki
STATE := .certpilot/state

# Each component is its own Go module, so tooling has to iterate rather than
# rely on a single ./... from the repository root.
MODULES := pkg core

CORE_BIN := $(BIN)/certpilot-core

# The gateways live in their own repositories now and are run from a release
# rather than built from this tree. Pinned, so `make dev` is reproducible and
# does not silently follow whatever is on somebody's main branch.
GW_VERSION    := v0.4.2
GW_SELFSIGNED := github.com/certpilot/certpilot-gateway-selfsigned/cmd@$(GW_VERSION)
GW_ACME       := github.com/certpilot/certpilot-gateway-acme/cmd@$(GW_VERSION)
GW_VAULT      := github.com/certpilot/certpilot-gateway-vault/cmd@$(GW_VERSION)

# ── Build ────────────────────────────────────────────────
all: build

build: build-core

build-core:
	$(GO) build -o $(CORE_BIN) ./core/cmd/

# ── Setup ────────────────────────────────────────────────

## Generate a key encryption key. Certificate private keys and CA credentials
## are sealed with it before they reach the database.
generate-kek: build-core
	@$(CORE_BIN) --generate-kek

## Generate development mTLS material for the core-to-gateway channel.
## That channel carries CSRs, private keys, and CA credentials, so it is
## mutually authenticated by default; this makes turning it on a single command.
dev-certs: build-core
	@$(CORE_BIN) --generate-dev-certs=$(PKI)

## Apply outstanding database migrations. Reads CERTPILOT_DB_URL (or DATABASE_URL);
## override with `make migrate DB=postgres://...`.
##
## Deliberately not run by the server on startup: a schema change should be
## something an operator decides to do, not a side effect of a replica restarting
## mid-deploy while older replicas are still reading the old shape.
migrate: build-core
	@$(CORE_BIN) --migrate $(if $(DB),--db=$(DB),)

# ── Run (Development) ───────────────────────────────────
#
# Each of these runs in its own terminal. Run `make dev-certs` first.

## Start PostgreSQL, the local gateway, the API, and the frontend in one
## terminal, migrating the database first. Export CERTPILOT_DB_URL to use a
## database of your own instead of the local certpilot_dev one.
dev:
	./scripts/dev.sh

## Fill a running CertPilot with a realistic estate: a CA hierarchy, certificates
## across the whole expiry range, metadata fields of every type, and values on
## every certificate. Idempotent, and deletes nothing.
seed:
	./scripts/seed-demo.sh

## Regenerate docs/routes.json from the router and the handlers. The
## documentation site is built from it, so it is checked in CI — a new route
## with a stale inventory fails.
##
## Two passes, because they read different things. extract-routes reads the
## router: what exists, and who may call it. schemagen reads the handlers:
## what to send, what comes back, and which refusals are possible. Neither
## question is answerable from the other file.
##
## One pipeline and one writer, deliberately. These used to be two commands
## that both wrote docs/routes.json, so a schemagen failure left the first
## pass's output on disk: valid JSON, every route listed, and none of the
## request or response shapes the API reference is generated from (#50). Now
## nothing touches the checked-in file until the second pass has succeeded.
##
## bash -o pipefail explicitly, not $(SHELL) and not .SHELLFLAGS. A pipeline
## reports only its last command's status, so extract-routes.py can emit a
## whole document, fail, and have make call the run a success. .SHELLFLAGS is
## the usual way to fix that and it is silently ignored by GNU Make 3.81 —
## which is what macOS ships, so the protection would have existed only on CI.
routes:
	bash -o pipefail -c 'python3 scripts/extract-routes.py | $(GO) run scripts/schemagen/main.go -o docs/routes.json'

## Prove a failed `make routes` leaves docs/routes.json byte-identical. Runs
## the real recipe with the generator rigged to fail, five different ways.
test-routes:
	./scripts/test-routes-atomicity.sh

## Check every curl example in docs/ against docs/routes.json: that the route
## exists, and that an example carries a credential when its route needs one.
## Written after twenty-eight examples were found to be 401s, left behind when
## anonymous access was removed and only the prose around them was updated.
test-docs:
	python3 scripts/check-doc-examples.py

## Check every link in docs/ resolves — including the anchor, which the
## documentation site's build does not. VitePress fails on a dead page and is
## silent on a dead heading, so three links that had already shipped were
## landing readers at the top of the right page with no way to tell.
test-doc-links:
	python3 scripts/check-doc-links.py

## Check every version the documentation pins — image tags, module versions,
## the quickstart's two variables — is published, that each page agrees with
## itself, and that a pinned gateway or agent is one compatibility.md measured.
## Asks the registries, so it needs the network; --offline skips that and says so.
test-doc-versions:
	python3 scripts/check-doc-versions.py

## Break each documentation check's input on purpose and require it to fail,
## then correct it and require it to pass. A check never seen to fail has not
## been shown to work, and three here once passed while checking less than
## they claimed.
test-doc-checks:
	./scripts/test-doc-checks.sh

## Fetch every vendor page docs/comparison.md quotes and check the quoted text
## is still there, and that every claim cites a source the page lists. The
## comparison speaks about other companies' products; a vendor rewriting a page
## is how it would go stale without anybody noticing. Needs the network;
## --offline checks the table and the citations only, and says so.
test-comparison-sources:
	python3 scripts/check-comparison-sources.py

## Send every documented GET that is safe to send to a core built from this
## tree, signed in, and require each to succeed. Reading an example against the
## route table proves it could run; this proves it does.
test-docs-live:
	./scripts/doc-examples-live.sh

## Run docs/evaluation.md as written, block by block, against the release it
## pins, and check every claim it makes. Needs Docker and ports 3000 and 8080.
## Under colima, pass a directory it shares: make test-evaluation EVAL_DIR=...
test-evaluation:
	python3 scripts/run-evaluation-doc.py $(if $(EVAL_DIR),--workdir $(EVAL_DIR),)

## Upgrade a released quickstart to the core built from this tree, then back
## up, restore, start with the wrong key and give a lost one up, checking each
## against the sentence in docs/operations.md that says what should happen.
## Needs Docker and port 8080; RECOVERY_DIR must be somewhere Docker can mount.
test-recovery:
	python3 scripts/run-recovery-drill.py $(if $(RECOVERY_DIR),--workdir $(RECOVERY_DIR),)

## Measure which released gateways this core still works with, and write
## docs/compatibility.md from what happened rather than from memory.
compatibility:
	./scripts/gateway-compatibility.sh $(GATEWAY)

## Does this core still work with the agent? Enrol, grant, request, install and
## report, against a real core, a real gateway and a real released agent.
##
## Nothing else asks this. The core tests its handlers, the agent tests its
## logic, and the contract between them is verified by neither.
##
##   make agent-lifecycle
##   make agent-lifecycle AGENT_VERSION=v0.1.0
##   make agent-lifecycle AGENT_BIN=/path/to/certpilot-agent
agent-lifecycle:
	./scripts/agent-lifecycle.sh

## The same question asked of every released agent, written into the agent
## section of docs/compatibility.md beside the gateway rows.
##
## Run scripts/gateway-compatibility.sh first: it owns the page and this fills
## in one section of it. `make compatibility agent-compatibility` does both in
## the right order, which is what the weekly workflow runs.
##
## A list rather than one version, because the useful question is not "does the
## newest work" but "which of the ones people are running still do".
AGENT_VERSIONS ?= latest

agent-compatibility:
	AGENT_VERSIONS="$(AGENT_VERSIONS)" ./scripts/agent-lifecycle.sh

## Do alerts reach a real mail server and a real webhook receiver? Email to
## Mailpit over STARTTLS, implicit TLS and a plain relay; webhooks to a receiver
## that checks the signature with the snippet from the API reference; and a CA
## crossing its expiry threshold, alerting with nobody prompting it. Needs Docker.
live-notifications:
	./scripts/live-notifications.sh

## Does single sign-on work against a real identity provider? Keycloak, signed
## into the way the console does it, its tokens used as bearer credentials, the
## refusals that keep both honest, and a rotation of its signing key.
live-oidc:
	./scripts/live-oidc.sh

## Does CT monitoring work against the real index? A public site's served
## certificate, imported through discovery, must be found in crt.sh and matched
## to the inventory. Needs the internet, so CI runs it daily, not per pull request.
##
##   make live-ct
##   make live-ct CT_DOMAIN=example.org
CT_DOMAIN ?= badssl.com

live-ct:
	CT_DOMAIN="$(CT_DOMAIN)" ./scripts/live-ct.sh

## Does the Kubernetes inventory work against a real cluster? A kind cluster
## with cert-manager, a token scoped as documented, an Ingress, and more TLS
## secrets than one page holds. Needs Docker; fetches kind if it is missing.
live-kubernetes:
	./scripts/live-kubernetes.sh

## Does External Account Binding work against an ACME server that requires it?
## The released ACME gateway against Pebble with a binding required: a correct
## one issues and renews; none, a wrong HMAC key, and an unknown key id are
## refused. Needs Docker.
live-eab:
	./scripts/live-eab.sh

## live-acme runs certbot, lego and acme.sh against the core's ACME server.
live-acme:
	./scripts/live-acme.sh

## live-winacme runs win-acme against the core's ACME server. Windows only.
live-winacme:
	pwsh ./scripts/live-winacme.ps1

run-core:
	$(GO) run ./core/cmd/ --config=config.dev.yaml

## The gateways are fetched from their own repositories at $(GW_VERSION).
## Nothing here builds them, and nothing here can: the contract between this
## core and any gateway is provider.v1 over the network, which is what makes a
## gateway somebody else wrote as usable as these three.
run-gateway-selfsigned:
	$(GO) run $(GW_SELFSIGNED) \
		--port=9091 \
		--tls-cert=$(PKI)/gateway.pem \
		--tls-key=$(PKI)/gateway-key.pem \
		--tls-ca=$(PKI)/ca.pem

run-gateway-acme:
	$(GO) run $(GW_ACME) \
		--port=9092 \
		--directory=letsencrypt-staging \
		--state-dir=$(STATE)/acme \
		--tls-cert=$(PKI)/gateway.pem \
		--tls-key=$(PKI)/gateway-key.pem \
		--tls-ca=$(PKI)/ca.pem

## The Vault gateway takes no credential of its own. Each CA account carries
## the AppRole or Kubernetes identity it issues under, so nothing here is
## authorised to sign anything.
run-gateway-vault:
	$(GO) run $(GW_VAULT) \
		--port=9093 \
		--address=$(VAULT_ADDR) \
		--tls-cert=$(PKI)/gateway.pem \
		--tls-key=$(PKI)/gateway-key.pem \
		--tls-ca=$(PKI)/ca.pem

run-frontend:
	cd frontend && npm run dev

# ── Test ─────────────────────────────────────────────────
test:
	@for m in $(MODULES); do \
		echo "==> $$m"; \
		(cd $$m && $(GO) test ./... -cover) || exit 1; \
	done

## test-store runs the store conformance suite against a real PostgreSQL.
##
## The same assertions run against the in-memory store on every `make test`.
## This adds the implementation that has produced every defect the unit tests
## could not express: constraints, column lists, NULL, and type inference.
##
## Either of these gives it a server:
##
##   docker compose -f deploy/plain-postgres/docker-compose.yml up -d
##   make test-store
##
##   brew services start postgresql@17
##   make test-store DB="postgres://$$(whoami)@127.0.0.1:5432/postgres?sslmode=disable"
##
## It creates and drops a database per test, so point it at something
## throwaway. The harness refuses the obvious production hostnames, which is a
## guard rather than a control.
TEST_DB ?= postgres://postgres:conformance@127.0.0.1:55432/postgres?sslmode=disable

test-store:
	@CERTPILOT_TEST_DB_URL="$(if $(DB),$(DB),$(TEST_DB))" \
		$(GO) test ./core/store/ -count=1 -v -run 'Conformance|TestEveryValue|TestAnUnset|TestAnUpdateKeeps|TestABindingKeeps|TestAnEmptyResult|TestTheDeploymentQueue|TestAnAgentTarget'

test-race:
	@for m in $(MODULES); do \
		echo "==> $$m"; \
		(cd $$m && $(GO) test ./... -race) || exit 1; \
	done

## Typecheck the frontend and run its checks.
## Needs Node 22.18+ — the checks import TypeScript directly, using Node's own
## type stripping rather than adding a test runner to the dependency tree.
test-frontend:
	cd frontend && npx vue-tsc --noEmit \
		&& node scripts/check-sse.mjs \
		&& node scripts/check-chain.mjs \
		&& node scripts/check-display-token.mjs \
		&& node scripts/check-signin.mjs \
		&& node scripts/check-renewal.mjs

test-coverage:
	@for m in $(MODULES); do \
		(cd $$m && $(GO) test ./... -coverprofile=coverage.out && $(GO) tool cover -func=coverage.out | tail -1); \
	done

lint:
	@for m in $(MODULES); do \
		echo "==> $$m"; \
		(cd $$m && $(GO) vet ./...) || exit 1; \
	done
	@## The build tools are outside every module, so the loop above never sees
	@## them. schemagen decides what the published API reference says about
	@## request bodies; it rotting silently is the same failure as the docs
	@## rotting silently, which is what it exists to prevent.
	@echo "==> scripts"
	@$(GO) vet scripts/schemagen/main.go
	@gofmt -l $(MODULES) scripts | grep . && echo "gofmt needed on the files above" && exit 1 || true
	@## staticcheck when it is installed, because it catches a class go vet does
	@## not: dead assignments, impossible conditions, and code nothing reaches.
	@## Not a hard requirement, so a clone can be linted without installing it.
	@##   go install honnef.co/go/tools/cmd/staticcheck@latest
	@if command -v staticcheck >/dev/null 2>&1; then \
		for m in $(MODULES); do \
			echo "==> staticcheck $$m"; \
			(cd $$m && staticcheck ./...) || exit 1; \
		done; \
	else \
		echo "staticcheck not installed; skipping (go install honnef.co/go/tools/cmd/staticcheck@latest)"; \
	fi

tidy:
	@for m in $(MODULES); do (cd $$m && $(GO) mod tidy); done

# ── Clean ────────────────────────────────────────────────
clean:
	rm -rf $(BIN)/
	rm -f coverage.out coverage.html
	@for m in $(MODULES); do rm -f $$m/coverage.out; done

## Also removes development keys and ACME account state.
clean-all: clean
	rm -rf .certpilot/

# ── Help ─────────────────────────────────────────────────
help:
	@echo "CertPilot"
	@echo ""
	@echo "Setup"
	@echo "  make dev-certs               Generate development mTLS material"
	@echo "  make generate-kek            Print a new CERTPILOT_KEK"
	@echo ""
	@echo "Build"
	@echo "  make build                   Build the core"
	@echo ""
	@echo "Run (one per terminal)"
	@echo "  make dev                      Start the complete local development stack"
	@echo "  make run-core                CertPilot Core        :8080"
	@echo "  make run-gateway-selfsigned  Self-signed gateway   :9091  (fetched, $(GW_VERSION))"
	@echo "  make run-gateway-acme        ACME gateway          :9092  (fetched, $(GW_VERSION))"
	@echo "  make run-gateway-vault       Vault PKI gateway     :9093  (fetched, $(GW_VERSION))"
	@echo "  make run-frontend            Vue frontend          :3000"
	@echo ""
	@echo "Docs"
	@echo "  make routes                  Regenerate docs/routes.json from the router"
	@echo "  make test-routes             Prove a failed regeneration damages nothing"
	@echo "  make test-docs               Check every documented curl still runs"
	@echo "  make agent-lifecycle         Enrol, request, install and report, end to end"
	@echo "  make agent-compatibility     The same, for every released agent, into docs/"
	@echo "  make live-notifications      Alerts to a real SMTP server and webhook receiver"
	@echo "  make live-oidc               Sign-in and bearer tokens against Keycloak"
	@echo "  make live-ct                 CT monitoring against crt.sh (needs the internet)"
	@echo "  make live-kubernetes         Kubernetes inventory against a kind cluster"
	@echo "  make live-eab                ACME External Account Binding against Pebble"
	@echo ""
	@echo "Check"
	@echo "  make test                    Run all tests"
	@echo "  make test-race               Run all tests under the race detector"
	@echo "  make test-frontend           Typecheck the UI and run its checks"
	@echo "  make lint                    go vet and gofmt"
	@echo ""
	@echo "Clean"
	@echo "  make clean                   Remove build artifacts"
	@echo "  make clean-all               Also remove development keys and ACME state"