Repository navigation
v1.1.0 — hardened, keyless again, and gated on a booted stack
Minor release. It closes the security gaps found against ISO 27001, NIST CSF 2.0,
SSDF and ASVS 5.0, restores a basemap that works with no key, and stops images
from being published unless the real stack boots and renders.
Read "Upgrading" before you pull: several defaults now fail closed.
The globe works without a key again
CARTO began stamping "API KEY REQUIRED" onto every keyless Dark Matter tile,
server-side requests included, so v1.0.x globes showed the watermark. The default
basemap is now Esri's World Dark Gray canvas, with its label layer composited on
the server and cached as before.
- If the tile proxy can't be reached (backend down or still booting), the browser
fetches Esri base tiles directly, so the globe is never blank. Those fallback
tiles have no labels. - The map no longer waits on
/api/config. It renders on keyless defaults with a
"connecting to backend…" label, then upgrades in place. - The sign-in prompt appears only after the backend actually answers 401, not
whenever the backend is unreachable.
Trade-off: Esri's canvas stops at zoom 16 (CARTO went to 20), so street level is
upsampled. The satellite basemap still reaches 19.
Colour schemes
The seven hand-rolled schemes now use published palettes: IBM Carbon (default,
Daylight), GitHub Primer (Midnight, High contrast) and Radix Colors (Slate,
Night watch, Paper). The four Blueprint schemes are unchanged. Every scheme clears
WCAG AA in the contrast guard.
Security
The full gap analysis is docs/security/gap-analysis-2026-09.md, and all 253
ASVS 5.0 Level 1 + 2 requirements are assessed in
docs/security/asvs-l2-assessment.md. Highlights:
op.pythonruns in a bubblewrap jail and refuses to run without one.- Running a workflow or managing a model requires operator authority.
- The rate limiter no longer trusts a caller's own
X-Forwarded-For, and
X-Velocity-Tieris ignored from every peer. - Foundry is closed on a keyless box, and
/mcpanswers 503 untilAPI_KEYis set. - Baseline security headers, and a CSP in every production web build.
- The audit log is append-only and hash-chained (
GET /api/audit/verify). - Supabase sessions are verified against JWKS and re-checked with GoTrue, failing
closed. MFA and a maximum session age are opt-in. - Sidecars require a per-spawn bearer token.
Releases are gated
publish.yml now pushes images only after ci.yml and the new
release-gate.yml pass for the tagged commit. The gate builds the shipped
images, boots them with docker-compose.prod.yml, and drives the page in a real
browser. That includes loading with the API stopped and recovering in place when
it starts. The Cloudflare gateway and deploy.sh are gone; releases ship as
ghcr images only.
Upgrading
docker-compose.prod.ymlrequiresVELOCITY_VERSION(there is no
:latest):VELOCITY_VERSION=v1.1.0 docker compose -f docker-compose.prod.yml pull VELOCITY_VERSION=v1.1.0 docker compose -f docker-compose.prod.yml up -d
- nginx binds
127.0.0.1:8080. Put a TLS reverse proxy on the host in front
of it. ?key=works on WebSocket upgrades only. HTTP callers must send
X-API-KeyorAuthorization: Bearer.- Secrets shorter than 32 characters refuse to boot.
- Alert-rule webhooks must be public hosts unless listed in
WORKFLOWS_HTTP_ALLOW_HOSTS. op.pythonreturns 503 where the kernel blocks unprivileged user
namespaces, including the production container. Set
WORKFLOWS_PYTHON_UNSANDBOXED=1only if you accept running it unjailed.- The first tile requests after upgrade fetch from Esri. Old CARTO tiles stay in
the cache directory but are no longer served.
The operator-facing list is in docs/decisions.md and
docs/security/operator-hardening.md.
Images
ghcr.io/andrewctf/velocity-api:v1.1.0ghcr.io/andrewctf/velocity-web:v1.1.0
Full changelog: v1.0.1...v1.1.0