Commit Graph

143 Commits

Author SHA1 Message Date
lerko aac8d4dd0e fix(security): remove unused openssh-client from Docker image
CI / test (pull_request) Successful in 2m25s
CI / lint (pull_request) Successful in 40s
CI / vulncheck (pull_request) Successful in 41s
openssh-client was never used — uptop uses pure Go SSH via
charmbracelet/ssh. Removing it eliminates CVE-2026-25680,
CVE-2026-35386, CVE-2026-35387, and CVE-2026-35388.
2026-05-29 20:19:08 -04:00
lerko 13a0860dd3 fix(security): patch Docker Scout CVEs in x/net and Alpine packages
CI / test (pull_request) Successful in 2m26s
CI / lint (pull_request) Successful in 51s
CI / vulncheck (pull_request) Successful in 46s
Upgrade golang.org/x/net v0.54.0 → v0.55.0 (CVE-2026-41589 critical,
CVE-2025-60876, CVE-2026-42502, CVE-2026-42506, CVE-2026-25681,
CVE-2026-35414). Add apk upgrade to Dockerfile for openssh and busybox
CVEs (CVE-2026-25680, CVE-2026-27136, CVE-2026-35386, CVE-2026-35387,
CVE-2026-35388).
2026-05-29 20:05:28 -04:00
lerko ec898ff943 Merge pull request 'fix(ci): use docker-builder runner for image builds' (#40) from fix/docker-release into main
CI / test (push) Successful in 2m36s
CI / lint (push) Successful in 1m11s
CI / vulncheck (push) Successful in 56s
Release / release (push) Successful in 2m28s
Release / docker (push) Successful in 26m59s
Reviewed-on: #40
2026.05.5
2026-05-29 22:38:24 +00:00
lerko 38c7739995 fix(ci): use docker-builder runner for Docker image builds
CI / lint (pull_request) Successful in 2m14s
CI / vulncheck (pull_request) Successful in 51s
CI / test (pull_request) Successful in 3m59s
2026-05-29 18:01:07 -04:00
lerko 5679dffffa fix(ci): use internal Gitea URL for GoReleaser API calls
CI / test (push) Successful in 2m49s
CI / lint (push) Successful in 1m11s
CI / vulncheck (push) Successful in 1m1s
Release / release (push) Successful in 2m18s
Release / docker (push) Failing after 3m38s
2026-05-29 17:26:57 -04:00
lerko 9a4985e355 Merge pull request 'fix(ci): install git and gcc for GoReleaser' (#39) from fix/release-pipeline into main
CI / test (push) Successful in 2m36s
CI / lint (push) Successful in 1m22s
CI / vulncheck (push) Successful in 46s
Release / release (push) Failing after 2m12s
Release / docker (push) Has been skipped
Reviewed-on: #39
2026-05-29 20:13:01 +00:00
lerko 65406ce69c fix(ci): install git and gcc for GoReleaser in release pipeline
CI / test (pull_request) Successful in 2m49s
CI / lint (pull_request) Successful in 1m12s
CI / vulncheck (pull_request) Successful in 56s
2026-05-29 16:02:28 -04:00
lerko 2474b341ad chore: clean up dockerignore
CI / test (push) Successful in 2m36s
CI / lint (push) Successful in 1m11s
CI / vulncheck (push) Successful in 56s
Release / release (push) Failing after 30s
Release / docker (push) Has been skipped
2026-05-29 15:42:51 -04:00
lerko b0762800ac docs: update changelog for 2026.05.5
CI / test (push) Successful in 2m49s
CI / lint (push) Successful in 1m12s
CI / vulncheck (push) Successful in 46s
2026-05-29 15:37:49 -04:00
lerko 08bcdd6481 chore: move docker-compose files to deploy/
CI / test (push) Successful in 2m54s
CI / lint (push) Successful in 1m12s
CI / vulncheck (push) Successful in 56s
2026-05-29 15:30:49 -04:00
lerko ebf8bfb097 chore: add CI status badge to README
CI / test (push) Successful in 2m44s
CI / lint (push) Successful in 1m11s
CI / vulncheck (push) Successful in 46s
2026-05-29 15:17:09 -04:00
lerko b62a721277 Merge pull request 'chore: migrate module path to lerkolabs org' (#38) from chore/org-namespace into main
CI / test (push) Successful in 2m36s
CI / lint (push) Successful in 1m1s
CI / vulncheck (push) Successful in 56s
Reviewed-on: #38
2026-05-29 19:07:06 +00:00
lerko 8f17deba67 chore: migrate module path to lerkolabs org
CI / test (pull_request) Successful in 2m39s
CI / lint (pull_request) Successful in 1m6s
CI / vulncheck (pull_request) Successful in 46s
Move Go module from gitea.lerkolabs.com/lerko/uptop to
gitea.lerkolabs.com/lerkolabs/uptop. Updates all imports,
go.mod, goreleaser owner, and README links.
2026-05-29 14:22:49 -04:00
lerko 026e969b74 chore: TUI screenshots, README polish, changelog rewrite (#32)
CI / test (push) Successful in 2m41s
CI / lint (push) Successful in 1m11s
CI / vulncheck (push) Successful in 56s
- Add 6 TUI screenshots to assets/ (monitors, alerts, logs, nodes, detail, theme)
- Rewrite README with hero image, badges, collapsible install sections
- Rewrite changelog to match actual CalVer tag history
- VHS tooling extracted to lerko/uptop-vhs

Reviewed-on: lerko/uptop#32
2026-05-29 17:45:31 +00:00
lerko cfbf01274d chore(tui): visual polish — detail sections, column headers, alert detail (#37)
CI / test (push) Successful in 2m40s
CI / lint (push) Successful in 1m2s
CI / vulncheck (push) Successful in 51s
Release / docker (push) Has been cancelled
Release / release (push) Has been cancelled
## Summary

Bundled remaining UX polish items from the screenshot review.

### Changes

**Detail panel sections (#5)**
- Fields grouped into ENDPOINT, TIMING, HTTP, CONFIG sections with subtle headers
- Matches existing PROBE RESULTS and STATE CHANGES section pattern
- Cleaner visual hierarchy without box-drawing clutter

**Omit unconfigured fields (#6)**
- Timeout hidden when 0 (unconfigured)
- Method hidden when default GET
- AcceptedCodes shows "200-299" explicitly when empty

**Column header (#7)**
- `LATENCY` → `LAT` (design short, never truncate — htop/btop pattern)

**Alert detail view (#8)**
- `i` key on Alerts tab opens full detail panel
- Shows: type, health status, last sent time, send/fail counts, last error
- Full config key:value pairs (untruncated)
- Keybinding: `[i/Esc] Back  [e] Edit  [t] Test  [q] Quit`

### Files (3)
- `internal/tui/tab_sites.go` — section headers, field omission, LAT header
- `internal/tui/tab_alerts.go` — viewAlertDetailPanel()
- `internal/tui/tui.go` — stateAlertDetail, key handler, render routing

Reviewed-on: lerko/uptop#37
2026-05-28 20:40:29 +00:00
lerko 26e297cbae Merge pull request 'feat: alert channel health indicator + test alerts' (#36) from feat/alert-health into main
CI / test (push) Successful in 2m48s
CI / lint (push) Successful in 1m17s
CI / vulncheck (push) Successful in 1m6s
Reviewed-on: lerko/uptop#36
2026-05-28 01:33:00 +00:00
lerko 0aa2f9cd8a feat: alert channel health indicator + test alerts
CI / test (pull_request) Successful in 2m46s
CI / lint (pull_request) Successful in 1m1s
CI / vulncheck (pull_request) Successful in 51s
Track alert delivery health at runtime:
- AlertHealth struct: LastSendAt, LastSendOK, LastError, SendCount, FailCount
- triggerAlert records success/failure after each Send()
- Health data exposed via GetAlertHealth() for TUI

Alerts tab enriched:
- Health dot column: green (OK), red (failed), gray (never sent)
- LAST SENT column: relative time ("2m ago", "never")
- [t] key sends test notification through selected channel

Inspired by Grafana's contact point health columns.
2026-05-27 21:23:06 -04:00
lerko f17f06a1c6 Merge pull request 'feat: logs tab overhaul — severity tags, filtering, recovery durations' (#35) from feat/logs-overhaul into main
CI / test (push) Successful in 2m47s
CI / lint (push) Successful in 1m16s
CI / vulncheck (push) Successful in 56s
Reviewed-on: lerko/uptop#35
2026-05-28 00:35:24 +00:00
lerko b14d5e19db feat: logs tab overhaul — severity tags, filtering, recovery durations
CI / test (pull_request) Successful in 2m36s
CI / lint (pull_request) Successful in 1m1s
CI / vulncheck (pull_request) Successful in 51s
Logs tab visual overhaul:
- Severity-classified entries: DOWN (red), UP (green), WARN (amber),
  SYS (cyan), info (gray) — rendered as inline tags, not whole-line color
- Column-aligned format: [timestamp] [severity tag] [message]
- Filter toggle (f key): All vs Important only (hides retry noise)
- Header shows entry count, filter state, hidden count

Engine log improvements:
- Recovery messages include downtime duration ("was down 14m")
- LATE transition logged ("heartbeat overdue")
- Push monitor recovery includes downtime duration
2026-05-27 20:14:43 -04:00
lerko a2b38ddc60 Merge pull request 'feat: proper push monitor lifecycle — PENDING, LATE, DOWN' (#34) from feat/push-monitor-states into main
CI / test (push) Successful in 2m48s
CI / lint (push) Successful in 1m17s
CI / vulncheck (push) Successful in 56s
Reviewed-on: lerko/uptop#34
2026-05-28 00:01:56 +00:00
lerko 5dc31108f8 feat: proper push monitor lifecycle — PENDING, LATE, DOWN states
CI / test (pull_request) Successful in 2m41s
CI / lint (pull_request) Successful in 1m7s
CI / vulncheck (pull_request) Successful in 46s
Push monitors no longer lie about status:

- PENDING stays until first heartbeat (no auto-promote to UP)
- LATE state (amber) when overdue but within grace period
- DOWN only after grace period expires
- Grace period = interval/2, minimum 60s

RecordHeartbeat now handles all transitions:
- PENDING → UP (first heartbeat, logged)
- LATE → UP (late arrival, logged)
- DOWN → UP (recovery, alert + state change persisted)

TUI updates:
- LATE rendered in amber/warning color
- Status bar shows LATE count separately
- Tab badge shows ⚠ for late monitors
- Sort order: DOWN > LATE > UP > PENDING > PAUSED
- Detail panel shows error for LATE monitors

Inspired by Healthchecks.io state machine (new/up/grace/down).
2026-05-27 19:56:50 -04:00
lerko 63773b13d0 Merge pull request 'feat: show error reason when monitors go DOWN' (#33) from feat/error-reason into main
CI / test (push) Successful in 2m51s
CI / lint (push) Successful in 1m1s
CI / vulncheck (push) Successful in 56s
Reviewed-on: lerko/uptop#33
2026-05-27 23:38:26 +00:00
lerko bc3a44beac feat: show error reason when monitors go DOWN
CI / test (pull_request) Successful in 2m42s
CI / lint (pull_request) Successful in 1m11s
CI / vulncheck (pull_request) Successful in 51s
Propagate check failure reasons through the entire stack:
- Checker captures specific errors (DNS, timeout, HTTP status, SSL, etc.)
- Engine tracks LastError, StatusChangedAt, LastSuccessAt per monitor
- State transitions persisted to new state_changes table
- Detail panel shows error reason, HTTP code, state duration, last
  success time, and last 5 state change events
- Monitor table shows inline error preview for DOWN services
- Alert messages include error reason
- Probe nodes forward error reasons to leader

15 files changed across models, checker, engine, store, TUI, and probes.
2026-05-27 19:32:30 -04:00
lerko d8a2cab90f feat: seed SSH users from env var and authorized_keys file (#31)
CI / test (push) Successful in 2m36s
CI / lint (push) Successful in 1m12s
CI / vulncheck (push) Successful in 56s
Release / release (push) Has been cancelled
Release / docker (push) Has been cancelled
## Summary

Docker onboarding was broken — no way to add first SSH user without `docker attach` to TUI.

Now reads SSH public keys from two sources on startup:
- `UPTOP_ADMIN_KEY` env var — single key for quick single-user setup
- `UPTOP_KEYS` file path — authorized_keys format for team setup

Dockerfile already sets `UPTOP_KEYS=/data/authorized_keys` and compose mounts `./data:/data`, so the flow is:

```
echo "ssh-ed25519 AAAA... me@host" > ./data/authorized_keys
docker compose up -d
ssh -p 23234 localhost
```

### Behavior
- Skips keys already in DB (idempotent across restarts)
- All seeded users get admin role
- Username parsed from key comment (e.g. `tyler@macbook` → `tyler`)
- Comments and blank lines in keys file are ignored

### Tested
- UPTOP_ADMIN_KEY seeds single admin user
- UPTOP_KEYS file seeds multiple users with correct usernames
- Second startup skips existing keys (no duplicates)
- Build and all tests pass

Reviewed-on: lerko/uptop#31
2026.05.4
2026-05-27 21:15:00 +00:00
lerko ea721601ab Merge pull request 'ci: overhaul pipeline — caching, GoReleaser, govulncheck' (#30) from ci/pipeline-overhaul into main
CI / test (push) Successful in 2m50s
CI / lint (push) Successful in 1m11s
CI / vulncheck (push) Successful in 56s
Reviewed-on: lerko/uptop#30
2026-05-27 00:37:32 +00:00
lerko b1935aa682 fix(deps): bump golang.org/x/crypto v0.47.0 → v0.52.0
CI / test (pull_request) Successful in 2m46s
CI / lint (pull_request) Successful in 1m12s
CI / vulncheck (pull_request) Successful in 56s
Fixes 7 vulns (GO-2026-5014 through GO-2026-5023) found by govulncheck.
Also bumps x/net, x/sys, x/text, x/sync, x/mod, x/tools to latest.
2026-05-26 20:20:23 -04:00
lerko 2cd3dcddb4 chore: bump Go 1.24.4 → 1.26.3, Alpine 3.21 → 3.23
CI / test (pull_request) Successful in 2m57s
CI / lint (pull_request) Successful in 1m11s
CI / vulncheck (pull_request) Failing after 1m1s
Go 1.24 EOL since Feb 2026. Fixes 33 stdlib vulns found by
govulncheck (database/sql, os/exec, net/http). Gets Green Tea GC.
2026-05-26 20:12:43 -04:00
lerko 7d4ef1f594 fix(ci): remove explicit container, use sh shell
CI / test (pull_request) Successful in 2m44s
CI / lint (pull_request) Successful in 1m11s
CI / vulncheck (pull_request) Failing after 1m7s
Act runner is Alpine-based — container: directive breaks node-based
actions (checkout, setup-go). Runner already has apk natively.
Added shell: sh to all jobs since runner lacks bash.
2026-05-26 18:44:08 -04:00
lerko f0ff87c0d0 fix(ci): rename GITEA_TOKEN to RELEASE_TOKEN
CI / test (pull_request) Failing after 31s
CI / lint (pull_request) Successful in 1m9s
CI / vulncheck (pull_request) Failing after 15s
Gitea reserves the GITEA_ prefix for repo action secrets.
2026-05-26 18:36:11 -04:00
lerko 5aab391b74 ci: overhaul pipeline — caching, GoReleaser, govulncheck
- Add module + build cache to CI (was only caching go-build, not go/pkg/mod)
- Declare explicit Alpine container instead of relying on runner image
- Drop redundant go vet (already in golangci-lint)
- Add govulncheck job for dependency CVE scanning
- Add GoReleaser config for Gitea-native binary releases + checksums
- Replace .github/workflows/docker.yml with .gitea/workflows/release.yml
- Docker multiarch (amd64+arm64) via buildx in release workflow
- Dockerfile: add --mount=type=cache for mod/build, add -trimpath
2026-05-26 18:24:19 -04:00
lerko 8ad213c96c Merge pull request 'fix(security): phase 4 code quality and low-severity fixes' (#29) from security/phase-4-quality into main
CI / test (push) Successful in 4m35s
CI / lint (push) Successful in 1m7s
Reviewed-on: lerko/uptop#29
2026-05-26 21:31:40 +00:00
lerko 986f9f1d55 fix(security): phase 4 code quality and low-severity fixes
CI / test (pull_request) Successful in 4m24s
CI / lint (pull_request) Successful in 1m1s
- Fix limitStr to handle multi-byte UTF-8 characters correctly
- Sanitize log messages: strip ANSI escape sequences and newlines
- URL-encode probe node_id instead of string concatenation
- Fix follower resp.Body leak on non-200 responses
- Make SSH host key path configurable via UPTOP_SSH_HOST_KEY env var
- Add HTTP method checks on GET-only endpoints (405 for wrong methods)
- Extract magic numbers into named constants across monitor/store/server
- Standardize error output to stderr for all startup errors
2026-05-26 17:25:47 -04:00
lerko c50ec82dcb Merge pull request 'fix(security): phase 3 medium reliability and hardening' (#28) from security/phase-3-reliability into main
CI / test (push) Successful in 4m25s
CI / lint (push) Successful in 1m6s
Reviewed-on: lerko/uptop#28
2026-05-26 21:07:30 +00:00
lerko bd561d9a5e fix(security): phase 3 medium reliability and hardening
CI / test (pull_request) Successful in 4m23s
CI / lint (pull_request) Successful in 1m11s
- Fail hard on critical migration errors (ignore only "already exists")
- Cache SSH user keys with 30s TTL (avoid DB query per auth attempt)
- Configure DB connection pooling (25 open, 5 idle, 5m lifetime)
- Enable SQLite WAL mode for concurrent read/write
- Optimize check history pruning (only prune above 1100 rows)
- Add security headers: X-Content-Type-Options, X-Frame-Options, CSP, Referrer-Policy
- Add CORS policy on /status/json via UPTOP_CORS_ORIGIN env var
- Add HTTP request logging middleware (method, path, status, duration, IP)
- Fix config file permissions from 0644 to 0600
- Pin Docker images: golang:1.24-alpine3.21, alpine:3.21
- Fix Docker CI tag pattern for CalVer (was semver)
- Pass build args (VERSION, COMMIT, BUILD_DATE) to Docker build
2026-05-26 16:57:03 -04:00
lerko 7a8f2ad15b Merge pull request 'fix(security): phase 2 high-severity hardening' (#27) from security/phase-2-hardening into main
CI / test (push) Successful in 4m33s
CI / lint (push) Successful in 1m6s
Reviewed-on: lerko/uptop#27
2026-05-26 15:31:18 +00:00
lerko d30d1460bd fix(security): phase 2 high-severity hardening
CI / test (pull_request) Successful in 4m31s
CI / lint (pull_request) Successful in 56s
- Push heartbeat accepts Authorization: Bearer header (query string deprecated)
- Gotify alerts use X-Gotify-Key header instead of token in URL
- Per-IP rate limiting on all API endpoints (token-bucket)
- /metrics gated behind cluster secret (UPTOP_METRICS_PUBLIC=true to opt out)
- Config export redacts passwords/tokens by default (redact_secrets=false to override)
- Fix rewritePlaceholders for 100+ SQL parameters
- Fix AddSiteReturningID/AddAlertReturningID race with LastInsertId/RETURNING
- HTTP server timeouts: read 30s, write 60s, idle 120s
2026-05-25 21:15:33 -04:00
lerko b43dfae98f Merge pull request 'fix(security): phase 1 critical fixes for public release' (#26) from security/phase-1-critical into main
CI / test (push) Successful in 4m19s
CI / lint (push) Successful in 1m6s
Reviewed-on: lerko/uptop#26
2026-05-26 00:43:52 +00:00
lerko 60b30935b3 fix(security): phase 1 critical fixes for public release
CI / test (pull_request) Successful in 4m40s
CI / lint (pull_request) Successful in 1m2s
- Redact PostgreSQL DSN password from stdout/logs
- Harden .dockerignore to exclude .ssh/, .claude/, *.db, *.local files
- SSRF protection: block private/loopback/link-local IPs by default
  (UPTOP_ALLOW_PRIVATE_TARGETS=true to override for homelab use)
- Fix email header injection via CRLF in monitor names
- AES-256-GCM encryption for alert credentials at rest
  (UPTOP_ENCRYPTION_KEY env var, migrate-secrets subcommand)
- TLS support for HTTP server (UPTOP_TLS_CERT/UPTOP_TLS_KEY)
  with HSTS header when TLS enabled
2026-05-25 11:26:47 -04:00
lerko b70edaace5 Merge pull request 'chore: rename project from go-upkeep to uptop' (#25) from chore/rename-uptop into main
CI / test (push) Successful in 4m26s
CI / lint (push) Successful in 1m1s
Reviewed-on: lerko/uptime#25
2026.05.3
2026-05-25 01:02:30 +00:00
lerko 9d12e3ecf1 chore: complete rename from go-upkeep to uptop
CI / test (pull_request) Successful in 4m26s
CI / lint (pull_request) Successful in 1m11s
- Module path: gitea.lerkolabs.com/lerko/uptop
- Binary: cmd/uptop/
- All imports updated to full module path
- Env vars: UPKEEP_* → UPTOP_*
- Prometheus metrics: upkeep_* → uptop_*
- Default DB: uptop.db
- Docker image: lerko/uptop
- All docs, compose files, CI updated

Only remaining "go-upkeep" reference is the fork attribution in README.
2026-05-24 20:20:35 -04:00
lerko 36a4b69837 Merge pull request 'feat(tui): theme system with 5 curated dark palettes' (#24) from feat/themes into main
CI / test (push) Successful in 4m51s
CI / lint (push) Successful in 1m12s
Reviewed-on: lerko/uptime#24
2026-05-24 23:30:25 +00:00
lerko fee84c9363 fix(tui): tighten zebra row contrast for Tokyo Night and Gruvbox
CI / test (pull_request) Successful in 4m48s
CI / lint (pull_request) Successful in 1m11s
Previous ZebraBg was too far from Bg, washing out text on those
themes. Reduced to a 2-step shift for subtle row alternation.
2026-05-24 19:19:51 -04:00
lerko 87edd4aa40 feat(tui): swap light theme for Tokyo Night and Gruvbox
Light theme doesn't work well on dark terminals. Replace with
two proven dark palettes. Now 5 themes: Flexoki Dark, Tokyo Night,
Catppuccin Mocha, Nord, Gruvbox.
2026-05-24 19:10:29 -04:00
lerko 602f1b2c52 feat(tui): add theme system with 4 curated palettes
Flexoki Dark (default), Flexoki Light, Catppuccin Mocha, Nord.
Press T to cycle themes; selection persists in preferences.

All hardcoded colors replaced with theme-driven values.
Dedicated ZebraBg per theme for subtle row striping.
2026-05-24 19:05:40 -04:00
lerko 6e659cf6ee Merge pull request 'fix(tui): scope form validators to relevant monitor types' (#23) from fix/ssl-threshold-validation into main
CI / test (push) Successful in 4m48s
CI / lint (push) Successful in 56s
Reviewed-on: lerko/uptime#23
2026-05-24 22:03:33 +00:00
lerko 0a56f01929 fix(tui): guard max retries validator for group type
CI / test (pull_request) Successful in 4m40s
CI / lint (pull_request) Successful in 1m1s
Consistent with interval/timeout validators that already skip for
group monitors. Prevents potential validation block if field is
cleared while editing.
2026-05-24 17:45:19 -04:00
lerko b5b9cc81a5 fix(tui): skip irrelevant field validation by monitor type
URL, SSL threshold, and port validators blocked form progression
when editing monitors that don't use those fields (e.g. ping monitors
failing URL validation, non-SSL sites failing threshold check).

Scope each validator to fire only for its relevant monitor type.
2026-05-24 17:38:40 -04:00
lerko f64b46f055 Merge pull request 'ci: cache Go build artifacts between runs' (#22) from chore/ci-cache into main
CI / test (push) Successful in 4m40s
CI / lint (push) Successful in 1m12s
Reviewed-on: lerko/uptime#22
2026-05-24 20:01:05 +00:00
lerko d038361320 ci: cache Go build artifacts between runs
CI / test (pull_request) Successful in 6m18s
CI / lint (pull_request) Successful in 56s
2026-05-24 15:52:21 -04:00
lerko d03dc0c1ea Merge pull request 'docs: community polish for public readiness' (#21) from chore/community-polish into main
CI / test (push) Successful in 4m44s
CI / lint (push) Successful in 1m7s
Reviewed-on: lerko/uptime#21
2026-05-24 19:40:00 +00:00