Skip to content

Releases: seitzbg/heliograph

v2.4.0

Choose a tag to compare

@seitzbg seitzbg released this 10 Oct 19:56
6e03843

Feature and security release: a y-axis fit option for the graphs, and Go and Caddy toolchain updates for new net/http and crypto/tls advisories.

Upgrade notes

  • No configuration changes are needed. Graphs keep their current scaling (Peaks) until a viewer picks Typical on the Graphs toolbar, or you set SMOKED_Y_FIT=typical (or -y-fit typical) to make it the default. An unknown value stops smoked at startup.
  • Bundled Caddy: if you run the root docker-compose.yml with the federation profile, rebuild its Caddy image (docker compose --profile federation build caddy) to pick up Go 1.27.2 and Caddy v2.11.7. The examples/federation stack uses the stock upstream caddy:2.11-alpine image, which this release doesn't change.

Added

  • A y-axis fit option for the graphs. The Graphs toolbar has a new Fit control. Peaks
    (the default, unchanged) scales each graph so every median spike fits. Typical scales to the
    98th percentile of the median line and ignores the smoke, the way SmokePing scales to its median:
    a few rare spikes clip at the top frame instead of squeezing the usual latency into the bottom of
    the plot. This matters most on a short step (60 s by default), which can catch more brief stalls
    as median spikes than SmokePing's 300 s rounds. The choice applies to the grid, the four-range view,
    zoom and the unison scale, and each browser remembers it. -y-fit / SMOKED_Y_FIT=typical sets
    the default for viewers who haven't chosen; an unknown value stops smoked at startup.
    /api/version reports it as y_fit.

Security

  • Go toolchain bumped 1.26.6 → 1.26.9 and golang.org/x/net v0.58.0 → v0.60.0 for the
    standard-library fixes in GO-2026-6603, GO-2026-6605, GO-2026-6607 to GO-2026-6613 and GO-2026-6617
    (net/http, net/textproto, crypto/tls; five of them are also fixed in x/net), which govulncheck
    flagged as reachable from the collector's HTTP server and API, the agent client, the HTTP and DNS
    probes, the alert notifiers and smoked mcp. The collector image's Go build stage moves to the
    matching golang:1.26-alpine digest. No source changes.
  • Bundled Caddy image rebuilt on Go 1.27.2 and Caddy v2.11.7 (from Go 1.26.6 and v2.11.4), clearing
    the same net/http/crypto/tls CVEs in the Caddy binary (CVE-2026-78667, CVE-2026-78669,
    CVE-2026-97031). Caddy 2.11.7 already requires the patched x/text, x/crypto and grpc versions, so
    those build-time floors are dropped; the golang.org/x/net floor moves to v0.60.0.

v2.3.0

Choose a tag to compare

@seitzbg seitzbg released this 08 Oct 04:39
e7dbe41

Backward-compatible fix release: everything from the 2026-10-07 whole-repo review.

Upgrade notes

  • Vantage certificates are now tracked by serial. On first start the hub records that existing vantages are legacy registrations: their deployed certificates keep working with no action needed. Revoking a vantage and re-adding it now really retires its earlier certificates; re-add a legacy vantage once to bring it under serial checking. See Certificate serial tracking in docs/federation.md.
  • FreeBSD rc.d: the extra-flags setting is renamed from smoked_flags / smoke_agent_flags to smoked_args / smoke_agent_args. A leftover _flags value still works and logs a warning. The v2.2.0 scripts could not start their services.
  • SmokePing --history: rows are now stored under the configured target's stable id. Pass --config if your targets live in YAML.

