feat: Sign in with OTM, health, changelog, tides beacon, Ideas — first OTM release (0.4.0)
Build / Build and release (push) Failing after 19s

app/otm.py is the Python port of pickup's ticket verifier (HS256, mandatory
exp, audience check, alg only read to reject, never raises) plus a signed
session cookie and an in-memory single-use jti guard. portable.py gates every
route but PUBLIC_PATHS behind a session and fails CLOSED (503) with no secret
— it is a fetch proxy. /api/health reports the version, /changelog renders
CHANGELOG.md, the footer carries version/sign-out/Ideas, tides beacon from
TIDES_HOST/TIDES_SITE_ID. Dockerfile: OTM labels + HEALTHCHECK. 17 tests.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014LCQmFvKshyAJsE8C3B5ET
This commit is contained in:
2026-10-18 22:22:27 -05:00
co-authored by Claude Fable 5.1
parent d2d8c55d46
commit 71abf89784
8 changed files with 586 additions and 8 deletions
+8 -1
View File
@@ -44,7 +44,14 @@ Make it a proper **OTM first-party app** per
4. Keep the Dockerfile's non-root user (`thirteener`) and gunicorn; add a
`HEALTHCHECK`.
Until step 2 lands, basic auth stays — it is the whole gate.
**Status 2026-10-18 (v0.4.0): steps 1–4 are built.** `app/otm.py` holds the ticket
verifier + session cookie + health/changelog/footer/Ideas; `portable.py` mounts the
`before_request` gate (everything but `otm.PUBLIC_PATHS` needs a session; no secret =
503, never open) and the routes. Tests: `cd app && ../.venv/bin/python -m unittest`
(pure `test_otm.py` + Flask test-client `test_app.py`). The platform catalogue entry
landed in otm-admin 0.148.0. Deploy = stop the hand stack (`cd /srv/otm/clients/13ft
&& docker compose down`), then `build_app 13ft` + `deploy_app 13ft`; grant `app:13ft`
to each reader on /users. The in-memory jti guard assumes gunicorn's single worker.
## Dev