Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4c79f93d53 | |||
| 9ce6153bd8 |
@@ -1,10 +1,15 @@
|
|||||||
.git
|
.git
|
||||||
.ssh/
|
|
||||||
.gitea/
|
|
||||||
tmp/
|
tmp/
|
||||||
vendor/
|
vendor/
|
||||||
*.db
|
|
||||||
*.db-journal
|
# Security: keep sensitive/local files out of Docker build context
|
||||||
|
.ssh/
|
||||||
|
.claude/
|
||||||
|
.github/
|
||||||
|
.gitea/
|
||||||
|
CLAUDE.md
|
||||||
*.local.json
|
*.local.json
|
||||||
*.local.md
|
*.local.md
|
||||||
*.local
|
*.local
|
||||||
|
*.db
|
||||||
|
*.db-journal
|
||||||
|
|||||||
@@ -1,53 +0,0 @@
|
|||||||
name: Release Binaries
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
tags:
|
|
||||||
- "[0-9]*"
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
release:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
shell: sh
|
|
||||||
steps:
|
|
||||||
- name: Install build tools
|
|
||||||
run: apk add --no-cache git gcc musl-dev
|
|
||||||
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- uses: actions/setup-go@v5
|
|
||||||
with:
|
|
||||||
go-version: "1.26"
|
|
||||||
|
|
||||||
- uses: actions/cache@v4
|
|
||||||
with:
|
|
||||||
path: |
|
|
||||||
~/go/pkg/mod
|
|
||||||
~/.cache/go-build
|
|
||||||
key: release-go-${{ hashFiles('go.sum') }}
|
|
||||||
restore-keys: release-go-
|
|
||||||
|
|
||||||
- name: Install git-cliff
|
|
||||||
run: |
|
|
||||||
apk add --no-cache curl
|
|
||||||
curl -sSL https://github.com/orhun/git-cliff/releases/latest/download/git-cliff-x86_64-unknown-linux-musl.tar.gz | tar xz
|
|
||||||
mv git-cliff-*/git-cliff /usr/local/bin/
|
|
||||||
git-cliff --version
|
|
||||||
|
|
||||||
- name: Generate release notes
|
|
||||||
run: git-cliff --current --strip header -o /tmp/release-notes.md
|
|
||||||
|
|
||||||
- name: Run GoReleaser
|
|
||||||
uses: goreleaser/goreleaser-action@v7
|
|
||||||
with:
|
|
||||||
distribution: goreleaser
|
|
||||||
version: "~> v2"
|
|
||||||
args: release --clean --release-notes=/tmp/release-notes.md
|
|
||||||
env:
|
|
||||||
GORELEASER_FORCE_TOKEN: gitea
|
|
||||||
GITEA_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
|
||||||
GITEA_API_URL: http://gitea:3000/api/v1
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
name: Release Docker
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
tags:
|
|
||||||
- "[0-9]*"
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
tag:
|
|
||||||
description: "Image tag (e.g. 2026.06.1). Defaults to latest commit SHA."
|
|
||||||
required: false
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
docker:
|
|
||||||
runs-on: docker-builder
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Resolve image tag
|
|
||||||
id: meta
|
|
||||||
run: |
|
|
||||||
SHORT_SHA=$(echo "${{ github.sha }}" | cut -c1-7)
|
|
||||||
echo "short_sha=$SHORT_SHA" >> "$GITHUB_OUTPUT"
|
|
||||||
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
|
||||||
TAG="${{ github.event.inputs.tag }}"
|
|
||||||
if [ -z "$TAG" ]; then
|
|
||||||
TAG="${{ github.sha }}"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
TAG="${{ github.ref_name }}"
|
|
||||||
fi
|
|
||||||
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
|
|
||||||
|
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v3
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v3
|
|
||||||
|
|
||||||
- name: Log in to Docker Hub
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Build and push
|
|
||||||
uses: docker/build-push-action@v5
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
push: true
|
|
||||||
platforms: linux/amd64,linux/arm64
|
|
||||||
sbom: true
|
|
||||||
provenance: mode=max
|
|
||||||
tags: |
|
|
||||||
lerkolabs/uptop:${{ steps.meta.outputs.tag }}
|
|
||||||
lerkolabs/uptop:latest
|
|
||||||
lerkolabs/uptop:sha-${{ steps.meta.outputs.short_sha }}
|
|
||||||
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
|
|
||||||
grype lerkolabs/uptop:${{ steps.meta.outputs.tag }} --fail-on critical --output table
|
|
||||||
|
|
||||||
- name: Update Docker Hub description
|
|
||||||
uses: peter-evans/dockerhub-description@v4
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
repository: lerkolabs/uptop
|
|
||||||
|
|
||||||
- name: Cleanup Docker artifacts
|
|
||||||
if: always()
|
|
||||||
run: |
|
|
||||||
docker image prune -f
|
|
||||||
docker builder prune -f --keep-storage=2GB
|
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
name: Release
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- "[0-9]*"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version: "1.26"
|
||||||
|
|
||||||
|
- uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/go/pkg/mod
|
||||||
|
~/.cache/go-build
|
||||||
|
key: release-go-${{ hashFiles('go.sum') }}
|
||||||
|
restore-keys: release-go-
|
||||||
|
|
||||||
|
- name: Run GoReleaser
|
||||||
|
uses: goreleaser/goreleaser-action@v7
|
||||||
|
with:
|
||||||
|
distribution: goreleaser
|
||||||
|
version: "~> v2"
|
||||||
|
args: release --clean
|
||||||
|
env:
|
||||||
|
GORELEASER_FORCE_TOKEN: gitea
|
||||||
|
GITEA_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||||
|
|
||||||
|
docker:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [release]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v3
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
- name: Log in to Docker Hub
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Build and push
|
||||||
|
uses: docker/build-push-action@v5
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
push: true
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
tags: |
|
||||||
|
lerkolabs/uptop:${{ github.ref_name }}
|
||||||
|
lerkolabs/uptop:latest
|
||||||
|
build-args: |
|
||||||
|
VERSION=${{ github.ref_name }}
|
||||||
|
COMMIT=${{ github.sha }}
|
||||||
|
BUILD_DATE=${{ github.event.head_commit.timestamp }}
|
||||||
@@ -1,3 +1,10 @@
|
|||||||
|
# Created by https://www.toptal.com/developers/gitignore/api/go
|
||||||
|
# Edit at https://www.toptal.com/developers/gitignore?templates=go
|
||||||
|
|
||||||
|
### Go ###
|
||||||
|
# If you prefer the allow list template instead of the deny list, see community template:
|
||||||
|
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
|
||||||
|
#
|
||||||
# Binaries for programs and plugins
|
# Binaries for programs and plugins
|
||||||
*.exe
|
*.exe
|
||||||
*.exe~
|
*.exe~
|
||||||
@@ -17,11 +24,16 @@
|
|||||||
# Go workspace file
|
# Go workspace file
|
||||||
go.work
|
go.work
|
||||||
|
|
||||||
|
# End of https://www.toptal.com/developers/gitignore/api/go
|
||||||
|
|
||||||
/uptop
|
/uptop
|
||||||
/dist
|
|
||||||
uptop.db*
|
uptop.db*
|
||||||
|
|
||||||
.ssh
|
.ssh
|
||||||
|
|
||||||
authorized_keys
|
authorized_keys
|
||||||
|
|
||||||
tmp
|
tmp
|
||||||
|
|
||||||
*.local.json
|
*.local.json
|
||||||
*.local.md
|
*.local.md
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
version: 2
|
version: 2
|
||||||
|
|
||||||
gitea_urls:
|
gitea_urls:
|
||||||
api: "{{ if index .Env \"GITEA_API_URL\" }}{{ .Env.GITEA_API_URL }}{{ else }}https://gitea.lerkolabs.com/api/v1{{ end }}"
|
api: https://gitea.lerkolabs.com/api/v1
|
||||||
download: https://gitea.lerkolabs.com
|
download: https://gitea.lerkolabs.com
|
||||||
|
|
||||||
release:
|
release:
|
||||||
gitea:
|
gitea:
|
||||||
owner: lerkolabs
|
owner: lerko
|
||||||
name: uptop
|
name: uptop
|
||||||
|
|
||||||
builds:
|
builds:
|
||||||
@@ -33,41 +33,10 @@ archives:
|
|||||||
checksum:
|
checksum:
|
||||||
name_template: checksums.txt
|
name_template: checksums.txt
|
||||||
|
|
||||||
nfpms:
|
|
||||||
- package_name: uptop
|
|
||||||
file_name_template: "{{ .ConventionalFileName }}"
|
|
||||||
vendor: LerkoLabs
|
|
||||||
homepage: https://gitea.lerkolabs.com/lerkolabs/uptop
|
|
||||||
maintainer: Tyler Koenig <tyler@lerkolabs.com>
|
|
||||||
description: Self-hosted uptime monitoring with a TUI over SSH
|
|
||||||
license: MIT
|
|
||||||
section: net
|
|
||||||
priority: optional
|
|
||||||
formats:
|
|
||||||
- deb
|
|
||||||
- rpm
|
|
||||||
bindir: /usr/bin
|
|
||||||
contents:
|
|
||||||
- src: ./LICENSE
|
|
||||||
dst: /usr/share/doc/uptop/LICENSE
|
|
||||||
type: doc
|
|
||||||
|
|
||||||
homebrew_casks:
|
|
||||||
- name: uptop
|
|
||||||
homepage: https://gitea.lerkolabs.com/lerkolabs/uptop
|
|
||||||
description: Self-hosted uptime monitoring with a TUI over SSH
|
|
||||||
directory: Casks
|
|
||||||
skip_upload: true
|
|
||||||
commit_msg_template: "update uptop to {{ .Tag }}"
|
|
||||||
url:
|
|
||||||
template: "https://gitea.lerkolabs.com/lerkolabs/uptop/releases/download/{{ .Tag }}/{{ .ArtifactName }}"
|
|
||||||
repository:
|
|
||||||
owner: lerkolabs
|
|
||||||
name: homebrew-tap
|
|
||||||
git:
|
|
||||||
url: "ssh://git@gitea.lerkolabs.com:2222/lerkolabs/homebrew-tap.git"
|
|
||||||
private_key: "{{ if index .Env \"TAP_SSH_KEY\" }}{{ .Env.TAP_SSH_KEY }}{{ end }}"
|
|
||||||
ssh_command: "ssh -o StrictHostKeyChecking=accept-new"
|
|
||||||
|
|
||||||
changelog:
|
changelog:
|
||||||
disable: true
|
sort: asc
|
||||||
|
filters:
|
||||||
|
exclude:
|
||||||
|
- "^docs:"
|
||||||
|
- "^chore:"
|
||||||
|
- "^style:"
|
||||||
|
|||||||
@@ -1,109 +1,46 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## [2026.06.1] — 2026-06-01
|
## [2026.05.2] — 2026-05-23
|
||||||
|
|
||||||
### 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
|
### Added
|
||||||
- SBOM and provenance attestations on Docker images for supply chain compliance (#44)
|
- Comprehensive test suite (94 tests across monitor, server, cluster)
|
||||||
- Entrypoint script with volume writability check and migration guidance (#44)
|
- golangci-lint config with CI enforcement
|
||||||
|
- Gitea Actions CI pipeline (test + lint)
|
||||||
|
- Graceful shutdown for HTTP and SSH servers
|
||||||
|
- Context-aware alert delivery with timeout
|
||||||
|
- Request size limits on all POST endpoints
|
||||||
|
- Constant-time secret comparison
|
||||||
|
- Check interval jitter to prevent thundering herd
|
||||||
|
- `--version` flag with build metadata injection
|
||||||
|
|
||||||
### Breaking
|
### Fixed
|
||||||
- Existing Docker volumes with root-owned files require migration before upgrading:
|
- Silent JSON unmarshal failures in alert settings
|
||||||
`docker run --rm -v <volume>:/data alpine chown -R 1000:1000 /data`
|
- Panic on crypto/rand failure replaced with error return
|
||||||
|
- Alert delivery errors now logged instead of swallowed
|
||||||
## [2026.05.5] — 2026-05-29
|
- log.Fatalf in goroutines replaced with log.Printf
|
||||||
|
- Deprecated LineUp/LineDown API calls
|
||||||
### 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
|
### Security
|
||||||
- Phase 1: SSRF protection, input validation, safe dial (#26)
|
- Cluster secret compared with crypto/subtle (timing-safe)
|
||||||
- Phase 2: TLS hardening, auth bypass fixes, rate limiting (#27)
|
- http.MaxBytesReader on all JSON endpoints
|
||||||
- Phase 3: Graceful degradation, connection limits, timeout enforcement (#28)
|
- ReadHeaderTimeout added to HTTP server
|
||||||
- Phase 4: Code quality, error handling, linter fixes (#29)
|
|
||||||
|
|
||||||
## [2026.05.3] — 2026-05-25
|
## [2026.05.1] — 2026-05-14
|
||||||
|
|
||||||
### 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
|
### Added
|
||||||
- Distributed probing with leader + probe nodes
|
- Distributed probing with leader + probe nodes
|
||||||
- Config-as-code — YAML apply/export with dry-run and prune
|
- Config-as-code (YAML apply/export with dry-run, prune)
|
||||||
- TUI polish — status bar, tab badges, detail panel, modals
|
- TUI visual polish (zebra striping, sparklines, breadcrumbs)
|
||||||
- DOWN-first sort, health pulse, site filter
|
- Incident management and maintenance windows
|
||||||
- Type icons in sites table
|
- 9 alert providers (Discord, Slack, Email, Ntfy, Telegram, PagerDuty, Pushover, Gotify, Webhook)
|
||||||
- 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
|
## [2026.04.1] — Initial independent fork
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- SSH-accessible TUI built on Bubble Tea + Wish
|
- SSH-accessible TUI (Bubble Tea + Wish)
|
||||||
- 6 check types — HTTP, Push, Ping, Port, DNS, Group
|
- 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
|
- SQLite and PostgreSQL support
|
||||||
- HA clustering with automatic failover
|
- HA clustering with automatic failover
|
||||||
- Prometheus /metrics endpoint
|
- Prometheus metrics endpoint
|
||||||
- Public status page (HTML + JSON)
|
- Public status page
|
||||||
- Uptime Kuma backup import
|
- Uptime Kuma import
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# --- Stage 1: Builder ---
|
# --- Stage 1: Builder ---
|
||||||
FROM golang:1.26-alpine3.23@sha256:91eda9776261207ea25fd06b5b7fed8d397dd2c0a283e77f2ab6e91bfa71079d AS builder
|
FROM golang:1.26-alpine3.23 AS builder
|
||||||
RUN apk add --no-cache gcc musl-dev
|
RUN apk add --no-cache gcc musl-dev
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY go.mod go.sum ./
|
COPY go.mod go.sum ./
|
||||||
@@ -15,23 +15,20 @@ RUN --mount=type=cache,target=/go/pkg/mod \
|
|||||||
go build -trimpath -ldflags="-s -w -X main.version=${VERSION} -X main.commit=${COMMIT} -X main.date=${BUILD_DATE}" -o uptop ./cmd/uptop/main.go
|
go build -trimpath -ldflags="-s -w -X main.version=${VERSION} -X main.commit=${COMMIT} -X main.date=${BUILD_DATE}" -o uptop ./cmd/uptop/main.go
|
||||||
|
|
||||||
# --- Stage 2: Runner ---
|
# --- Stage 2: Runner ---
|
||||||
FROM alpine:3.23@sha256:5b10f432ef3da1b8d4c7eb6c487f2f5a8f096bc91145e68878dd4a5019afde11
|
FROM alpine:3.23
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
RUN apk add --no-cache ca-certificates && apk upgrade --no-cache
|
RUN apk add --no-cache ca-certificates openssh-client
|
||||||
RUN addgroup -g 1000 -S uptop && adduser -u 1000 -S uptop -G uptop
|
RUN mkdir /data
|
||||||
RUN mkdir -p /data/.ssh && chown -R uptop:uptop /data
|
|
||||||
|
|
||||||
COPY --from=builder /app/uptop .
|
COPY --from=builder /app/uptop .
|
||||||
COPY --chmod=755 docker-entrypoint.sh /usr/local/bin/
|
|
||||||
|
|
||||||
|
# Set Default Configuration via ENV
|
||||||
|
# Docker users can override these in docker-compose.yml
|
||||||
ENV LIPGLOSS_RENDERER_HAS_DARK_BACKGROUND=true
|
ENV LIPGLOSS_RENDERER_HAS_DARK_BACKGROUND=true
|
||||||
ENV UPTOP_DB_TYPE=sqlite
|
ENV UPTOP_DB_TYPE=sqlite
|
||||||
ENV UPTOP_DB_DSN=/data/uptop.db
|
ENV UPTOP_DB_DSN=/data/uptop.db
|
||||||
ENV UPTOP_KEYS=/data/authorized_keys
|
ENV UPTOP_KEYS=/data/authorized_keys
|
||||||
ENV UPTOP_SSH_HOST_KEY=/data/.ssh/id_ed25519
|
|
||||||
ENV UPTOP_PORT=23234
|
ENV UPTOP_PORT=23234
|
||||||
|
|
||||||
EXPOSE 23234
|
EXPOSE 23234
|
||||||
USER uptop
|
|
||||||
ENTRYPOINT ["docker-entrypoint.sh"]
|
|
||||||
CMD ["./uptop"]
|
CMD ["./uptop"]
|
||||||
@@ -1,50 +1,19 @@
|
|||||||
<div align="center">
|
# uptop
|
||||||
<h1>uptop</h1>
|
|
||||||
<p>Self-hosted uptime monitoring with a TUI over SSH.</p>
|
|
||||||
<p>No browser. No client install. Just <code>ssh -p 23234 your-server</code>.</p>
|
|
||||||
|
|
||||||
<p>
|
Self-hosted uptime monitor with a TUI you can access over SSH. No browser, no install on the client — just `ssh -p 23234 your-server`.
|
||||||
<a href="https://gitea.lerkolabs.com/lerkolabs/uptop/actions/workflows/ci.yml"><img src="https://gitea.lerkolabs.com/lerkolabs/uptop/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
|
|
||||||
<img src="https://img.shields.io/badge/license-MIT-blue" alt="MIT License">
|
|
||||||
<img src="https://img.shields.io/badge/go-1.26-00ADD8?logo=go&logoColor=white" alt="Go 1.26">
|
|
||||||
<img src="https://img.shields.io/docker/pulls/lerkolabs/uptop" alt="Docker Pulls">
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<img src="assets/monitors.png" alt="uptop monitors view" width="800">
|
Built on the foundation of [RDGames/go-upkeep](https://github.com/RDGames/go-upkeep).
|
||||||
</div>
|
|
||||||
|
|
||||||
## What is this
|
## What it does
|
||||||
|
|
||||||
An uptime monitor you manage entirely from the terminal. It runs as a server, exposes an SSH endpoint, and drops you into a full TUI — monitors, alerts, logs, nodes, all there.
|
- **6 check types**: HTTP, Push (heartbeat), Ping, Port, DNS, Groups
|
||||||
|
- **9 alert providers**: Discord, Slack, Email, Ntfy, Webhook, Telegram, PagerDuty, Pushover, Gotify
|
||||||
Built on [RDGames/go-upkeep](https://github.com/RDGames/go-upkeep). Rewritten for clustering, config-as-code, and a proper dashboard.
|
- **Config as code**: define monitors in YAML, apply declaratively, version control your setup
|
||||||
|
- **HA clustering**: leader/follower with automatic failover
|
||||||
## Features
|
- **Prometheus metrics**: `/metrics` endpoint for Grafana dashboards
|
||||||
|
- **Public status page**: HTML + JSON, toggle with an env var
|
||||||
- **6 check types** — HTTP, Push (heartbeat), Ping, Port, DNS, Groups
|
- **SQLite or Postgres**: SQLite for single-node, Postgres for production
|
||||||
- **9 alert providers** — Discord, Slack, Email, Ntfy, Webhook, Telegram, PagerDuty, Pushover, Gotify
|
- **Uptime Kuma import**: migrate from Kuma with one command
|
||||||
- **Config as code** — define monitors in YAML, apply declaratively, version control your setup
|
|
||||||
- **HA clustering** — leader/follower with automatic failover
|
|
||||||
- **Prometheus metrics** — `/metrics` endpoint, wire it straight to Grafana
|
|
||||||
- **Public status page** — HTML + JSON, toggle with an env var
|
|
||||||
- **SQLite or Postgres** — SQLite for single-node, Postgres for production
|
|
||||||
- **Uptime Kuma import** — migrate from Kuma with one command
|
|
||||||
|
|
||||||
## Screenshots
|
|
||||||
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<td><img src="assets/detail.png" alt="detail panel" width="400"></td>
|
|
||||||
<td><img src="assets/alerts.png" alt="alerts view" width="400"></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><img src="assets/logs.png" alt="logs view" width="400"></td>
|
|
||||||
<td><img src="assets/nodes.png" alt="cluster nodes" width="400"></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td colspan="2" align="center"><img src="assets/theme.png" alt="theme selection" width="600"></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
## Quick start
|
## Quick start
|
||||||
|
|
||||||
@@ -53,7 +22,7 @@ go run cmd/uptop/main.go
|
|||||||
ssh -p 23234 localhost
|
ssh -p 23234 localhost
|
||||||
```
|
```
|
||||||
|
|
||||||
Want some data to look at first:
|
Seed some demo data to see it in action:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
go run cmd/uptop/main.go -demo
|
go run cmd/uptop/main.go -demo
|
||||||
@@ -61,45 +30,22 @@ go run cmd/uptop/main.go -demo
|
|||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
<details>
|
### From source
|
||||||
<summary><strong>Docker (recommended)</strong></summary>
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
services:
|
|
||||||
uptop:
|
|
||||||
image: lerkolabs/uptop:latest
|
|
||||||
restart: unless-stopped
|
|
||||||
ports:
|
|
||||||
- "23234:23234"
|
|
||||||
- "8080:8080"
|
|
||||||
environment:
|
|
||||||
- UPTOP_DB_TYPE=sqlite
|
|
||||||
- UPTOP_DB_DSN=/data/uptop.db
|
|
||||||
- UPTOP_STATUS_ENABLED=true
|
|
||||||
# - UPTOP_ADMIN_KEY=ssh-ed25519 AAAA... you@host
|
|
||||||
volumes:
|
|
||||||
- ./data:/data
|
|
||||||
```
|
|
||||||
|
|
||||||
First run: set `UPTOP_ADMIN_KEY` to your SSH public key, or attach to the container and add it in the Users tab.
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><strong>Binary</strong></summary>
|
|
||||||
|
|
||||||
Download from [Releases](https://gitea.lerkolabs.com/lerkolabs/uptop/releases).
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><strong>From source</strong></summary>
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
go install gitea.lerkolabs.com/lerkolabs/uptop/cmd/uptop@latest
|
go install gitea.lerkolabs.com/lerko/uptop/cmd/uptop@latest
|
||||||
```
|
```
|
||||||
|
|
||||||
</details>
|
### Docker
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker pull lerko/uptop:latest
|
||||||
|
docker run -p 23234:23234 -p 8080:8080 -v ./data:/data lerko/uptop
|
||||||
|
```
|
||||||
|
|
||||||
|
### Binary
|
||||||
|
|
||||||
|
Download from [Releases](https://gitea.lerkolabs.com/lerko/uptop/releases).
|
||||||
|
|
||||||
## Config as code
|
## Config as code
|
||||||
|
|
||||||
@@ -117,11 +63,35 @@ uptop apply -f monitors.yaml --dry-run # see what would change
|
|||||||
uptop apply -f monitors.yaml --prune # delete anything not in the YAML
|
uptop apply -f monitors.yaml --prune # delete anything not in the YAML
|
||||||
```
|
```
|
||||||
|
|
||||||
Full reference in [docs/config-as-code.md](docs/config-as-code.md).
|
See [docs/config-as-code.md](docs/config-as-code.md) for the full reference.
|
||||||
|
|
||||||
|
## Docker
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
monitor:
|
||||||
|
build: .
|
||||||
|
restart: unless-stopped
|
||||||
|
stdin_open: true
|
||||||
|
tty: true
|
||||||
|
ports:
|
||||||
|
- "23234:23234"
|
||||||
|
- "8080:8080"
|
||||||
|
volumes:
|
||||||
|
- ./data:/data
|
||||||
|
- ./ssh_keys:/app/.ssh
|
||||||
|
environment:
|
||||||
|
- UPTOP_DB_TYPE=sqlite
|
||||||
|
- UPTOP_DB_DSN=/data/uptop.db
|
||||||
|
- UPTOP_STATUS_ENABLED=true
|
||||||
|
- UPTOP_CLUSTER_SECRET=change-me
|
||||||
|
```
|
||||||
|
|
||||||
|
First run: attach to the container (`docker attach uptop`), go to the Users tab, add your SSH public key. Then detach with `Ctrl+P, Ctrl+Q` and connect normally over SSH.
|
||||||
|
|
||||||
## Environment variables
|
## Environment variables
|
||||||
|
|
||||||
| Variable | Default | Description |
|
| Variable | Default | What it does |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `UPTOP_PORT` | `23234` | SSH server port |
|
| `UPTOP_PORT` | `23234` | SSH server port |
|
||||||
| `UPTOP_HTTP_PORT` | `8080` | HTTP server port (status page, push, metrics) |
|
| `UPTOP_HTTP_PORT` | `8080` | HTTP server port (status page, push, metrics) |
|
||||||
@@ -133,7 +103,6 @@ Full reference in [docs/config-as-code.md](docs/config-as-code.md).
|
|||||||
| `UPTOP_PEER_URL` | | Leader URL for follower nodes |
|
| `UPTOP_PEER_URL` | | Leader URL for follower nodes |
|
||||||
| `UPTOP_CLUSTER_SECRET` | | Shared key for cluster + API auth |
|
| `UPTOP_CLUSTER_SECRET` | | Shared key for cluster + API auth |
|
||||||
| `UPTOP_INSECURE_SKIP_VERIFY` | `false` | Skip TLS verification for checks |
|
| `UPTOP_INSECURE_SKIP_VERIFY` | `false` | Skip TLS verification for checks |
|
||||||
| `UPTOP_ADMIN_KEY` | | SSH public key seeded as first admin on startup |
|
|
||||||
|
|
||||||
## Migrating from Uptime Kuma
|
## Migrating from Uptime Kuma
|
||||||
|
|
||||||
|
|||||||
@@ -1,45 +0,0 @@
|
|||||||
[changelog]
|
|
||||||
header = """
|
|
||||||
# Changelog\n
|
|
||||||
"""
|
|
||||||
body = """
|
|
||||||
{% if version %}\
|
|
||||||
## [{{ version }}] — {{ timestamp | date(format="%Y-%m-%d") }}
|
|
||||||
{% else %}\
|
|
||||||
## [Unreleased]
|
|
||||||
{% endif %}\
|
|
||||||
{% for group, commits in commits | group_by(attribute="group") %}
|
|
||||||
### {{ group | striptags | trim }}
|
|
||||||
{% for commit in commits %}
|
|
||||||
- {{ commit.message | split(pat="\n") | first | trim }}\
|
|
||||||
{% endfor %}
|
|
||||||
{% endfor %}\n
|
|
||||||
"""
|
|
||||||
trim = true
|
|
||||||
|
|
||||||
[git]
|
|
||||||
conventional_commits = true
|
|
||||||
filter_unconventional = true
|
|
||||||
split_commits = false
|
|
||||||
protect_breaking_commits = false
|
|
||||||
filter_commits = false
|
|
||||||
tag_pattern = "[0-9]*"
|
|
||||||
topo_order = false
|
|
||||||
sort_commits = "oldest"
|
|
||||||
|
|
||||||
commit_parsers = [
|
|
||||||
{ message = "^feat", group = "Added" },
|
|
||||||
{ message = "^fix", group = "Fixed" },
|
|
||||||
{ message = "^perf", group = "Changed" },
|
|
||||||
{ message = "^refactor", group = "Changed" },
|
|
||||||
{ message = "^security", group = "Security" },
|
|
||||||
{ body = ".*security", group = "Security" },
|
|
||||||
{ body = "BREAKING", group = "Breaking" },
|
|
||||||
{ footer = "BREAKING.CHANGE", group = "Breaking" },
|
|
||||||
{ message = "^docs", skip = true },
|
|
||||||
{ message = "^style", skip = true },
|
|
||||||
{ message = "^chore", skip = true },
|
|
||||||
{ message = "^ci", skip = true },
|
|
||||||
{ message = "^test", skip = true },
|
|
||||||
{ message = "^build", skip = true },
|
|
||||||
]
|
|
||||||
@@ -17,14 +17,14 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/cluster"
|
"gitea.lerkolabs.com/lerko/uptop/internal/cluster"
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/config"
|
"gitea.lerkolabs.com/lerko/uptop/internal/config"
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/importer"
|
"gitea.lerkolabs.com/lerko/uptop/internal/importer"
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/models"
|
"gitea.lerkolabs.com/lerko/uptop/internal/models"
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/monitor"
|
"gitea.lerkolabs.com/lerko/uptop/internal/monitor"
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/server"
|
"gitea.lerkolabs.com/lerko/uptop/internal/server"
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/store"
|
"gitea.lerkolabs.com/lerko/uptop/internal/store"
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/tui"
|
"gitea.lerkolabs.com/lerko/uptop/internal/tui"
|
||||||
|
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
"github.com/charmbracelet/ssh"
|
"github.com/charmbracelet/ssh"
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
set -e
|
|
||||||
|
|
||||||
if [ ! -w /data ]; then
|
|
||||||
echo "ERROR: /data is not writable by uptop user (UID $(id -u))." >&2
|
|
||||||
echo "" >&2
|
|
||||||
echo "If upgrading from a previous version that ran as root:" >&2
|
|
||||||
echo " docker run --rm -v <your_volume>:/data alpine chown -R 1000:1000 /data" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
mkdir -p /data/.ssh
|
|
||||||
|
|
||||||
exec "$@"
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
module gitea.lerkolabs.com/lerkolabs/uptop
|
module gitea.lerkolabs.com/lerko/uptop
|
||||||
|
|
||||||
go 1.26.3
|
go 1.26.3
|
||||||
|
|
||||||
@@ -53,7 +53,7 @@ require (
|
|||||||
golang.org/x/crypto v0.52.0 // indirect
|
golang.org/x/crypto v0.52.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
|
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
|
||||||
golang.org/x/mod v0.35.0 // indirect
|
golang.org/x/mod v0.35.0 // indirect
|
||||||
golang.org/x/net v0.55.0 // indirect
|
golang.org/x/net v0.54.0 // indirect
|
||||||
golang.org/x/sync v0.20.0 // indirect
|
golang.org/x/sync v0.20.0 // indirect
|
||||||
golang.org/x/sys v0.45.0 // indirect
|
golang.org/x/sys v0.45.0 // indirect
|
||||||
golang.org/x/text v0.37.0 // indirect
|
golang.org/x/text v0.37.0 // indirect
|
||||||
|
|||||||
@@ -107,8 +107,8 @@ golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0
|
|||||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
|
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
|
||||||
golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM=
|
golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM=
|
||||||
golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU=
|
golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU=
|
||||||
golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8=
|
golang.org/x/net v0.54.0 h1:2zJIZAxAHV/OHCDTCOHAYehQzLfSXuf/5SoL/Dv6w/w=
|
||||||
golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww=
|
golang.org/x/net v0.54.0/go.mod h1:Sj4oj8jK6XmHpBZU/zWHw3BV3abl4Kvi+Ut7cQcY+cQ=
|
||||||
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
|
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
|
||||||
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/models"
|
"gitea.lerkolabs.com/lerko/uptop/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
var alertClient = &http.Client{Timeout: 10 * time.Second}
|
var alertClient = &http.Client{Timeout: 10 * time.Second}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/models"
|
"gitea.lerkolabs.com/lerko/uptop/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestHTTPProviderDiscord(t *testing.T) {
|
func TestHTTPProviderDiscord(t *testing.T) {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/monitor"
|
"gitea.lerkolabs.com/lerko/uptop/internal/monitor"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/models"
|
"gitea.lerkolabs.com/lerko/uptop/internal/models"
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/monitor"
|
"gitea.lerkolabs.com/lerko/uptop/internal/monitor"
|
||||||
)
|
)
|
||||||
|
|
||||||
// --- Mock Store (minimal, for monitor.NewEngine) ---
|
// --- Mock Store (minimal, for monitor.NewEngine) ---
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/models"
|
"gitea.lerkolabs.com/lerko/uptop/internal/models"
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/monitor"
|
"gitea.lerkolabs.com/lerko/uptop/internal/monitor"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ProbeConfig struct {
|
type ProbeConfig struct {
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ package config
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/models"
|
"gitea.lerkolabs.com/lerko/uptop/internal/models"
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/store"
|
"gitea.lerkolabs.com/lerko/uptop/internal/store"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/models"
|
"gitea.lerkolabs.com/lerko/uptop/internal/models"
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/store"
|
"gitea.lerkolabs.com/lerko/uptop/internal/store"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/models"
|
"gitea.lerkolabs.com/lerko/uptop/internal/models"
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/store"
|
"gitea.lerkolabs.com/lerko/uptop/internal/store"
|
||||||
|
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/models"
|
"gitea.lerkolabs.com/lerko/uptop/internal/models"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package importer
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/models"
|
"gitea.lerkolabs.com/lerko/uptop/internal/models"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ package metrics
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/models"
|
"gitea.lerkolabs.com/lerko/uptop/internal/models"
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/monitor"
|
"gitea.lerkolabs.com/lerko/uptop/internal/monitor"
|
||||||
"net/http"
|
"net/http"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/models"
|
"gitea.lerkolabs.com/lerko/uptop/internal/models"
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/monitor"
|
"gitea.lerkolabs.com/lerko/uptop/internal/monitor"
|
||||||
)
|
)
|
||||||
|
|
||||||
type mockStore struct {
|
type mockStore struct {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/models"
|
"gitea.lerkolabs.com/lerko/uptop/internal/models"
|
||||||
|
|
||||||
"github.com/miekg/dns"
|
"github.com/miekg/dns"
|
||||||
probing "github.com/prometheus-community/pro-bing"
|
probing "github.com/prometheus-community/pro-bing"
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/models"
|
"gitea.lerkolabs.com/lerko/uptop/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestRunCheck_HTTP_Success(t *testing.T) {
|
func TestRunCheck_HTTP_Success(t *testing.T) {
|
||||||
|
|||||||
@@ -11,9 +11,9 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/alert"
|
"gitea.lerkolabs.com/lerko/uptop/internal/alert"
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/models"
|
"gitea.lerkolabs.com/lerko/uptop/internal/models"
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/store"
|
"gitea.lerkolabs.com/lerko/uptop/internal/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/models"
|
"gitea.lerkolabs.com/lerko/uptop/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
// --- Mock Store ---
|
// --- Mock Store ---
|
||||||
|
|||||||
@@ -11,11 +11,11 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/importer"
|
"gitea.lerkolabs.com/lerko/uptop/internal/importer"
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/metrics"
|
"gitea.lerkolabs.com/lerko/uptop/internal/metrics"
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/models"
|
"gitea.lerkolabs.com/lerko/uptop/internal/models"
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/monitor"
|
"gitea.lerkolabs.com/lerko/uptop/internal/monitor"
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/store"
|
"gitea.lerkolabs.com/lerko/uptop/internal/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
const maxRequestBody = 1 << 20
|
const maxRequestBody = 1 << 20
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/models"
|
"gitea.lerkolabs.com/lerko/uptop/internal/models"
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/monitor"
|
"gitea.lerkolabs.com/lerko/uptop/internal/monitor"
|
||||||
)
|
)
|
||||||
|
|
||||||
// --- Mock Store ---
|
// --- Mock Store ---
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/models"
|
"gitea.lerkolabs.com/lerko/uptop/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package store
|
package store
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/models"
|
"gitea.lerkolabs.com/lerko/uptop/internal/models"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package store
|
package store
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/models"
|
"gitea.lerkolabs.com/lerko/uptop/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Store interface {
|
type Store interface {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/monitor"
|
"gitea.lerkolabs.com/lerko/uptop/internal/monitor"
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
"github.com/charmbracelet/huh"
|
"github.com/charmbracelet/huh"
|
||||||
"github.com/charmbracelet/lipgloss"
|
"github.com/charmbracelet/lipgloss"
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/models"
|
"gitea.lerkolabs.com/lerko/uptop/internal/models"
|
||||||
|
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
"github.com/charmbracelet/huh"
|
"github.com/charmbracelet/huh"
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/models"
|
"gitea.lerkolabs.com/lerko/uptop/internal/models"
|
||||||
|
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
"github.com/charmbracelet/huh"
|
"github.com/charmbracelet/huh"
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/models"
|
"gitea.lerkolabs.com/lerko/uptop/internal/models"
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/monitor"
|
"gitea.lerkolabs.com/lerko/uptop/internal/monitor"
|
||||||
"gitea.lerkolabs.com/lerkolabs/uptop/internal/store"
|
"gitea.lerkolabs.com/lerko/uptop/internal/store"
|
||||||
|
|
||||||
"github.com/charmbracelet/bubbles/viewport"
|
"github.com/charmbracelet/bubbles/viewport"
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 84 KiB After Width: | Height: | Size: 84 KiB |
|
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 78 KiB |
|
Before Width: | Height: | Size: 206 KiB After Width: | Height: | Size: 206 KiB |
|
Before Width: | Height: | Size: 232 KiB After Width: | Height: | Size: 232 KiB |
|
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 57 KiB |
|
Before Width: | Height: | Size: 253 KiB After Width: | Height: | Size: 253 KiB |