Fixed

  • Fresh container image builds work again. The collector Dockerfile and Caddy.Dockerfile pinned
    security-patched Alpine packages (libcrypto3/libssl3, and in the Caddy image curl/libcurl/
    c-ares) to exact revisions. Alpine's repository keeps only the newest revision of each package, so
    once a newer revision was published (libcrypto3/libssl3 3.5.9-r0, curl 8.22.0-r0), the pinned ones
    disappeared and every fresh build failed in the apk step. Those pins are now >= minimum
    versions: the CVE fixes still can't regress, and newer revisions install without breaking the build.
  • A delayed NTP round no longer brings back an obsolete clock offset after it was cleared. When a
    remote vantage reports an unsynchronized round, the hub clears that vantage's clock stat for the
    target, but the clear also dropped the stat's freshness timestamp. A store-and-forward replay of an
    older synchronized round could then re-set the offset, so /api/targets?vantage=… and the
    dashboard showed an out-of-date offset next to the newer round. The clear now keeps its timestamp,
    so only a round newer than it can set the stat again.
  • A config reload no longer pre-fills a redefined target's alert window with its old measurement.
    On a reload (SIGHUP or a config apply), alert windows are warm-started from stored history, which
    was matched only by host, probe, metric and step. Changing what a target measures without changing
    those, such as a TCPConnect port from 443 to 22, re-imported the old port's rounds, so a
    CheckLoss(x=3) alert fired on the first failure of the new port. A target whose measurement
    identity changed in a reload is no longer warm-started: its alerts wait for x rounds of the new
    measurement. A target that only gains an alert on reload is still warm-started. On a cold start,
    smoked has no record of a target's previous definition, so a target redefined while smoked was
    stopped can still be warm-started from its recent old rounds.
  • smoked import smokeping --history now stores history where the target's graph reads it.
    --apply gives every imported target a new stable id, but --history stored each RRD's rows
    under the SmokePing path, so the backfilled history never appeared on the configured target's
    graph or in /api/series. --history now looks each target up by path in the DB config and, when
    given, the YAML config passed with --config, and stores its rows under that target's id. A target
    that matches no configured target, or more than one, is named on stderr, counted as unresolved
    in the summary, and not imported; the run then exits 3, the same as other partial failures.
    With no --config and no targets in the DB config, rows are still keyed by SmokePing path, which
    matches a YAML target that has no id, and the run says so. History already imported under
    SmokePing paths is not moved; re-run --history to store it under the target ids.
  • The FreeBSD rc.d scripts now actually start their services. The v2.2.0 scripts in
    contrib/freebsd/ built a daemon(8) command line that could never run, for
    three independent reasons: the unquoted two-word title (-t Heliograph hub) split, so daemon(8)
    tried to run hub / vantage as the program; rc.subr hands ${name}_flags to $command, so
    smoked_flags (default -downsample) went to daemon(8), which rejected it; and rc.subr started
    daemon(8) through su as smoke, which then could not create /var/run/<name>.pid (and was also
    given -u smoke). The scripts now follow the FreeBSD ports convention: rc.subr runs daemon(8) as
    ${name}_user with no -u, the pidfile lives in a /var/run/<name>/ directory that user owns,
    and the process title and syslog tag are the service name, so output is logged as smoked /
    smoke_agent rather than daemon. Knob rename: extra flags move from smoked_flags /
    smoke_agent_flags to smoked_args / smoke_agent_args. A leftover _flags value is still used,
    with a warning. Also fixed: smoke_agent_spool="" now disables the on-disk spool as documented
    (the old default assignment replaced an empty value, so the agent always spooled), and
    smoked_args="" now drops the default -downsample. The freebsd-test CI job now installs both
    scripts in its FreeBSD VM and drives start/status/restart/stop through service(8), checking the
    service user, argv, environment and pidfile, plus smoked's API.
  • heliograph_triage covers the hub's own local vantage and works on a single-host hub. It
    took its vantage list from the remote-vantage registry (GET /api/admin/vantages), which never
    includes local. With a remote vantage registered, triage never read local measurements, so a
    target at 100% loss from the hub but healthy from the remote was reported healthy, and
    vantage=local was rejected as unknown. On a hub without the registry (no database or no admin
    password, e.g. the memory-store demo), triage failed outright with a 404. It now reads the
    vantages from each target's own vantage set in /api/targets, counts a target only at the
    vantages that measure it, and uses the registry only for stale-collector detection when the hub
    has one. Errors other than an absent registry (a 5xx, an auth failure) still fail the call.
    heliograph_vantages on a hub without the registry now explains that instead of returning
    "404 page not found".
  • config_stage_edit_target no longer deletes a target moved into its own subtree. Moving a
    target to a group path at or below itself (e.g. g/a into g/a/sub) detached it into an
    unreachable cycle, and the target vanished from the staged config with no error. The move is
    now rejected and the staged config is left unchanged.
  • MCP config change summaries report group-level changes. The config_stage_* results and
    config_review compared only host-bearing nodes, so changing a group's own settings (its step,
    probe params, vantages, alerts) was summarized as no change at all, although it changes every
    target beneath it. Summaries now list groups added, removed, or with changed settings, and count
    a target as changed when a group above it changes a setting it inherits.
  • MCP config staging validates against the hub's real file config. Local validation composed
    the staged DB fragment onto a defaults-only config, so a DB target that inherits its probe from
    the hub's file config (valid on the hub, and allowed by the dashboard) failed with "no probe set",
    and because every edit revalidates the whole fragment, one such target blocked all staging.
    Staging now derives the hub's file config from its effective config and composes onto it as the
    hub does. When that can't be reproduced locally, problems are reported as warnings instead of
    blocking, and config_apply's server-side validation stays authoritative.

