Commit graph

129 commits

Author SHA1 Message Date
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
cad00fee06 ci: install hex/rebar before deps.get to fix OTP 28 compat
The previous commit bumped CI from OTP 27.2/Elixir 1.18.1 to
OTP 28.5/Elixir 1.19.5. The broad mix cache restore-keys was
restoring a stale ~/.mix cache with hex compiled for the old
OTP, causing beam_load errors on new bs_add instructions.

Adding explicit mix local.hex --force ensures the correct hex
version for the running OTP is installed before deps.get.
2026-06-02 17:20:06 -05:00
f58312ca82 bump elixir/erlang version in ci 2026-06-02 17:06:06 -05:00
c00be779f9 chore: remove stale renovate config 2026-05-11 13:53:32 -05:00
31cbd18128 ci: cache slow runtime apt deps in a prebuilt base image
Splits the runtime apt installs (gdal-bin, snmp, libsnmp40, locales,
BEAM runtime libs) into k8s/Dockerfile.base, hosted at
codeberg.org/gmcintire/towerops-base:latest. The app Dockerfile now
does FROM that base instead of re-installing gdal (~500 MB) on every
push.

The new build-base workflow rebuilds the base image only when
k8s/Dockerfile.base or the workflow itself changes, weekly via cron
(Sundays 06:00 UTC, with CACHE_BUST=<ISO week> to force apt-get update
on a week boundary), or via workflow_dispatch.

Production workflow now uses buildx + does docker login before the
build so it can pull the private base image.
2026-05-05 11:19:49 -05:00
222253b7c8 ci: move container image to codeberg.org/gmcintire/towerops
The repo got renamed towerops-web → towerops on the Codeberg side,
so the published image follows: image is now
codeberg.org/gmcintire/towerops with the same main-<ts>-<sha> tag
pattern. Login URL is the hardcoded env.REGISTRY rather than
secrets.REGISTRY_URL so a stale URL secret can't push to the wrong
registry.
2026-05-05 10:57:24 -05:00
fde6158251 ci: enable PostGIS in test workflows + add tests covering ~3pp more
CI: switch postgres service image to timescale/timescaledb-ha:pg17-all
which bundles PostGIS, fixing the lidar migration failure in PR and
production workflows.

