Commit Graph

5 Commits

Author SHA1 Message Date
jhodgkin 199d0da675 Alert on genuinely new (never-seen-before) devices
CI / web (push) Successful in 16s
CI / api (push) Successful in 23s
New seen_macs table: permanent, insert-only, MAC-keyed record of the
first time each device was ever seen -- deliberately decoupled from
devices.first_seen (IP-keyed, would false-positive on every DHCP
lease change). Bootstrap-safe: first call seeds the baseline from
whatever's currently on the network without alerting on all 71+
existing devices at once. Verified locally: bootstrap call reports
nothing new, repeat calls with the same MACs report nothing new, one
genuinely new MAC gets reported exactly once.

Pushes a Home Assistant persistent_notification when a new MAC
appears (gated behind HOME_ASSISTANT_TOKEN + homeAssistant.url in
hosts.yaml -- missing config just means no push, detection still
runs). Also surfaced directly in the dashboard as a blue "new" badge
for anything first seen in the last 24h, independent of HA config.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-12 23:58:26 -06:00
jhodgkin 542a3d8ce0 Wire up on-demand deep-check: API route + dashboard button
CI / web (push) Successful in 18s
CI / api (push) Successful in 24s
POST /api/devices/:ip/deep-check runs deep-check-device.sh on the
CT122 host via SSH (reaches its own LAN IP), returns mDNS/SSDP/port
scan results. "Deep check" button on unknown device rows in the
dashboard shows results inline below the row.

Verified end-to-end via SSH before wiring into the API: correctly
identified Home Assistant via SSDP (friendlyName/manufacturer/model),
and confirmed both a shell-injection attempt and an out-of-subnet IP
get rejected cleanly by the forced command's input validation.

Closes #15 (all four pieces: OUI, mDNS, manual labels, deep check).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-12 23:15:24 -06:00
jhodgkin 04282232cc Add LAN device discovery (ping sweep + ARP, known/unknown labeling)
CI / web (push) Successful in 17s
CI / api (push) Successful in 23s
Runs as a host-level systemd timer on CT122 (scripts/discover-devices.sh)
rather than inside the api container, since real ARP entries live in the
host's network namespace, not Docker's bridge network. See
docs/device-discovery.md for the full writeup, including why literal
passive-only ARP reading was dropped (near-empty result in practice).

API reads the resulting JSON file each poll cycle, cross-references
config/hosts.yaml's knownDevices list by IP, and serves /api/devices.
Dashboard gets a new "Network Devices" table.

Closes #9.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-12 20:49:22 -06:00
jhodgkin 7df08cd16d Add SshHostCollector for .180 (omv) and .171 (ripper)
CI / web (push) Successful in 20s
CI / api (push) Successful in 27s
Extends monitoring to the two bare-metal boxes Proxmox can't see.
Uses a dedicated ed25519 key with a forced authorized_keys command
(see docs/ssh-collector-key-setup.md) so a leaked key can only ever
run the fixed read-only stats script, never arbitrary commands.

CPU is approximated from 1-min load average / core count (a true
utilization % would need two /proc/stat samples).

Closes #8.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-12 20:40:10 -06:00
jhodgkin a075488f4b Scaffold homelab-monitor: Fastify API + React dashboard + CI
CI / web (push) Failing after 1m11s
CI / api (push) Successful in 1m19s
Vertical slice for Phase 1 (v1-dashboard milestone): Proxmox collector,
SQLite storage, local auth, and a dashboard UI showing host/container
status cards. Config-driven collector registry so future data sources
(SSH-based hosts, Zabbix, network discovery) plug in without rewiring.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-12 20:18:44 -06:00