Skip to content

NetIgnite V2 - #5

Merged
LeiCraft merged 19 commits into
mainfrom
v2
Oct 21, 2026
Merged

LeiCraft merged 19 commits into
mainfrom
v2

Conversation

@LeiCraft

Copy link
Copy Markdown
Member

No description provided.

…(v2 foundation)

NetIgnite v2, milestone 1: Nuxt 4 + Nuxt UI dashboard, Hono API at /api/v1 with OpenAPI docs,
Drizzle on bun:sqlite, opaque bearer sessions and API keys.

- Agent gateway at /ws/agent with protocol v2 (JSON frames, HELLO with capabilities,
  per-request answers, keep-alive). Agents enroll with a single-use token and generate their
  own secret; the server stores only its hash.
- Devices with Wake-on-LAN, status checks (MAC link-local, IPv4, IPv6, SSH port, host agent),
  shutdown/reboot through a host agent, favorites.
- Sharing devices with other users as viewer, operator or manager.
- Public sign-up as an admin setting; admin settings page.
- One-time import of NetIgnite v1 databases (scripts/import-v1.ts, bundled into the image).
- Port 18232 kept from v1; the database moves to data/netignite.sqlite.
- SQLite foreign keys enabled; transactions that need atomicity are synchronous.

BREAKING CHANGE: v1 agents can't connect to v2 and have to be set up again. The REST API is
replaced by /api/v1.
It makes about 20 requests whose tokens are verified with argon2id, which can exceed the
default 5-second timeout on a busy machine.
ESP32 firmware v2 is set up from its serial console with
`setup <server-url> <enrollment-token>`. The agent page now shows that command, like the
pairing command for Linux agents, until the browser installer is available.
- CI also runs on pushes to v2 and builds the Docker image, starts it and checks health, the
  dashboard, the initial admin and the bundled v1 import tool.
- Create Release tags the commit it runs on (it used to tag the default branch), includes the
  database migrations in app.tar.gz, validates the version and publishes the Docker image.
  Versions with a suffix (2.0.0-beta.1) are always pre-releases.
- Publish Docker Images refuses to publish a stable image (which moves `latest`) from any
  branch other than main.
- CI also runs on pushes to v2 and builds the Docker image, starts it and checks health, the
  dashboard, the initial admin and the bundled v1 import tool.
- Create Release tags the commit it runs on (it used to tag the default branch), includes the
  database migrations in app.tar.gz, validates the version and publishes the Docker image.
  Versions with a suffix (2.0.0-beta.1) are always pre-releases.
- Publish Docker Images refuses to publish a stable image (which moves `latest`) from any
  branch other than main.
- Firmware catalog: syncs Agent-ESP32 GitHub releases (release.json + flash images) into
  NETIGNITE_FIRMWARE_DIR on start and every 6 hours, checks size and SHA-256 of every file and,
  with NETIGNITE_FIRMWARE_PUBLIC_KEY, the ECDSA signature of the app image. Keeps the 5 newest
  releases plus the newest stable one.
- NVS v2 image writer, byte-identical to Espressif's nvs_partition_gen.py (fixtures generated
  with esp-idf-nvs-partition-gen 0.3.0).
- POST /v1/agents/:id/flash-image: NVS image with the server URL, the agent's name and a new
  single-use enrollment token (no-store).
- GET /v1/firmware, GET /v1/firmware/:version/files/:file, GET /v1/admin/firmware,
  POST /v1/admin/firmware/sync; admin setting firmware_channel (stable/prerelease).
- Dashboard: agent Install tab with ESP Web Tools 10.4.0 (manifest and all parts as blob: URLs,
  parts checked against their SHA-256 in the browser), firmware section in Server Settings.