Security

  • Revoking and re-adding a vantage now retires its earlier certificates. Agent authorization
    checked only the client certificate's CommonName against the registry, so after
    smoked vantage revoke <name> followed by vantage add <name> — the documented way to retire a
    credential — every certificate ever issued for that name (CA-signed, valid for ten years)
    authenticated again. The hub now records the serial of every certificate it issues and accepts a
    certificate only if its serial was issued for the vantage's current registration; revoking drops
    the recorded serials, so a re-added name accepts only certificates issued after the re-add.
    Regenerate (the dashboard's Regenerate, or vantage add for a registered name) is unchanged:
    earlier certificates keep working alongside the new one. Upgrade: vantages registered before
    this release have no recorded serials, so on the first start they become legacy registrations
    that keep accepting any hub-CA certificate bearing their name — deployed agents keep reporting
    with no action — until they are revoked. Revoke and re-add such a vantage once (and redeploy its
    new bundle) to bring it under serial checking. Certificates minted by an older smoked binary
    against an upgraded database are not recorded and are refused for vantages registered after the
    upgrade. See Certificate serial tracking in docs/federation.md.
  • golang.org/x/text bumped from v0.39.0 to v0.42.0 for GO-2026-6629
    (a panic in x/text/secure/precis, fixed in v0.41.0). govulncheck flagged it through pgx's
    SCRAM password handling. That path runs the operator-supplied database password through a
    different precis profile from the one the advisory names, so no remote trigger is known; the bump
    clears the scan. Caddy's --with golang.org/x/text floor is raised to match.
  • smoked vantage add -out writes the onboarding bundle owner-only. The .tar.gz embeds the
    vantage's client private key in agent.yaml, but was created with the default 0666-minus-umask
    mode, w...
Read more

v2.2.0

Choose a tag to compare

@seitzbg seitzbg released this 05 Sep 01:16
bc6d98d

Heliograph v2.2.0

Backward-compatible minor release: first-class FreeBSD support.

Added

  • FreeBSD support. Both binaries are pure Go and run natively on FreeBSD (amd64/arm64). This release attaches native FreeBSD binaries — heliograph_2.2.0_freebsd_amd64.tar.gz and heliograph_2.2.0_freebsd_arm64.tar.gz (each verified against SHA256SUMS), containing smoked + smoke-agent + web/ + config.example.yaml + contrib/ + LICENSE. A new freebsd-test CI job runs the full go test ./... suite inside a real FreeBSD VM on every push. Added contrib/freebsd/ with daemon(8)-supervised rc.d scripts for smoke-agent and smoked, and a Native binary (FreeBSD & other Unix) README section covering the ICMP privilege model (native Ping needs root; FPing works via pkg install fping).

Changed

  • The native Ping probe's "no ICMP listener available" error is now OS-aware — it spells out the remedy per OS instead of naming only Linux's net.ipv4.ping_group_range, including FreeBSD (no unprivileged ICMP datagram socket: run as root with mode: privileged, or use the FPing probe).

Container image: ghcr.io/seitzbg/heliograph:v2.2.0 (Linux). FreeBSD: download a tarball below, or see contrib/freebsd/README.md.

Full changelog: v2.1.0...v2.2.0

v2.1.0

Choose a tag to compare

@seitzbg seitzbg released this 04 Sep 10:45
0bde84a

Adds the MCP server (smoked mcp) — a stdio Model Context Protocol server wrapping Heliograph's HTTP API, so an MCP-aware assistant can diagnose the network and manage the monitoring config. Backward compatible; no breaking changes.

Added

  • MCP server (smoked mcp) — 13 tools: read-only diagnosis (heliograph_status, heliograph_sla, heliograph_series, heliograph_triage, heliograph_vantages), config read (heliograph_config_get), and a local stage → review → apply config-write flow (config_stage_add_target/edit_target/remove_target/replace, config_review, config_apply, config_discard).
  • Config edits are staged and validated locally with the daemon's own config parser; config_apply is the only tool that writes to the live hub (PUT /api/admin/config, optimistic concurrency — the hub's own validation stays authoritative).
  • Credentials are sent only over HTTPS — a plaintext http:// hub URL is refused when Basic Auth or an admin password is set (loopback excepted).

