The control plane, as far as identity
Tier 2 exists now. It holds one context of seven, inventory, and does one thing with it: brings its schema up to date. That is step 3 of the substrate bootstrap -- the step the first node cannot get past. Verified against a real PostgreSQL, with the built binary: applied 0001-nodes, reported 'already up to date' on the second run, and the node table is there with the index and the unique constraint the migration asks for. Written in Go, and the image is FROM scratch holding one file. Confirmed by unpacking it. That is the whole argument of ADR 0024: the bundle pins this image by digest and runs it where nothing can check it, so everything in it is something a person has to audit before trusting a first node. Exclusive store ownership is built as a rule about credentials rather than about intentions. There is no mesh-wide connection setting and no way to ask for one -- a context reads MESH_STORE_<ITS OWN NAME> and holds nothing else, so reaching another context's store needs a new variable, which is visible in the declaration that runs it. The migration runner is mostly refusals: an edited migration that already ran, a migration numbered below one that has run, duplicate numbers, misnamed files, empty files. All stop rather than warn, because at the moment any of them is true nobody knows what the database holds. It stops before identity, deliberately. What a node presents to prove who it is has not been decided anywhere, and a migration is the most expensive place in this system to guess. Two tests did not defend what they claimed, and both are fixed rather than removed. One asked only whether Open returned an error, which it did either way -- a bad context name and a missing credential both fail, so deleting the name check changed nothing. The other claimed to prove the migration runs in a transaction, but PostgreSQL already wraps a multi-statement query in one of its own, so it passed with the transaction taken out. What the transaction actually buys is that the schema change and the row recording it commit together, and there is now a test for that which fails when they are split.
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
# novox/hq ADR 0024 — the control plane, in Go.
|
||||
#
|
||||
# The image the bundle pins holds the program and nothing else, so the build is static and the
|
||||
# container is built FROM scratch. That is not a size optimisation: this image is fetched by
|
||||
# digest and run on a machine where no mesh exists to check anything, and everything in it is
|
||||
# something a person would have to audit.
|
||||
|
||||
VERSION ?= $(shell git describe --tags --always --dirty 2>/dev/null || echo development)
|
||||
LDFLAGS := -s -w -X main.version=$(VERSION)
|
||||
|
||||
# Where `make check` raises PostgreSQL. A high port and a throwaway container: nothing here
|
||||
# touches a database anybody else is using. Override PG_PORT if this one is taken -- the first
|
||||
# port chosen was already serving something that had been up for six days.
|
||||
PG_PORT ?= 55532
|
||||
PG_CONTAINER ?= mesh-control-check
|
||||
PG_IMAGE ?= postgres:17-alpine
|
||||
export MESH_TEST_POSTGRES ?= postgres://postgres:check@127.0.0.1:$(PG_PORT)/postgres?sslmode=disable
|
||||
|
||||
.PHONY: build image check test vet fmt postgres postgres-stop clean
|
||||
|
||||
build:
|
||||
CGO_ENABLED=0 go build -trimpath -ldflags '$(LDFLAGS)' -o build/mesh-control ./cmd/mesh-control
|
||||
|
||||
IMAGE ?= mesh-control:$(VERSION)
|
||||
|
||||
image:
|
||||
docker build --build-arg VERSION=$(VERSION) -t $(IMAGE) .
|
||||
@echo
|
||||
@docker image inspect $(IMAGE) --format 'built {{.RepoTags}} {{.Size}} bytes'
|
||||
|
||||
# The whole gate. Raises a database, runs everything against it, and takes it down again --
|
||||
# including when the tests fail, which is why the teardown is not conditional.
|
||||
check: fmt vet postgres
|
||||
@go test ./... ; status=$$? ; $(MAKE) postgres-stop ; exit $$status
|
||||
|
||||
# Without a database the live tests skip rather than fail, so this is the honest subset and not
|
||||
# the gate.
|
||||
test:
|
||||
go test ./...
|
||||
|
||||
vet:
|
||||
go vet ./...
|
||||
|
||||
fmt:
|
||||
@unformatted=$$(gofmt -l . 2>/dev/null) ; \
|
||||
if [ -n "$$unformatted" ] ; then echo "not gofmt'd:" ; echo "$$unformatted" ; exit 1 ; fi
|
||||
|
||||
postgres:
|
||||
@docker rm -f $(PG_CONTAINER) >/dev/null 2>&1 || true
|
||||
@docker run -d --name $(PG_CONTAINER) -e POSTGRES_PASSWORD=check \
|
||||
-p 127.0.0.1:$(PG_PORT):5432 $(PG_IMAGE) >/dev/null
|
||||
@printf 'waiting for postgres'
|
||||
@for i in $$(seq 1 60) ; do \
|
||||
if docker exec $(PG_CONTAINER) pg_isready -U postgres >/dev/null 2>&1 ; then \
|
||||
echo ' — ready' ; exit 0 ; fi ; \
|
||||
printf '.' ; sleep 1 ; \
|
||||
done ; \
|
||||
echo ' — never came up' ; docker logs $(PG_CONTAINER) | tail -20 ; exit 1
|
||||
|
||||
postgres-stop:
|
||||
@docker rm -f $(PG_CONTAINER) >/dev/null 2>&1 || true
|
||||
|
||||
clean:
|
||||
rm -rf build/
|
||||
Reference in New Issue
Block a user