Commit graph

102 commits

Author SHA1 Message Date
0bb76dbe68 feat: add /.well-known discovery endpoints for agent readiness
Adds WellKnownController with 6 public, no-auth endpoints:
api-catalog, openid-configuration, oauth-authorization-server,
oauth-protected-resource, mcp/server-card.json, and agent-skills/index.json.
2026-04-17 14:06:51 -05:00
3f82c1c110 feat: add /sitemap.xml and update robots.txt for agent discovery 2026-04-17 13:58:19 -05:00
a97340873f feat: Add network weathermap with real-time utilization visualization (#172)
- Create WeathermapLive module at /weathermap with 60s auto-refresh
- Extend Topology.get_topology_for_weathermap with bandwidth utilization data
- Add WeathermapViewer JavaScript hook with color-coded edges:
  * Green (0-30%) → Yellow (30-60%) → Orange (60-80%) → Red (80%+)
- Display throughput/capacity labels on edges (e.g., '847 Mbps / 1 Gbps')
- Add utilization stats dashboard with link count by usage level
- Support full-screen mode for NOC displays
- Integrate with existing dark mode and responsive design
- Add navigation links in sidebar and mobile menu

Technical implementation:
- Leverages existing Capacity module for interface utilization calculations
- Extends topology edges with utilization_level, utilization_pct, throughput_bps
- Builds on NetworkMapLive foundation with enhanced edge styling
- Auto-refresh via Phoenix PubSub and 60s timer
- Filter support for high/critical utilization links

Reviewed-on: graham/towerops-web#172
2026-03-25 16:26:11 -05:00
28e97ff5f0 add service checks REST API, GraphQL API, and ping executor (#52)
- REST CRUD at /api/v1/checks for HTTP, TCP, DNS, ping checks
- GraphQL queries (checks, check) and mutations (create/update/delete)
- ping executor using system ping with macOS/Linux parsing
- check config validation for ping type (requires host)
- API documentation updated with checks resource section

Reviewed-on: graham/towerops-web#52
2026-03-16 18:40:18 -05:00
c5481c2cd3 add mobile token auth to GraphQL endpoint (#48)
Extend the GraphQL API and socket to accept mobile session tokens
alongside existing API tokens. Add OrganizationScope middleware
that extracts organization_id from query args for mobile users.
Add my_organizations query for mobile app org listing.

Reviewed-on: graham/towerops-web#48
2026-03-16 15:23:07 -05:00
0fa1fa800b fix/suppress-health-check-logs (#47)
Reviewed-on: graham/towerops-web#47
2026-03-16 15:22:12 -05:00
42bfc8b9d2 paperclip/TOW-21-uisp-integration-phase1 (#31)
Reviewed-on: graham/towerops-web#31
2026-03-15 17:57:36 -05:00
1b8fb606a5
remove dedicated capacity page from nav and routing
Capacity functionality will be surfaced through insights instead.
2026-03-12 12:20:23 -05:00
17fa005781
add maintenance windows REST API and GraphQL support
REST endpoints for CRUD, scoped filtering (active/upcoming/past).
GraphQL queries and mutations for maintenance windows.
Fix agent edit test assertion message.
2026-03-11 14:33:25 -05:00
f6e9063577
feat: add REST API and GraphQL for on-call schedules and escalation policies
REST API v1 endpoints for schedules (14 endpoints) and escalation
policies (10 endpoints) with full CRUD for nested resources (layers,
members, overrides, rules, targets). GraphQL types, resolvers, and
schema mutations for both resource trees.
2026-03-11 14:01:15 -05:00
0cd2ed3567
feat: add on-call schedules and escalation policies
Built-in PagerDuty-equivalent system for on-call scheduling and alert
escalation. Users can now manage schedules, rotation layers, overrides,
and escalation policies directly in the app alongside PagerDuty.

- On-call schedules with rotation layers (daily/weekly/custom), member
  management, and temporary overrides
- Escalation policies with ordered rules, timeout-based escalation,
  and user/schedule targets
- Automatic escalation via Oban worker with configurable repeat count
- Email notifications via Swoosh for on-call alerts
- Resolver computes who's on-call from layer stacking and overrides
- AlertNotificationWorker integration: starts escalation alongside
  PagerDuty, acknowledges/resolves incidents on alert state changes
- Device and organization schemas support escalation_policy_id
- Escalation policy picker on device form
- Schedules nav item with tabbed index (schedules + escalation policies)
- Full CRUD UI for schedules, layers, members, overrides, rules, targets
- 62 LiveView tests, 56 context/schema/resolver/escalation tests
- 26 E2E Playwright tests for smoke and critical path coverage
2026-03-11 12:32:54 -05:00
e026930f25
logging fix and some other codex fixes 2026-03-10 15:04:28 -05:00
1c222f8ff5
feat: add capacity insight worker, UI, and reporting views
Add CapacityInsightWorker (every 15 min) that generates critical/warning
insights when backhaul utilization exceeds 90%/75% and auto-resolves
when it drops below 70%.

Add capacity and utilization columns to the device ports tab with
set/clear capacity controls. Add organization-level /capacity page
with summary cards and per-site capacity table. Add capacity summary
card to site show page. Add Capacity link to nav menu.
2026-03-07 14:42:40 -06:00
b3cff9afbb
stripe and email after signup 2026-03-06 10:07:27 -06:00
8f52d87854
feat: add rate limiting to admin endpoints (100 req/min)
- Add :admin type to RateLimit plug with 100 requests per minute per IP
- Apply rate limiting to all /admin routes (LiveView and controller actions)
- Protects superuser endpoints from abuse and brute force attempts
- Aligns with existing auth (10 req/min) and API (1000 req/min) limits
2026-03-05 14:11:19 -06:00
1d928d4356
security: implement comprehensive security audit fixes
Critical Fixes:
- Remove /health/time endpoint exposing system time information
  * Prevents attackers from detecting time sync issues for TOTP attacks
  * Removed route and controller function, updated tests
- Add email confirmation check to account data export
  * GDPR export now requires confirmed email address
  * Prevents unconfirmed accounts from accessing data export
- Add path traversal validation for MIB archive uploads
  * Extract to temp directory, validate all paths, then copy if safe
  * Prevents malicious tar/zip files from writing outside target directory
  * Added validate_extracted_paths/1 helper function

High Priority Fixes:
- Add comprehensive input validation for mobile auth
  * Length limits: device_name (255), device_os (100), app_version (50), push_token (512)
  * Prevents database corruption and storage exhaustion
- Add heartbeat rate limiting to agent channel
  * Limit database updates to once per 30 seconds (max ~2/min per agent)
  * Prevents malicious agents from exhausting database connections
- Sanitize 500 error responses
  * Return generic error messages to clients
  * Log full details server-side with request_id for support
  * Prevents leaking stack traces and module names
- Add message size limits to agent channel
  * 10MB maximum for all protobuf messages (result, heartbeat, error)
  * Prevents DoS attacks via oversized payloads

Medium Priority Fixes:
- Add GraphQL query depth limits (max_depth: 10)
  * Prevents DoS from deeply nested queries
  * Complements existing complexity limits

Code Quality:
- Refactor agent channel handlers to reduce nesting depth
  * Extract message processing into separate private functions
  * Fixes Credo warnings about excessive nesting
  * Improves code readability and maintainability

Files changed:
- lib/towerops_web/controllers/health_controller.ex
- lib/towerops_web/controllers/api/account_data_controller.ex
- lib/towerops_web/controllers/api/v1/mib_controller.ex
- lib/towerops/mobile_sessions/mobile_session.ex
- lib/towerops_web/channels/agent_channel.ex
- lib/towerops_web/controllers/error_json.ex
- lib/towerops_web/router.ex
- CHANGELOG.txt
- priv/static/changelog.txt
- test/towerops_web/controllers/health_controller_test.exs
- test/towerops_web/controllers/error_json_test.exs

All 7,424 tests passing.
2026-03-05 13:08:10 -06:00
c56496f7cc
fix: org switching now correctly updates session
The select_org LiveView event was updating default_organization_id in
the database but not the session's current_organization_id. Since
load_default_organization prioritizes the session value, users would
always get redirected back to the stale org.

Replaced with a controller POST action that updates both the session
and DB default before redirecting.
2026-03-04 17:04:49 -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
7160bf95d6 Add admin endpoint to flush Oban jobs by state 2026-02-16 16:50:23 -06:00
2735c1a032 Add onboarding flow for new organizations 2026-02-16 10:14:45 -06:00
9ecd01dc8f Security hardening: remaining audit fixes
- Encrypt session cookies (add encryption_salt to endpoint)
- X-Frame-Options: SAMEORIGIN → DENY (match CSP frame-ancestors 'none')
- Remove unsafe-eval from CSP script-src
- Apply security headers in all environments (not just prod)
- Add GraphQL query complexity limit (max 500) via Absinthe.Plug
- GraphQL introspection already blocked in prod via plug

Closes audit items #6, #7, #12, #13, #14, #16
2026-02-15 12:54:38 -06:00
34fe5d7e49 Security fixes: mask credentials in logs/API, fix cookie/CSP/LIKE injection/webhooks
CRITICAL fixes:
- Mask SNMP community string in agent channel logs (CRITICAL-1)
- Remove snmpv3 passwords from REST API responses, return _set booleans (CRITICAL-2)
- Replace snmp_community with snmp_community_set in GraphQL type (CRITICAL-3)

HIGH fixes:
- Fix cookie same_site from invalid 'Towerops' to 'Lax' (HIGH-4)
- Remove unsafe-eval from CSP script-src (HIGH-6)
- Block GraphQL introspection queries in production (HIGH-7)
- Sanitize LIKE wildcards in SNMP device name search (HIGH-8)
- Reject webhooks when no secret configured instead of accepting (HIGH-9)

MEDIUM fixes:
- Hash mobile session tokens (SHA-256) before DB storage (MEDIUM-10)
- Apply security headers in all environments, not just prod (MEDIUM-14)
- Add GraphQL query complexity limit (500) in production (MEDIUM-16)
- Fix X-Frame-Options to DENY to match frame-ancestors 'none' (MEDIUM-13)
2026-02-15 09:09:04 -06:00
a3730db579 i18n: add Spanish locale with full translations, language selector, and locale hook 2026-02-14 17:44:01 -06:00
7b72ed3164 PagerDuty two-way sync: webhook receiver for resolve/acknowledge
- POST /api/v1/webhooks/pagerduty/:organization_id endpoint
- HMAC-SHA256 signature verification (optional, via webhook_secret)
- incident.resolved → resolve_alert_silent (no re-notify to PagerDuty)
- incident.acknowledged → acknowledge_alert_silent (no re-notify)
- Matches alerts via dedup_key format: towerops-alert-<uuid>
- Webhook secret configurable in org settings PagerDuty panel
- Setup instructions in UI for PagerDuty Generic Webhooks (v3)
2026-02-14 14:58:58 -06:00
5df5c97c45 feat: add geographic location to sites with geocoding, address fields, and Leaflet.js network map 2026-02-14 13:07:14 -06:00
eb76f9475e feat: add GraphQL API with Absinthe, full schema, resolvers, and documentation 2026-02-14 11:28:57 -06:00
a8339797fa feat: expand REST API with alerts, agents, org settings, members, integrations, metrics, activity endpoints 2026-02-14 11:28:57 -06:00
f326eb5dd4 feat: require email verification before first login
- Remove auto-confirmation on registration (register_user and register_user_with_organization)
- Add deliver_user_confirmation_instructions/2 and confirm_user/1 to Accounts context
- Add verify_email_token_query/2 and by_user_and_contexts_query/2 to UserToken
- Make deliver_confirmation_email public in UserNotifier
- Send confirmation email after registration in both flows
- Block unconfirmed users at password login with helpful message
- Add UserConfirmationController with confirm/resend routes
- Add resend confirmation link to login page
- Update test fixtures to confirm users after registration
2026-02-14 11:28:57 -06:00
608bad0cf6 Add What's New changelog page
- ChangelogParser: parses priv/static/changelog.txt into structured entries
- ChangelogLive: timeline view with DaisyUI styling
- Route at /changelog in authenticated scope
- What's New link in org dropdown menu
2026-02-13 19:01:19 -06:00
9c266e57ff feat: wire up Trace and Activity Feed routes + nav 2026-02-13 18:50:28 -06:00
5a3ede1f71 feat: config change → performance correlation system (Roadmap #2)
- New config_change_events table linking backup diffs to time windows
- ConfigChanges context with record/list functions and date filters
- Auto-detect changed sections from MikroTik config diffs
- Agent channel emits change events after backup creation
- Correlator engine: 2h before / 4h after QoE metric comparison
- Creates suspect_config_change insights on significant degradation
- Config Timeline LiveView with chart data, change list, detail view
- Device page: Config Timeline tab + Recent Config Changes card
- Dashboard: Recent Config Changes section with impact indicators
- Fix pre-existing integrations_live.html.heex scope bug
2026-02-13 17:56:55 -06:00
bd647b8251 feat: unified insights page, integration nav improvements, sync transparency
- Promote Insights to top-level nav at /insights with source/urgency/status filters
- Unified insights page shows all sources (Preseem, Gaiia, SNMP, System)
- Bulk select/dismiss support
- Integration pages now show sync schedule and next sync estimate
- Expose sync_interval_minutes as editable config field
- Add tab navigation between integration sub-pages
- Dashboard insights section links to /insights
- Integration 'Network Insights' link now points to /insights?source=preseem
- Add product roadmap (ROADMAP.md)
2026-02-13 16:40:27 -06:00
55382a7ec6
add gaiia inventory reconciliation (stage 7) 2026-02-13 13:28:52 -06:00
bad1590fed
add gaiia webhook listener with per-org signature verification
Stage 3 of Gaiia integration: webhook event processing for real-time
incremental updates from Gaiia. HMAC-SHA256 signature verification
using per-organization secrets stored in integration credentials.
Handles account, billing subscription, and inventory item events.
2026-02-13 10:40:49 -06:00
3cd2303b6f
add gaiia integration stages 1-2: sync engine and entity mapping UI
Stage 1 - Foundation:
- GraphQL client with Relay cursor pagination and rate limiting
- 4 Ecto schemas: accounts, network sites, inventory items, billing subscriptions
- Gaiia context with upsert operations preserving user mappings
- Sync module orchestrating full organization sync
- Oban cron worker running every 15 minutes
- Migration creating 4 tables with org-scoped unique constraints

Stage 2 - Entity Mapping:
- GaiiaMappingLive with two tabs (Network Sites / Inventory Items)
- Match suggestion engine (IP/name matching with confidence levels)
- Inline search and link/unlink UI following Preseem devices pattern
- Filter by all/mapped/unmapped with URL-driven state
- Amber suggestion badges for potential matches
2026-02-13 10:31:32 -06:00
860fb7c3b6
Merge remote-tracking branch 'origin/main' into feature/preseem-integration
# Conflicts:
#	lib/towerops_web/live/device_live/show.ex
#	lib/towerops_web/live/device_live/show.html.heex
2026-02-13 09:11:45 -06:00
9ccea8daaf
add network insights feed page with filters and bulk dismiss 2026-02-13 09:00:34 -06:00
b9db1d2224
add preseem devices management page with manual linking 2026-02-12 18:12:27 -06:00
9ab0380c87
add integrations settings page with preseem configuration 2026-02-12 17:02:26 -06:00
d7741cdc0e
feat: implement unified checks system (Phase 1-4)
This commit implements the unified checks architecture that consolidates
SNMP monitoring with HTTP/TCP/DNS checks under a single "check" abstraction,
enabling consistent graphing, alerting, and management across all check types.

Database Changes:
- Add source_type and source_id to checks table for tracking auto-discovered
  vs manually created checks
- Add value field to check_results for storing numeric sensor readings
- Maintain backward compatibility with existing check_results data

New SNMP Executors:
- SnmpSensorExecutor: Poll sensor OIDs and return formatted values with
  status determination (OK/WARNING/CRITICAL based on limits)
- SnmpInterfaceExecutor: Poll interface stats (bandwidth, packets, errors)
- SnmpProcessorExecutor: Poll CPU/processor usage
- SnmpStorageExecutor: Poll disk/memory usage with percentage calculations

Check Execution Worker:
- CheckExecutorWorker: Unified Oban worker that dispatches to appropriate
  executor based on check_type (snmp_sensor, snmp_interface, http, tcp, etc.)
- Self-schedules next execution with distributed polling offsets
- Records results in check_results TimescaleDB hypertable
- Updates check state (OK/WARNING/CRITICAL/UNKNOWN)

Discovery Integration:
- Auto-creates checks during SNMP discovery for sensors, interfaces,
  processors, and storage
- Links checks to source entities via source_id for data lookup
- Enables/disables checks based on discovery results

UI Enhancements:
- Checks tab on device detail page with grouped display
- FormComponent for adding manual HTTP/TCP/DNS checks
- Empty state with "Run Discovery" prompt
- Check status badges and last checked times

Graphing:
- Update GraphLive to accept check_id parameter
- Query check_results table for time-series data
- Support all check types (SNMP, HTTP response times, etc.)

Testing:
- Comprehensive test suite for SnmpSensorExecutor (5 tests)
- Test suite for CheckExecutorWorker (7 tests)
- Test coverage for discovery check creation (6 tests)
- Remove deprecated monitoring_test.exs testing old API

Bug Fixes:
- Fix SNMP executors reading credentials from correct Device schema fields
  (device.snmp_version instead of device.snmp_device.version)
- Update agent channel test to query MonitoringCheck table directly

Code Quality:
- Extract add_snmp_credentials helper to reduce cyclomatic complexity
- Use map-based lookups for sensor formatting and check type grouping
- Apply pattern matching in dispatcher to reduce complexity
- All credo checks passing with no issues

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-12 16:58:40 -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
c7df6a8569
Add CI-triggered mass agent update webhook
POST /api/v1/webhooks/agent-release triggers all connected agents
to self-update via their existing WebSocket channels. Authenticated
with a shared secret (AGENT_WEBHOOK_SECRET env var).

- Add ReleaseChecker.invalidate_cache/0 for fresh GitHub fetch
- Add Agents.list_updatable_agents/0 (enabled + seen < 10min)
- Add Agents.broadcast_mass_update/0 orchestration function
- Add WebhookAuth plug with timing-safe secret comparison
- Add AgentReleaseWebhookController with :webhook pipeline
- Configure AGENT_WEBHOOK_SECRET in dev/test/runtime configs
2026-02-10 13:40:32 -06:00
183f2a89ac
Add admin agents page at /admin/agents
Superuser-only page showing all agents across all organizations
and cloud pollers in a single table with live-ticking timestamps
and real-time status updates via PubSub.
2026-02-10 10:56:10 -06:00
bb9e6f0b0c
feat: create MonitoringLive base structure with PubSub subscription
Add LiveView for real-time job monitoring dashboard:
- Subscribe to job:lifecycle PubSub topic for live updates
- Display health metrics (completed, failed, avg duration, active jobs)
- Show active operations with real-time updates
- Display problems section (stuck/failed job counts)
- Add router entry under /admin/monitoring

Tests verify PubSub subscription and basic rendering.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-06 18:27:40 -06:00
156d9a47bf
UI improvements 2026-02-05 14:57:11 -06:00
f938b263cd
Mikrotik backup and gettext start 2026-02-02 09:11:22 -06:00
91517aa934 Merge branch 'gmcintire/security-audit' into 'main'
Add rate limiting to auth and API endpoints using Hammer

See merge request towerops/towerops!2
2026-02-01 14:59:54 -06:00
02833d0b44 Add rate limiting to auth and API endpoints using Hammer 2026-02-01 14:59:54 -06:00
9ff9c4ddc8
fix: address UserSudoController critical issues
Critical fixes:
- Renamed controller actions to follow Phoenix conventions (verify→new, create→verify)
- Added sudo mode check in GET action using last_sudo_at timestamp
- Added TOTP enrollment check in GET action with redirect
- Changed default return path from /orgs to /users/settings
- Updated route paths from /users/sudo/verify to /users/sudo-verify (dash separator)
- Added success flash message "Identity verified."

Implementation details:
- new/2 (GET): Checks recently_verified_sudo?/1 helper that examines last_sudo_at
  instead of authenticated_at to distinguish sudo verification from regular login
- verify/2 (POST): Adds info flash and defaults to /users/settings
- recently_verified_sudo?/1: Private helper checking last_sudo_at within 10 minutes
- Updated all routes, templates, and tests to use new paths and action names

Tests:
- Added tests for already-in-sudo-mode redirect behavior
- Added test for TOTP enrollment requirement
- Updated all test assertions for new route paths and success messages
- All 15 controller tests passing
- Full test suite passing (4076 tests, 0 failures)
2026-02-01 14:45:05 -06:00
264154a3d8
feat: implement sudo mode MFA-only verification controller
- Add UserSudoController with GET and POST /users/sudo/verify routes
- Create verify.html.heex template for TOTP verification form
- Only accept TOTP codes (6 numeric digits), reject recovery codes
- Update grant_sudo_mode to set authenticated_at virtual field
- Exclude /users/sudo paths from return_to overwriting
- Add comprehensive controller tests (12 test cases)
- Verify redirect behavior, error handling, and session management

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-01 14:34:17 -06:00