Commit graph

2620 commits

Author SHA1 Message Date
012a8ece95 Migrate images from codeberg.org to git.mcintire.me
Some checks failed
Production Deployment / Run ExUnit Tests (push) Failing after 59s
Production Deployment / Build and Push Docker Image (push) Has been skipped
2026-07-24 14:38:50 -05:00
ec8e32726b Use Kaniko for Docker builds
Some checks failed
Build base image / Build and push base image (push) Failing after 2s
Production Deployment / Run ExUnit Tests (push) Failing after 1m0s
Production Deployment / Build and Push Docker Image (push) Has been skipped
2026-07-24 14:36:25 -05:00
2edc158880 Use Kaniko for Docker builds
Some checks failed
Production Deployment / Run ExUnit Tests (push) Has been cancelled
Production Deployment / Build and Push Docker Image (push) Has been cancelled
2026-07-24 14:36:04 -05:00
f4dc72c811 Migrate from codeberg.org to git.mcintire.me
Some checks failed
Production Deployment / Run ExUnit Tests (push) Failing after 1m3s
Production Deployment / Build and Push Docker Image (push) Has been skipped
2026-07-24 14:23:24 -05:00
c243949045 Migrate from codeberg.org to git.mcintire.me
Some checks are pending
Production Deployment / Run ExUnit Tests (push) Waiting to run
Production Deployment / Build and Push Docker Image (push) Blocked by required conditions
Build base image / Build and push base image (push) Successful in 1m2s
2026-07-24 14:23:23 -05:00
dfb3dfd9e8 update prometheus ip in doc
Some checks failed
Production Deployment / Run ExUnit Tests (push) Failing after 2m4s
Production Deployment / Build and Push Docker Image (push) Has been skipped
2026-07-22 11:01:44 -05:00
3bf21c746f refactor: upgrade to Elixir 1.20, extract GraphLive.Polling, async subscriber impact
- Bump elixir requirement from ~> 1.19 to ~> 1.20 for gradual typing
- Extract SNMP polling functions from graph_live/show.ex (1492→1118 lines)
  into new GraphLive.Polling module (363 lines) — 374 lines net reduction
- Defer subscriber impact API call via start_async/handle_async in
  device_live/show.ex, avoiding synchronous Gaiia API call in handle_params
- Add terminate/2 to graph_live/show.ex for live_poll timer cleanup
- Fix .tool-versions to match installed Erlang 27.3.4.2
- Relax AGENTS.md dialyzer policy: allow ignore file for deps/vendored code
2026-07-22 11:01:00 -05:00
Graham McInitre
24eaccd7a8 chore: track .envrc, gitignore .envrc.local for secrets
.envrc contains shared direnv/Nix setup (no secrets). Local overrides
and secrets belong in .envrc.local, which is now gitignored.
2026-07-22 08:37:17 -05:00
Graham McInitre
bff35368b0 Revert "feat: add beacon monitors with user and admin management"
This reverts commit 88fae5d752.
2026-07-22 08:25:04 -05:00
Graham McInitre
88fae5d752 feat: add beacon monitors with user and admin management
Backend:
- Migration: beacon_monitors table (binary_id PK, org/user FK, check_type, target_url, config, monitoring fields)
- Schema: BeaconMonitor with changeset (pattern-matched port validation, check_type inclusion)
- Query: BeaconMonitorQuery — composable scopes (by org, by user, by type, enabled, ordered, preloaded)
- Context: Towerops.Beacons — CRUD, toggle, record_check_result (36/36 tests pass)

Frontend:
- User LiveView: /beacons — stream-based list, create/edit modals, toggle/delete actions
- Admin LiveView: /admin/beacons — cross-org view with preloads (20/20 tests pass)
- Form component: LiveComponent modal with validation
- Helpers: check_type badges, status indicators, response time formatting
- Router: user routes + admin route configured
- Nav: sidebar + mobile links added
- 30+ gettext translations