The MCP server is a client-side subcommand (runs on your machine over stdio, talks to the hub over HTTPS), so no hub redeploy is required to use it — pull the :v2.1.0 image (or build the binary) and run smoked mcp. See the README's MCP server section and examples/mcp/.

Full changelog: v2.0.0...v2.1.0

v2.0.0

Choose a tag to compare

@seitzbg seitzbg released this 03 Sep 07:54
42662d2

⚠️ Breaking change — re-onboard your vantages

The per-vantage API key is gone, replaced by mutual-TLS federation. smoke-agent's -key flag and the config key: field no longer exist; agents now authenticate with a CA-signed client certificate and connect straight to the hub's -agent-addr mTLS listener (the reverse proxy's /agent/v1/* path is removed). Every existing federated vantage must be re-onboarded with a certificate bundle: run smoked vantage add <name> (or use the dashboard's Add vantage) and redeploy the agent with the new agent.yaml.

Added

  • Opt-in mutual-TLS federation — a dedicated mTLS listener (-agent-addr :8443 -agent-hostname <domain>), self-bootstrapped CA, per-vantage client certs whose CommonName is the vantage identity (revoke takes effect on the next request).
  • One-click vantage onboarding — Add vantage downloads a ready-to-run <name>-vantage.tar.gz (agent.yaml + docker-compose.yml + README); CLI equivalent smoked vantage add <name> -out ….
  • Copyable example stacks under examples/ (standalone/ and federation/).

Security

  • Minting a vantage requires HTTPS — POST /api/admin/vantages refuses to mint over plaintext (403) so the embedded private key never crosses the wire in the clear (reads X-Forwarded-Proto: https from the proxy; loopback exempt; CLI is the local escape hatch).
  • Open config reads redact credentials embedded anywhere in a probe URL (userinfo, query, and path).

Changed

  • The Graphs vantage selector caps at 4 simultaneous overlaid vantages (palette size).

Fixed

  • Overview no longer reports a target down from a vantage that doesn't measure it; a batch of Graphs correctness/robustness fixes — peak clipping, blank-on-refresh, stalled-body aborts, overlay color collisions, narrow-viewport overflow, and refusing to mint an onboarding bundle when no agent listener is configured.

Full changelog: CHANGELOG.md · compare v1.0.16...v2.0.0

Image: ghcr.io/seitzbg/heliograph:v2.0.0

v1.0.16

Choose a tag to compare

@seitzbg seitzbg released this 24 Aug 21:25
4e10296

