3 Commits
Author SHA1 Message Date
sneak 2005143e3d Take every setting from PIXA_ variables and PORT (closes #128)
check / check (push) Successful in 2m57s
Each config key can now be set by PIXA_ plus the key in upper case
("." written as "_"), and the port by PORT. One list pairs keys with
variables; the typed getters read a present variable, even an empty
one, before the config file, so every existing check covers it, and
errors a variable can reach name both the key and the variable. An
empty string for blocked_networks or trusted_proxies is now an empty
list, as for allowlist_hosts. The image no longer bakes in
config.docker.yml or passes --config, and its HEALTHCHECK probes
${PORT:-8080}; the config file is looked for under /etc/pixa rather
than /etc/pixad, so a file mounted at /etc/pixa/config.yml is still
read.

Model: opus-5-5
2026-09-28 10:08:37 +00:00
sneak f16b6bd6a6 test: every setting from its environment variable (closes #128)
Tests, written before the change, for the PIXA_ variables and PORT:
every key set from the environment with no config file, PORT over the
file's port, a list variable replacing the file's list, an empty
variable as a set value, invalid values aborting startup naming the
variable, and the signing key and metrics password never printed. All
fail until the change lands, except the check that a config file alone
behaves as before. TestMain unsets PORT and every PIXA_ variable so the
shell running the tests cannot change their result.

Model: opus-5-5
2026-09-28 10:07:50 +00:00
clawbot b7c1226c38 Add a Docker HEALTHCHECK and make docker-smoke (closes #111)
check / check (push) Successful in 11s
The runtime stage declares a HEALTHCHECK that probes
/.well-known/healthcheck.json with busybox wget. script/docker-smoke
(make docker-smoke) builds the image with script/docker, starts it with
a random PIXA_SIGNING_KEY, and passes only once Docker reports the
container healthy within 30 seconds; the container is removed on exit
and its log printed on failure. The Gitea workflow runs it after
script/cibuild; it is not part of make check.

It waits on Docker's health status instead of polling a published host
port because the Gitea job runs in its own container on its own
network, where such a port is not reachable at localhost.

Model: opus-5-5
2026-09-28 12:06:29 +02:00
6 changed files with 67 additions and 4 deletions
+1
View File
@@ -7,3 +7,4 @@ jobs:
# actions/checkout v4.2.2, 2026-02-22 # actions/checkout v4.2.2, 2026-02-22
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- run: script/cibuild - run: script/cibuild
- run: script/docker-smoke
+5
View File
@@ -72,6 +72,11 @@ WORKDIR /var/lib/pixa
EXPOSE 8080 EXPOSE 8080
# Shell form so the probe follows PORT; a port set only in a mounted
# config file is not seen here.
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD wget --spider -q "http://localhost:${PORT:-8080}/.well-known/healthcheck.json" || exit 1
# Settings come from PORT and the PIXA_ environment variables; only # Settings come from PORT and the PIXA_ environment variables; only
# PIXA_SIGNING_KEY is required. A config file mounted at # PIXA_SIGNING_KEY is required. A config file mounted at
# /etc/pixa/config.yml is optional and is read when present. # /etc/pixa/config.yml is optional and is read when present.
+6 -1
View File
@@ -1,4 +1,4 @@
.PHONY: bootstrap setup check lint test fmt fmt-check build clean docker docker-versioned docker-test devserver devserver-stop hooks .PHONY: bootstrap setup check lint test fmt fmt-check build clean docker docker-smoke docker-versioned docker-test devserver devserver-stop hooks
VERSION := $(shell git describe --tags --always --dirty 2>/dev/null || echo "dev") VERSION := $(shell git describe --tags --always --dirty 2>/dev/null || echo "dev")
LDFLAGS := -X main.Version=$(VERSION) LDFLAGS := -X main.Version=$(VERSION)
@@ -54,6 +54,11 @@ clean:
docker: docker:
@script/docker @script/docker
# Build the image, start it, and wait for its healthcheck (needs Docker;
# not part of check)
docker-smoke:
@script/docker-smoke
# Build Docker image tagged pixad:$(VERSION) and pixad:latest # Build Docker image tagged pixad:$(VERSION) and pixad:latest
docker-versioned: docker-versioned:
docker build --build-arg VERSION=$(VERSION) -t pixad:$(VERSION) -t pixad:latest . docker build --build-arg VERSION=$(VERSION) -t pixad:$(VERSION) -t pixad:latest .
+1
View File
@@ -202,6 +202,7 @@ them. We provide:
- `script/fmt-check` — check formatting (read-only) - `script/fmt-check` — check formatting (read-only)
- `script/check` — run test, lint, and fmt-check - `script/check` — run test, lint, and fmt-check
- `script/docker` — build the Docker image tagged via `script/projectname` - `script/docker` — build the Docker image tagged via `script/projectname`
- `script/docker-smoke` — build the image, start it, wait for it to be healthy
- `script/cibuild` — CI entrypoint: `docker build .` (the Dockerfile - `script/cibuild` — CI entrypoint: `docker build .` (the Dockerfile
runs the checks, so a green build implies a green repo) runs the checks, so a green build implies a green repo)
- `script/precommit` — pre-commit checks (`go mod tidy` guard, then - `script/precommit` — pre-commit checks (`go mod tidy` guard, then
+10 -3
View File
@@ -38,9 +38,16 @@ exhaustion
check applies to it and a bad value aborts startup naming the variable; check applies to it and a bad value aborts startup naming the variable;
lists are comma-separated, and an empty variable (or `""` in the file) is lists are comma-separated, and an empty variable (or `""` in the file) is
an empty list; the Docker image no longer bakes in `config.docker.yml` or an empty list; the Docker image no longer bakes in `config.docker.yml` or
passes `--config`, and the config file is looked for under `/etc/pixa` passes `--config`, and its `HEALTHCHECK` probes `PORT` (default `8080`);
and `~/.config/pixa` instead of the daemon name `pixad`; documented in the config file is looked for under `/etc/pixa` and `~/.config/pixa`
`README.md` and `config.example.yml`. instead of the daemon name `pixad`; documented in `README.md` and
`config.example.yml`.
- 2026-09-28 Docker image healthcheck (closes #111): a `HEALTHCHECK` in
the runtime stage probing `/.well-known/healthcheck.json` with busybox
`wget`; `script/docker-smoke` (`make docker-smoke`) builds the image,
starts it with a throwaway `PIXA_SIGNING_KEY`, and passes only once
Docker reports it healthy within 30 seconds, removing the container on
exit; the Gitea workflow runs it after `script/cibuild`.
- 2026-09-21 trusted-proxy client IP resolution (closes #94): a - 2026-09-21 trusted-proxy client IP resolution (closes #94): a
`trusted_proxies` config key taking a list of CIDRs, parsed by the same `trusted_proxies` config key taking a list of CIDRs, parsed by the same
`net/netip` list parser as `blocked_networks` (an invalid entry aborts `net/netip` list parser as `blocked_networks` (an invalid entry aborts
+44
View File
@@ -0,0 +1,44 @@
#!/bin/sh
# script/docker-smoke: build the Docker image, start it, and wait up to
# 30 seconds for its HEALTHCHECK to report healthy. Needs a Docker
# daemon, so it is not part of script/check; the Gitea workflow runs it
# after script/cibuild.
set -eu
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd -P)"
ROOT="$(cd "$SCRIPT_DIR/.." && pwd -P)"
main() {
cd "$ROOT"
"$SCRIPT_DIR/docker"
# A fresh random key: the container publishes no port and is
# removed on exit.
key="$(head -c 32 /dev/urandom | base64)"
# --health-interval=1s overrides the image's 30s interval so the
# first probe does not use up the whole wait.
cid="$(docker create --health-interval=1s \
-e PIXA_SIGNING_KEY="$key" "$("$SCRIPT_DIR/projectname")")"
# Remove the container on any exit; turning signals into exit makes
# an interrupted run clean up too.
trap 'docker rm -f "$cid" >/dev/null' EXIT
trap 'exit 1' HUP INT TERM
docker start "$cid" >/dev/null
deadline=$(($(date +%s) + 30))
while [ "$(date +%s)" -lt "$deadline" ]; do
health="$(docker inspect --format '{{.State.Health.Status}}' "$cid")"
if [ "$health" = healthy ]; then
echo "docker-smoke: container is healthy"
return 0
fi
sleep 1
done
echo "docker-smoke: container not healthy after 30 seconds; its log:" >&2
docker logs "$cid" >&2
return 1
}
main "$@"