Commit graph

96 commits

Author SHA1 Message Date
Graham McInitre
5b8f83671e update deps 2026-07-20 09:45:05 -05:00
Graham McInitre
f1868908de fix: remove hex-sourced oban_pro/met/web from mix.lock — all vendored
oban_pro, oban_met, and oban_web are resolved via path: vendor/...
in mix.exs, so they must not have hex lock entries. The old lock
had oban_pro sourced from 'oban' (getoban.pro/repo) which would
cause hex to contact the live repo on every deps.get.
2026-07-16 09:37:21 -05:00
Graham McInitre
7ce9309a69 fix: resolve dependency vulnerabilities (mint CVE-2026-59249, cowlib CVE-2026-43966/43969)
- Override mint to 1.9.3 to fix HTTP/1 chunk-size parser CVE-2026-59249
- Remove plug_cowboy dependency by switching PromEx standalone metrics server
  to PromEx.Plug in the main endpoint (Bandit), eliminating cowlib CVEs
- Update castore transitive dep 1.0.19→1.0.20
2026-07-16 07:48:26 -05:00
Graham McInitre
eb444cb012 chore: update dependencies to latest versions
- hackney: 4.5.2 → 4.6.0 (constraint ~> 4.4 → ~> 4.6)
- stream_data: 1.3.0 → 1.4.0
- mint: 1.9.1 → 1.9.2 (fixes CVE-2026-58229, CVE-2026-59246)
- oban_pro: 1.7.6 → 1.7.8 (vendor sync from Oban Pro private repo)
- oban_web: lock synced to 2.12.6 (vendor already had it)
2026-07-15 12:50:20 -05:00
749932082f chore: update phoenix_live_view 1.1.32→1.2.6, relax constraint to ~> 1.2 2026-07-08 10:57:31 -05:00
de012ec366 chore: update transitive dep redix 1.5.3→1.6.0 2026-07-08 10:50:48 -05:00
a719135c1e chore: update dependencies. phoenix 1.8.8→1.8.9, swoosh 1.26.2→1.26.3, oban_pro 1.7.6→1.7.7, oban_web 2.12.5→2.12.6, hackney 4.4.5→4.5.2, plus transitive deps 2026-07-08 10:47:26 -05:00
51c23a9659 chore: update all dependencies, fix hackney CVEs
- Upgraded 17 packages including phoenix 1.8.8, live_view 1.1.32,
  bandit 1.12.0, tailwind 0.5.1, req 0.6.2, prom_ex 1.12.0
- Forced hackney 4.4.5 + httpoison 3.0.0 via overrides to fix
  4 CVEs (GHSA-gp9c-pm5m-5cxr and others)
- Security audit clean, no new test failures
2026-07-01 08:45:36 -05:00
86ad19fc74 chore: update vendored oban_pro to 1.7.6 2026-06-23 09:57:21 -05:00
7a3950d1ad chore: add jump_credo_checks ~> 0.4 with all 19 checks enabled
All checks set to exit_status: 0 initially to avoid blocking on
pre-existing violations. Remove exit_status overrides as each
check category is cleaned up incrementally.

Dependency added to dev/test only.
2026-06-12 13:45:59 -05:00
a797bc7cef upgrade: re-vendor oban_pro 1.7.5, oban_web 2.12.5, oban_met 1.2.0; fix Oban unique states warnings; update deps and elixir to 1.19 2026-06-03 14:38:34 -05:00
1f9fe2ee29 chore: add gaiia library dep, remove stale honeybadger/tidewave/cbor
- Add vendored Gaiia library (path: vendor/gaiia) with auto-generated GraphQL
  queries and mutations from the Gaiia API schema
