b637947ffd
Operator ruled 2026-08-18 on the 5-character PARK_API_KEY flagged during the v1.0.0-beta.2 deploy: leave it. The henge is LAN/WG-internal and never internet-exposed. Written down so the next audit does not re-raise a question that has already been answered.
74 lines
4.2 KiB
Markdown
74 lines
4.2 KiB
Markdown
# park (stonehenge-park — "the henge")
|
|
|
|
Self-contained needs-attention tracker: FastAPI + SQLite (FTS5) + an in-process
|
|
scheduler, one container. Source: `gitea.phasefinal.com/vh/stonehenge-park`,
|
|
deployed at tag **v1.0.0-beta.2** (commit `2c258f7`). Owned by `park-dev`.
|
|
|
|
- **Host:** ana-docker (`10.250.50.70`), compose home `/opt/docker/compose/park/`.
|
|
Permanent home since 2026-08-13 (migrated off nh3-docker before the v1.0.0 final cut).
|
|
- **Stable name:** `park.phasefinal.com` → `10.250.50.70` (Cloudflare, DNS-only/internal) — clients
|
|
and Homepage point at the name so future moves need no client edits.
|
|
- **Port:** `8420` (host + container). **LAN/WG-internal only — never internet-exposed.**
|
|
- **Data:** named volume `park-data` → `/data`; SQLite single file `/data/park.db`
|
|
(the sole source of truth). Covered by restic via the host's `/var/lib/docker/volumes`
|
|
backup source — no per-volume add needed. (⚠ nh3-docker's restic repo was broken as of
|
|
2026-08-12 — see fleet infra notes.)
|
|
- **Secret:** `PARK_API_KEY` from the vault (`secret get nh3-dev/park-api-key`), in the
|
|
host `.env` (chmod 600). `/healthz` and the UI shell are unauthenticated, asset GETs
|
|
under `/ui/assets/` are public, and `/park/*` needs the bearer key.
|
|
**The key is 5 characters, and that is a settled decision — leave it.** Surfaced to
|
|
the operator 2026-08-18 with a rotation offer; ruled *leave as is*. The service is
|
|
LAN/WG-internal and never internet-exposed, so the exposure is "already on the
|
|
network", not the open web. Do not re-flag this on the next audit.
|
|
- **Health:** `GET /healthz` → `{"status":"ok"}` (image `HEALTHCHECK` built in).
|
|
|
|
## Image is built locally (no registry yet)
|
|
|
|
```bash
|
|
# ⚠ on ana-docker (10.250.50.70) — NOT nh3-docker, decommissioned for this stack 2026-08-13.
|
|
# The source is exported per-tag from a checkout that has the tag, so the previous
|
|
# tag's tree stays on the host as a rollback. From a box with the repo:
|
|
git -C ~/development/stonehenge-park archive --format=tar v1.0.0-beta.2 | \
|
|
ssh infra-ops@10.250.50.70 'mkdir -p ~/deploy-src/stonehenge-park-v1.0.0-beta.2 &&
|
|
tar xf - -C ~/deploy-src/stonehenge-park-v1.0.0-beta.2'
|
|
|
|
# then on ana-docker (infra-ops is in the docker group — no sudo needed):
|
|
cd ~/deploy-src/stonehenge-park-v1.0.0-beta.2
|
|
docker build -t park:v1.0.0-beta.2 .
|
|
cd /opt/docker/compose/park && docker compose up -d park
|
|
```
|
|
|
|
⚠ **Never `docker compose down -v`** — that removes `park_park-data` and every parked
|
|
idea with it. `up -d` and plain `down` both preserve it.
|
|
|
|
Swap `image:` for a registry ref once one exists (park-dev left the door open).
|
|
|
|
## althing wiring (TODO)
|
|
|
|
The scheduler posts needs-attention snapshots to althing handle `henge-crow` by
|
|
shelling out to `althing-cli post` inside the container. `althing-cli` is **not yet
|
|
wired into the container**, so `PARK_ALTHING_CHANNEL` is set **empty** in the host
|
|
`.env` (push disabled; REST endpoints fully functional — graceful by design). To
|
|
enable: get `althing-cli` reachable in-container (bind-mount + config / sidecar /
|
|
host-run), set `PARK_ALTHING_CHANNEL=henge-crow`, recreate.
|
|
|
|
## Verify
|
|
|
|
```bash
|
|
curl -s http://park.phasefinal.com:8420/healthz # {"status":"ok"}
|
|
curl -s http://park.phasefinal.com:8420/ # UI shell
|
|
curl -s http://park.phasefinal.com:8420/ui/assets/favicon.svg # brand assets (public GET)
|
|
curl -s -H "Authorization: Bearer $KEY" \
|
|
"http://park.phasefinal.com:8420/park?limit=100" # the parked items themselves
|
|
```
|
|
|
|
⚠ **Use GET, never `curl -I`.** Every route on this app 401s on **HEAD** — including
|
|
`/healthz` and `/`, so it is app-wide and not an asset or auth-scope problem. `curl -sI`
|
|
therefore reports a false failure on a perfectly healthy deploy. Verified 2026-08-18:
|
|
`HEAD /healthz -> 401` while `GET /healthz -> 200`. Reported upstream to park-dev.
|
|
|
|
⚠ **`/park/due-count` returning 0 is not a data-loss signal.** It counts what is *due
|
|
now*; a henge holding 28 items can legitimately report `{"count":0}` with `/park/due`
|
|
empty across overdue/today/stale. To check items actually survived a redeploy, hit
|
|
`GET /park` (or count rows in `/data/park.db`), not the due counters.
|