Skip to content

Changelog

4.1.0 (2026-08-15)

Features

  • chart: add Artifact Hub metadata and point home at the docs site (5a5abbe)
  • docs: take the fleet project icon for the site logo and favicon (c35a2c2)
  • docs: take the fleet-generated social card (73a9fda)
  • logship: structure dpinger lifecycle, so a restart stops looking like a recovery (8cca5da), closes #668
  • logship: structure kernel promiscuous-mode toggles and sudo (3ea6692), closes #669
  • logship: structure rule-updater.py, making Suricata ruleset freshness observable (10f315a), closes #666
  • logship: structure syslog-ng lines, the box's own report that our feed dropped (26ce3c5), closes #665
  • logship: structure the Kea lease-file-cleanup syslog family (e85af85), closes #664
  • logship: structure Unbound's log-queries/log-replies syslog output (8928d15), closes #659
  • mint release-please token from the OpenBao broker (2c7fb11)
  • mint the docs-sync token from the OpenBao broker (81a03ea)

Bug Fixes

  • alerts: add hysteresis to gateway flapping rule, add RTT baseline-deviation rule (b64d34b), closes #658
  • archive: redact 26 more v6 addresses the hand-rolled pattern missed (1be7545)
  • author is Rob Knight, not Rob Knighton (1a53b73)
  • canary: let oli start the live canary instead of GitHub's cron (e9c8c1b), closes #654
  • correct eight defects found by the production verification sweep (671098d), closes #637 #638 #639 #640 #641 #642 #643 #644 #645
  • deps: update module github.com/grafana/pyroscope-go to v1.4.2 (#674) (9a67a58)
  • deps: update module github.com/oschwald/maxminddb-golang/v2 to v2.5.0 (#670) (e7c8e8c)
  • deps: update module google.golang.org/protobuf to v1.36.12 (#671) (b1338c9)
  • deps: update opentelemetry (#635) (94b8bfd)
  • docs: render the changelog instead of the include directive (213863d)
  • flow: pair merge endpoints by address, not by position (0cf91c3), closes #647
  • flow: pair NAT copies by conversation when the exact window cannot close (07e7242), closes #636
  • grafana: bound percent gauges, gate opt-in flow panels, disambiguate one title (1100c10), closes #649
  • grafana: keep instance identity in the #647 panel aggregation (cb5829d)
  • grafana: let the datasource own the min interval, not 815 panels (ffa9335), closes #650
  • grafana: make OPNsenseNetmapRingFull mean sustained, not one burst (72585d3), closes #675
  • grafana: pick instant-query format by viz, not by instant (287d019), closes #661
  • interfaces,firmware: close two gaps found verifying 671098d on the box (787dde3)
  • logship: bound batches by ingest rate, split and pace on 429 (a32463d), closes #663
  • logship: put documentation addresses back in the dpinger and unbound fixtures (5b23445)
  • logship: structure the config-apply event, and only it (dc76bc2), closes #667
  • opnsense: decode unbound query-class counters as a map, not a fixed IN field (99b7814)
  • pass the JWT role explicitly for docs-sync (fc46201)

Miscellaneous

  • deps: update anthropics/claude-code-action action to v1.0.184 (#648) (2f5943b)
  • deps: update anthropics/claude-code-action action to v1.0.185 (#651) (a56bb3d)
  • deps: update anthropics/claude-code-action action to v1.0.186 (#657) (bb1dd4f)
  • deps: update anthropics/claude-code-action action to v1.0.187 (#662) (54faf9e)
  • deps: update anthropics/claude-code-action action to v1.0.193 (#676) (f17cb5e)
  • deps: update module github.com/anchore/syft to v1.51.0 (#672) (cb26976)
  • deps: update module github.com/anchore/syft/cmd/syft to v1.51.0 (#673) (2a9bfa8)
  • deps: update step-security/harden-runner action to v2.20.1 (#652) (4787fdb)
  • deps: update step-security/harden-runner action to v2.21.0 (#677) (bb6bcee)
  • gitignore the build artifacts the hub injects (f79080b)
  • logship: wire the capture-triage wave's shared seams (0ad3d46)
  • tracker: close OPN-0002 — main is green on 5b23445a (9a09bb4)
  • tracker: move issue tracking from GitHub to in-repo backlog.md (f72a941)

Documentation

  • add a "Why This Exporter" positioning page (c9f587c)
  • add an FAQ (4c2db9f)
  • adopt the m7kni.io inverted docs model (d5cf9c3)
  • archive: archive the GitHub Issues tracker before deleting it (7999e7c)
  • drop two overrides that never did anything (3317545)
  • fix broken internal links (3e868a6)
  • flow: correct two claims #636's own verification disproved (eaab369)
  • flow: state the three ways the per-WAN byte ratio lies (c9a5b9d)
  • put a copy-paste quickstart on the landing page (dc7ae7c)
  • re-import the fan-out protocol after promoting four orphan rules (06d64b4)
  • re-import the fan-out protocol, now harness-neutral (c80b7b4)
  • tracker: note that the bare --notes/--plan denial is hook-enforced (be7b05c)

CI/CD

  • mint the GitSync token from OpenBao instead of GITSYNC_PAT (4200b25)

4.0.0 (2026-08-01)

⚠ BREAKING CHANGES

  • The default OTLP/log service.name and Pyroscope application name, plus the Grafana annotation base tag, change from opnsense-exporter to opnsense2otel in v4. Update identity-based selectors or explicitly retain the configurable v3 names.
  • grafana: move the alert folders to opnsense2otel-*
  • the environment variable prefix OPNSENSE_EXPORTER_* is now OPN2OTEL_*, with no back-compat aliases. Operators rewrite it with sed -i 's/OPNSENSE_EXPORTER_/OPN2OTEL_/g' over their compose/env files. The unprefixed *_FILE secret aliases (OPS_API_KEY_FILE and friends) are a separate convention and are unchanged. The container image is now ghcr.io/rknightion/opnsense2otel and the Helm chart lives at charts/opnsense2otel. docs/upgrading.md carries the full migration.
  • cpu: opnsense_activity_cpu_{user,nice,system,interrupt,idle}_percent are removed. CPU utilisation is now opnsense_cpu_seconds_total{mode="user|nice|system|interrupt|idle"}, so panels and alerts move to 100 * rate(...). The bundled dashboard and rules are migrated.
  • logship: organization, policyid, scope_name and the four geo coordinate keys are no longer shipped as Loki structured metadata on Zenarmor records. They remain in the log body, which is unchanged. A LogQL filter naming one of them stops matching; read it from the body with | json instead. --logs.zenarmor.exclude rules naming organization or policyid now fail at startup as unknown fields.
  • telemetry: opnsense_exporter_otlp_enabled, opnsense_exporter_otlp_exports_total, opnsense_exporter_otlp_consecutive_failures and opnsense_exporter_otlp_last_success_timestamp_seconds now carry an opnsense_instance label. A query that aggregates them without by (opnsense_instance) returns one series per exporter instead of one overall; add the grouping or use sum without (opnsense_instance) (...) to keep the old shape. Single-instance deployments see no change beyond the extra label. The bundled dashboard and rules are already updated. See docs/upgrading.md.
  • metrics: nine counters are renamed with a total suffix: opnsense_ipsec_phase{1,2} (eight series, e.g. opnsense_ipsec_phase1_bytes_in -> opnsense_ipsec_phase1_bytes_in_total) and opnsense_vnstat_total_bytes -> opnsense_vnstat_bytes_total. Direct-scrape consumers must update; OTLP consumers will only ever have seen the suffixed names once the series exists. See docs/upgrading.md.}_{in,out
  • metrics: the eight opnsense_firewall_packets series are renamed to opnsense_firewall_packets_total. Direct-scrape consumers must update; OTLP consumers already saw the suffixed names. See docs/upgrading.md.
  • logship: make delivery and freshness outcomes explicit
  • container: add native health and config checks
  • config: remove obsolete scrape deadline surfaces

Features

  • activity: aggregate the process table we already fetch and discard (0d0d6a5), closes #552
  • activity: export the ZFS ARC composition breakdown (e6427a6), closes #551
  • annotations: link pushed annotations back to the dashboard (7b943b6)
  • apidrift: stamp the OPNsense generation into the canary report (c268df4), closes #490
  • autodiscovery: probe every plugin-gated collector, not just the opt-in three (a53d2c5), closes #525
  • autodiscovery: report and enable available-but-off collectors (#517) (eef61c7)
  • canary: per-profile scoping on the coverage ledger (78d20f4), closes #611
  • collector: capacity context, mbuf pools, and the audit-tooling hardening (b0728fc), closes #595
  • collector: export four more fields the API already hands us (5b5da4b), closes #557
  • collector: export the dropped-data residue for SMART, IPsec, pf, FRR and unbound (4439d18)
  • collector: kernel memory zones, collapsed dimensions restored, flow country label on (49913c9), closes #534 #537 #543
  • collector: kernel telemetry wave — netisr per-CPU, netmap, WAN DHCP, pf refs, TCP recovery (b04cd2c), closes #536 #538 #541 #542 #545
  • collector: re-audit every collector's poll tier against the #568 rule (20b38b4), closes #569
  • container: add native health and config checks (ed8fa84), closes #438 #446
  • contract: detect unexpected nested response keys (53da29f), closes #376
  • cpu: consume cpu_usage/stream over SSE into cumulative CPU counters (316641e), closes #559
  • deploy: make supported paths executable (80e3e46), closes #437 #440 #444
  • dhcp6c: lease gauges for the WAN IPv6 address, the IA_NA twin of #546 (63709b4), closes #560
  • dhcp: keep the raw interface id on every lease grid, not just its description (6166221), closes #556
  • docs: generate example configs covering every flag (b0f4338), closes #515
  • firewall: export per-rule protocol, and nothing else from that payload (6094b7a), closes #558
  • firmware: expose update-check health and pending download size (2d0769b), closes #373 #380
  • flow: alert on conclusively dead NetFlow hooks (9a05d9e), closes #402
  • flow: count repair 4's four silent exits (749b473), closes #624
  • flow: NetFlow debug capture, and stop stepping over the unidentified in silence (689ef5b), closes #360
  • flow: preserve event time and interval fields (6caece7), closes #391 #411
  • flow: publish the ifIndex map so device and description space can be joined (ff5b9c7), closes #368
  • flow: publish the unmapped-record counter so the cold-start window is visible (70c9b2b), closes #367
  • flow: resolve policy-routed egress from pf's own state table (e5deddb), closes #603
  • flow: split policy-route refusals by the interface they are attributed to (75a9241)
  • geoip: enrich flow records from local MaxMind databases (a6fa9c9), closes #520
  • geoip: extend enrichment to filterlog, sshd/auth and Suricata logs (2fd9cc1), closes #528
  • geoip: ship DB-IP Lite in the image and default enrichment on (21b97af), closes #549
  • grafana: add a generated event-annotation timeline and push it to Grafana (9f20ac9)
  • grafana: add a tested Grafana 11/12 compatibility dashboard (8e49f4e), closes #420
  • grafana: alert when one exporter vanishes and the others do not (4c529e3), closes #427
  • grafana: close the consumption gaps, add the posture set, and end three classes of gate blindness (954d82a), closes #578 #579 #581 #582 #583 #589 #591 #592
  • grafana: generate context-preserving drilldowns from a frozen UID registry (6100ad6), closes #419
  • grafana: link every alert to its canonical dashboard panel (49eb77a), closes #530
  • grafana: make the Zenarmor client picker enumerable (e543af8), closes #474
  • grafana: move the alert folders to opnsense2otel-* (0bb033f)
  • grafana: route exporter self-health alerts to their own folder (4a33aa5), closes #431
  • grafana: split exporter self-observability onto its own dashboard (a486d0c), closes #431
  • interfaces: export the driver and HW offload capabilities we already fetch (99571ed), closes #555
  • interfaces: expose unknown-protocol packets and the stats-reset epoch (3699176), closes #375
  • logship,grafana,schemas: close the consumption-audit follow-ons from #593 (b847b6d), closes #596 #597 #598 #599 #600
  • logship: dhcp6c and kea-dhcp6 coverage — the IPv6 twin of #541 (b15d78f), closes #546
  • logship: parse ppp, firewall aliases, acme and unbound's dnsbl chatter (a02e9ee), closes #631
  • logship: put device category and interface on the log resource (ea161c7), closes #473
  • model three canary-found data gaps and add a soft series budget (1c54c58)
  • netflow: expose the configured capture set and time since last record (0f83056), closes #366
  • netflow: model TOS, prefix masks and next hop so a stock box reports no unknown elements (183fd43), closes #630
  • otlp: gzip by default on both signals, one exporter per worker (669f524), closes #505
  • protocol: break down TCP connection drops by timeout reason (9fc10ba), closes #374
  • rename the project opnsense-exporter -> opnsense2otel (bed4889)
  • scheduler: poll cadence follows the export lane that consumes it (286b3f5), closes #550
  • schema: scope canary ledger entries to a probe profile (1d97e0e)
  • security: generate collector ACL guidance (d8a7824), closes #442
  • server: instrument the /metrics serving path (a73f84c), closes #426
  • startup: log the resolved config and the discovered plugin inventory (73d2205), closes #526
  • syslog: add privacy-safe FreeRADIUS events (18b4b90), closes #407
  • syslog: derive CARP state and demotion events (f0f1a26), closes #405
  • syslog: derive gateway alarm transitions (8ef49ed)
  • syslog: derive miniupnpd mapping expiry and failure events (6d812f8)
  • syslog: normalize IPsec and OpenVPN lifecycle events (3c51776), closes #406
  • telemetry: honest data age, upstream health, and OTLP delivery visibility (58a51e5), closes #382 #384 #388 #389 #390
  • testbed: power the lab down outside the canary window (3a8f9be), closes #625

Bug Fixes

  • alerts: delete OPNsenseFlowSourceDivergence, its threshold sits below the metric's floor (fc8a370), closes #602
  • alerts: stop OPNsenseDHCP6AllocationFailures firing on a single event (144992e), closes #594
  • annotations: bound the annotation dedupe set (af78295), closes #421
  • annotations: cap posts per cycle by attempts, not successes (eec1461), closes #519
  • annotations: never follow a redirect with the bearer token attached (c16fc37), closes #566
  • annotations: stop pushing threat-feed events the dashboard defaults off (a53bba9), closes #540
  • canary: camden's prod canary closes its own issue, and stops calling breaking drift clean (8148653), closes #612
  • canary: give each probe target its own drift issue (f7e95ab), closes #490
  • canary: scope the tailscaleStatus Self.KeyExpiry exemption to prod (d28029b), closes #614
  • canary: stop apidrift validating ipsecSad against the placeholder row (b8475fe), closes #618
  • captiveportal: skip the session search when no zones are configured (d1bd9e0), closes #524
  • carp: a disabled VIP is not an unparseable one (f4b3c4e), closes #503
  • ci: allowlist the well-known resolver literals in the #581 unbound infra fixtures (3dc2005)
  • ci: give fuzz-smoke a timeout that is not consumed by build time (0a838db), closes #469
  • ci: post the compat dashboard body from a file, not an argument (3f6ac71)
  • ci: unbreak main — hide the GOOS-dependent flag, guard the availability map (d3d5790), closes #532
  • collector: one inventory row per Zenarmor device, not one per attribute set (96a35b7), closes #476
  • config: remove obsolete scrape deadline surfaces (0168186), closes #439
  • correct opnsense_up semantics and cover three untested subsystems (2203852), closes #488
  • deploy: make hosted contracts portable (af16b85), closes #440 #444
  • deploy: set secret mode before ownership (428df7e), closes #440
  • deps: revert the phantom go.yaml.in/yaml/v3 require and block the major (f58126d), closes #533
  • deps: update module github.com/prometheus/client_golang to v1.24.1 (#369) (348caef)
  • deps: update module github.com/prometheus/prometheus to v0.313.2 (#570) (93fbe64)
  • deps: update module go.opentelemetry.io/proto/otlp to v1.11.0 (#463) (a9f2e21)
  • deps: update module go.yaml.in/yaml/v2 to v3 (#527) (dd0957d)
  • deps: update module google.golang.org/grpc to v1.83.0 (#554) (769a33e)
  • flow,annotations,config: triage-able ifIndex conflicts, 429 backoff, full preflight summary (4fde7ba), closes #516 #518 #519
  • flow: attribute VLAN child flows by subnet evidence instead of arrival order (1b203ee)
  • flow: bound the Zenarmor-controlled interface keys behind distinct-destinations (8ab7d28), closes #563
  • flow: close the expiry half of the policy-route miss window, and poll pf faster (8b0a506), closes #620
  • flow: correct the API's attach order into ifinfo order for the ifIndex map (9c39af6), closes #363
  • flow: count records a nil ifIndex map cannot label, and close the cold window (b214f4c), closes #365
  • flow: de-duplicate the two copies of a NAT'd conversation (e7b1504), closes #623
  • flow: decide a merged record's orientation by evidence, not arrival order (f88f7f9), closes #605
  • flow: derive the ifIndex enumeration from kernel indexes, not a rank heuristic (d829cff), closes #364
  • flow: do not advise enabling a NetFlow capture that is already running (765405b), closes #360
  • flow: do not treat a nameless ifIndex map as final (7305d63), closes #522
  • flow: label a cold-start interface "unresolved" instead of its kernel device (80d8f62), closes #606
  • flow: read the NetFlow ifIndex enumeration from the box, not from a row count (fb1c7f3), closes #361
  • flow: resolve VLAN duplicates to the child copy, not the first arrival (f63b391), closes #357
  • flow: split a merged record's two halves into Tx and Rx (92d5256), closes #617
  • flow: state the byte basis on merged records, and stop comparing a window partial against a whole connection (2e3057e), closes #604
  • flow: union repair markers across a conversation's fragments (b1a8c96)
  • frr: compose the OSPFv3 route type from destinationType and pathType (f199ef4), closes #458
  • frr: surface OSPF overview decode failures instead of partial success (9355aa4), closes #378
  • grafana: deep-link the CPU stream alert and bump the rule count pins (449f0f4)
  • grafana: floor the pending window at 10m in --stack mode (444cbfa), closes #629
  • grafana: give loki_table a real key column instead of a label set (a81fc38), closes #471
  • grafana: keep the alert folder UIDs, retitle them instead (7b7c984)
  • grafana: make every Loki top-N table an instant query, ranked to 200 (df1a448), closes #479
  • grafana: make log delivery loss-aware (e0b497d), closes #393 #394 #395 #399 #400
  • grafana: move rarely-toggled annotation layers and links into the controls menu (db30892), closes #470
  • grafana: normalise threshold steps too, and assert the shape not the field (bf13e4e), closes #616
  • grafana: pin the unbounded-label Loki tables to their own window (7ed2631)
  • grafana: populate the device variable from every device-bearing source (4002fb1), closes #424
  • grafana: preserve exporter-instance identity through aggregations and tables (875641f), closes #468
  • grafana: repair dashboard-health's field overrides and verify the sync landed (109e36e)
  • grafana: repair the rendering layer the #491 sweep found broken (ef9b911), closes #509 #510 #511 #512 #513 #514
  • grafana: run the builder unit tests in CI and repair the three that had rotted (52ef4b2)
  • grafana: scope feature sentinels and Loki panels to the selected instance (d55384c), closes #413 #414 #466
  • grafana: separate event and byte rates in the three ingest panels (7aca7f5), closes #416
  • grafana: stop fabricating severity thresholds on bar gauges (4b59030), closes #415
  • grafana: stop injecting synthetic thresholds into radial gauges (b386df6), closes #467
  • grafana: three of the #491 fixes did not survive being rendered (615f850)
  • grafana: validate generated PromQL (9470bf6), closes #412
  • interfaces: emit SFP RX optical power in both mW and dBm (8098023), closes #456
  • interfaces: suppress a queue-drop figure that has wrapped through uint32 (12abef6), closes #548
  • logevents: netmap ring-full counts per kernel line, not per interval (34c1524), closes #610
  • logship: bound a drained batch by bytes, not just by record count (e334c9e), closes #506
  • logship: export resource partitions concurrently, raise queue defaults (5394a5c), closes #505
  • logship: keep one example per shape in the syslog debug capture (8b6997c), closes #362
  • logship: make delivery and freshness outcomes explicit (adabcad), closes #392 #394 #395
  • logship: redact reusable credentials before request headers reach a capture (3bf1dd5), closes #561
  • metrics: suffix PF packet counters with _total (3514a9e), closes #418
  • metrics: suffix the nine remaining counters that lack _total (ae0f13d), closes #464
  • netflow: bound the v9 template cache (4cd385f), closes #564
  • netflow: mark PPPoE devices capture-unsupported and stop alerting on them (2b61ca7), closes #521
  • nginx,logship,schemas: overCounts is an object, netbird's real app-name, and the prod-vs-testbed canary correction (2148c3d), closes #609 #601
  • nginx: model overCounts per zone kind instead of one union struct (db05cf5)
  • opnsense: correct BFD counter json tags and ledger the untriaged canary keys (c7d8007), closes #480
  • opnsense: name the right endpoint in missing-endpoint errors (48e5fe7), closes #576
  • opnsense: split plugin-gating from 404-cacheability (66eb588), closes #495
  • opnsense: tolerate rule_stats returning an empty array (83ec406), closes #481
  • opnsense: tolerate the empty-cache [] shape from netflow cacheStats (9226132), closes #499
  • options: drop the doubled prefix from the enable-all-available env var (c5fb503), closes #517
  • release: restore third-party notices pipeline (3ad3966), closes #436
  • scheduler: make poll clocks, reachability and health cadence honest (f159ad3), closes #381 #383 #385 #386 #387
  • schema: model nd6 as the object upstream actually serves (7754b36), closes #371
  • scripts: restore the executable bit the rename sed stripped (2785d77)
  • smart: decode smartctl's wear percentages as objects, not numbers (d293332), closes #615
  • smart: endurance_used has no threshold_percent, so stop modelling one (2583827)
  • syslog: count pre-record connection rejections (8283826), closes #399
  • syslog: derive dnsmasq DHCP metrics (cd5fdcb), closes #396
  • syslog: preserve malformed structured data (d164384), closes #397
  • syslog: recover from oversized TCP frames (b64a790), closes #398
  • telemetry: drop service.version from the metrics resource (00a1672), closes #472
  • telemetry: give the otlp_* self-metrics an opnsense_instance label (46e90f5), closes #466
  • web: refuse a client-SAN config that lets a certificate-less peer panic (d94bff9), closes #562

Performance

  • cache: body-TTL seven config GETs, shorten the global TTL to 30m (1d97337), closes #574
  • crowdsec: split the hub inventory onto a slower sub-cadence (c509793), closes #575
  • enrich: stop the refresher re-fetching what the collectors just decoded (cc8a5a1), closes #571
  • grafana: bound cold-load query fan-out with a measured budget (421bf96), closes #422
  • grafana: scope presence sentinels to the tab that consumes them (4da1b31), closes #619
  • logship: stop re-extracting six redundant Zenarmor metadata keys (e3a957c), closes #475
  • netflow,interfaces: the first two fast-tier body caches (568d84a)

Refactoring

  • collector: justify fast-tier body caches per endpoint, don't ban them (cc0c20b), closes #567
  • grafana: describe dashboards by spec instead of by module globals (474605f), closes #431
  • grafana: make the coverage gate span the dashboard family (076971a), closes #431
  • grafana: merge the Zenarmor companion's unique content and retire its UID (59c4dfe), closes #435
  • grafana: retire the Observability domain, rework the health dashboard IA (d4f45b3), closes #523
  • grafana: split the seven oversized leaves and add autogrid_row (f5070ac), closes #619
  • syslog: make processor rebuilds safe (81b983f), closes #401

Miscellaneous

  • deps: update anthropics/claude-code-action action to v1.0.182 (#370) (34e4f00)
  • deps: update anthropics/claude-code-action action to v1.0.183 (#454) (34e0f04)
  • deps: update module github.com/anchore/syft to v1.50.0 (#498) (5cdd8b7)
  • deps: update module github.com/anchore/syft/cmd/syft to v1.50.0 (#500) (f1d50c0)
  • deps: update opnsense-docs digest to 2c46934 (#501) (af2513d)
  • deps: update opnsense-docs digest to 691b61a (#461) (26dc26c)
  • deps: update opnsense-docs digest to bf303ba (#359) (ab035e6)
  • pin the GoReleaser project name and ignore local Claude state (cb27a80)
  • regenerate docs, dashboards and rules for the field-export wave (e56014d)
  • release: declare GoReleaser v2 schema (05eb570), closes #634
  • repo: repair ownership and intake (1753ddf)
  • schemas: ledger the first per-target canary batch (0a58534)
  • schemas: ledger the nightly-box canary findings (9850b0e)
  • schemas: ledger the release-box canary findings (26549e8), closes #496
  • testbed: lint firewall configs for silently-inert settings (52c9cf1), closes #504

Documentation

  • canary: correct the false 404 claim in smartInfo's exemption note (540f3ac), closes #613
  • canary: correct the trafficShaper blocker — the shaper was configured all along (f497233), closes #621
  • canary: ledger the 17 firewallStates row keys the pf-state repair does not model (731ddf8)
  • canary: ledger verdict for healthCheck's seven subsystem notice fields (957cc1e), closes #613
  • canary: ledger verdict for unboundBlocklistPolicies' ten config fields (36b0c79), closes #613
  • canary: ledger verdicts for the 17 quaggaOspfOverview per-area fields (d029712), closes #613
  • canary: profile-scope smartInfo's wear fields, and correct my own wrong note (16fbfd1), closes #613
  • collector: write the fast-tier admission rule as a test, not a description (025e54f), closes #568
  • document v4 telemetry identity migration (bded064), closes #633
  • flowanon: stop naming the device WAN2 used to be on (012ff0d)
  • flow: correct the refusal-floor claim I got wrong this morning (ae91385), closes #624
  • flow: correct why the stated ifIndex and the derived position diverge (f2bae6e)
  • flow: point --flow.netflow.ifindex-map at the whole enumeration (f9517a3)
  • flow: state the multi-WAN attribution limits and correct the refusal-floor claim (1d900e6)
  • grafana: describe the panels whose semantics the title cannot carry (1c3ce49), closes #423
  • grafana: generate a runbook per alert instead of one shared anchor (2d303c1), closes #430
  • grafana: generate the feature-sentinel contract (fd94cbd), closes #417
  • grafana: record the per-folder permission that made the folder move 403 twice (41ab129)
  • logship: ship-concurrency is a no-op on gRPC, and not for the reason stated (24cf485), closes #505
  • re-pin the dashboard metric count after the ifIndex guard metric (a4e4dae)
  • readme: voice and de-AI pass (db16f8a)
  • settle the cross-poller OTLP attribute contract (a4340cc), closes #477
  • syslog: document the ppp, firewall-alias, acme and unbound-dnsbl parsers (823f45a), closes #631
  • update documentation (4206f8d)
  • update documentation (08d9fb1)
  • update documentation (2ed53ab)

Build & Infrastructure

  • type-aware check for API fields decoded and never read (6ff859d), closes #544

Tests

  • alerts: model Grafana's rule state machine against the shipped manifests (b5afdac), closes #429
  • collector: drain collectMetrics concurrently instead of buffering 500 (8cdc140), closes #547
  • collector: drain Describe concurrently so a new metric cannot deadlock CI (804670d)
  • contract: make unexpected nested keys a warning again (206026a), closes #457
  • contract: reflect through RawMessage envelopes so their paths are checked (0a24a5a), closes #459
  • contract: track live coverage for metric-bearing response paths (b171804), closes #377
  • grafana: contract-check the alert fields Prometheus cannot model (55d3ce9), closes #429
  • grafana: gate zero-filled panels on same-collector sentinel provenance (a62b25a), closes #478
  • grafana: inventory the exporter's self-metrics and gate them (bf581a7), closes #428 #455
  • grafana: pin coverage() to panel queries only (81d14c0), closes #619
  • grafana: syntax-check alert and recording expressions in CI (7db33f3)
  • grafana: update the rule-count pins for the GeoIP stale alert (b7c2e1e)
  • parsers: continuously fuzz network inputs (d47b09a), closes #443
  • syslog: use RFC 5737 documentation addresses in the ppp fixtures (a493795)
  • testbed: cover hasync and CARP from a real two-node HA pair (4f0da1d), closes #460

CI/CD

  • grafana: publish dashboards and rules to the m7kni stack on push to main (a62f248), closes #529

3.0.0 (2026-07-23)

⚠ BREAKING CHANGES

  • zenarmor,syslog: close username-only auth bypass, bound receiver resources
  • zenarmor: the receiver no longer ships records describing its own ingest connection. Set --logs.zenarmor.drop-self-traffic=false to restore the old behaviour.
  • logship: opnsense_exporter_logs_parse_errors_total and opnsense_exporter_logs_rejected_total gain a source label. Aggregations such as sum by (stage) / sum by (reason) are unaffected; only exact full-label-set matches need updating.
  • pyroscope: --pyroscope.enable-mutex-block (default off) is replaced by --pyroscope.disable-mutex-block (default off = contention profiling ON), following the repo disable-* convention for default-on features. Env var is now OPNSENSE_EXPORTER_PYROSCOPE_DISABLE_MUTEX_BLOCK.
  • logship: --logs.diaglog.enabled DEFAULTED TO TRUE, so this is not a quiet opt-in removal -- every existing log-shipping user loses the config-change/gateway/CARP/portal audit trail until they configure a syslog target on the firewall pointing at the exporter. --logs.firewall.enabled and --logs.scopes are removed with it.

Features

  • collector: add StatusTracker + RunCollector for web UI (33e4976), closes #302
  • collector: decouple serving from collection via internal poll scheduler (#336 phase 1) (ac86cb9)
  • collector: derive bounded counters from Zenarmor records (a632f14), closes #276
  • collector: flow volume metrics, flags, docs and dashboard (280dcb5), closes #346
  • collector: per-collector poll tiers + interval config (#336 phase 2) (165d400)
  • collector: poll-observability metrics + interval in status snapshot (#336 phase 3) (8edea9c)
  • flow: bounded top-N rollup with monotone other folding (c266b48), closes #346
  • flow: correlator + DNS answer cache (#346 phase 3 seam) (8e35af9)
  • flow: DNS-domain enrichment, §9 metrics, Zenarmor conn attrs in place (#353) (8c1be6c)
  • flow: interface topology and the NetFlow ifIndex map (b303514)
  • flow: NetFlow pipeline, metrics, flags, docs and dashboard (20d5684)
  • flow: NetFlow v5/v9 decoder and hardened UDP receiver (d56d1c6)
  • flow: normalized flow.Record seam and community-id join key (0f14ede), closes #346
  • flow: OTLP flow-log emission path (#346 phase 3) (c00e524)
  • flow: VLAN de-dup, WAN egress correction and direction inference (06701db)
  • flow: wire correlator -> OTLP flow logs, phase-4 dashboard + rules (#346) (c974d21)
  • grafana: comprehensive coverage — Zenarmor tab, mixed Prometheus+Loki panels, curated alerts/recording rules (8818c03), closes #301
  • grafana: overhaul OPNsense dashboard (659c98a), closes #303
  • logship: add debug-capture mode for unmodelled receiver signals (f973082), closes #330
  • logship: add opnsense.action, a binary pass/block resource attribute (19d407b), closes #276
  • logship: add the Zenarmor Elasticsearch receiver (02edcdc), closes #276
  • logship: align syslog log attributes with OTel semantic conventions (f461953), closes #266
  • logship: map every lane's disposition onto opnsense.action (1060108), closes #276
  • logship: per-record source override for transport-agnostic sources (47c4476)
  • logship: replace the firewall and diaglog poll lanes with the syslog receiver (6f98b35), closes #238 #248
  • logship: source-label the receiver self-metrics (c990cc7), closes #276
  • logship: syslog receiver with OPNsense API log enrichment (174212d), closes #248
  • metricsnap: passive last-scrape family recorder (7b815cc), closes #302
  • opnsense: CacheSnapshot accessor for web UI freshness card (39d9323), closes #302
  • options: add --logs.zenarmor.transport selector (elasticsearch|syslog) (cf87f79)
  • options: require the syslog receiver for zenarmor transport=syslog (f6610a5)
  • options: web UI flags + redacted EffectiveConfig (53081ff), closes #302
  • options: wire the Zenarmor receiver behind --logs.zenarmor.* (6d0cbae), closes #276
  • pyroscope: collect all profile types by default incl. goroutine-leak (f5ab4d8), closes #269
  • syslog: add optional ProgramProcessor delegation hook (4d27493)
  • syslog: derive metrics from received logs, sample raw lines, and add TLS transport (18c2024), closes #258 #259
  • syslog: enrich every record, not just filterlog (+ parser registry) (310dd28), closes #261
  • syslog: optional program and severity filtering (269c7e9), closes #261
  • syslog: parse Suricata EVE alerts, and refuse to double-ship them (8ce1e9b), closes #261
  • syslog: parse the residual unparsed tail (cron, radvd, kea-dhcp6, dnsmasq-dhcp, configd.py) (2d1a718), closes #335
  • syslog: parse unbound local-zone query log (fecf5e3), closes #332
  • syslog: structure unbound SERVFAIL resolution failures (b169933), closes #334
  • syslog: structured parsers for audit, sshd, DHCP and HAProxy + tunnel names (e829bf6), closes #261
  • webui: active-series, log-throughput and fleet trend charts (58e48bb), closes #347
  • webui: cardinality suite (hub, drill-downs, label-values, export) (68cc734), closes #302
  • webui: connected-devices page with embedded OUI lookup (8211cce), closes #302
  • webui: fold cardinality into status snapshot for the single-page tabs (#337) (1705605)
  • webui: per-collector interval/next-run/freshness on CollectorRow (#337) (e5f55b2)
  • webui: redacted /config page with kill switch (d37523d), closes #302
  • webui: Run Now trigger endpoint + live-polling/filter/sort JS (6f2ce75), closes #302
  • webui: runtime-stats sampler for Overview parity (#337) (3f0e3bc)
  • webui: show pretty + raw collector names on /config (d9ed4fd), closes #302
  • webui: single inline tabbed console page (#337) (99630de)
  • webui: status console page + /api/status.json + render core (5e7a5b1), closes #302
  • webui: wire operator console into main + passive metrics recorder (0d34fcd), closes #302
  • zenarmor: derive flow.Record from conn documents (fbf51a1), closes #346
  • zenarmor: drive the shared processor from the syslog receiver (142575f)
  • zenarmor: drop records describing our own ingest connection (b454b0e), closes #278
  • zenarmor: handle _alias / _settings control-plane probes (b74523a), closes #331
  • zenarmor: let operators exclude known-boring traffic from the log stream (d31296f), closes #279
  • zenarmor: parse the daemon=zenarmor syslog message envelope (f2e1fba)

Bug Fixes

  • canary: exempt firmware upgrade_packages[].size as box state, not drift (47c8d9b)
  • canary: triage the live-box drift, and stop plugin-gated 404s warning (1473097), closes #243
  • config: reject telemetry paths that collide with health/ready routes (f3a96b1), closes #291
  • deps: update module github.com/prometheus/client_golang to v1.24.0 (#339) (9b126b8)
  • deps: update module github.com/prometheus/common to v0.70.1 (#352) (1e60b7f)
  • deps: update module google.golang.org/grpc to v1.82.1 (#273) (3eb0fac)
  • logship,collector: bound sender-controlled derived metric cardinality (8dc167f), closes #311 #326 #327
  • logship: actually rename subsystem to opnsense.subsystem on the wire (1ea8afd), closes #266
  • logship: HAProxy status_class label was always empty (e312922), closes #277
  • logship: make OTLP delivery observable with in-memory at-least-once (736289b), closes #290
  • logship: publish labelled counters at zero from startup (9f64c66), closes #280
  • logship: stop a permanently-refused batch wedging delivery, bound queue bytes (f697018), closes #304 #318 #325
  • opnsense: block credential-forwarding redirects, redact URL secrets, reject non-finite floats (2be2b4c), closes #305 #306 #307 #321 #323
  • opnsense: drop the metadata.subsystems model; it exists on no release (80649b1), closes #284
  • pyroscope: always collect goroutine profiles, not just under mutex/block (31d2aa7), closes #268
  • pyroscope: cap backend response bodies and make the flush timeout bound shutdown (1bb8c2e), closes #309 #310
  • server,otlp: bound scrape admission and stop echoing header secrets (342d15e), closes #308 #313 #324
  • server: gate /-/ready on poll-scheduler warm-up (9d43334), closes #341 #338
  • syslog: reassemble multi-line messages, and put promotable keys on the resource (9763ebf), closes #262 #263
  • syslog: satisfy errcheck and staticcheck (1788afb), closes #248
  • zenarmor,syslog: close username-only auth bypass, bound receiver resources (4865dca), closes #314 #315 #316 #317 #328
  • zenarmor: bound decompressed body size and request-body time (1605294), closes #288 #289
  • zenarmor: decode alertinfo arrays/number/string sid (9b2a0fb), closes #297
  • zenarmor: log which endpoint an unhandled call hit (bc800b0), closes #285
  • zenarmor: match self-traffic against any bound syslog port (ccf8b9d), closes #299

Performance

  • collector: tier wholly-static collectors cold/slow, dedupe plugin-gated list (bcb5caf), closes #344
  • runtime: bound concurrent OPNsense API fan-out during scrapes (8847e3f), closes #294

Refactoring

  • remove per-collector Run Now (POST trigger + inflight guard + RunCollector plumbing) (#337) (0d4b061)
  • zenarmor: extract shared docProcessor from handleDoc (6e8e988)

Miscellaneous

  • deps: update actions/checkout action to v7.0.1 (#340) (527651d)
  • deps: update actions/setup-go action to v7 (#275) (0896994)
  • deps: update actions/setup-python action to v7 (#333) (bbe5c45)
  • deps: update anthropics/claude-code-action action to v1.0.172 (#245) (260c8da)
  • deps: update anthropics/claude-code-action action to v1.0.173 (#247) (373c8dc)
  • deps: update anthropics/claude-code-action action to v1.0.174 (#265) (b4ae77e)
  • deps: update anthropics/claude-code-action action to v1.0.175 (#272) (27eeb7a)
  • deps: update anthropics/claude-code-action action to v1.0.176 (#287) (a334691)
  • deps: update anthropics/claude-code-action action to v1.0.177 (#300) (7e1fa25)
  • deps: update anthropics/claude-code-action action to v1.0.178 (#329) (84d20d2)
  • deps: update anthropics/claude-code-action action to v1.0.179 (#342) (892c72c)
  • deps: update anthropics/claude-code-action action to v1.0.180 (#351) (842351d)
  • deps: update anthropics/claude-code-action action to v1.0.181 (#354) (d20f894)
  • deps: update gcr.io/distroless/static-debian13:nonroot docker digest to f7f8f72 (#244) (047ef4e)
  • deps: update module github.com/anchore/syft to v1.47.0 (#274) (c3bfe94)
  • deps: update module github.com/anchore/syft to v1.48.0 (#282) (b2a1da5)
  • deps: update module github.com/anchore/syft to v1.49.0 (#345) (9cc3f33)
  • deps: update module github.com/anchore/syft/cmd/syft to v1.47.0 (#281) (94a3eec)
  • deps: update module github.com/anchore/syft/cmd/syft to v1.48.0 (#283) (98b3166)
  • deps: update module github.com/anchore/syft/cmd/syft to v1.49.0 (#348) (310c0c3)
  • deps: update opnsense-docs digest to aced3de (#355) (46f85a4)
  • deps: update opnsense-docs digest to c296d26 (#264) (12de5b4)
  • deps: update opnsense-docs digest to ee0a0c6 (#343) (92e8b7d)
  • deps: update opnsense-docs digest to f9807ac (#349) (a8da466)

Documentation

  • assets: replace the hub's social card with a real project card (efda35b)
  • canary: record healthCheck subsystems and nginxVts cacheZones as box state (dfd73ee), closes #271
  • claude: add box-state as the fifth canary drift verdict (5a5c62a)
  • collector: document the poll model + fix stale references (#336 phase 4) (7ebc2cb)
  • config: regenerate flag reference for the web UI flags (9b19a00)
  • correct two false claims left behind by #92 and #248 (c1ae453)
  • deployment: document the web UI operator console (28ff317), closes #302
  • docker: show the receiver ports in the compose example (37a0e7f)
  • nav: add the syslog receiver page to the site nav (7fd56da), closes #248
  • readme,site: lead with OTLP, syslog and flow differentiators; add GitHub backlinks (ce54152)
  • security: fix distroless private-CA trust recipe (ea9b864), closes #292
  • syslog: align prose with the phase-4 receiver features (0dd307e), closes #267
  • syslog: document the LogQL name mangling, and fix a duplicated bullet (69a7a62)
  • syslog: document the parsers, universal enrichment and filtering (cabb84a), closes #261
  • syslog: setup guide, k8s manifests and dashboard panels for the receiver (f41a600), closes #248
  • telemetry: document the OTLP resource-attribute convention (eee3006), closes #270
  • voice + de-AI pass across the docs base (63fb0ef), closes #267
  • webui: describe the single-page tabbed console; drop multi-page/Run-Now refs (#337) (eaa00c5)
  • zenarmor: document the elasticsearch|syslog transport selector (410b0f0)
  • zenarmor: document the receiver and add its dashboard panels (9e217a8), closes #276

Tests

  • cache: guard body TTLs against fast-polling collectors (e43abb4)
  • flow: fix flaky TestReplayRepair_VLANParentDuplicateSuppressed (06e5262)
  • flow: golden NetFlow v9 replay fixture from real capture (#346) (2d20aeb)
  • syslog: benchmark the enrichment path and pin its allocations (54e62fc), closes #286
  • zenarmor: cover the syslog-transport factory branch; note filter bypass (cf5f150)
  • zenarmor: end-to-end syslog transport across all five families (20ca1b7)

CI/CD

2.2.1 (2026-07-13)

CI/CD

  • release: repin shared binaries workflow, grant attestations: write (9fb6409)

2.2.0 (2026-07-13)

Features

  • otlp: emit synthetic up series in OTLP push mode (#240) (80049a6)

Bug Fixes

  • grafana: set targetDatasourceUID on recording-rule manifests (514d0ca)

2.1.0 (2026-07-13)

Features

  • apidrift: live schema canary binary for the devel box (4c73097)
  • apidrift: subtree-prefix exemptions and the cross-version compat ledger (e207e3f), closes #236
  • auth: local user / group / API-key security-posture counts (97c4ac5), closes #222
  • captiveportal: voucher inventory by state (fdec957), closes #207
  • clamav: engine version and signature database freshness (e22020e), closes #204
  • client: cache slow-moving API responses; cache firmware for 12h (9ec1801), closes #193
  • core: config backup freshness + ZFS boot environment inventory (96174f0), closes #220
  • crowdsec: hub component health (tainted/outdated) + engine version (8d7fca5), closes #205
  • firewall: GeoIP database freshness + optional NAT rule inventory (c9b55c9), closes #221
  • frr: BGP neighbor detail, OSPF/OSPFv3 interface parity, route volumes (c846f42), closes #197 #198 #199
  • haproxy: stick-table occupancy + show-stat latency/health/capacity (77d94bf), closes #201
  • hardware: DMI system identity (dmidecode) + Deciso PSU status (dechw) (27c3509), closes #217
  • hostdiscovery: discovered-host inventory counts (0a22773), closes #223
  • ids: Suricata service status, alert activity, ruleset and rule inventory (1be18bf), closes #203
  • interfaces: LAGG member state, SFP/DOM optics, bridge membership (e62ddb8), closes #214
  • ipsec: kernel SAD/SPD tables, per-lease detail, pending-config flag (6c7c946), closes #213
  • kea: lease state/type breakdown, PD pool capacity, pool utilization (b68eadb), closes #208
  • lldpd: LLDP neighbor table collector (8fa19ab), closes #216
  • logship: crowdsec source — alert/decision records (opt-in) (402cc29), closes #232
  • logship: firewall log source — digest-cursor tailing with rule labels (bacc16e), closes #229
  • logship: generic diagnostics-log source — audit, gateway, CARP, portal, configd (0d4314a), closes #230
  • logship: IDS source — full Suricata EVE alert records (opt-in) (0c6dcea), closes #231
  • logship: log-shipping foundation — internal/logship pipeline (opt-in) (0a27446), closes #228
  • logship: unbound source — per-query DNS log (opt-in, accepted loss) (55a49ab), closes #233
  • metrics: cache hit/miss self-metrics for the response cache (884a849), closes #196
  • metrics: minor extension candidates — ntpd GPS, siproxd, shaper last-match (3f29b3d), closes #224
  • metrics: struct extensions from new 26.1.11/26.7 payload keys (f80174f), closes #237
  • monit: per-check resource telemetry (a44ef75), closes #219
  • netbird: management/signal connectivity, relays, per-peer telemetry (06c02f6), closes #211
  • nginx: cache zones, latency counters, cache-status, reload timestamp + bans (555f59e), closes #200
  • openvpn: per-session traffic counters and connected-since (5f6a9ce), closes #212
  • relayd: virtual server / table / host health via status/sum (2b81bf9), closes #202
  • schema: capture request bodies for every POST endpoint (5a7d74d)
  • schema: committed golden schemas + make schemas staleness gate (dfc36d6)
  • schema: endpoint→response-struct registry covering the full 107-endpoint manifest (2601327)
  • schema: live-payload structural validator (93967a4)
  • schema: reflection walker deriving structure-only schemas from response structs (aae08d2)
  • system: export all system-status subsystems from the health payload (7ea8cb9), closes #218
  • tor: circuit and stream telemetry from the control port (opt-in) (18da737), closes #206
  • unbound: DNSBL query-stats totals and blocklist size (opt-in) (0289a3d), closes #209
  • vnstat: persistent per-interface traffic accounting (opt-in) (8c71d6d), closes #215

Bug Fixes

  • apidrift: fail fast when the box is unreachable (e4e1f95)
  • apidrift: force HTTP/2 and retry transient transport failures (0ba9482), closes #236
  • deps: update module github.com/grafana/pyroscope-go to v1.4.1 (#189) (58505a0)
  • deps: update module github.com/prometheus/common to v0.70.0 (#191) (f9a28ee)
  • grafana: regenerate dashboard artifacts to a fixed point (83e74cf)
  • lint: stop misspell rewriting ECT as ETC (5a75f97), closes #236
  • opnsense: gate unbound extended-statistics series on payload presence (f25dae2), closes #236
  • opnsense: read per-subsystem health detail from metadata.subsystems (0bda657), closes #236
  • opnsense: resolve the 26.1.11 jumbo-page mbuf key renames (bd06b50), closes #236
  • opnsense: resolve the 26.1.11 tcp ECN counter renames (1b78b94), closes #236
  • schema: model json.Number as 'numeric' (accepts number or numeric string) (d2edbb6)
  • unbound: migrate off deprecated overview/isBlockListEnabled (a849c38), closes #210

Performance

  • client: negative-cache plugin-absent 404s on POST endpoints too (5e9f561), closes #194
  • client: negative-cache plugin-absent 404s; cache slow-moving endpoints (3b709ce), closes #194

Miscellaneous

  • deps: update anthropics/claude-code-action action to v1.0.166 (#177) (3158c01)
  • deps: update anthropics/claude-code-action action to v1.0.167 (#182) (e9d0532)
  • deps: update anthropics/claude-code-action action to v1.0.168 (#183) (83457fe)
  • deps: update anthropics/claude-code-action action to v1.0.169 (#186) (509bcb3)
  • deps: update anthropics/claude-code-action action to v1.0.170 (#190) (ea3d2f8)
  • deps: update anthropics/claude-code-action action to v1.0.171 (#192) (d9ed73e)
  • deps: update gcr.io/distroless/static-debian13:nonroot docker digest to d29e660 (#184) (0e55c5b)
  • deps: update mirror.gcr.io/library/golang:1.26-alpine docker digest to 0178a64 (#185) (c4b0f77)
  • deps: update mirror.gcr.io/library/golang:1.26-alpine docker digest to 9097beb (#180) (fcf47a7)
  • deps: update opnsense-docs digest to 5d84fe3 (#181) (25ce2dd)
  • deps: update opnsense-docs digest to 77f33a4 (#187) (d6dfe82)
  • deps: update opnsense-docs digest to 95acbed (#188) (904e3d0)
  • deps: update step-security/harden-runner action to v2.20.0 (#179) (411ba8f)
  • lint (a749c6b)

Documentation

  • add the OPNsense compatibility policy page and canary triage recipe (feafbc6), closes #236
  • add the schema-registry step to the new-collector recipe (f84963d)
  • API-absent telemetry — no SSH channel, node_exporter + textfile recipe (c622632), closes #225
  • native log-export recipe and exporter-vs-native decision matrix (33fe5b3), closes #234
  • re-pin dashboard panel counts after #218 regeneration (ce7cfcb)
  • record do-not-scrape API landmines and confirmed-empty modules (1341145), closes #226

Tests

  • kea: regression fixtures from live dev-box captures (c6399a2), closes #208

CI/CD

  • api-contract: run the endpoint-manifest canary daily (7c5a397), closes #195
  • live-canary: adjust the metric-name floor for gated unbound extended stats (965f6fb), closes #236
  • live-canary: close the drift issue on any clean run, not just scheduled (140ef06), closes #236
  • live-canary: daily schema+smoke canary against the devel box over tailnet (6266019)
  • live-canary: drop the stale 'scheduled' wording from the close comment (d9a0a83)
  • live-canary: harden the tailnet-credentialed workflow (22704c2)
  • live-canary: keep runner DNS after the tailnet join (34e19cf)
  • live-canary: place the SC2016 directive where actionlint's shellcheck honours it (0ec4e83)

2.0.2 (2026-07-05)

Miscellaneous

  • deps: update anthropics/claude-code-action action to v1.0.165 (#174) (d8c75d9)

Documentation

  • upgrading: add v2.0 breaking-changes section and fix instance-label note (#176) (22dcb32)

2.0.1 (2026-07-04)

Bug Fixes

  • grafana: emit valid alert noDataState "Ok" (was "OK", rejected by the API) (d75d02c)

Miscellaneous

  • deps: update anthropics/claude-code-action action to v1.0.164 (#172) (345f0e1)

2.0.0 (2026-07-04)

⚠ BREAKING CHANGES

  • smart: the SMART collector is now off by default. Set --exporter.enable-smart (env OPNSENSE_EXPORTER_ENABLE_SMART=true) to restore the opnsense_smart_* metrics.
  • arp,ndp: opnsense_arp_table_entries and opnsense_ndp_entries per-entry series are no longer emitted by default. Set --exporter.enable-arp-details / --exporter.enable-ndp-details to restore them; otherwise use the new opnsense_arp_table_entries_total / opnsense_ndp_entries_total aggregates.
  • interfaces: distinguish unknown link state from down so PPPoE WANs aren't reported down
  • when --exporter.instance-label is unset, the instance label now defaults to the configured OPNsense address rather than the API hostname. Set --exporter.instance-use-hostname to keep hostname-derived labels, or set --exporter.instance-label explicitly.
  • firewall: opnsense_firewall_interface_hits_total is renamed to opnsense_firewall_interface_log_entries_recent and changed from counter to gauge. Any user dashboards/alerts using rate()/increase() on the old name must switch to plotting the new gauge directly. The shipped dashboard is updated.
  • grafana: grafana/alerts/opnsense.rules.yaml is removed. Users loading that file into Prometheus/Mimir/the Grafana Cloud ruler should migrate to the Grafana-managed manifests under grafana/alerts/grafana-managed/ (gcx resources push).

Features

  • apicapture: resolve OPS_API_KEY_FILE/OPS_API_SECRET_FILE like the exporter (428353b), closes #157
  • arp,ndp: gate per-entry metrics behind opt-in details flags (2ac1221), closes #125
  • collector: add disable switches for interfaces, protocol, services (ef94751), closes #143
  • config: make OPNsense API timeout and retry count configurable (045571f), closes #140
  • docs: align docs site with m7kni.io brand + server-side SEO/LLM metadata (9bca073), closes #70
  • grafana: drop portable Prometheus rules format, ship Grafana-managed alerting only (2af458a), closes #76 #95
  • metrics: add per-endpoint API request count and duration self-metrics (802c53a), closes #126
  • security: warn at startup when --opnsense.insecure disables TLS verification (2d3914d), closes #159
  • smart: make SMART collector opt-in (--exporter.enable-smart, default-off) (4c8af5c), closes #139

Bug Fixes

  • activity: parse thread states independently so zombie/stopped states don't zero metrics (73ba3f8), closes #82
  • alerts: make OPNsenseEndpointErrors for:15m require sustained errors (586563a), closes #94
  • apicontract: filter abstract-controller phantom endpoints from the manifest (9ab2ee9), closes #146
  • apicontract: isolate per-controller parse failures in extract.py (fca0054), closes #111
  • captiveportal: decode zones map serialized as a JSON array (27fef5b), closes #73
  • carp: source VIP label from the subnet field and dedupe multi-address vhids (30641c1), closes #166
  • certificates: omit valid_from/valid_to for pending CSRs instead of epoch 0 (b80a1da), closes #167
  • chrony: skip sources metrics on sub-fetch failure instead of false zero (4aed2cf), closes #163
  • ci: match drift issue by label+title, not the broken bot-login filter (5944a81), closes #83
  • ci: surface api-contract verb-drift warnings instead of burying them (e8cfff8), closes #93
  • collector: bound no-deadline collections to stop a stalled box blackout (4baabb8), closes #128
  • collector: dedupe services/wireguard/ntp label tuples to prevent scrape-wide 500s (45e3403), closes #85
  • collector: distinguish deadline-expired skipped scrapes from completed ones (6664350), closes #122
  • collector: emit cumulative counters as CounterValue in firewall/ipsec/protocol (5621823), closes #106
  • collector: keep dhcpv4/acme/smart/dyndns silent when their plugin is absent (52a72d8), closes #87
  • collector: skip scalar metrics whose backing sub-call failed in pf-stats/system (47145c2), closes #91
  • collector: surface interfaces-overview fetch failures via success/errors (14d9190), closes #123
  • collector: use panic: sentinel on endpoint-errors label, not subsystem slug (86326fc), closes #120
  • config: consistent env-var surface — telemetry-path envar + prefixed *_FILE aliases (6a4d64e), closes #141
  • config: empty OPS_API_KEY_FILE/OPS_API_SECRET_FILE falls back to flag (9e56123), closes #109
  • config: reject empty/invalid --web.telemetry-path instead of panicking (945cfb4), closes #108
  • config: validate Pyroscope server-address scheme at startup (e328a7c), closes #142
  • crowdsec: mark bouncers/machines absent on row decode failure instead of false zero (75c758f), closes #104
  • dashboard: add $device variable so pf-traffic/netflow panels stop blanking (b8506a5), closes #98
  • dashboard: gate DHCP backend rows on presence, not lease count (2d16b13), closes #114
  • dashboard: key multi-query table renames/units on Value #A..N, not metric names (4800d96), closes #97
  • dashboard: match Exporter Runtime panels on job=~"opnsense.*", not hardcoded job (479560e), closes #113
  • dashboard: scale epoch-seconds timestamps to ms for dateTimeAsIso panels (baacea2), closes #78
  • dashboard: show lease-expiry column in dnsmasq/Kea lease-detail tables (0dbfe5c), closes #112
  • deps: update module github.com/grafana/pyroscope-go to v1.4.0 (#69) (fb582e6)
  • deps: update module github.com/prometheus/exporter-toolkit to v0.17.0 (#62) (0783001)
  • deps: update module github.com/prometheus/exporter-toolkit to v0.17.1 (#65) (77f9eb2)
  • deps: update module google.golang.org/grpc to v1.82.0 (#63) (637e901)
  • docgen: cover top-level Collector metrics + fatal on unparsed constructors (02a90a2), closes #119
  • docgen: derive metric Type from emission ValueType, not _total suffix (3dc7c1c), closes #100
  • docgen: make doclint flag/env extraction shape-based and lint grafana tabs (f6fbbde), closes #151
  • docker: rename build ARG Version→VERSION so published images embed the version (c92830e), closes #79
  • docs: correct container UID to 65532 (distroless nonroot), not 65534 (44fa537), closes #115
  • docs: pin grafana/README tab list + alert/recording counts to generated data (53061bb), closes #116
  • docs: pin sub-collector count (47) in CLAUDE.md + 3 docs pages, close drift gap (1774373), closes #117
  • docs: replace oversized gradient hero with a compact docs-friendly intro (fca3dc6), closes #70
  • firewall: filter pfctl pseudo-entries and strip mutable (skip) suffix from interface label (9009e04), closes #105
  • firewall: re-type interface hit count as a sliding-window gauge, not a counter (8b3fdfa), closes #74
  • frr: make frrAFLabel lossless per SAFI to avoid duplicate BGP series (3fda9d2), closes #162
  • gateways: emit status for enabled monitor-disabled gateways (GatewayDown blind spot) (85a95ec), closes #77
  • haproxy: omit HTTP response-code counters for tcp-mode proxies (4b6cc40), closes #164
  • interfaces: distinguish unknown link state from down so PPPoE WANs aren't reported down (cfd1d63), closes #86
  • interfaces: parse counter fields tolerantly so one bad field doesn't drop all interface metrics (b0f9ee0), closes #102
  • k8s: pin image tag and add seccomp/SA-token hardening to example manifest (7f5df45), closes #147
  • k8s: raise example scrapeTimeout to 30s and use resolvable Service DNS (393f998), closes #99
  • main: gracefully drain HTTP server on SIGTERM/SIGINT instead of os.Exit(0) (123b774), closes #161
  • make: pass API creds to local-run/capture via env, not world-readable argv (8729693), closes #160
  • ntp: parse unit-suffixed ntpq when/poll intervals instead of coercing to 0 (f9001f0), closes #89
  • openvpn: count only real client rows as sessions (a0b9c70), closes #88
  • opnsense: widen byte/packet counter fields to int64 for 32-bit source builds (4ef3662), closes #103
  • otlp: close three config-validation gaps that silently break export (dcd76f3), closes #92
  • otlp: isolate gatherers so one bad collector can't black out export (ab0fdcc), closes #101
  • otlp: post to the /v1/metrics signal path for base-URL endpoints (22d841e), closes #80
  • profiling: flush final Pyroscope window on shutdown instead of dropping it (962bead), closes #121
  • protocol: expose IPv6/ICMPv6 stats instead of silently dropping them (579a2b2), closes #165
  • resilience: short-circuit when firewall unreachable + backoff/jitter retries (d228260), closes #127
  • resolve instance label deterministically instead of via a startup race (3ec7122), closes #75
  • server,collectors: stop duplicate label tuples from 500-ing the whole scrape (6980c93), closes #81
  • server: reject NaN/Inf/absurd scrape-timeout header values (c8e574b), closes #124
  • system: correct DST-transition skew in uptime and config_last_change (f49edc2), closes #107
  • unbound: capture all RR query types, not a fixed 16-field whitelist (6b955fd), closes #138
  • unbound: skip stats series when unbound-control is unavailable (c6b652e), closes #90
  • unbound: stop clamp_min(denom,1) collapsing cache hit ratio below 1 qps (0381b26), closes #96

Performance

  • mbuf: read extended fields from systemMbuf, skip redundant API call (3712561), closes #137
  • opnsense: parallelize independent multi-endpoint Fetch functions (baa4964), closes #129

Miscellaneous

  • deps: update anthropics/claude-code-action action to v1.0.160 (#61) (4966911)
  • deps: update anthropics/claude-code-action action to v1.0.161 (#64) (511cee1)
  • deps: update anthropics/claude-code-action action to v1.0.162 (#66) (a442589)
  • deps: update anthropics/claude-code-action action to v1.0.163 (#71) (5196a33)
  • deps: update docker/build-push-action action to v7.3.0 (#67) (54eba0e)
  • deps: update docker/setup-buildx-action action to v4.2.0 (#68) (4b6eb3e)
  • deps: update module github.com/anchore/syft to v1.46.0 (#169) (0960135)
  • deps: update module github.com/anchore/syft/cmd/syft to v1.46.0 (#170) (7a86913)
  • deps: update module github.com/google/go-licenses to v2 (#171) (c10f69e)
  • docs: remove committed zensical site/ build output and gitignore it (224998e), closes #152
  • remove Snyk from CI (0c80fcf)

Documentation

  • apicontract: correct false "live-box stage (P3)" exemption claim (7b777a1), closes #110
  • drop false promhttp_* claim from --web.disable-exporter-metrics help (360e12d), closes #149
  • firmware: correct misleading needs_reboot help text (1d66d54), closes #168
  • geo: content-shape pass for LLM/search retrievability (eb025ae)
  • mark shipped collectors COMPLETED in stale todos.txt (7fe6e8b), closes #158
  • troubleshooting: flag the activity collector as the top scrape-latency cost (6be042e), closes #150

Build & Infrastructure

  • docker: digest-pin the golang builder image + Renovate pinDigests (b6069f8), closes #148

Tests

  • contract: derive postEndpoints from POST call sites to catch drift (2e54b96), closes #145
  • contract: extend response-shape contracts beyond healthCheck (dabe778), closes #144
  • main: gate that every collector disable switch is wired in main.go (4f99761), closes #153
  • opnsense: drop duplicated testEndpoints(), build test clients from defaultEndpoints() (386aa39), closes #154
  • opnsense: pin hasync single-node {"response": false} shape (ed8dec9), closes #156
  • opnsense: use raw JSON fixtures for services/arp/ntp/carp instead of mustMarshal(struct) (10b1831), closes #155

CI/CD

  • add OpenSSF Scorecard via shared reusable workflow (3759427)
  • bump shared rknightion reusables v1.0.0 -> v1.3.1 (f8c2fa0)
  • drop CodeQL pull_request trigger to trim Actions fan-out (3bb206c)
  • grafana: enforce dashboard coverage, regen freshness & manifest validity (311267e), closes #84
  • lint: pin golangci-lint version and enforce gofmt in CI (ee2e1c2), closes #132
  • release: fall back to github.token when RELEASE_PLEASE_TOKEN is absent (7aa5d42), closes #131
  • remove claude issue-triage workflow (b70aa01)
  • remove dead build-telemetry OTEL config referencing non-existent secrets (03a748d), closes #133
  • remove notify-maintainer-on-new-issue workflow (91e343f)
  • renovate: track pinned syft / go-licenses versions via custom managers (65b3e38), closes #135
  • run extract_test.py parser-contract tests in the api-contract job (457802b), closes #136
  • security: narrow api-contract-enrich agent gh allowlist + document ingress (e34e288), closes #134
  • security: pin opnsense/docs SHA and parser pip deps in api-contract (b2cf72e), closes #130

1.0.1 (2026-06-29)

Bug Fixes

  • resolve review findings in gateway collector, client, and registration (8f1ba70)

Miscellaneous

  • deps: update golangci/golangci-lint-action action to v9.3.0 (#59) (7d46c39)
  • deps: update goreleaser/goreleaser-action action to v7.2.3 (#57) (763504e)
  • renovate: group lockstep dependency families (cbef9d7)

CI/CD

  • add Snyk -> Snyk Cloud monitor (SCA/SAST/IaC/container) (2109b7e)
  • build release binaries via shared binaries reusable (35396fc)
  • codacy: align exclude_paths convention; use project token for coverage (df73e81)
  • open the release-please PR under a PAT so CI runs without manual approval (8471e9c)
  • pin shared rknightion reusables to v1.0.0 (3d3d6e9)
  • publish image via shared container-publish reusable (a0a680b)
  • sign release binaries + emit archive SBOMs (supply-chain parity) (ece4d2b)

1.0.0 (2026-06-28)

⚠ BREAKING CHANGES

  • health: opnsense_up no longer flips to 0 for a reachable box that OPNsense self-reports as degraded (e.g. a leftover crash report). Such a box now triggers the warning-level OPNsenseCrashReports / OPNsenseFirewallUnhealthy alerts instead of the critical OPNsenseExporterDown. Users of the bundled alert rules should expect that severity change.
  • readme: thin README — hard-fork notice replaces upstream changelog, docs site is canonical
  • collectors: opnsense_openvpn_sessions is no longer emitted by default (set --exporter.enable-openvpn-details to restore it), and IPsec phase2 metrics no longer carry spi_in/spi_out labels.

Features

  • alias: firewall alias table size collector with opt-in pf counters (763adc7)
  • apcupsd: APC UPS metrics collector (plugin-gated) (6040ba1)
  • apicontract: API contract diff tool (fb12ea0)
  • bpf: BPF listener statistics collector (b4983ab)
  • build: docs/docs-check make targets and install-hooks pre-commit gate (a94de13)
  • captiveportal: captive portal zone and session collector (bc6dc5a)
  • certificates: CA certificate expiry metrics (19c634b)
  • chrony: chrony tracking/source metrics collector (plugin-gated) (9ba2f75)
  • client: register interfaces overview and unbound dumpinfra endpoints (b141b10)
  • collector: export SubsystemDisplayNames and AllCollectors for docgen (70431b5)
  • collectors: freeze stream-C seams (endpoints, subsystem consts) (c8bb99b)
  • collectors: freeze stream-D phase-1 seams (endpoints, subsystem consts) (8b2d1ab)
  • collectors: freeze stream-D phase-2 seams (endpoints, subsystem consts) (c432ec7)
  • collectors: freeze stream-D phase-3 seams (endpoints, subsystem consts) (c8c997e)
  • collectors: opt-in OpenVPN session details, drop IPsec SPI labels, gateways disable flag (bb60966)
  • collectors: wire CrowdSec, NUT, apcupsd and captive portal collectors (phase 2 plugin-gated set) (a1610bd)
  • collectors: wire HAProxy, nginx, FRR and Monit collectors (phase 1 plugin-gated set) (da0cd05)
  • collectors: wire syslog, qfeeds, tailscale, alias collectors and regenerate docs (9cf501c)
  • collectors: wire traffic shaper, HA sync, chrony, DHCPv6 and BPF collectors (phase 3 set) (de88e48)
  • contract: add response-shape canary for payload drift at unchanged endpoints (2522b21)
  • crowdsec: CrowdSec alert/decision/bouncer/machine collector (plugin-gated) (87280a4)
  • dhcp: pool-size metrics for kea and dnsmasq, kea service status (d37f733)
  • dhcpv6: ISC DHCPv6 lease and delegated-prefix collector (plugin-gated) (6309da8)
  • docgen: doclint token validation and Describe() registry verification gate (69b75a1)
  • docgen: marker-region injection and stat-rule engines (4c47cfa)
  • docgen: render grouped flag tables from the kingpin model (db2f6c6)
  • docs: generate configuration.md flag tables in-place; wire doclint, registry gate and -check mode into docgen (4f839c5)
  • firewall-rules: configured-rule inventory gauge in details mode (5c277b6)
  • firmware: opt-in package_update_available and plugin_installed metrics (e19cafd)
  • frr: FRR routing collector — BGP, OSPF and BFD (plugin-gated) (5cfa890)
  • grafana: emit dashboard-stats.json for docs count injection (2b274d9)
  • grafana: gateway status values 4-6, firmware package detail panels (ad27d5e)
  • grafana: panels for SMART attributes/NVMe, interface identity, unbound infra, rule inventory (952300f)
  • grafana: per-collector scrape duration and success panels (b54df15)
  • grafana: syslog, qfeeds, tailscale and alias tabs; DHCP pool and CA expiry panels (0203029)
  • haproxy: HAProxy statistics collector (plugin-gated) (69c4266)
  • hasync: opt-in HA sync status collector (e1fa4f0)
  • interfaces: admin_up and info enrichment from interfaces overview (18df78e)
  • ipsec: mode-cfg pool utilization metrics (cc1ce8f)
  • monit: Monit service check collector (ab2cd92)
  • nginx: nginx VTS statistics collector (plugin-gated) (fc0ab05)
  • nut: NUT UPS metrics collector (plugin-gated) (3ecb8b0)
  • openvpn: real_address label on opt-in session details (upstream #97) (b3ef0e8)
  • opnsense: add FetchServiceStatusOptional with 404-as-absent semantics (bbc9ca9)
  • opnsense: endpoint contract manifest with HTTP verbs (664923a)
  • opnsense: register core/firmware/info endpoint (e78c1ce)
  • opnsense: request-scoped context support via Client.WithContext (7247845)
  • options: --exporter.enable-firmware-package-details flag and wiring (699efbf)
  • options: CollectorFlags metadata + RegisterAllFlags for docgen; fix flag help typos (8e221d7)
  • otlp: add OpenTelemetry OTLP metrics export with Prometheus parity (2e8dda9)
  • qfeeds: Q-Feeds threat-intel collector (plugin-gated) (7e149bb)
  • server: /-/healthy and /-/ready endpoints, collect[]/exclude[] filtering, scrape-timeout deadline handler (5e323d3)
  • server: wire health endpoints, filtered metrics handler and scrape deadline into main (31fc19f)
  • smart: per-attribute SATA table and NVMe health-log metrics (3feff7f)
  • syslog: syslog-ng statistics collector (09c21f9)
  • tailscale: node-local Tailscale collector, complementary to tailscale2otel (5cb6512)
  • tools: OPNsense API endpoint extractor shim (2751521)
  • trafficshaper: pipe/queue/rule statistics collector (bdcfa5b)
  • unbound: opt-in infra cache RTT/RTO metrics (--exporter.enable-unbound-infra) (91ddf9f)

Bug Fixes

  • apicontract: exempt kea leases4/6 (inherited-controller parser blind spot) (049487a)
  • ci: gate image publish on docs job; doclint also scans CLAUDE.md (790db7d)
  • deps: bump golang.org/x/crypto to v0.52.0 and Go to 1.26.4 (bafaf29)
  • deps: update module github.com/prometheus/common to v0.69.0 (#47) (3dfa4dd)
  • firmware: use last_check for validity (upstream #101), parse UnixDate timestamps, add FetchFirmwareInfo (03afc7c)
  • gateways: document status enum 4-6, skip rtt/rttd/loss when probe data unavailable (4995f0f)
  • gateways: parse Packetloss/Latency/forced-offline statuses, '~' probe values, null force_down (upstream #103, #106) (b249ada)
  • harden API drift enrichment workflow (f892fe9)
  • harden API drift enrichment workflow (740f445)
  • health: parse OPNsense 26.1 status shape; opnsense_up is reachability-only (6443052)
  • kea: tolerate string-typed expire values across OPNsense API variants (e095d76)
  • opnsense: align captive portal service-status endpoint name with frozen seam (654813f)
  • opnsense: migrate string-to-int parsing to int64 for 32-bit safety (upstream #81, extended) (7f58a29)
  • security: harden HTTP server, API client, and CI workflows (27bfc19)
  • security: redact CA private keys (prv/prv_payload) in error log excerpts (6129acb)
  • security: redact credentials in error log excerpts, pin GoReleaser, drop CDN JavaScript (7b49f2f)
  • security: set TLS 1.2 minimum and run container as non-root (d19fdd7)

Refactoring

  • collector: thread context through CollectorInstance.Update, add per-collector scrape metrics and ScrapeView filtering (1814ef5)
  • docgen: source flag and display-name metadata from code via kingpin model (5ced3ce)
  • opnsense: extract defaultEndpoints() for contract tooling (ca0a84c)

Miscellaneous

  • codacy: exclude fixtures/scratch from analysis and drop unused import (0c7fc40)
  • deps: pin rknightion/.github action to 8629ccb (#54) (0074388)
  • deps: update actions/checkout action to v6.0.3 (#50) (88b7eb7)
  • deps: update anthropics/claude-code-action action to v1.0.158 (#49) (d402091)
  • deps: update anthropics/claude-code-action action to v1.0.159 (#52) (e6a7117)
  • deps: update gcr.io/distroless/static-debian13:nonroot docker digest to 963fa6c (#53) (287c936)
  • deps: update github actions (#46) (11b8436)
  • deps: update github actions (#48) (11922e8)
  • deps: update github actions (#51) (05ea078)
  • deps: update rknightion/.github digest to 0e80ff5 (#56) (a77b9c2)
  • deps: update rknightion/.github digest to 17626c1 (#55) (daa4910)
  • gitignore local roadmap.md (7ec2842)
  • renovate: slim to repo-specific overrides (1dcb6a3)
  • resolve Codacy quality findings and tune doc linting (9793e91)
  • security: add Snyk policy excluding vendor + offline dev tooling (e35a9c0)

Documentation

  • codacy: note that path excludes also gate default-on tools (a7b53d2)
  • dev: document generated-docs workflow, drop fork-changelog convention (9eff6d4)
  • note contract manifest step when adding a collector (540c501)
  • pin metric/collector/dashboard counts via docgen stat rules (305/30/16) (6673cea)
  • readme: thin README — hard-fork notice replaces upstream changelog, docs site is canonical (56aec9c)
  • regenerate for gateway status enum 4-6 and firmware package details flag (9c18429)
  • regenerate for per-collector scrape metrics and scrape-timeout-offset flag (1c0baba)
  • regenerate for stream E collector enhancements (0803709)
  • site: add troubleshooting and upgrading pages, promote security in nav, custom-CA example (033068b)

Tests

  • dhcp: pool helper unit tests (7905998)

CI/CD

  • add Claude issue-triage workflow (42e64c7)
  • add hadolint + trivy Docker security scans (bcda939)
  • adopt shared rknightion/.github reusable security workflows (6c309b3)
  • auto-assign maintainer on new issues (notify by email) (0f8197c)
  • fail the build when generated docs drift from code (e73c073)
  • fix Renovate automerge stall + add required ci-success gate (a94ed62)
  • harden GitHub Actions workflows (zizmor) (1349dc4)
  • hybrid issue-triage (no-tools AI analysis + deterministic apply) (93cba4a)
  • OPNsense API contract canary + Claude enrichment workflows (689cd4f)
  • reference rknightion/.github reusables @main (unpin from digest) (f2c44d4)
  • report coverage to Codacy and ship SBOMs + third-party notices (7ea83cb)
  • resolve actionlint/shellcheck + zizmor workflow findings (ceab80f)
  • security: drop unused id-token: write from issue-triage (65deb99)
  • security: replace LLM issue-triage with deterministic labeler (48acd41)

0.4.0 (2026-06-09)

Features

  • options: add pyroscope profiling configuration (061d893)
  • profiling: add pyroscope SDK integration package (df888e5)
  • push profiles to pyroscope and drop unauthenticated pprof endpoints (99577df)

Documentation

  • document pyroscope profiling and pprof removal (16e6f84)
  • remove stale pprof references from architecture and index (a047bd6)

Build & Infrastructure

  • tidy vendor after pyroscope integration (78486ef)

0.3.0 (2026-06-08)

Features

  • collector: add DHCPv4, ACME and SMART disk collectors (83b0a8e)
  • collector: add DynDNS (ddclient) account status collector (da5216e)
  • collector: add exporter build and collector-enabled self-observability metrics (ca82ebb)
  • collector: export crash-reporter health status (58c838d)
  • default instance label to the OPNsense hostname (f49855b)
  • gateways: export force_down, virtual, dynamic and priority metrics (d48d484)
  • grafana: comprehensive v2 dynamic dashboard with alerts and recording rules (81d36dd)
  • smart: enable collector by default and degrade gracefully when absent (7c49635)
  • wireguard: add peer handshake-age gauge and fix last-handshake type (b1f68b1)

Bug Fixes

  • client: close response body to prevent gzip connection leak (2182b99)
  • collector: recover from panics in sub-collector goroutines (12fa832)
  • health: stop reporting a healthy firewall as unhealthy on OPNsense 25.1+ (f292a50)
  • ntp: avoid narrowing int conversion of NTP reach value (02b687a)
  • opnsense: correct seven API-shape mismatches found in OPNsense 26.1 audit (baf14f0)
  • startup: bound the instance-label hostname lookup with a short timeout (258205c)
  • system: correct uptime/config-change skew in non-UTC timezones (9d561e5)

Documentation

  • align documentation with code reality (721305a)
  • claude: note the dashboard coverage gate in the add-a-collector flow (532c636)
  • claude: require docgen + doc-table updates when adding a collector (8078c80)
  • document new collector flags and regenerate generated docs (1674ba7)
  • readme: update fork changelog for new collectors, enhancements and fixes (5682bda)

CI/CD

  • pull Go build image from mirror.gcr.io to drop Docker Hub dependency (23069fb)

0.2.2 (2026-06-08)

Bug Fixes

  • collectors: tolerate OPNsense 25.7 API model drift (0e6b9bc)
  • deps: update module github.com/grafana/pyroscope-go/godeltaprof to v0.1.10 (#38) (8bc67f1)
  • deps: update module github.com/grafana/pyroscope-go/godeltaprof to v0.1.11 (#41) (fb21d9f)
  • deps: update module github.com/prometheus/exporter-toolkit to v0.16.0 (#30) (9c0094e)
  • docs: remove glightbox slide_effect option (rejected by zensical 0.0.44) (42a31e6)

Miscellaneous

  • automerge Renovate vulnerability-fix PRs (d3b0977)
  • deps: update actions/setup-go digest to 4a36011 (#28) (9d094ca)
  • deps: update actions/upload-artifact digest to 043fb46 (#32) (d0f2ae2)
  • deps: update docker/build-push-action digest to bcafcac (#31) (02232b6)
  • deps: update docker/login-action digest to 4907a6d (#29) (8b4ff11)
  • deps: update github actions (#34) (06fc36e)
  • deps: update github/codeql-action digest to 3869755 (#25) (d196062)
  • deps: update github/codeql-action digest to 68bde55 (#39) (fdf085c)
  • deps: update github/codeql-action digest to b8bb9f2 (#26) (d7ba908)
  • deps: update github/codeql-action digest to c10b806 (#27) (7f9164a)
  • deps: update github/codeql-action digest to c6f9311 (#23) (5ed9dbe)
  • deps: update github/codeql-action digest to e46ed2c (#37) (60ecb55)
  • deps: update googleapis/release-please-action action to v5 (#35) (9f57415)
  • deps: update googleapis/release-please-action digest to 5c625bf (#33) (2b9008e)
  • deps: update goreleaser/goreleaser-action digest to 1a80836 (#36) (21925be)

0.2.1 (2026-03-16)

Miscellaneous

  • deps: update gcr.io/distroless/static-debian13:nonroot docker digest to e3f9456 (#20) (a542a93)
  • deps: update github/codeql-action digest to b1bff81 (#21) (3378bb1)
  • replace old Grafana dashboard with comprehensive v2 dashboard (da5a351)

0.2.0 (2026-03-14)

Features

  • client: add new API endpoints for enhanced collectors (6c6cde9)
  • collectors: add NDP collector for IPv6 neighbor discovery table (2a2dffe)
  • collectors: add PF statistics deep dive collector (28ec3d6)
  • collectors: enhance firewall collector with per-interface hit counters (499eb01)
  • collectors: enhance mbuf collector with additional memory statistics (cb78df6)
  • collectors: enhance network diagnostics collector with pfsync HA metrics (a03b23d)
  • collectors: enhance system collector with detailed system information (b123643)
  • netflow: add configuration options and CLI flags (546ccfe)
  • netflow: add NetFlow collector implementation (63e5154)

Bug Fixes

  • add markdown attribute to hero-badges div (fb6884f)
  • use direct type conversion to satisfy staticcheck S1016 (2964580)

Refactoring

  • docgen: replace if-else chain with switch statement for metric parsing (65d7dd4)
  • remove GOMAXPROCS configuration option (190bd1e)

Miscellaneous

  • deps: pin dependencies (#5) (f28c389)
  • deps: update actions/checkout action to v6 (#10) (e2493c8)
  • deps: update actions/download-artifact digest to 3e5f45b (#6) (98e119d)
  • deps: update actions/setup-go action to v6 (#11) (9d83482)
  • deps: update actions/setup-go digest to 40f1582 (#8) (5f1a7a5)
  • deps: update docker/build-push-action action to v7 (#12) (733c911)
  • deps: update docker/login-action action to v4 (#13) (89b8997)
  • deps: update docker/metadata-action action to v6 (#14) (3adce41)
  • deps: update docker/setup-buildx-action action to v4 (#15) (a2a0a05)
  • deps: update github/codeql-action action to v4 (#16) (da86204)
  • deps: update golangci/golangci-lint-action action to v9 (#17) (21b76d0)
  • deps: update goreleaser/goreleaser-action action to v7 (#18) (647277e)
  • deps: update goreleaser/goreleaser-action digest to e435ccd (#9) (494a4cc)

Documentation

  • add auto-generated collector reference and update metrics documentation structure (d41b180)
  • add comprehensive documentation infrastructure with automated generation (e519f1a)
  • add comprehensive documentation infrastructure with mkdocs (3854de8)
  • reorganize completed TODOs and expand remaining tasks (0b942d0)
  • restructure and expand metrics documentation (bf1d7a0)
  • update README and metrics documentation for NetFlow collector (3cb4185)
  • update README with new collector descriptions (45feac4)
  • update todos with completed implementation status (b2aa505)

CI/CD

  • restrict docs sync trigger to docs-related path changes (746c084)
  • trigger PR checks for branch protection (5b9d965)
  • trigger PR checks for branch protection setup (5a49761)

0.1.0 (2026-03-03)

Features

  • activity: add system activity collector (7f1893c)
  • add certificate expiry collector (acd8503)
  • add CLI flags for new collectors (dfd501f)
  • add collector configuration options (c2dbe10)
  • Add default_gateway label to status metric (#54) (5010f43)
  • add dnsmasq DHCP lease collector with configuration options (a838de2)
  • add firewall rules statistics collector (9b173c9)
  • Add ipsec_phase1_status (#71) (260b70a)
  • add mbuf statistics collector (6b344a1)
  • add more ipsec phase1/phase2 metrics (#86) (5a2621d)
  • add NTP status collector (1c19562)
  • add profiling support with pprof and godeltaprof (278334d)
  • add system resources collector (68c02fa)
  • add system status code to health metrics (8a833da)
  • add temperature collector (76515a3)
  • carp: add CARP/VIP status collector (c8280f3)
  • client: add new collector endpoints (651d11d)
  • Collect more gateway information (#50) (fcdd2d6)
  • collector: add network diagnostics collector with netisr, socket, and route metrics (bab3bf0)
  • collector: add service running metrics to network service collectors (d8bc04f)
  • collector: integrate new collectors (7837e97)
  • docs: opnsense permissions (#40) (bc6ff67)
  • docs: update README to reflect new collector structure and options (ee547ca)
  • enhance firewall collector with bytes and states (05551da)
  • enhance protocol statistics collector with comprehensive network protocol metrics (271fca8)
  • enhance unbound DNS collector with comprehensive metrics (02748e5)
  • enhance unbound DNS with additional metrics (8f0d1b8)
  • expand interfaces collector with additional network metrics (f876193)
  • expand protocol statistics metrics (642fa1c)
  • kea: add Kea DHCP lease collector (76a2194)
  • main: wire new collector options (e8213f1)
  • opnsense: implement network diagnostics API clients (ed93071)
  • options: add collector configuration flags (800c443)
  • register new API endpoints in client (3e5faf7)
  • wire new collectors into main application (962dfd5)

Bug Fixes

  • allow opnsense http client to handle gzip responses (#2) (395aca9)
  • Change Docker CMD for ENTRYPOINT (#11) (4c83613)
  • correct gateway config fallback logic (a68980c)
  • fix startup checks and k8s health-check (#20) (b2da78b)
  • health check; flags; metrics list (#19) (98788e8)
  • kea: handle disabled DHCP service response (2e47279)
  • let the CI run on pushed to main as well (30436b9)
  • let the docker push happen only on tags (30436b9)
  • let the docker push happen only on tags (30436b9)
  • parse interface line rate with unit suffix (428fd41)
  • protocolStatistics API path (#69) (e59e0d3)
  • resolve gateway probe_period emission bug (4c577cb)
  • sync README with the latest state (7523d61)
  • System status API changes in OPNsense>=25.1 (#60) (6207256)

Refactoring

  • firmware: rework metrics to follow Prometheus best practices (a3e4057)
  • fix import ordering across collectors (2e928d8)
  • fork project from AthennaMind to rknightion (d080810)
  • modernize Go syntax patterns (ea2d70f)

Miscellaneous

  • add completed TODO documentation (a0b1c03)
  • add utility functions for safe string parsing (3ac6bed)
  • remove dead system.go code (20e9860)
  • rename VERSION to version.txt (04e8094)

Documentation

  • add Claude AI development guidance (03ec5b5)
  • Add metrics list (#15) (e422536)
  • clarify firewall rules collector description (7ddcad5)
  • document new collectors (fa26340)
  • mark completed TODOs in task list (5279015)
  • todos: mark TODO 19, 20, and 21 as complete (e40122b)
  • update README with new collector features (0f01325)
  • update README with new collector features (d04b53f)

Build & Infrastructure

  • add prometheus client_model dependency (47a20ad)
  • modernize goreleaser configuration (d6f37cf)
  • optimize Docker build for performance (7eeb896)
  • update Dockerfile with version labels (09a745a)
  • upgrade Go version from 1.25 to 1.26 (ea3eb6b)

Tests

  • add comprehensive test coverage for collectors (eef6317)
  • expand utility function coverage (04c4078)
  • update collector tests for new collectors (81fc4d3)

CI/CD

  • add comprehensive release-please workflow (76e14a0)
  • implement release-please automation (e0d814c)
  • modernize main CI workflow (3e43475)
  • remove arm/v6 platform support (78b80f9)
  • remove legacy workflow files (fb8120a)