Compare commits
7 Commits
37bf443e29
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
de51dde6e6
|
|||
|
e2024bcab1
|
|||
|
fb4e14ecd1
|
|||
|
9ee5908af5
|
|||
|
eff67332aa
|
|||
|
dc4c5fdf8a
|
|||
|
96eb3e8185
|
@@ -35,8 +35,12 @@ jobs:
|
|||||||
|
|
||||||
TAGS="lerkolabs/uptop:${TAG}"
|
TAGS="lerkolabs/uptop:${TAG}"
|
||||||
TAGS="${TAGS},lerkolabs/uptop:sha-${SHORT_SHA}"
|
TAGS="${TAGS},lerkolabs/uptop:sha-${SHORT_SHA}"
|
||||||
|
# :latest only for real releases — rc rehearsal tags must not move it
|
||||||
if [ "${{ github.ref_type }}" = "tag" ]; then
|
if [ "${{ github.ref_type }}" = "tag" ]; then
|
||||||
TAGS="${TAGS},lerkolabs/uptop:latest"
|
case "$TAG" in
|
||||||
|
*-*) ;;
|
||||||
|
*) TAGS="${TAGS},lerkolabs/uptop:latest" ;;
|
||||||
|
esac
|
||||||
fi
|
fi
|
||||||
echo "tags=$TAGS" >> "$GITHUB_OUTPUT"
|
echo "tags=$TAGS" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
@@ -52,6 +56,26 @@ jobs:
|
|||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
|
# Scan must gate the push: build amd64 locally, scan it, and only then run
|
||||||
|
# the multi-arch push (amd64 layers come from the builder cache, so the
|
||||||
|
# second build only adds the arm64 work).
|
||||||
|
- name: Build for scan (amd64, local)
|
||||||
|
uses: docker/build-push-action@v5
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
load: true
|
||||||
|
platforms: linux/amd64
|
||||||
|
tags: uptop-scan:${{ steps.meta.outputs.tag }}
|
||||||
|
build-args: |
|
||||||
|
VERSION=${{ steps.meta.outputs.tag }}
|
||||||
|
COMMIT=${{ github.sha }}
|
||||||
|
BUILD_DATE=${{ github.event.head_commit.timestamp }}
|
||||||
|
|
||||||
|
- name: Scan image for CVEs
|
||||||
|
run: |
|
||||||
|
curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin v0.114.0
|
||||||
|
grype uptop-scan:${{ steps.meta.outputs.tag }} --fail-on critical --output table
|
||||||
|
|
||||||
- name: Build and push
|
- name: Build and push
|
||||||
uses: docker/build-push-action@v5
|
uses: docker/build-push-action@v5
|
||||||
with:
|
with:
|
||||||
@@ -66,11 +90,6 @@ jobs:
|
|||||||
COMMIT=${{ github.sha }}
|
COMMIT=${{ github.sha }}
|
||||||
BUILD_DATE=${{ github.event.head_commit.timestamp }}
|
BUILD_DATE=${{ github.event.head_commit.timestamp }}
|
||||||
|
|
||||||
- name: Scan image for CVEs
|
|
||||||
run: |
|
|
||||||
curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin v0.114.0
|
|
||||||
grype lerkolabs/uptop:${{ steps.meta.outputs.tag }} --fail-on critical --output table
|
|
||||||
|
|
||||||
- name: Update Docker Hub description
|
- name: Update Docker Hub description
|
||||||
uses: peter-evans/dockerhub-description@v4
|
uses: peter-evans/dockerhub-description@v4
|
||||||
with:
|
with:
|
||||||
@@ -81,5 +100,7 @@ jobs:
|
|||||||
- name: Cleanup Docker artifacts
|
- name: Cleanup Docker artifacts
|
||||||
if: always()
|
if: always()
|
||||||
run: |
|
run: |
|
||||||
|
# the scan image is tagged, so image prune won't catch it
|
||||||
|
docker image rm "uptop-scan:${{ steps.meta.outputs.tag }}" 2>/dev/null || true
|
||||||
docker image prune -f
|
docker image prune -f
|
||||||
docker builder prune -f --keep-storage=2GB
|
docker builder prune -f --keep-storage=2GB
|
||||||
|
|||||||
@@ -19,22 +19,29 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
API="https://gitea.lerkolabs.com/api/v1/repos/lerkolabs/uptop/releases/tags/${TAG}"
|
API="https://gitea.lerkolabs.com/api/v1/repos/lerkolabs/uptop/releases/tags/${TAG}"
|
||||||
|
|
||||||
for i in $(seq 1 20); do
|
# 40 x 30s = 20 min: the Gitea release can queue behind the ~18-min
|
||||||
|
# Docker job on the single runner. Asset count must hold steady for
|
||||||
|
# two consecutive polls — GoReleaser uploads one file at a time, and
|
||||||
|
# mirroring mid-upload would publish a partial asset set.
|
||||||
|
PREV_COUNT=0
|
||||||
|
ASSET_COUNT=0
|
||||||
|
for i in $(seq 1 40); do
|
||||||
if RESPONSE=$(curl -sf "$API" 2>/dev/null); then
|
if RESPONSE=$(curl -sf "$API" 2>/dev/null); then
|
||||||
ASSET_COUNT=$(echo "$RESPONSE" | jq '.assets | length')
|
ASSET_COUNT=$(echo "$RESPONSE" | jq '.assets | length')
|
||||||
if [ "$ASSET_COUNT" -gt 0 ]; then
|
if [ "$ASSET_COUNT" -gt 0 ] && [ "$ASSET_COUNT" -eq "$PREV_COUNT" ]; then
|
||||||
echo "Found release with $ASSET_COUNT assets"
|
echo "Found release with $ASSET_COUNT assets (stable)"
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
echo "Release exists but no assets yet... attempt $i/20"
|
echo "Release has $ASSET_COUNT assets (was $PREV_COUNT)... attempt $i/40"
|
||||||
|
PREV_COUNT="$ASSET_COUNT"
|
||||||
else
|
else
|
||||||
echo "Waiting for Gitea release... attempt $i/20"
|
echo "Waiting for Gitea release... attempt $i/40"
|
||||||
fi
|
fi
|
||||||
sleep 30
|
sleep 30
|
||||||
done
|
done
|
||||||
|
|
||||||
if [ -z "$RESPONSE" ] || [ "$ASSET_COUNT" -eq 0 ]; then
|
if [ -z "$RESPONSE" ] || [ "$ASSET_COUNT" -eq 0 ]; then
|
||||||
echo "::error::Gitea release for ${TAG} not found or has no assets after 10 minutes"
|
echo "::error::Gitea release for ${TAG} not found or has no assets after 20 minutes"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
+171
-121
@@ -1,129 +1,179 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## [2026.06.2] — 2026-06-02 (infrastructure)
|
## [v0.1.0] — 2026-06-12
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- initial commit — uptime monitor (forked from go-upkeep)
|
||||||
|
- enhanced dashboard with lipgloss tables, huh forms, mouse support, and animations
|
||||||
|
- upgrade users tab with lipgloss table, edit support, role select
|
||||||
|
- upgrade alerts tab with lipgloss table, click zones, colored types
|
||||||
|
- widen Site struct and DB schema for ping, port, dns, group monitor types
|
||||||
|
- add ping, port, and DNS check routines
|
||||||
|
- add ntfy notification provider with TUI support
|
||||||
|
- add Uptime Kuma backup converter with CLI and API
|
||||||
|
- add mouse wheel scrolling for all tabs
|
||||||
|
- add per-site pause, fix viewport, polish status page
|
||||||
|
- add monitor groups with collapse/expand and tree view
|
||||||
|
- add Telegram, PagerDuty, Pushover, Gotify providers
|
||||||
|
- add Prometheus /metrics endpoint
|
||||||
|
- expose HTTP method and accepted status codes in monitor form
|
||||||
|
- add config-as-code YAML import/export
|
||||||
|
- add distributed probing foundation — schema, models, and probe APIs
|
||||||
|
- add probe execution mode, check extraction, and result aggregation
|
||||||
|
- add region affinity, Nodes TUI tab, and probe metrics
|
||||||
|
- add status bar, tab badges, and detail panel
|
||||||
|
- bordered modals, welcome state, and dynamic name width
|
||||||
|
- DOWN-first sort, health pulse, and site filter
|
||||||
|
- split available width evenly between NAME and HISTORY columns
|
||||||
|
- add type icons to sites table
|
||||||
|
- persist logs to DB, load on startup
|
||||||
|
- add incident management and maintenance windows
|
||||||
|
- zebra striping, detail breadcrumb, sparkline stats, collapse persistence
|
||||||
|
- add --version flag with build metadata injection
|
||||||
|
- add theme system with 4 curated palettes
|
||||||
|
- swap light theme for Tokyo Night and Gruvbox
|
||||||
|
- seed SSH users from env var and authorized_keys file (#31)
|
||||||
|
- show error reason when monitors go DOWN
|
||||||
|
- proper push monitor lifecycle — PENDING, LATE, DOWN states
|
||||||
|
- logs tab overhaul — severity tags, filtering, recovery durations
|
||||||
|
- alert channel health indicator + test alerts
|
||||||
|
- add GitHub release relay workflow
|
||||||
|
- classify error reasons on DOWN monitors
|
||||||
|
- add state change history view with outage duration
|
||||||
|
- add Opsgenie provider
|
||||||
|
- add STALE state for push monitors
|
||||||
|
- add SLA reporting view
|
||||||
|
- overhaul latency sparkline scaling, color, and layout
|
||||||
|
- auto-prune expired maintenance windows
|
||||||
|
- click-to-inspect sparkline tooltips in detail view
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Split release pipeline into separate binary and Docker workflows (#45)
|
|
||||||
- Pin Docker base images by digest (#45)
|
- replace database ID column with row counter
|
||||||
- Add GitHub release relay — mirrors Gitea releases to GitHub (#49)
|
- unify SQLite and Postgres into dialect-based SQLStore
|
||||||
- Add Grype CVE scanning to Docker pipeline (#45)
|
- add error returns to all Store interface methods
|
||||||
- Make CVE scan non-blocking for non-exploitable wish SCP vulnerability (#48)
|
- remove store global singleton, thread store explicitly
|
||||||
|
- extract shared HTTPProvider for webhook-based alerts
|
||||||
|
- extract shared table rendering, fix cursor bounds
|
||||||
|
- encapsulate engine state, add graceful shutdown and tests
|
||||||
|
- split release pipeline, add nfpm/homebrew/git-cliff
|
||||||
|
- decompose god files into single-concern modules
|
||||||
|
- consistent chrome across all views
|
||||||
|
- status icons, clean STATUS column, relative time
|
||||||
|
- extract magic numbers into named constants
|
||||||
|
- check all discarded errors in sqlstore_test.go
|
||||||
|
- overhaul tab bar — consistent counts, active highlight, colored alerts
|
||||||
|
- responsive column hiding — 3-tier priority-based layout
|
||||||
|
- swap mattn/go-sqlite3 for modernc.org/sqlite
|
||||||
|
- propagate context.Context through all Store methods
|
||||||
|
- typed Status constants with IsBroken() predicate
|
||||||
|
- schema_version migration table + DeleteAlert FK fix
|
||||||
|
- shared storetest.BaseMock replaces 5 duplicated mocks
|
||||||
|
- consolidate env parsing into appConfig struct
|
||||||
|
- extract Server type with named handler methods
|
||||||
|
- split Site into SiteConfig + SiteState
|
||||||
|
- unify logging with log/slog
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- git-cliff install in CI — resolve download URL dynamically, extract to /tmp (#46, #47)
|
|
||||||
|
|
||||||
## [2026.06.1] — 2026-06-01
|
- forward all msg types to huh forms, improve row selection UX
|
||||||
|
- harden TLS, timeouts, validation, logging, and token generation
|
||||||
|
- add delete confirm, input validation, XSS fix, history persistence
|
||||||
|
- correctness and robustness fixes across all subsystems
|
||||||
|
- make status bar and tab badges visible
|
||||||
|
- use stable sort to prevent site list shuffling each tick
|
||||||
|
- sort children by ID before status to prevent map-order shuffling
|
||||||
|
- sparkline now spans full column width
|
||||||
|
- sparkline right-aligned — current time at right edge, dots fill left
|
||||||
|
- increase history buffer to 60 so sparkline fills completely
|
||||||
|
- compute uptime from windowed statuses, not running counters
|
||||||
|
- seed status and latency from DB history on startup
|
||||||
|
- strip push tokens from /status/json response
|
||||||
|
- correct viewport sizing and dynamic chrome calculation
|
||||||
|
- constrain form height to terminal and forward resize events
|
||||||
|
- skip children in maintenance when computing group status
|
||||||
|
- exclude maintenance'd monitors from down count and pulse
|
||||||
|
- group selection highlight, layout constants, group history graphs
|
||||||
|
- stable monitor count and universal group icons
|
||||||
|
- replace panic with error return, handle unmarshal errors
|
||||||
|
- add context to Provider.Send, log alert failures
|
||||||
|
- constant-time secret comparison, request size limits
|
||||||
|
- graceful shutdown for HTTP, SSH servers and database
|
||||||
|
- add jitter to check intervals and stagger startup
|
||||||
|
- use sh instead of bash for runner compatibility
|
||||||
|
- enable CGO for race detector, use lint-action v7
|
||||||
|
- install gcc for race detector support
|
||||||
|
- skip irrelevant field validation by monitor type
|
||||||
|
- guard max retries validator for group type
|
||||||
|
- tighten zebra row contrast for Tokyo Night and Gruvbox
|
||||||
|
- phase 1 critical fixes for public release
|
||||||
|
- phase 2 high-severity hardening
|
||||||
|
- phase 3 medium reliability and hardening
|
||||||
|
- phase 4 code quality and low-severity fixes
|
||||||
|
- rename GITEA_TOKEN to RELEASE_TOKEN
|
||||||
|
- remove explicit container, use sh shell
|
||||||
|
- bump golang.org/x/crypto v0.47.0 → v0.52.0
|
||||||
|
- install git and gcc for GoReleaser in release pipeline
|
||||||
|
- use internal Gitea URL for GoReleaser API calls
|
||||||
|
- use docker-builder runner for Docker image builds
|
||||||
|
- patch Docker Scout CVEs and remove unused openssh-client (#41)
|
||||||
|
- non-root user, supply chain attestations, build cleanup
|
||||||
|
- move SSH host key path into /data for non-root user
|
||||||
|
- create .ssh dir explicitly, ensure entrypoint is executable
|
||||||
|
- resolve git-cliff download URL dynamically
|
||||||
|
- extract git-cliff to /tmp to avoid dirty worktree
|
||||||
|
- make Grype CVE scan non-blocking for known wish vuln
|
||||||
|
- bump Go 1.26.3 → 1.26.4
|
||||||
|
- remove error truncation from detail panel
|
||||||
|
- classify safedial "failed to connect" as TCP
|
||||||
|
- resolve staticcheck lint errors in history view
|
||||||
|
- trigger immediate recheck after site config edit
|
||||||
|
- broken tick chain after form/dialog + retries off-by-one
|
||||||
|
- wire up [e] edit key in detail panel
|
||||||
|
- show push token and URL in detail panel
|
||||||
|
- show correct push heartbeat curl command in detail panel
|
||||||
|
- propagate STALE/LATE child status to group
|
||||||
|
- quick wins batch — version footer, column widths, zebra, sparkline
|
||||||
|
- logs tab use viewport for scrollable content
|
||||||
|
- pin footer to bottom of terminal
|
||||||
|
- normalize content whitespace for consistent footer position
|
||||||
|
- clip overflowing content to keep footer pinned
|
||||||
|
- remove extra blank lines above footer
|
||||||
|
- expand log viewport to fill content area
|
||||||
|
- log STALE recovery in push heartbeat handler
|
||||||
|
- check fmt.Sscanf return value (errcheck lint)
|
||||||
|
- inject time into ComputeDailyBreakdown for testability
|
||||||
|
- cascade delete related rows when removing a site
|
||||||
|
- merge check results into live state, never overwrite
|
||||||
|
- serialize DB writes through a single drained writer
|
||||||
|
- close XFF bypass and three secret-leak paths
|
||||||
|
- move blocking DB IO out of Update/View into tea.Cmds
|
||||||
|
- move theme styles onto the Model to end cross-session races
|
||||||
|
- finish moving keypress DB reads into tea.Cmds
|
||||||
|
- move all store writes out of Update into tea.Cmds
|
||||||
|
- mask alert secrets in the TUI detail panel and table
|
||||||
|
- serve /status/json through a public DTO
|
||||||
|
- make SSH key revocation fail closed
|
||||||
|
- six correctness fixes for the state machine
|
||||||
|
- migrate Postgres timestamps to TIMESTAMPTZ
|
||||||
|
- seven quick-win bug fixes across engine, server, TUI, CLI
|
||||||
|
- SSRF guard gaps + DNS port restriction + metrics auth
|
||||||
|
- track selection by site ID + q means back everywhere
|
||||||
|
- apply convergence + push/group check history
|
||||||
|
- Kuma import tokens/paused, Docker hardening, migrate-secrets idempotency
|
||||||
|
- six small fixes — rate limiter leak, DST SLA, probe sort, TUI cleanup
|
||||||
|
- seven fixes — token scan, variadic cleanup, TUI layout, compose secrets
|
||||||
|
- chmod SQLite DB files to 0600 on open
|
||||||
|
- close DNS-rebind TOCTOU on ping/port checks
|
||||||
|
- API import no longer replaces user accounts
|
||||||
|
- email send respects context deadline
|
||||||
|
- rename X-Upkeep-Secret header to X-Uptop-Secret
|
||||||
|
- apply log filter to full log list, not viewport window
|
||||||
|
- repair pipeline defects found in v0.1.0-rc.1 rehearsal
|
||||||
|
- suppress wish GHSA alias in grype, fold rc tags into launch notes
|
||||||
|
- scan gates docker push, rc tags spare :latest, mirror waits for stable assets
|
||||||
|
- remove tagged scan image in cleanup step
|
||||||
|
- exclude rc tags from cliff tag_pattern so launch notes span full history
|
||||||
|
- fall back to embedded build info when ldflags absent
|
||||||
|
|
||||||
### Changed
|
|
||||||
- Container runs as non-root user `uptop` (UID/GID 1000) instead of root (#44)
|
|
||||||
- SSH host key relocated to `/data/.ssh/id_ed25519` for non-root compatibility (#44)
|
|
||||||
- Release workflow prunes dangling images and build cache after Docker push (#44)
|
|
||||||
|
|
||||||
### Added
|
|
||||||
- SBOM and provenance attestations on Docker images for supply chain compliance (#44)
|
|
||||||
- Entrypoint script with volume writability check and migration guidance (#44)
|
|
||||||
|
|
||||||
### Breaking
|
|
||||||
- Existing Docker volumes with root-owned files require migration before upgrading:
|
|
||||||
`docker run --rm -v <volume>:/data alpine chown -R 1000:1000 /data`
|
|
||||||
|
|
||||||
## [2026.05.6] — 2026-05-30 (infrastructure)
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
- Sync README to Docker Hub on release (#43)
|
|
||||||
|
|
||||||
### Security
|
|
||||||
- Patch Docker Scout CVEs, remove unused openssh-client (#41)
|
|
||||||
|
|
||||||
## [2026.05.5] — 2026-05-29
|
|
||||||
|
|
||||||
### Added
|
|
||||||
- Error reason display when monitors go DOWN (#33)
|
|
||||||
- Push monitor lifecycle — PENDING, LATE, DOWN states (#34)
|
|
||||||
- Logs tab overhaul — severity tags, filtering, recovery durations (#35)
|
|
||||||
- Alert channel health indicator and test alerts (#36)
|
|
||||||
- TUI screenshots in `assets/` (#32)
|
|
||||||
- CI status badge in README
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
- Visual polish — detail sections, column headers, alert detail (#37)
|
|
||||||
- README rewritten with hero image, badges, collapsible install sections (#32)
|
|
||||||
- Changelog rewritten to match actual CalVer tag history
|
|
||||||
- Migrated to `lerkolabs` org namespace (#38)
|
|
||||||
- Docker-compose files moved to `deploy/`
|
|
||||||
|
|
||||||
## [2026.05.4] — 2026-05-27
|
|
||||||
|
|
||||||
### Added
|
|
||||||
- SSH user seeding from `UPTOP_ADMIN_KEY` env var and `UPTOP_KEYS` file (#31)
|
|
||||||
- GoReleaser for binary releases
|
|
||||||
- govulncheck in CI pipeline
|
|
||||||
- Multi-arch Docker builds (amd64 + arm64)
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
- CI overhaul — Go 1.26, build caching, streamlined pipeline (#30)
|
|
||||||
- Bumped golang.org/x/crypto v0.47.0 → v0.52.0
|
|
||||||
- Bumped Alpine 3.21 → 3.23
|
|
||||||
|
|
||||||
### Security
|
|
||||||
- Phase 1: SSRF protection, input validation, safe dial (#26)
|
|
||||||
- Phase 2: TLS hardening, auth bypass fixes, rate limiting (#27)
|
|
||||||
- Phase 3: Graceful degradation, connection limits, timeout enforcement (#28)
|
|
||||||
- Phase 4: Code quality, error handling, linter fixes (#29)
|
|
||||||
|
|
||||||
## [2026.05.3] — 2026-05-25
|
|
||||||
|
|
||||||
### Added
|
|
||||||
- Theme system with 5 dark palettes — Default, Dracula, Nord, Tokyo Night, Gruvbox (#24)
|
|
||||||
- `--version` flag with build metadata injection
|
|
||||||
- Gitea Actions CI pipeline — test + lint (#20)
|
|
||||||
- golangci-lint configuration
|
|
||||||
- Comprehensive test suite — 94 tests across monitor, server, cluster (#19)
|
|
||||||
- CONTRIBUTING.md and SECURITY.md
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
- Renamed project from go-upkeep to uptop (#25)
|
|
||||||
- Updated LICENSE with dual copyright for independent fork
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
- Form validators scoped to relevant monitor types (#23)
|
|
||||||
- Graceful shutdown for HTTP, SSH servers and database (#19)
|
|
||||||
- Constant-time secret comparison, request size limits (#19)
|
|
||||||
- Check interval jitter to prevent thundering herd (#19)
|
|
||||||
- TUI visual polish — zebra striping, group icons, sparkline stats (#18)
|
|
||||||
|
|
||||||
## [2026.05.2] — 2026-05-22
|
|
||||||
|
|
||||||
### Added
|
|
||||||
- Incident management and maintenance windows (#17)
|
|
||||||
- Production docker-compose.yml
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
- Viewport sizing and dynamic chrome calculation (#16)
|
|
||||||
- Form height constrained to terminal with resize forwarding
|
|
||||||
- Maintenance'd monitors excluded from down count and pulse
|
|
||||||
- Group status correctly skips children in maintenance
|
|
||||||
|
|
||||||
## [2026.05.1] — 2026-05-16
|
|
||||||
|
|
||||||
### Added
|
|
||||||
- Distributed probing with leader + probe nodes
|
|
||||||
- Config-as-code — YAML apply/export with dry-run and prune
|
|
||||||
- TUI polish — status bar, tab badges, detail panel, modals
|
|
||||||
- DOWN-first sort, health pulse, site filter
|
|
||||||
- Type icons in sites table
|
|
||||||
- Sparkline history graphs
|
|
||||||
- Persistent state — uptime, status, latency, and logs survive restarts
|
|
||||||
- Push token stripping from /status/json response
|
|
||||||
|
|
||||||
## [2026.04.1] — 2026-04-01
|
|
||||||
|
|
||||||
### Added
|
|
||||||
- SSH-accessible TUI built on Bubble Tea + Wish
|
|
||||||
- 6 check types — HTTP, Push, Ping, Port, DNS, Group
|
|
||||||
- 9 alert providers — Discord, Slack, Email, Ntfy, Telegram, PagerDuty, Pushover, Gotify, Webhook
|
|
||||||
- SQLite and PostgreSQL support
|
|
||||||
- HA clustering with automatic failover
|
|
||||||
- Prometheus /metrics endpoint
|
|
||||||
- Public status page (HTML + JSON)
|
|
||||||
- Uptime Kuma backup import
|
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ An uptime monitor you manage entirely from the terminal. It runs as a server, ex
|
|||||||
|
|
||||||
Built on [RDGames/go-upkeep](https://github.com/RDGames/go-upkeep). Rewritten for clustering, config-as-code, and a proper dashboard.
|
Built on [RDGames/go-upkeep](https://github.com/RDGames/go-upkeep). Rewritten for clustering, config-as-code, and a proper dashboard.
|
||||||
|
|
||||||
|
Canonical repo: [gitea.lerkolabs.com/lerkolabs/uptop](https://gitea.lerkolabs.com/lerkolabs/uptop) — [GitHub](https://github.com/lerkolabs/uptop) is a mirror; releases are published to both.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- **6 check types** — HTTP, Push (heartbeat), Ping, Port, DNS, Groups
|
- **6 check types** — HTTP, Push (heartbeat), Ping, Port, DNS, Groups
|
||||||
@@ -51,14 +53,14 @@ Built on [RDGames/go-upkeep](https://github.com/RDGames/go-upkeep). Rewritten fo
|
|||||||
## Quick start
|
## Quick start
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
go run cmd/uptop/main.go
|
go run ./cmd/uptop
|
||||||
ssh -p 23234 localhost
|
ssh -p 23234 localhost
|
||||||
```
|
```
|
||||||
|
|
||||||
Want some data to look at first:
|
Want some data to look at first:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
go run cmd/uptop/main.go -demo
|
go run ./cmd/uptop -demo
|
||||||
```
|
```
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
@@ -85,16 +87,16 @@ services:
|
|||||||
- net.ipv4.ping_group_range=0 2147483647
|
- net.ipv4.ping_group_range=0 2147483647
|
||||||
```
|
```
|
||||||
|
|
||||||
First run: set `UPTOP_ADMIN_KEY` to your SSH public key, or attach to the container and add it in the Users tab.
|
First run: set `UPTOP_ADMIN_KEY` to your SSH public key.
|
||||||
|
|
||||||
The `sysctls` line enables unprivileged ICMP inside the container — without it, ping monitors get no response and silently report DOWN.
|
The `sysctls` line enables unprivileged ICMP inside the container — without it, ping monitors get no response and silently report DOWN.
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary><strong>Binary (Linux amd64)</strong></summary>
|
<summary><strong>Binary (Linux, macOS, Windows)</strong></summary>
|
||||||
|
|
||||||
Download from [Releases](https://github.com/lerkolabs/uptop/releases).
|
Download from [Releases](https://github.com/lerkolabs/uptop/releases) — amd64 and arm64 tarballs (zip for Windows), plus `.deb`/`.rpm` packages and `checksums.txt`.
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
|||||||
+8
-6
@@ -23,11 +23,13 @@ filter_unconventional = true
|
|||||||
split_commits = false
|
split_commits = false
|
||||||
protect_breaking_commits = false
|
protect_breaking_commits = false
|
||||||
filter_commits = false
|
filter_commits = false
|
||||||
tag_pattern = "v[0-9].*"
|
# Only final tags count as releases — rc rehearsal tags must not become
|
||||||
# rc tags are pipeline rehearsals, not releases — without this, the final
|
# section boundaries, or the final tag's notes would cover only
|
||||||
# tag's notes would only cover commits since the last rc (near-empty for
|
# commits-since-last-rc (v0.1.0 rendered 0 commits with ignore_tags, which
|
||||||
# v0.1.0). Ignored tags fold their commits into the next real release.
|
# drops rc-tagged commits instead of folding them forward). With rc tags
|
||||||
ignore_tags = "v.*-rc.*"
|
# outside the pattern, finals render the full span and rc tags render
|
||||||
|
# [Unreleased] with everything pending. Verified empirically on both.
|
||||||
|
tag_pattern = 'v[0-9]+\.[0-9]+\.[0-9]+$'
|
||||||
topo_order = false
|
topo_order = false
|
||||||
sort_commits = "oldest"
|
sort_commits = "oldest"
|
||||||
|
|
||||||
@@ -37,7 +39,7 @@ commit_parsers = [
|
|||||||
{ message = "^perf", group = "Changed" },
|
{ message = "^perf", group = "Changed" },
|
||||||
{ message = "^refactor", group = "Changed" },
|
{ message = "^refactor", group = "Changed" },
|
||||||
{ message = "^security", group = "Security" },
|
{ message = "^security", group = "Security" },
|
||||||
{ body = ".*security", group = "Security" },
|
{ message = "^polish", group = "Changed" },
|
||||||
{ body = "BREAKING", group = "Breaking" },
|
{ body = "BREAKING", group = "Breaking" },
|
||||||
{ footer = "BREAKING.CHANGE", group = "Breaking" },
|
{ footer = "BREAKING.CHANGE", group = "Breaking" },
|
||||||
{ message = "^docs", skip = true },
|
{ message = "^docs", skip = true },
|
||||||
|
|||||||
+36
-4
@@ -12,6 +12,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"runtime/debug"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
@@ -39,6 +40,30 @@ var (
|
|||||||
date = "unknown"
|
date = "unknown"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// GoReleaser stamps the vars above via ldflags, but `go install module@tag`
|
||||||
|
// compiles without them and would report "dev". The module version and any
|
||||||
|
// vcs stamps are embedded in every binary, so fall back to those.
|
||||||
|
func init() {
|
||||||
|
if version != "dev" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
info, ok := debug.ReadBuildInfo()
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if mv := info.Main.Version; mv != "" && mv != "(devel)" {
|
||||||
|
version = strings.TrimPrefix(mv, "v")
|
||||||
|
}
|
||||||
|
for _, s := range info.Settings {
|
||||||
|
switch s.Key {
|
||||||
|
case "vcs.revision":
|
||||||
|
commit = s.Value
|
||||||
|
case "vcs.time":
|
||||||
|
date = s.Value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
slog.SetDefault(slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{
|
slog.SetDefault(slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{
|
||||||
Level: slog.LevelInfo,
|
Level: slog.LevelInfo,
|
||||||
@@ -64,11 +89,18 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func printVersion() {
|
func printVersion() {
|
||||||
if version == "dev" {
|
out := "uptop " + version
|
||||||
fmt.Println("uptop dev")
|
var meta []string
|
||||||
} else {
|
if commit != "none" {
|
||||||
fmt.Printf("uptop %s (%s, %s)\n", version, commit, date)
|
meta = append(meta, commit)
|
||||||
}
|
}
|
||||||
|
if date != "unknown" {
|
||||||
|
meta = append(meta, date)
|
||||||
|
}
|
||||||
|
if len(meta) > 0 {
|
||||||
|
out += " (" + strings.Join(meta, ", ") + ")"
|
||||||
|
}
|
||||||
|
fmt.Println(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
func envOrDefault(key, fallback string) string {
|
func envOrDefault(key, fallback string) string {
|
||||||
|
|||||||
Reference in New Issue
Block a user