- Add startAddInventoryItemsJob + updateInventoryItem mutations
- Remove `:cbor` (was unused — no references anywhere)
- Remove stale Honeybadger filter module, tests, router plug, and config
- Remove stale Tidewave plug from endpoint (dev-only, dep already gone)
- Unlock leftover deps from lock file
2026-05-11 14:46:27 -05:00
d90d24198c chore(deps): update absinthe, honeybadger, phoenix, swoosh
absinthe 1.10.1 → 1.10.2
honeybadger 0.26.0 → 0.27.0
phoenix 1.8.6 → 1.8.7
swoosh 1.25.1 → 1.25.2
+ transitive: decimal 3.1.0, mint 1.8.0, telemetry 1.4.2
2026-05-11 09:36:45 -05:00
50324c61ce feat(metrics): expose Prometheus /metrics via PromEx on :9568
Add PromEx with Application/BEAM/Phoenix/LiveView/Ecto/Oban plugins plus
a custom plugin that bridges existing Towerops Oban/Redis telemetry events.
The metrics HTTP server runs isolated on port 9568 so scrape traffic never
traverses the public Traefik IngressRoute.

The pod template carries prometheus.io annotations (scrape, port, path, job)
so the external Prometheus on 10.0.15.31 discovers each pod through the
existing kubernetes-pods scrape job (apiserver-proxy).
2026-05-08 10:25:25 -05:00
79d7848df9 chore: bump deps
absinthe 1.10.0 → 1.10.1
absinthe_phoenix 2.0.4 → 2.0.5
bandit 1.10.4 → 1.11.0
ecto 3.13.5 → 3.13.6
error_tracker 0.8.0 → 0.9.0
jason 1.4.4 → 1.4.5
phoenix 1.8.5 → 1.8.6
phoenix_live_view 1.1.28 → 1.1.30
postgrex 0.22.0 → 0.22.1
swoosh 1.25.0 → 1.25.1

Compiles with --warnings-as-errors. Full test suite (10750 tests, 137
properties) passes.
2026-05-05 12:12:27 -05:00
158ee9d323 feat: add Texas LIDAR DEM catalog with on-demand elevation reads
Catalog-only system for LIDAR-derived 1m DEMs covering Texas. We do not
mirror raster data — the DB stores tile metadata (URL + footprint
geometry) and elevation values are streamed on-demand from public USGS
3DEP / TNRIS Cloud-Optimized GeoTIFFs via GDAL /vsicurl/ HTTP byte-range
reads. Used for future tower coverage line-of-sight calculations.

- Enable PostGIS extension; tile footprints indexed via GiST
- Catalog sync from USGS 3DEP (primary) and TNRIS (fallback for gaps)
- Tile dedup by ST_Contains so TNRIS doesn't duplicate 3DEP coverage
- Single-point reads via gdallocationinfo with tile fallthrough on nodata
- Grid retrieval via gdal_translate AAIGrid with multi-tile mosaicing
- Monthly Oban cron worker keeps catalog fresh
- gdal-bin added to runtime image; geo_postgis dep added
2026-05-04 13:03:28 -05:00
3b3d506769 chore: drop stale oban_pro hex lock entry
oban_pro is sourced from vendor/oban_pro via path dep; the leftover hex
entry in mix.lock was unused.
2026-05-01 12:39:19 -05:00
6c05d45dd6 deps: upgrade oban_pro to 1.7.0
Bumps vendored Oban Pro from 1.6.13 to 1.7.0, which transitively bumps
oban core to 2.22.1 (requires migrations v14) and db_connection to 2.10.0.

- mix.exs constraint: ~> 1.6 → ~> 1.7
- vendor/oban_pro/ replaced with v1.7.0 hex package
- migration 20260430142200: Oban core v12 → v14 (must run first)
- migration 20260430142241: Oban Pro 1.7.0 schema additions

