# Changelog All notable changes to this project are documented here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [v0.0.1] — 2026-05-15 Initial public release. ### Added - **Quorum-based uptime monitoring.** Multiple cooperating nodes run the same probes (HTTP, TCP, ICMP) and vote on the cluster-wide truth. A check flips state only after two consecutive aggregate evaluations agree (hysteresis), so single-node flake doesn't page anyone. - **Deterministic master election.** Among the live members of the quorum the lexicographically smallest NodeID wins — no negotiation step, no split-brain window. - **mTLS inter-node transport** with TLS 1.3 minimum, SSH-style fingerprint pinning, and a pre-shared `cluster_secret` gating the Join RPC. - **Replicated `cluster.yaml`** carrying peers, checks, and alerts. Master is the only writer; followers receive monotonic-versioned snapshots and converge on the latest. Hand-edits to the file on any node are picked up by the manual-edit watcher and forwarded through the master. - **HTTP, TCP, and ICMP probes** with configurable interval, timeout, expected status, and optional body-substring match. ICMP defaults to unprivileged UDP-mode pings so the daemon can run as a non-root user. - **SMTP and Discord alerts** with optional Go `text/template` subject/body overrides per alert, default-attach mode (`default: true`), and per-check opt-outs via `suppress_alert_ids`. - **Docker-friendly env-var configuration.** Every field in `node.yaml` can also be supplied via a `QUPTIME_*` environment variable; `qu serve` auto-initialises a fresh data volume from these on first start, so `docker compose up` is enough to launch a node. - **Interactive TUI** (`qu tui`) for peers, checks, and alerts with live refresh. - **Hardened systemd unit** shipped via `install.sh`: dedicated `quptime` user, `ProtectSystem=strict`, all capabilities dropped by default. - **Multi-arch Docker images** (`linux/amd64`, `linux/arm64`) published to `git.cer.sh/axodouble/quptime`. - **Static Linux binaries** (`amd64`, `arm64`) published per tag with a `SHA256SUMS` file; the official installer verifies the checksum before placing the binary on disk. ### Security - Cluster secret is compared in constant time (`crypto/subtle.ConstantTimeCompare`). - Self-signed RSA certs minted at `qu init`; SPKI SHA-256 fingerprints are what's pinned, matching the canonical OpenSSL representation. - Private keys are written with mode `0600`; data and runtime directories with `0700`/`0750`. - All `cluster.yaml` writes go through an atomic `tmpfile + rename`. - `install.sh` downloads the published `SHA256SUMS` and refuses to install if the downloaded binary doesn't match. ### Known limitations - **Cluster-wide secret distribution.** SMTP passwords and Discord webhook URLs configured via `qu alert add …` are stored in `cluster.yaml`, which is replicated to every node. Treat every node as having read access to every alert credential. Restrict who can reach the data directory accordingly. See [docs/security.md](docs/security.md) for the threat model. - **No automatic key rotation.** Rolling a node's identity means wiping its data directory, running `qu init` again, and re-adding it from another node. - **No historical metrics.** Only the current aggregate state is kept in memory. There is no built-in graph store, SLA calculator, or audit log. - **Master-flap state.** Aggregator hysteresis state lives in memory on the current master. When leadership changes the new master starts from `StateUnknown` and re-accumulates hysteresis — expect a few seconds of delayed alerting after a master switch. - **No release signing beyond SHA256SUMS** (no cosign / GPG). Planned for a future release. [v0.0.1]: https://git.cer.sh/axodouble/quptime/releases/tag/v0.0.1