Changed

  • The Config tab now defaults to your Effective config, not the DB fragment. The Effective | DB
    source toggle now applies to both the Tree and YAML views (previously YAML-only), and the tab opens
    on Effective — the file+DB merged config the collector actually runs — so you see your real
    config instead of an empty database fragment. Effective is read-only (you can't edit file-defined
    targets from the browser); switch the source to DB to add or edit database-backed targets. New
    read-only endpoint GET /api/admin/config?source=effective (open read, same non-secret data as the
    effective YAML) backs the effective tree.

v1.0.15

Choose a tag to compare

@seitzbg seitzbg released this 24 Aug 20:01
8e945c7

Added

  • View the config as YAML in the Config tab. A Tree | YAML toggle sits beside the target tree; the
    YAML view is read-only and offers two sources — DB (just the targets stored in the database) and
    Effective (your YAML files merged with the DB targets, exactly as the collector runs it). It reads
    like a hand-written config file: durations render as 60s, and unset/inherited fields are omitted
    rather than shown as null. Served by a new open read GET /api/admin/config.yaml?source=db|effective
    (alongside GET /api/admin/config); the config holds no secrets, so it needs no admin login, and every
    write endpoint stays gated.

Fixed

  • The dashboard no longer serves stale JavaScript after an upgrade. Static assets (index.html,
    dashboard.js, smoke.js, CSS) were served with only a Last-Modified header, so a browser could
    keep running the pre-upgrade dashboard against a freshly-deployed server until a hard refresh — which
    could leave panels stuck on "loading" after switching vantages. They now carry Cache-Control: no-cache, forcing the browser to revalidate (a cheap 304 when unchanged, a fresh copy the moment the
    file changes). Assets are still cached; they're just never served stale.

v1.0.14

Choose a tag to compare

@seitzbg seitzbg released this 24 Aug 18:46
a4870d8

Read-only admin pages and a cleaner Graphs toolbar.

Changed

  • Vantages + Config pages are viewable without logging in. Anyone who can reach the dashboard (behind the reverse proxy's Basic Auth) can now see the vantage list and the DB config tree read-only; adding/revoking a vantage and editing/importing config still require an admin login. The vantage list never includes keys, and the config doc holds no secrets (notifiers are referenced by name; the real credentials come from the environment), so nothing sensitive is exposed.
  • Tidier Graphs toolbar. The reference key (jitter + loss) and the interactive controls (vantages/cols/unison) are separated into two zones with a divider, and the 8-chip loss legend is now a single compact green→red strip (each bucket's threshold on hover). It scales down cleanly — the zones wrap and the divider drops on narrow screens.

Ships as ghcr.io/seitzbg/heliograph:v1.0.14. See the CHANGELOG.

v1.0.13

Choose a tag to compare

@seitzbg seitzbg released this 24 Aug 17:55
06803b5

Multi-vantage overview polish.

Changed

  • Graphs grid hides targets a selected vantage doesn't measure. Viewing the grid from a vantage that doesn't probe some targets (e.g. a Comcast vantage that doesn't measure the hub's loopback or internal resolvers) no longer draws blank "collecting…" panels — those are hidden with an "N targets not measured — hidden" note, and each shown panel's band follows the first selected vantage that actually measures it, so a shown panel never blanks either. Hidden targets stay in the nav tree and detail view.

Ships as ghcr.io/seitzbg/heliograph:v1.0.13. See the CHANGELOG.

v1.0.12

Choose a tag to compare

@seitzbg seitzbg released this 24 Aug 17:06
1487657

Multi-vantage reaches the overview.

Highlights

  • Vantages on the Graphs page. A vantage control on the Graphs toolbar (shown only when a deployment measures from more than one vantage) picks which vantages draw on every panel: the focused one owns the min–max band + median, the rest overlay as median lines — so selecting one vantage is a clean single view and selecting all is a full fiber-vs-vantage overlay. The nav and panel status dots now reflect the worst vantage (even one you've hidden), so a target healthy locally but losing packets from another vantage still flags on the overview. Defaults to local; the selection is remembered per browser.
  • Docs: config.example.yaml now shows a vantages: example, so the reference config demonstrates measuring a subtree from both the hub and a remote vantage.

See the CHANGELOG. Ships as ghcr.io/seitzbg/heliograph:v1.0.12.