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