The firmware uses its name as the DHCP host name, so "Garage ESP32" is written as "Garage-ESP32".
- OTA updates of ESP32 agents: POST /v1/agents/:id/update and /v1/agents/bulk-update (one agent
  after another). The server sends OTA_BEGIN with a path on this server; the agent downloads the
  image with its own credential (GET /v1/firmware/:version/files/:file now accepts ESP32 agent
  credentials), reports OTA_PROGRESS and restarts. HELLO with the new version, or
  info.ota_failed_version after a rollback, finishes the update. Agents report `update` and
  `update_available` (newer release of the admin's channel).
- Console: /ws/console streams an agent's log to its owner (first-message auth, Origin check,
  session checked every minute). REST: GET /logs, GET /info, PUT /device-config (server URL,
  host name, log level, IP; tried by the agent before it keeps them), POST /reboot,
  POST /factory-reset (also revokes the credential).
- Protocol: capabilities ota, logs, config, device.reboot, device.reset; LOG and OTA_PROGRESS
  events; the gateway notifies listeners when an agent disconnects.
- Enrollment takes the agent's kind; a token of another kind gets 409 and stays valid.
- /install/linux.sh: downloads the Linux agent from the Agent-Linux releases, checks SHA256SUMS,
  pairs and installs it. The dashboard shows it as the Linux agent's setup command.
- Dashboard: firmware card with update progress, Console tab, "Update n agents" on the list.
- Devices get an SSH login (owner only, write-only): a server-generated Ed25519 key pair (OpenSSH
  format; the dashboard shows the authorized_keys and sudoers lines) or a password. Secrets are
  encrypted with the server's secrets key (NETIGNITE_SECRETS_KEY or config/secrets.key).
- The device's agent logs in with SSH_CHECK (authentication only, no session) and SSH_EXEC (fixed
  shutdown/reboot command per OS, sudo optional). Host keys are trusted on first use: test the
  login, then trust the fingerprint; changing host or port un-trusts it.
- Shutdown and reboot use the device's host agent first, then SSH.
- API: GET/PUT/DELETE /v1/devices/:id/ssh, POST /ssh/test, POST /ssh/trust. Dashboard: SSH tab.
…eboot

For POSIX devices the generated key's line gets a forced command that lets exactly the agent's two
commands through, so the key is useless for anything else. Status checks open no session, so the
forced command doesn't run for them.
- v1 import: the v1 admin's password only replaces the initial admin's while its password-reset
  link is unused; an admin who set a password and logged out kept losing it. The token file is
  only deleted in that case.
- An unreadable NETIGNITE_FIRMWARE_PUBLIC_KEY no longer crashes the server: every firmware sync
  fails with the reason (shown in Server Settings), so unsigned firmware is never accepted.
- Sign-up and admin "Create user" use the same password rule as changing and resetting a password,
  and the forms check it before submitting.
- "Remember me" keeps the session cookie for 7 days, as long as the session lasts.
- The SSH tab and README say that ESP32 agents (2.0.0-beta.2 and newer) log in over SSH too; OTA
  needs firmware 2.0.0-beta.2, not "2.1".
- docker-compose.yml: SMTP settings are commented out instead of pointing at a placeholder host.
…ver SSH

- PWA: web app manifest, icons, a service worker that only serves an offline
  page when the server can't be reached (no API or WebSocket caching), and the
  iOS home screen meta tags.
- SSH tab: explains why the Linux agent is the safer choice, asks for a
  dedicated user without other rights and warns when the login is root or an
  administrator.
- README: the same advice in the SSH section.
Windows only shuts down for administrators, so "never use an administrator"
can't be followed there. With Windows selected, the SSH tab explains that the
login can't be restricted and asks for a separate account, a generated key and
restrict,from="<agent's IP>" instead; the root/admin warning is Linux-only.
- Warn on start when a v1 database (data/db.sqlite) lies next to the v2 one
  and nothing was imported from it: the stable release moves `latest`, so v1
  servers that pull it start v2 with an empty database.
- The Linux agent install script takes the newest stable Agent-Linux release,
  and a pre-release only while there is none.
- "Firmware 2.0.0 or newer" instead of 2.0.0-beta.2 in the SSH tab and README.
- Changelog for 2.0.0, written as the release notes for v1 users.
@LeiCraft
LeiCraft merged commit 6cec2a3 into main Oct 21, 2026
3 checks passed
@LeiCraft
LeiCraft deleted the v2 branch October 21, 2026 20:38
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.

1 participant