The image apps build FROM, with its health check (closes #45)
check / check (push) Failing after 3s

The Dockerfile's last stage is now the image of "Deployment" in SPEC.md:
Ubuntu 26.04 with ca-certificates, nix-bin and runit from a dated
snapshot whose InRelease files are checked by hash, nixpkgs from its
release file checked by SHA-256, runsvinit built at a fixed commit, and
smallwebwaf as a runit service. smallwebwaf answers
/_smallwebwaf/healthz, and `smallwebwaf healthcheck`, which takes no
further argument, is the image's HEALTHCHECK. script/example-app builds
an app on the image and checks it end to end.

The Nix profile comes last on the PATH: first, busybox from nixpkgs
replaced runit's own runsvdir and sv. SPEC.md is corrected to match
what was built.

Model: opus-5-5
This commit was merged in pull request #57.
This commit is contained in:
2026-10-04 10:05:30 +02:00
parent 0750879e58
commit d4f90dba37
17 changed files with 617 additions and 71 deletions
+14
View File
@@ -13,6 +13,7 @@ import (
"sneak.berlin/go/smallwebwaf/internal/config"
"sneak.berlin/go/smallwebwaf/internal/lookup"
"sneak.berlin/go/smallwebwaf/internal/ratelimit"
"sneak.berlin/go/smallwebwaf/internal/requestlog"
)
// The request line and headers a client may send, and how long a
@@ -34,6 +35,10 @@ const (
appIdleConnTimeout = 90 * time.Second
)
// HealthPath is smallwebwaf's health endpoint, which the container's
// health check asks.
const HealthPath = "/_smallwebwaf/healthz"
// Params are what New needs.
type Params struct {
Config *config.Config
@@ -111,6 +116,15 @@ func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
rq := h.newRequest(w, r)
defer rq.finish()
// The health endpoint is answered at once, before any check, so that
// a health checker is never refused. It does not ask the app.
if r.Method == http.MethodGet && r.URL.Path == HealthPath {
rq.line.Action = requestlog.ActionAdmin
_, _ = io.WriteString(rq.out, "ok\n")
return
}
refused := rq.check(r.Context())
if refused != nil {
rq.answer(*refused)