Commit graph

6 commits

Author SHA1 Message Date
c7229e23ff feat(setup): gate setup with the config toggle and an optional code
D-045 — the setup gate is now `config.setup`, not the peer/SSH tunnel:

- setup: true      -> /setup serves the wizard (the code form first when
                      `setup_code` is set, via the existing D-044 gate);
                      GET / points at the wizard; every other route -> 404.
- setup: false + no admin -> LOCKED: GET / and /setup render an "enable
                      setup" boilerplate; every other route -> 404; the
                      wizard is not claimable.
- completion       -> writes `setup: false` and creates the admin.

`setup_code` is now OPTIONAL: blank => Gate.Required() false => the toggle
alone admits; set => required (reusing the unlock cookie/fingerprint/
redaction/rate-limit). The peer/tunnel gate is retired: `httpx.
SetupRequestAllowed` and `httpx.IsLoopbackIP` are deleted; the XFF/XFP
handling is kept for the client IP and the Secure/__Host- cookies + HSTS
(A6/A11/D-043). The !bootstrapped() fail-safe becomes the locked predicate,
latched at startup.

New door seams: Deps.LockedMode and SetupGate.{Required,CodeForm,Landing,
Locked}; the Gate renders three first-run pages. The startup banner states
the mode and prints the code only when required.

Tests cover the three states, the boilerplate, the code optionality and the
unlock mechanics; live-smoked end to end (locked / wizard / code form /
full bootstrap -> setup: false).
2026-10-15 06:47:33 +00:00
6d421b61fd feat(setup): gate first run with a printed setup code and a first-run page
The real topology is an LXC container (11020) behind Proxmox + Zoraxy, so
the SSH tunnel is impractical: it lands on the container gateway, not
loopback. D-025 is re-revised and D-044 adds the general gate.

- core/setup: a Gate (gate.go) holding the 128-bit setup code (generated at
  first run, or pinned by config `setup_code`) plus a signed unlock cookie
  (`myday_setup`) that carries a keyed one-way FINGERPRINT of the code, never
  the code itself. The code is single-use (retired on the first success) and
  the comparison ignores case/separators.
- The unlock action (`POST /setup?do=setup&action=unlock`) is CSRF-protected
  (A15), rate-limited (the /setup A3 class) and audited; a wrong or absent
  code gets the same generic 403 page.
- The door (server.Deps.SetupGate): in setup mode the wizard is served to
  EITHER the direct tunnel (gate a) OR an unlocked request (gate b); `GET /`
  and an un-unlocked `GET /setup` render a friendly first-run page with the
  code form — never a bare 404 — and every other route stays 404.
- cmd/myday prints an unmistakable startup banner: setup mode, the wizard
  URL, the code, where to read it (journalctl / pct exec 11020) and the
  restart that adopts the persisted secrets.
- httpx.Signer.Fingerprint backs the unlock cookie; config gains `setup_code`.

Tests cover the boilerplate at `/` and `/setup` (200, not 404), the unlock
(code → wizard; wrong/absent → generic, 429 under the limit), single-use, the
CSRF requirement, access-log redaction, and that a non-/setup route is still
404. Gate green (build · vet · test -race); live-smoked against the binary.
2026-10-15 06:33:13 +00:00
f58d33aee1 docs: add the Zoraxy deployment guide and systemd unit
Document the D-043 deployment: the browser -> Zoraxy (10.1.0.10, TLS) ->
app (0.0.0.0:8080, http) topology, the config.yaml, the Zoraxy ProxyHost
headers (X-Forwarded-For + X-Forwarded-Proto), the firewall rule, the
tunnel-only bootstrap, systemd, and the misconfig warnings.

- config.example.yaml: trusted_proxies: ["10.1.0.10"] with the
  silent-failure and firewall caveats.
- deploy/myday.service: the systemd unit (Type=simple, Restart=on-failure,
  User/WorkingDirectory/ExecStart, After=network-online.target).
- docs/deploy-zoraxy.md: the full walkthrough.
- README.md: the Deployment section points at the guide.

Docs/deploy only — no code change.
2026-10-15 06:15:41 +00:00
9a9888fa7b docs: document the Zoraxy deployment (README + config example)
- config.example.yaml: listen 0.0.0.0:8080, base_url https://myday.sechpoint.app,
  trusted_proxies = Zoraxy; a comment stating :8080 must be firewalled to Zoraxy
  only and that the bootstrap is tunnel-only (D-025/D-043).
- README: a Deployment section (TLS at the proxy, the app on 0.0.0.0:8080, the
  firewall rule) and the tunnel-only bootstrap (ssh -L 8080:127.0.0.1:8080 →
  http://127.0.0.1:8080/setup, the one path a proxy request cannot take).
2026-10-15 05:40:38 +00:00
f5e4fd0055 refactor(config): drop the dead secrets.session_key
REVIEW-001 (M0) L1c/L2s: secrets.session_key was validated and generated by
the wizard but never read by any code path — dead config (KISS).

Remove the field, its validation entry and its generation; the example notes
that a placeholder is replaced at startup in setup mode (M1s) as well as by
the wizard's finish.
2026-10-14 11:30:06 +00:00
57610cdbae docs: add the project plan, M0/M0.1 specs, agent guide and README
- PROJECT_PLAN.md: the decision log of record through D-042 and the M0.1 slice
- docs/specs: SPEC-002…009 — routing · door · identity/sessions · /setup ·
  enroll/login · roles/chain/recovery · module registry · the web layer & PWA
  (plus docs/specs/README.md, the index)
- AGENT.md: the working rules — commit AND push at every submilestone (gate
  green), Conventional Commits, never commit secrets
- README.md: the quickstart, the first-run/SSH-tunnel steps and the
  localhost/loopback caveat (SPEC-009 §13 Q-3): with an https base URL the
  CSRF/session cookies are Secure, so reach the app at localhost/127.0.0.1
- config.example.yaml: the settings template (D-035)
2026-10-14 10:53:44 +00:00