Also corrects a pre-existing constraint name in AgentAssignment that was
left stale by the equipment→devices rename migration (20260117190134).
The unique index is named agent_assignments_device_id_index, but the
schema's unique_constraint/3 still pointed at the old equipment_id name,
causing the test suite to surface Ecto.ConstraintError instead of a
changeset error. Required to get the suite green for this upgrade.
2026-04-30 10:26:18 -05:00
e822bc9986 chore: rate_limit rewrite + on-call redesign plan + handoff_notifications_mode 2026-04-28 12:17:29 -05:00
fc51974d36 chore: update dependencies
Bumps hammer_backend_redis 7.1.0 → 7.1.1
2026-04-21 08:30:52 -05:00
2f3824cecc chore(deps): update all dependencies (#235)
Upgraded Elixir deps:
- absinthe 1.9.1 => 1.10.0
- credo 1.7.17 => 1.7.18
- fine 0.1.4 => 0.1.6
- honeybadger 0.25.0 => 0.26.0
- lazy_html 0.1.10 => 0.1.11
- mimerl 1.4.0 => 1.5.0
- phoenix_pubsub_redis 3.1.0 => 3.1.1
- swoosh 1.24.0 => 1.25.0

Updated npm deps in e2e:
- @playwright/test 1.58.2 => 1.59.1
- @types/node 25.4.0 => 25.6.0
- dotenv 17.3.1 => 17.4.2
- otplib 13.3.0 => 13.4.0

No security vulnerabilities found.

Reviewed-on: graham/towerops-web#235
2026-04-15 13:03:25 -05:00
978a72ad41 db-performance-migrations (#234)
Reviewed-on: graham/towerops-web#234
2026-04-04 14:22:25 -05:00
efaf5558ff refactor: convert 6 Gleam modules to idiomatic Elixir with TDD (#196)
Phase 1: Foundation Types (100% complete)
- query_helpers: SQL LIKE sanitization with pipe operators
- numeric: Integer parsing with pattern matching guards
- result: Pure Elixir Result monad (map, and_then, unwrap_or)

Phase 2: Ecto Domain Types (100% complete)
- ip_address: IPv4/IPv6 validation using :inet directly
- mac_address: Multi-format MAC parsing (colon/hyphen/dot/compact)
- snmp_oid: OID parsing/manipulation with recursive pattern matching

All 198 tests passing across converted modules.
API changed from Gleam-style {:some/:none to idiomatic {:ok/:error.
Refactored parse_numeric_oid to use with statement, reducing nesting depth.

Reviewed-on: graham/towerops-web#196
2026-03-28 09:52:07 -05:00
39039a4455 fix: remove stale oban hex repo references from mix.lock (#195)
The previous dependency update left mix.lock with references to the
"oban" hex repository for vendored packages (oban_pro, oban_web, oban_met).
This caused production deployment failures with error:
"Unknown repository 'oban', add new repositories with the mix hex.repo add task"

Since these packages are vendored from vendor/ directory, they should not
have hex repo references in the lock file. Removed the hex entries entirely
and regenerated the lock file with only the vendored path dependencies.

Reviewed-on: graham/towerops-web#195
2026-03-27 17:18:48 -05:00
0399b30d21 Update Elixir dependencies (#194)
Updated packages:
- bandit: 1.10.3 → 1.10.4
- phoenix_live_view: 1.1.27 → 1.1.28
- phoenix_pubsub_redis: 3.0.1 → 3.1.0
- oban_met: 1.0.6 → 1.1.0 (vendored)
- oban_web: 2.11.8 → 2.12.1 (vendored)

All tests passing (8923 tests, 0 failures).

Reviewed-on: graham/towerops-web#194
2026-03-27 17:13:12 -05:00
11f9c4450c done i think (#177)
Reviewed-on: graham/towerops-web#177
2026-03-26 10:23:26 -05:00
7656052395 update deps (#173)
Reviewed-on: graham/towerops-web#173
2026-03-25 16:35:12 -05:00
f703e61b12 fix: code quality improvements and test reliability (#139)
Various code quality improvements and fixes:

- Settings: return error instead of auto-creating unknown settings
- PagerDuty: proper backoff timing with to_timeout()
- Gaiia sync: remove unnecessary transaction wrapper
- HTTP/UISP: simplify test plug setup
- Agent channel: tagged tuple config for check types
- SNMP: fix Task.yield/shutdown pattern, remove stale preload
- Discovery: simplify error handling
- Tests: bump executor timeouts for CI reliability
- Dockerfile: remove unnecessary --force compile
- Renovate/CI: config cleanup

Split from #135.

Reviewed-on: graham/towerops-web#139
2026-03-24 09:12:59 -05:00
e54ee75513 Rewrite protobuf encoding/decoding in pure Gleam with integrated validation (#104)
Replace the protobuf hex package (agent.pb.ex) and hand-written validator
(validator.ex) with a pure Gleam implementation: wire format primitives,
all 23 message types, encode/decode functions, and validation merged into
decode. Thin Elixir wrappers in agent.ex preserve the existing struct API.

- Wire format: varint, length-delimited, double (IEEE 754 via FFI), tag encode/decode
- Types: all proto3 message types as Gleam custom types with enums and oneof
- Decode: field-level parsing with integrated validation (UUID, IP, hostname, limits)
- Encode: proto3 default omission, bytes_tree concatenation, map/repeated fields
- Wrappers: Elixir structs with encode/decode delegating to Gleam, enum atom conversion
- Remove {:protobuf, "~> 0.12"} dependency

Reviewed-on: graham/towerops-web#104
2026-03-21 16:08:40 -05:00
348975dcc9 Rewrite polling_offset, changelog_parser, and user_agent_parser in Gleam (#103)
Migrate three pure-function modules from Elixir to Gleam:

- polling_offset: deterministic hash-based polling offset (pure Gleam, no FFI)
- changelog_parser: text parsing logic in Gleam, thin Elixir wrapper for File I/O
- user_agent_parser: regex-based UA parsing in Gleam with Erlang FFI for
  atom-keyed map conversion

Add gleam_regexp dependency for regex support in Gleam modules.
Update all call sites and tests to use Gleam module atoms.

Reviewed-on: graham/towerops-web#103
2026-03-21 10:11:06 -05:00
6859525a1b Integrate Gleam into the build pipeline and rewrite three pure-function modules (#98)
Set up mix_gleam archive, gleam_stdlib, and gleeunit deps. Add Gleam
compiler to all Dockerfiles, CI workflows, nix shell, and .tool-versions.

Rewrite Numeric, QueryHelpers, and URLValidator from Elixir to Gleam with
full ExUnit test coverage. Update all callers to use the Gleam modules
directly via :towerops@module syntax. Remove duplicate sanitize_like/1
private functions in snmp.ex and trace.ex.

Reviewed-on: graham/towerops-web#98
2026-03-21 07:30:36 -05:00
36cb080823 update deps (#82)
Reviewed-on: graham/towerops-web#82
2026-03-19 11:26:22 -05:00
b0d645148a
chore: update dependencies
- phoenix_live_view 1.1.26 -> 1.1.27
- stream_data 1.2.0 -> 1.3.0
- tidewave 0.5.5 -> 0.5.6
- pre-commit hooks configuration
2026-03-13 16:11:27 -05:00
05d79287bc
chore: remove sobelow dependency 2026-03-12 16:03:08 -05:00
72f81c572d
add real-time GraphQL API with time-series queries and subscriptions
- add absinthe_phoenix for WebSocket subscription support
- create GraphQL WebSocket socket with API token auth at /socket/graphql
- add time-series queries: deviceSensors, sensorReadings, interfaceTraffic, checkResults
- add subscriptions: deviceStatusChanged, alertEvent, sensorReadingsUpdated
- wire subscription triggers into agent_channel and alerts contexts
- add org-scoped access control for sensors/interfaces via join queries
- add 17 tests covering queries, org isolation, empty data edge cases, and auth
- update GraphQL API docs page with time-series and subscription sections
2026-03-12 10:24:39 -05:00
3b97e437f2
fix: add castore dep and sanitize sync error messages
Add castore as a direct dependency to provide CA certificates in
environments where the OS trust store is not available (Dokku staging).

Stop leaking raw system errors (like CA trust store details) to the
UI by logging the full error server-side and showing a generic
user-friendly message instead.
2026-03-11 10:41:09 -05:00
d811bcb503
feat: add ErrorTrackerNotifier and fix PagerDuty notification handling
- Add error_tracker_notifier for email alerts on exceptions
  * Sends alerts to graham@towerops.net
  * Configured in production only (gracefully shuts down in dev/test)
  * Includes throttling to prevent duplicate error spam

- Fix AlertNotificationWorker when PagerDuty not configured
  * Worker now handles :not_configured gracefully instead of failing
  * Prevents unnecessary retries and error noise
  * Logs as debug when PagerDuty integration isn't set up

Files changed:
- mix.exs, mix.lock
- config/runtime.exs
- lib/towerops/application.ex
- lib/towerops/workers/alert_notification_worker.ex
- CHANGELOG.txt, priv/static/changelog.txt
2026-03-09 13:14:30 -05:00
f473d1e920
update deps 2026-03-08 12:23:59 -05:00
01ebb8968d
chore: filter out external uptime monitor HEAD requests from logs 2026-03-04 16:48:59 -06:00
61586d14e2
chore: update all hex dependencies
Upgrades: phoenix 1.8.4, phoenix_live_view 1.1.26, ecto_sql 3.13.5,
bandit 1.10.3, credo 1.7.17, swoosh 1.22.1, yaml_elixir 2.12.1,
styler 1.11.0, error_tracker 0.8.0, finch 0.21.0, honeybadger 0.25.0.

Fix site_aggregation_test assertion to match actual DB default (NULL,
not 0) for account_count on skipped sites.
2026-03-04 13:30:32 -06:00
998bdf39b8
update 2026-02-18 10:19:56 -06:00
c92dfff6c9
Add ErrorTracker, remove Honeybadger email notice filter
Replace the HoneybadgerNoticeFilter that emailed raw stacktraces on
every exception with ErrorTracker for self-hosted error tracking.
Honeybadger itself is retained. ErrorTracker dashboard is mounted at
/admin/errors behind the superuser auth wall.
2026-02-17 08:13:34 -06:00
146f5745cf
fix: resolve compilation errors, test failures, and credo issues
- Escape HEEx template braces in GraphQL/API docs with raw(~S[...])
- Fix test assertions for updated marketing copy and UI text
- Extract helper functions in GraphQL resolvers to reduce nesting depth
- Create shared ErrorHelpers module for API controllers
- Fix ETS race condition in brute force whitelist cache for async tests
- Fix property test generators to use ASCII instead of printable unicode
- Add alert_severity helper to site_live/show
- Update accounts fixtures for explicit user confirmation
2026-02-14 12:23:10 -06:00
07a6128877
feat: add checks tab to device detail page (TDD cycle 1)
- Add 'Checks' tab link to device navigation
- Display empty state when no checks configured
- Add tests for tab visibility and empty state
- Fix unused variable warnings in monitoring context
- Remove unused CheckResult alias and module attributes
- Add stub for legacy get_latency_data for backward compatibility

Tests: 2 new tests added, all passing
Following TDD: RED-GREEN cycle verified for each feature
2026-02-12 14:50:14 -06:00
4d73e77f3a
Add 404-based brute force protection system
Implements automated detection and blocking of IPs exhibiting scanning behavior (5+ unique 404s within 1 minute).

Key features:
- Progressive ban escalation (5 min → 1 hour → permanent)
- CIDR range and exact IP whitelisting
- Redis-backed 404 path tracking with 60s TTL
- Cloudflare WAF integration for permanent bans
- Admin UI for whitelist and blocked IP management
- Oban cron jobs for cleanup (expired bans, stale violations)
- ETS caching for whitelist performance

Components:
- Plug: ToweropsWeb.Plugs.BruteForceProtection
- Context: Towerops.Security.BruteForce
- Schemas: IpBlock, IpWhitelist
- Workers: CloudflareBanWorker, ExpiredBanCleanupWorker, StaleViolationCleanupWorker
- Admin UI: /admin/security (superuser only)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-10 16:31:48 -06:00
6b4c098de8
fix warnings 2026-02-08 10:50:27 -06:00
24236dbe30
update oban_web 2026-02-08 10:11:53 -06:00
d431931cfe
update hammer 2026-02-08 10:08:31 -06:00
38eeb1c7b8
fix: improve agent polling and SNMP testing
Changes:
- Fix traffic graph to handle nil interface octets gracefully
- Add comprehensive tests for nil octets scenarios
- Fix agent polling query to support devices assigned directly to org (left join on sites)
- Fix test SNMP connection to inherit credentials from site/org
- Refactor agent_channel process_polling_result to reduce nesting (Credo)
- Add alias for JobCleanupTask in application.ex (Credo)

This fixes crashes when interface stats have nil octets and ensures
devices without a site assignment can be polled by agents.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-05 12:34:28 -06:00
23af86ba73
add mikrotik device handling 2026-02-01 16:42:39 -06:00