Skip to content

2.1.0: local API (phase 1) and the input box's status through the diode - #6

Merged
nc-intezra merged 1 commit into
mainfrom
api-phase1
Oct 28, 2026
Merged

nc-intezra merged 1 commit into
mainfrom
api-phase1

Conversation

@nc-intezra

Copy link
Copy Markdown
Owner

Phase 1 of the API plan: each box serves its own status, read-only, and the output box serves the input box's too, from a status message that crosses the diode like everything else.

Status through the diode

  • Every lidi.heartbeat s the input box sends its status (modules, restarts, transfer.jsonl event counts, bytes, free space, static ARP entry, transport hash) on the lidi endpoint after the last module, signed with dyode.key. A forged status is refused (tested).
  • The output box keeps the last one and warns when it is older than 3 heartbeats or the transport hashes differ.
  • Counts come from a small registry fed by Event::emit (before the per-file switch) and the supervisor; no module code changed.
  • Both boxes write /run/dyode/status-<side>.json; dyode status [--json] prints it (no API needed). Units get RuntimeDirectory=dyode.

The API (cargo feature api, on by default)

  • GET /v1/health, /v1/openapi.json (no token); /v1/status, /metrics (Prometheus), /v1/check (token with read).
  • TLS with rustls (ring), parsing with httparse, a thread per connection up to max_clients, one request per connection.
  • Config: api: {in: {...}, out: {...}}, each box uses its own side. Refused: 0.0.0.0, the box's diode address, and (at start) any address on the diode NIC; tls: off only on loopback.
  • dyode api-token add|list|revoke (SHA-256 hashes, file per box, mode 600); dyode api-cert (self-signed P-256 via openssl, end-entity, prints the fingerprint).
  • Refusals are api_refused events and counters.
  • docs/API.md, docs/api/openapi.yaml (served built-in; a test keeps it equal to the routes).

Setup and install

  • Guided setup: "Local API" screen (address on a non-diode card, certificate, first token shown once).
  • install.sh installs openssl when missing (added to the offline bundle's core packages); the output box's nftables rules drop the API port on the diode NIC.

Compatibility

Both boxes need 2.1.0 (one more lidi endpoint). max_clients default +1; dyode check warns about an explicit value that is too low.

Testing

  • 60 unit tests, plus integration: status through real embedded lidi over loopback, a forged status refused, the API over TLS (health, 401 without/with a wrong token, status, metrics, check, openapi, 404); parallel_files loopback still passes.
  • Real dyode out + dyode in processes over loopback with both APIs: files crossed, both boxes in /metrics, dyode status shows both, killing the input box raised the silence warning after ~3 heartbeats.
  • fmt; clippy -D warnings with and without the api feature.
  • Not yet on hardware.

Monitoring for this (rules, dashboard, Zabbix 7 template): nc-intezra/dyode_monitoring#1.


Generated by Claude Code

- status channel: the input box sends its status every lidi.heartbeat on
  the lidi endpoint after the last module, signed; the output box keeps
  it and warns when it goes silent or the transport hash differs
- stats registry fed by transfer.jsonl events and the supervisor; status
  files in /run/dyode and 'dyode status [--json]'
- API (feature api, default): /v1/health, /v1/status, /metrics,
  /v1/check, /v1/openapi.json over rustls TLS with per-box bearer tokens;
  refuses the diode NIC; 'dyode api-token', 'dyode api-cert'
- guided setup: Local API screen (address, certificate, first token)
- install.sh: openssl when missing; nftables drops the API port on the
  diode NIC; units get RuntimeDirectory=dyode
- docs/API.md and docs/api/openapi.yaml (a test keeps the routes in step)
- tests: status through real lidi + forged status refused + API over TLS

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QXjQsiWnwLMndr5XU9g5LJ
@nc-intezra
nc-intezra merged commit 7600700 into main Oct 28, 2026
23 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants