Commit Graph
5 Commits
Author SHA1 Message Date
2GT-RichandClaude Opus 5 273a0da737 fix(deploy): restore NetFlow to the published compose file, and generate it (v0.23.34-beta)
Closes #121.

The Quick Deploy file was missing NETFLOW_BIND_PORT and the 2055/udp mapping, so
the collector bound inside the container and nothing reached it. NetFlow did
nothing, silently, with an empty traffic page and no error — for everyone
following the path the README tells new users to take.

The report was accurate and understated. docker-compose.ghcr.yml had drifted for
seven weeks, and three closed issues had never reached it:

  * NETFLOW_BIND_PORT and the UDP port — as reported
  * all five POLLER_* tunables — #114, whose fix was "pass the tunables through"
  * the Redis memory ceiling and eviction policy — #116
  * TZ on the postgres service, which nobody had noticed at all

The middle one is the uncomfortable part. Four days ago #114 was closed by
forwarding poller settings that were documented but inert, with a comment saying
setting them "did precisely nothing". On Quick Deploy that remained true, because
one compose file was fixed and the other was not — including the advice given to
that reporter about which knob to turn.

So patching the four gaps would have been treating the symptom. The two files
describe the same system and differ only in where images come from; maintaining
both by hand meant remembering every change twice, and the one forgotten was
always the file no maintainer runs.

docker-compose.ghcr.yml is now generated from docker-compose.yml by
scripts/generate-ghcr-compose.mjs, which performs the two build-to-image swaps
and nothing else. Substitution is textual rather than parse-and-reserialise so
comments survive — the reasoning about Redis eviction is worth more than the two
lines it explains. The file stays committed and browsable, because the README
tells people to curl it directly.

A --check mode runs as the first preflight gate and as its own CI job, both of
which fail when the committed file does not match what the generator produces.
Verified by deleting the NetFlow line and watching the guard reject it, with the
reason and the fix in the failure message.

Reported by @mamb1329, on their first issue.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-06 13:08:56 -07:00
2GT-RichandClaude Opus 4.8 9e962939ea fix(security): self-healing secrets + auth/SSRF/header hardening (v0.16.10-beta)
Follow-up to the /terminal authorization fix: a full-codebase security
review surfaced several more issues, fixed here. All changes are designed
to roll out with no interruption to existing deployments — no forced
migration, no manual re-key, no boot failure.

Self-healing secret management (utils/secrets.ts):
- JWT_SECRET / ENCRYPTION_KEY auto-generate to strong values on first boot
  and persist to the app_data volume (0600, outside the DB) when not set
  to a strong value in the environment. Replaces the prior behavior of
  running on the public repo defaults.
- decrypt() tries the current key plus every legacy/default key, so
  existing device credentials keep decrypting after a key change; a
  startup sweep re-encrypts stale rows forward (db/reencryptCredentials.ts).
- verifyToken() accepts the current signing secret plus prior *strong*
  secrets (never the public defaults), so rotation doesn't invalidate live
  sessions; sessions signed with a default secret require one re-login.
- Dockerfile pre-creates /app/data as the app user so the non-root
  process can persist to a fresh named volume; app_data volume added to
  both compose files; compose secret defaults changed to empty (auto-gen).

Authorization / input:
- Default Socket.IO namespace now requires a valid JWT (was unauthenticated
  and broadcasting fleet-activity events); frontend sends the token and
  drops the shared socket on logout.
- Webhook delivery blocks SSRF to loopback/private/link-local/CGNAT ranges
  and pins the request to the validated IP (WebhookService.ts).
- Rate limit added to /auth/totp/verify; global mutation backstop on /api.
- Password policy (>=10 chars, letter+digit) enforced on set/change/create.
- system.ts used verifyToken as middleware (always 500); now requireAuth.

Hardening:
- CSP + HSTS/nosniff/frame-deny headers in nginx, scoped to allow the
  OpenStreetMap tile/geocoding hosts the maps use.

Docs/tests:
- README secret section rewritten for the self-healing model.
- New unit tests for secret resolution, persistence, rotation, and
  legacy-key decryption (97 tests pass).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 12:42:46 -07:00
DenisandCursor Agent a12f52ebc7 feat: non-blocking bulk-add, CORS hardening, credential preset access control (#31)
* devices: hide discovered neighbors that are already managed

Discovered Devices showed every unresolved MikroTik neighbor, even when
the neighbor was obviously the same device a managed node is reporting
through a different link / MAC / alias. Since we already know every
managed device interface MAC, primary IP, and system identity, we can
flag those rows.

- /api/devices/discovered now annotates each row with duplicate_of_device_id
  and duplicate_of_device_name when the neighbor matches a managed device
  by interface MAC, primary IP, or system identity.
- Add a Hide duplicates of managed devices toggle (default on) above the
  table, with a count of how many matches were found. When enabled, the
  list hides matched rows; when disabled, matches stay visible but are
  dimmed and tagged Already managed so the origin is clear.
- Suppress the Add to Manager action for rows that are already a
  managed device, since adding them would create a second record for the
  same hardware.

Co-authored-by: Denis <denis-ev@users.noreply.github.com>

* devices: safer duplicate handling, try-all safeguards, and timezone/firmware fixes

Co-authored-by: Denis <denis-ev@users.noreply.github.com>

* Non-blocking follow-ups: parsePort util, tests, bulk-add queue, preset rate limit

Co-authored-by: Denis <denis-ev@users.noreply.github.com>

* fix(security): tighten CORS, Redis rate limits, and preset access controls

Require explicit CORS origins in production, align Socket.IO CORS with HTTP,
default Docker Compose to local HTTPS origins, and remove the in-memory
mutation limiter in favor of Redis. Also add operator-use flags for credential
presets in the UI and harden bulk-add job access and client error messages.

Co-authored-by: Denis <denis-ev@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-04-21 19:54:35 -07:00
Denis 30bf691596 feature(devices,topology,tz): devices bulk-add, duplicate safety, and firmware/timezone fixes
Squash-merge of PR #28 from @denis-ev. All three review blockers addressed: encryption key management documented, string truncation replaced with skip+warn validation, and undefined return on duplicate merge fixed with proper 500. Local test stack verified against cloned prod DB — migrations, new features, and backend all clean.
2026-04-21 16:52:04 -07:00
2GT-RichandClaude Sonnet 4.6 25ae3854b4 Add GHCR publish workflow and pre-built image deployment
Adds a GitHub Actions workflow that builds and pushes backend and nginx
images to GitHub Container Registry on every merge to main and on
releases. Adds docker-compose.ghcr.yml for end users who want to deploy
without cloning the repo, and updates the README with Quick Deploy
instructions alongside the existing build-from-source guide.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 10:21:21 -07:00