Commit graph

5 commits

Author SHA1 Message Date
Samuel James
70f88efdc8
Add mesh prerequisite gate (#33)
* Add mesh prerequisite gate (NetBird verification before app config)

Implements the design in docs/mesh-prerequisite-gate.md per the user's
DECIDE A-D answers: a permanent admin override, B1 (reachable) verification
with host mesh IP shown informationally, members allowed in with a notice
instead of being blocked, and mesh.required defaulting off so the live
production instance is unaffected.

- system_config kv table + getConfig/setConfig helpers
- /api/system/mesh-status, /mesh/verify, /mesh/override, /mesh/required
- AuthContext gains a 'needs-mesh' status (admins only) and exposes
  meshStatus for a member-facing banner
- MeshGate page reuses the integration create+test flow to connect NetBird

* Make mesh verification universal (CIDR check, not NetBird-specific)

Replace the NetBird-adapter-based "reachable" check with a vendor-agnostic
one: the admin supplies the mesh's IP range (CIDR), and verification just
confirms this host has an address inside it. Works identically for
NetBird, WireGuard, ZeroTier, Tailscale, or any other mesh tech, with no
integration record or vendor API call required.

* Add reachability fallback for routed meshes (VPC peering, etc.)

A host can be on the mesh's "side" of a routed network (e.g. a VPC peered
into a NetBird/WireGuard mesh) without holding a local IP in the mesh's
own CIDR. Local-IP-in-CIDR stays the primary check; if it fails, the admin
can supply a known peer/gateway IP on the mesh and we verify by pinging
it instead. Adds iputils to the backend image for the ping binary.

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-06-20 17:30:46 -04:00
Samuel James
7a1d260a35
Enable OpenSSL legacy provider for old-format encrypted SSH keys (#17)
* Add editable display-name field to generic integrations

Lets users set a custom name for Proxmox, Docker, AWS, Remote Desktop,
Netbird, Cloudflare, Uptime Kuma, and Weather integrations, separate
from the host/IP field, mirroring the SSH host rename pattern.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016kF4hZWEkRCPPvCZTeXxn4

* Surface the new-integration name field as a labeled input

The name field for new generic integrations was a faint header input
with only placeholder text, easy to miss. Move it into the form grid
as a proper labeled "Name" field next to the other connection fields.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016kF4hZWEkRCPPvCZTeXxn4

* Add file upload for SSH private key and certificate fields

Lets users pick a key file from disk (e.g. ~/.ssh) instead of pasting
its contents into the Private Key / OPKSSH Certificate fields.

* Fix SSH private key paste corrupting multi-line PEM format

Private Key and Certificate fields were single-line <input> elements,
which strip newlines on paste and corrupt PEM-formatted keys (causing
'Unsupported key format' errors). Render them as multi-line textareas
instead so pasted keys keep their line breaks.

* Enable OpenSSL legacy provider for old-format encrypted SSH keys

OpenSSL 3's default provider disables the MD5-based KDF used by
traditional encrypted PEM keys (BEGIN RSA PRIVATE KEY + DEK-Info
headers), causing "error in libcrypto: unsupported" when the ssh
binary tries to decrypt them for certificate-based auth.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016kF4hZWEkRCPPvCZTeXxn4

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-06-20 08:45:02 -04:00
Samuel James
5a3e4c51f9
Fix integration save data loss; add SSH host card collapse (#16)
* Add editable display-name field to generic integrations

Lets users set a custom name for Proxmox, Docker, AWS, Remote Desktop,
Netbird, Cloudflare, Uptime Kuma, and Weather integrations, separate
from the host/IP field, mirroring the SSH host rename pattern.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016kF4hZWEkRCPPvCZTeXxn4

* Surface the new-integration name field as a labeled input

The name field for new generic integrations was a faint header input
with only placeholder text, easy to miss. Move it into the form grid
as a proper labeled "Name" field next to the other connection fields.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016kF4hZWEkRCPPvCZTeXxn4

* Add file upload for SSH private key and certificate fields

Lets users pick a key file from disk (e.g. ~/.ssh) instead of pasting
its contents into the Private Key / OPKSSH Certificate fields.

* Fix SSH private key paste corrupting multi-line PEM format

Private Key and Certificate fields were single-line <input> elements,
which strip newlines on paste and corrupt PEM-formatted keys (causing
'Unsupported key format' errors). Render them as multi-line textareas
instead so pasted keys keep their line breaks.

* Fix integration save wiping untouched config fields

The PUT /api/integrations/:id route fully overwrites config_json with
whatever config object is sent (no merge), but buildPayload only
included fields the user had actually edited. Saving after editing
just one field (e.g. pasting a new SSH key) silently dropped every
other config field. Merge the existing integration's config into the
payload before sending.

* Add collapse/expand for SSH host cards

Click the chevron to collapse a host's card once it's configured.
Collapsed cards keep all field state in memory (just hidden), and
auto-collapse after a successful Save.

* Install openssh-client in backend image for certificate-auth SSH

Certificate-based SSH connections shell out to the system ssh binary
via node-pty (ssh2 has no OpenSSH certificate support), but the
alpine runtime image never installed openssh-client. This caused
'execvp(3) failed: No such file or directory' for any host with an
OPKSSH certificate configured.

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-06-20 08:30:21 -04:00
Samuel James
ef5e497554 Production deploy: nginx /api proxy, native-module toolchain, hardened CI
The frontend calls the API with relative paths (fetch('/api/...')), so in
production those requests hit the nginx frontend container on :8080 — which
previously only served the SPA and would 404 every API call and WebSocket
route. nginx.conf now proxies /api/ to the archnest-backend service with
WebSocket upgrade support, long timeouts for terminals/tunnels/transfers, and
a 1GB body limit matching the backend's upload cap.

The backend Dockerfile now installs python3/make/g++ in both the build and
runtime stages so the native modules (better-sqlite3, ssh2, node-pty) compile
on alpine instead of crashing the container at startup.

The deploy workflow gains a validate job (type-check + build both apps before
touching the host), a pre-flight check that refuses to deploy without the
host-side .env, and a post-deploy health check against /api/health and the
frontend, with concurrency guarding.
2026-06-19 14:22:08 -06:00
Claude
a0b71c7028
Add backend skeleton: Fastify + SQLite API with auth and integrations
- Single-user JWT auth with a first-run /api/setup endpoint, gated by
  GET /api/system/setup-status, to back an upcoming enrollment page
- SQLite schema for users, integrations, secrets (AES-256-GCM encrypted),
  bookmarks, and bookmark categories
- Integration adapter registry with real health-check adapters for
  Uptime Kuma and Docker, stubs for the rest, wired to
  POST /api/integrations/:id/test
- CRUD routes for integrations and bookmarks
- backend/ as its own Docker service in docker-compose.yml, Vite dev
  proxy for /api, .env.example for required secrets

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BbJV5nm8KPVH1oNJYKpnoF
2026-06-18 19:04:48 +00:00