Verification: compile ✓, format ✓, credo ✓, 56/56 new tests pass
2026-07-22 08:15:03 -05:00
Graham McInitre
5b91735b14 refactor: extract timeout helpers and replace conditionals in snmp/discovery.ex
- 12 identical *_with_timeout wrappers → 2 generic helpers (with_timeout/3, with_deferred_timeout/3)
- Removed commented-out code (# alias Towerops.Topology, # Auto-inference disabled)
- All if/case/cond replaced with pattern-matched function clauses (20+ refactors)
- Long lines fixed for credo compliance
- 11/11 tests pass, 0 credo issues
2026-07-21 17:08:03 -05:00
Graham McInitre
9d4a5f6d81 refactor: comprehensive simplification and functional programming improvements
- help_live/index.ex: 2,642→173 lines, 15 section modules + sidebar extracted
  MikroTik now real section, dead if false removed
- agent_channel.ex: 2,506→1,751 lines, 3 helper modules extracted
  (heartbeat/subscriptions/job_builder), decode_and_process/4 eliminates
  8 repeated handle_in patterns, guard-based size checks
- antenna_catalog.ex: 1,174→47 lines, 107 specs → priv/antennas/catalog.json
- topology.ex: unbounded query → batched loading (100/batch),
  all guard errors fixed, zero if/case/cond conditionals
- proto: decoder_macros.ex + field_specs.ex infrastructure for
  macro-generated protobuf decoders
2026-07-21 17:03:47 -05:00
Graham McInitre
5b8f83671e update deps 2026-07-20 09:45:05 -05:00
Graham McInitre
368e96f8c3 fix: remove towerops_nif from auto-compilers list
The Mix.Tasks.Compile.ToweropsNif module is part of the project source
and isn't on the code path when Mix first resolves compilers in a fresh
build — causes 'could not be found' in CI. NIF compilation is handled by:
- nix/shell.nix shellHook for dev (make -C c_src)
- nix/build.nix preBuild for CI/prod (injects towerops-nif package .so)
Run 'mix compile.towerops_nif' manually when changing C source in dev.
2026-07-16 09:49:43 -05:00
Graham McInitre
b0b085a2af fix: skip NIF compilation in prod — NIF is pre-built by Nix
The prod build runs MIX_ENV=prod without make/gcc/net-snmp. The NIF
is pre-built by the towerops-nif Nix package and injected via
build.nix preBuild. Skip the mix compiler task in prod to avoid
'could not be found' CI errors.
2026-07-16 09:42:40 -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
07a772a7f9 fix: pre-compile test deps in shellHook so mix test always works
Add MIX_ENV=test mix deps.compile after NIF build. The _build/test
tree is ephemeral (cleared when nix devShell derivation changes), which
causes 'Mox is not available' errors. This ensures test deps like Mox
are ready before the user ever runs mix test.
2026-07-16 09:33:55 -05:00
Graham McInitre
b038094dc4 fix: use Keyword.get for API key to respect explicit nil, add ecto.migrate to test alias
- DeepSeek.complete: use Keyword.get/3 instead of || so passing api_key: nil
  is respected even when DEEPSEEK_API_KEY env var is set (nil is explicit
  'no key', not 'use default'). Also fixed base_url and model for consistency.
- test alias: add ecto.migrate after ecto.load so Oban migrations are applied,
  fixing 'Found version 12, but version 14 is required' on oban 2.23
2026-07-16 09:31:11 -05:00
Graham McInitre
02f6d816de fix: upgrade Nix PostgreSQL from 16 to 17
- Change postgresql_16 → postgresql_17 in shell.nix (17.10 available)
- Both postgis and timescaledb confirmed available for PG17
- Remove PG17-only transaction_timeout SET from structure.sql
  (dump was already PG17, now compatible with running server)
- Auto-reinit triggers on version file mismatch
2026-07-16 09:23:44 -05:00
Graham McInitre
ee853db0b5 ignore local env 2026-07-16 09:20:03 -05:00
Graham McInitre
ed3c251142 fix: vendor oban_web — never pull oban_pro from live repo
Remove conditional oban_repo_configured?() check that would pull
oban_pro from repo.oban.pro when hex config contained credentials.
The root mix.exs already provides oban_pro via vendored path.
2026-07-16 09:19:02 -05:00
Graham McInitre
e6fba0c5a3 fix: register NIF compiler, add Nix shell NIF build, make NIF optional at boot
- Register :towerops_nif compiler in mix.exs so mix compile/test builds the C NIF
- Add 'make -C c_src' to nix devShell shellHook so NIF is pre-built
- Extract init_mib_resolution/0 from Application.start/2 (reduces CC)
- Wrap NIF calls in try/rescue ErlangError for graceful fallback
- Wrap test_helper.exs NIF calls in try/rescue ErlangError
- Add .nix-postgres-version to .gitignore
2026-07-16 09:15:53 -05:00
Graham McInitre
b7d8ea9668 fix: detach service startup to prevent nix develop hang
Run start-services in a background subshell with stdin closed so
nix develop doesn't wait on daemonized PostgreSQL/Redis child
processes before starting the interactive shell.
2026-07-16 09:09:38 -05:00
Graham McInitre
38b7fb00f1 fix: move PG version check before servicesFlag guard
The version check was after the early-exit guard, so if services were
already running it never triggered. Now it runs first, stopping and
reinitializing the cluster before checking the flag.
2026-07-16 09:04:27 -05:00
Graham McInitre
33cb8ca769 fix: auto-reinit PG cluster when extensions or version change
- Write pg derivation path to .nix-postgres-version after init
- On start, compare current pg path with stored version
- If changed (extensions added/removed/version bumped), destroy and
  reinitialize the cluster automatically
- Also reinit legacy clusters that have no version file
- Exclude .nix-postgres-version from release builds
2026-07-16 09:02:42 -05:00
Graham McInitre
05970d3649 feat: add PostGIS extension to dev PostgreSQL
- Add postgis to postgresql_16.withPackages alongside timescaledb
- Enable postgis extension on towerops_dev and towerops_test databases
2026-07-16 08:56:28 -05:00
Graham McInitre
e58767cf00 fix: guard shellHook heavy ops behind DIRENV_DIR check
When direnv evaluates the shellHook (DIRENV_DIR is set), skip mix local,
service startup, pre-commit install, and the welcome banner. These
operations block direnv and trigger nix profile cleanup hangs on macOS.
Only run them in interactive nix develop sessions.
2026-07-16 08:54:55 -05:00
Graham McInitre
3914d2e0b6 fix: remove EXIT trap and fix $USER expansion in DATABASE_URL
- Remove 'trap ... EXIT' that kills services when entering the dev shell
- Fix DATABASE_URL: $USER → $USER (no backslash) so bash expands it
  instead of passing the literal string 'USER' as the PG role name
2026-07-16 08:50:56 -05:00
Graham McInitre
a41c68420d fix: update nix flakes to work with nixpkgs 26.11
- Update nixpkgs lock (Feb → Jul 2026) for erlang_29 availability
- Fix erlang_29 reference: use beam.interpreters.erlang_29 instead of
  nonexistent top-level erlang_29
- Filter x86_64-darwin from systems (dropped in nixpkgs 26.11)
- Fix shell.nix flake-compat tarball hash
2026-07-16 08:47:37 -05:00
Graham McInitre
e5a6dd173c update imagens 2026-07-16 07:54:28 -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
ca992f1fd1 fix: add unique form IDs for LiveView 1.2 compatibility, add type attr to button component 2026-07-08 11:10:41 -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
bdb0dd8c38 refactor: apply FP patterns — with-chains + multi-clause over if/case
- accounts.ex: convert get_user_by_email_and_password if→with-chain
  with explicit User struct match and else→nil. Flatten delete_account
  nested if (password check + sole-owner check) into single with-chain
  with named else clauses, eliminating do_delete_account indirection.

- organizations.ex: flatten update_member_role nested if/case into
  with-chain — parse_role guard → membership fetch → owner check,
  each with explicit else branch. Prevents variable shadowing by using
  current_role for the membership pattern match.

- capacity.ex: extract calculate_throughput_from_stats inner if into
  multi-clause compute_throughput_from_pairs/1 — empty list clause
  returns zero_throughput(), non-empty clause handles the computation.
2026-07-01 18:04:36 -05:00
e77a848f2f fix: update tests to match Tailwind v4 utility classes after DaisyUI removal 2026-07-01 09:43:32 -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
4bd444f147 revert: remove custom color palette, restore standard Tailwind v4 colors 2026-06-23 12:29:46 -05:00
253657280b Revert "refactor: apply custom color palette across entire codebase"
This reverts commit 5a7cdc7138.
2026-06-23 12:26:57 -05:00
5a7cdc7138 refactor: apply custom color palette across entire codebase
- Replace gray->cool-steel, blue/indigo->cerulean, red->sweet-salmon, yellow/amber->wheat
- Dark sidebar: sidebar/footer use cool-steel-800 bg, text lightened for contrast
- ~11,600 color replacements across ~99 files
- Update tests for new color class names
2026-06-23 10:58:48 -05:00
ebcd54be5b refactor: remove daisyUI, use straight Tailwind v4 with custom color palette
- Remove daisyUI plugins and theme from app.css
- Define 5 custom color palettes: sweet-salmon, desert-sand, wheat, cool-steel, cerulean
- Add @utility card, badge, btn classes to replace daisyUI components
- Replace all daisyUI classes across 16+ template files
- Update tests for new class return values
- Set light mode as default theme
2026-06-23 10:44:20 -05:00
785f077c50 feat: change default theme from system to light mode 2026-06-23 10:28:31 -05:00
b76637c14f refactor: remove icons from sidebar and mobile nav menu items 2026-06-23 10:18:40 -05:00
86ad19fc74 chore: update vendored oban_pro to 1.7.6 2026-06-23 09:57:21 -05:00
8cb8b5b027 update elixir and erlang 2026-06-23 09:43:24 -05:00
3a408a8dc1 Security hardening + performance fixes across codebase
CRITICAL:
- Membership: remove :role/:org_id/:user_id from mass-assignment cast; use explicit create_changeset/4 and role_update_changeset/2
- GraphQL member resolver: add authorize_invite/3 checking admin/owner role and role hierarchy
- REST invitations controller: add auth check for invite creation

HIGH:
- ApiToken: remove :organization_id/:user_id from cast; use explicit create_changeset/4

MEDIUM:
- Move 8 LiveView Ecto queries into context modules (Admin, Alerts, Coverages, OnCall, Snmp)
- Replace Process.put/Process.get with socket assigns for unresolved_alert_count (user_auth + layouts + 50 templates)
- Add batch get_utilization_for_interfaces/1 to eliminate N+1 capacity queries in device show
- Replace Process.sleep with Process.monitor/assert_receive or Process.send_after in 5 test files

LOW:
- Add handle_params/3 to UserResetPasswordLive, UserRegistrationLive, StatusPageLive
- Remove redundant Repo.preload calls; add preloads to list_site_devices/1
- Fix @impl annotations and credo nesting warnings
2026-06-21 17:40:50 -05:00
89ed385865 bump elixir 2026-06-16 17:20:06 -05:00
0ef5c235c8 Fix ProfileWatcherTest: verify init return shape only 2026-06-16 16:44:38 -05:00