Tests: ~30 new test files / extensions, ~600+ new tests, taking total
coverage from 70.42% to 73.4%. Targets included GraphQL resolver
unauthenticated paths, SNMP context queries (mempools, processors,
ip_addresses, neighbors, wireless_clients, arp_entries), worker
routing/lifecycle (alert notification, alert digest, weather sync,
job cleanup, cn_maestro, uisp, mikrotik backup, report worker),
SNMP monitoring executors (storage, interface, processor) end-to-end
via stub adapter, NetBox + Sonar sync integration paths, ConfigChanges
listing and correlator, organizations membership query, and live-view
smoke tests for org-scoped settings, integrations, maintenance, agent,
device deep paths, schedules. Property tests used for query
composition and pure helpers where natural.
2026-05-05 10:35:22 -05:00
6a98787cfa ci: enable Debian non-free in deb822 sources for snmp-mibs-downloader
Bookworm runner images use /etc/apt/sources.list.d/*.sources (deb822),
which the legacy sed didn't touch — non-free stayed off and
snmp-mibs-downloader was unavailable. Patch the Components: line in
deb822 sources too.
2026-05-01 13:16:50 -05:00
28dd7a6953 ci: bump _build cache key v2 -> v3
Stale cache contains compiled oban_pro 1.6.13 artifacts that conflict
with the vendored 1.7.0 source.
2026-05-01 13:09:57 -05:00
45413095a9 ci: guard sources.list sed against missing file
Newer Ubuntu/Debian runners use /etc/apt/sources.list.d/ and don't have
/etc/apt/sources.list, causing the sed to fail with exit code 2.
2026-04-29 14:34:27 -05:00
f648b6cb9b fix(ci): modify existing sources.list to add non-free instead of creating new file 2026-04-17 17:42:34 -05:00
bc7651cec4 fix(ci): detect OS before enabling non-free — Debian needs it, Ubuntu multiverse already enabled 2026-04-17 17:38:06 -05:00
a878fb7abd fix(ci): remove bad Debian sources entry — runner is Ubuntu Noble with multiverse already enabled 2026-04-17 17:32:32 -05:00
dd028f6157 fix(ci): enable Debian non-free repo for snmp-mibs-downloader; loosen flaky timing assertion to 500ms 2026-04-17 17:24:15 -05:00
84f38b6491 fix(ci): remove sudo from apt-get — Forgejo runner runs as root 2026-04-17 17:16:18 -05:00
445cafa88b fix(ci): install docker cli before building image in production workflow (#237)
Runner doesn't have docker pre-installed; explicitly install docker.io
matching the pattern used in microwaveprop.

Reviewed-on: graham/towerops-web#237
2026-04-15 13:20:51 -05:00
8811a10b4d use-existing-docker-daemon (#227)
Reviewed-on: graham/towerops-web#227
2026-03-29 13:45:09 -05:00
344c6658e8 fix: use existing Docker daemon instead of starting new one (#226)
The CI runner already has a working Docker daemon and the runner user
is in the docker group. All previous failures were caused by the workflow
trying to start a NEW dockerd instance with vfs storage driver.

Solution: Remove all daemon startup code and just use the existing Docker
daemon directly. The runner user already has access via group membership.

Verified on ci host:
- Docker service running: overlayfs storage driver
- runner user in docker group: uid=1001(runner) groups=1001(runner),989(docker)
- docker info works as runner user

This is the simplest solution and should have been tried first.

Reviewed-on: graham/towerops-web#226
2026-03-29 13:28:37 -05:00
a0b916cc9a fix: use img for completely unprivileged container builds (#225)
Podman fails even with chroot isolation on this runner. The environment
is too restricted for standard container tools (Docker, Buildx, Podman).

Solution: Use 'img' by Jess Frazelle, designed specifically for truly
unprivileged environments:
- No root/sudo required for builds
- No user namespaces required
- No special capabilities required
- Pure userspace implementation
- Built for restricted CI environments

This is the last resort tool for environments where Docker/Podman
cannot run at all.

Reviewed-on: graham/towerops-web#225
2026-03-29 13:14:53 -05:00
26befb9f4f fix: use chroot isolation for Podman builds on unprivileged runner (#224)
Podman fails with 'cannot clone: Operation not permitted' on this runner
because it cannot create namespaces. The runner environment lacks the
capabilities for namespace-based container isolation.

Solution: Add --isolation=chroot flag to use chroot instead of namespaces.
This works in restricted environments without CAP_SYS_ADMIN or user
namespace support.

Trade-off: Chroot isolation is slower but functional on unprivileged
runners.

Reviewed-on: graham/towerops-web#224
2026-03-29 13:09:44 -05:00
964b16780d fix: use Podman instead of non-existent Kaniko binary (#223)
Kaniko doesn't provide standalone binary downloads - it's distributed as a
container image. The download URL returns 404.

Solution: Use Podman which:
- Available as standard apt package
- Runs rootless without daemon
- Works on unprivileged runners
- Docker-compatible CLI

This avoids both the Docker namespace issue and the missing Kaniko binary.

Reviewed-on: graham/towerops-web#223
2026-03-29 12:35:03 -05:00
284898dc2f prod docker change (#222)
Reviewed-on: graham/towerops-web#222
2026-03-29 12:19:52 -05:00
2dec841cf1 prod docker change (#221)
Reviewed-on: graham/towerops-web#221
2026-03-29 12:16:24 -05:00
e6f408aa33 fix: use legacy docker build without BuildKit for unprivileged runner (#220)
BuildKit (used by build-push-action and buildx) requires privileged mount
operations that fail on unprivileged runners with vfs storage driver.

Solution: Replace build-push-action with plain 'docker build' and 'docker push'
commands with DOCKER_BUILDKIT=0 to use the legacy builder.

Trade-offs:
- Works on unprivileged runners without privileged access
- Slower builds (no BuildKit caching/parallelism)
- No build attestations/provenance (already disabled)

Reviewed-on: graham/towerops-web#220
2026-03-29 12:04:54 -05:00
db33495d00 fix: use docker driver for buildx on unprivileged runner (#219)
The build-push-action was trying to use docker-container driver by default,
which requires privileged mount operations. This fails on unprivileged runners
with vfs storage driver.

Solution: Explicitly configure buildx to use 'docker' driver, which uses the
regular Docker daemon that's already running with vfs storage. This avoids
the need for privileged container mounts.

Resolves: operation not permitted during buildkit mount

Reviewed-on: graham/towerops-web#219
2026-03-29 11:12:43 -05:00
afb9fcc538 feat: re-enable tests in production CI workflow (#217)
Re-add the test-exunit job that runs all ExUnit tests before deployment.
The build-and-deploy job now depends on tests passing first.

All 8837 tests are currently passing locally with 0 failures.

Reviewed-on: graham/towerops-web#217
2026-03-29 10:47:25 -05:00
d9b929038b fix: use default buildx without attestations for unprivileged runner (#216)
Remove the setup-buildx-action step that was failing with unshare errors
when trying to create a docker-container builder.

Instead, use the default buildx that comes with dockerd and disable
attestation features (provenance and sbom) that require additional
mount operations.

This simpler approach should work within the constraints of the
unprivileged CI runner.

Reviewed-on: graham/towerops-web#216
2026-03-29 10:35:55 -05:00
993aef0f6b fix: skip tests in production deployment workflow (#215)
Remove the test-exunit job and its dependency from the production
deployment workflow. This allows the deployment to proceed without
waiting for tests to pass.

Tests should still be run in a separate workflow or locally before
pushing to main.

Reviewed-on: graham/towerops-web#215
2026-03-29 10:33:30 -05:00
c167de1223 fix: add Docker Buildx setup with docker-container driver (#214)
The docker/build-push-action@v5 requires proper BuildKit configuration
to work on unprivileged CI runners. The setup-buildx-action with the
docker-container driver creates a properly configured BuildKit builder
that can handle the mount operations required for builds.

This restores the configuration that was working before the Gleam
removal changes.

Reviewed-on: graham/towerops-web#214
2026-03-29 10:16:29 -05:00
677f5acc9e fix: restore working docker/build-push-action (#213)
Kaniko approach doesn't work on unprivileged runners because even
'docker run' to start the kaniko container requires unshare capabilities.

Restored the docker/build-push-action@v5 which was working before.
The Dockerfile still has Gleam removed - only the build method changed.

Reviewed-on: graham/towerops-web#213
2026-03-28 16:13:41 -05:00
0865d59b23 fix: add Docker daemon startup to run kaniko container (#212)
Kaniko itself doesn't need Docker, but we use 'docker run' to execute
the kaniko container. The daemon only needs to run containers, not
build images, so we use minimal flags (--iptables=false, --bridge=none,
--storage-driver=vfs).

Reviewed-on: graham/towerops-web#212
2026-03-28 16:06:53 -05:00
efc78c9185 fix: kaniko dockerfile path should be relative to context (#211)
Kaniko expects --dockerfile to be relative to --context, not an
absolute path. Changed from '/workspace/k8s/Dockerfile' to
'k8s/Dockerfile' since context is '/workspace'.

Reviewed-on: graham/towerops-web#211
2026-03-28 16:02:23 -05:00
7c1c4a0c63 fix: use kaniko for unprivileged container builds (#209)
- Replace Docker build with kaniko executor
- Kaniko doesn't require Docker daemon or unshare capabilities
- Works in unprivileged CI environments
- Builds and pushes directly to registry

Reviewed-on: graham/towerops-web#209
2026-03-28 12:51:10 -05:00
2a84df471d fix: use legacy Docker build to avoid permission errors in CI (#206)
- Replace BuildKit with legacy docker build (DOCKER_BUILDKIT=0)
- Use plain docker login instead of docker/login-action
- Remove BuildKit setup action entirely
- Works with VFS storage driver on unprivileged runners

Reviewed-on: graham/towerops-web#206
2026-03-28 12:16:20 -05:00
a3cdf02114 fix/remove-gleam-dockerfile-refs (#204)
Reviewed-on: graham/towerops-web#204
2026-03-28 12:09:01 -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
7606efc635 fix: use docker-container buildx driver to resolve mount permission errors (#191)
The production deployment was failing with "operation not permitted" errors
when BuildKit tried to perform bind mounts during Docker image builds.

Root cause:
- The workflow starts Docker with --storage-driver=vfs for unprivileged runners
- VFS storage driver doesn't support the advanced mount operations needed by BuildKit
- The Dockerfile uses --mount=type=cache for build performance
- Using buildx driver=docker tried to use the daemon's VFS storage directly

Solution:
- Switch to driver=docker-container which runs BuildKit in an isolated container
- This container has its own storage layer that properly supports BuildKit features
- BuildKit container uses overlay2 internally regardless of host storage driver

This is the recommended approach for CI/CD environments with storage limitations.

Reviewed-on: graham/towerops-web#191
2026-03-27 13:44:22 -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
fbbd3402b3 chore: skip staging deploy for Renovate PRs (#124)
Dependency update PRs from Renovate don't need to be deployed to
staging. Uses job-level condition to check head branch prefix.

Reviewed-on: graham/towerops-web#124
2026-03-23 09:58:48 -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
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
3c935ed56e e2e-workflow-separate (#67)
Reviewed-on: graham/towerops-web#67
2026-03-17 16:30:45 -05:00
f897b32999 Separate E2E tests into manual workflow (#66)
Moves e2e tests from production workflow into a separate workflow that requires manual triggering. This allows e2e tests to be run on-demand without blocking production deployments.

Changes:
- Created new .forgejo/workflows/e2e-tests.yaml with workflow_dispatch trigger
- Removed disabled e2e job from production.yaml workflow
- E2E tests can now be triggered manually from Actions tab with browser selection (all, chromium, firefox, webkit)
- Test results and videos uploaded as artifacts on all runs

Reviewed-on: graham/towerops-web#66
2026-03-17 16:26:41 -05:00
0f9ce9b711 feat/ssl-certificate-check (#65)
Reviewed-on: graham/towerops-web#65
2026-03-17 16:21:44 -05:00
b724aa4ab8 remove docker build cache options for docker driver (#62)
The docker buildx driver (required on unprivileged ci runner) does not
support registry cache export/import. Remove cache-from and cache-to
options to unblock builds.

Reviewed-on: graham/towerops-web#62
2026-03-17 13:40:54 -05:00
f4e75689d4 fix docker on unprivileged ci: use vfs storage driver (#61)
overlayfs requires mount/unmount capabilities not available on the
unprivileged ci runner. Switch to vfs storage driver and use buildx
docker driver (not docker-container) to avoid nested mount issues.

Reviewed-on: graham/towerops-web#61
2026-03-17 13:34:53 -05:00
cd19db0680 fix-sticky-header-overlap (#60)
Reviewed-on: graham/towerops-web#60
2026-03-17 13:21:58 -05:00