Releases: develeap/hyperping-exporter
v1.8.2
What this ships
Bundle of three fixes addressing user-reported issues against v1.8.1 on cgk8s:
hyperping-gov0.7.1 brings in the MCP client correctness fixes (canonicalarguments: {}serialization for nil-args calls plusAlertHistory/TeamMember/StatusSummaryresponse-shape corrections).- Warm 24h MTTA emit-suppression — the warm-tier per-UUID
GetMonitorMttacall was storing the aggregatereport.Mttafield as the per-UUID value, which silently emitted misleading zero-valued series for projects with no acknowledged alerts. - MTTA precondition documentation — README and CHANGELOG now state that
hyperping_monitor_mtta_secondsrequires acknowledged alerts in the upstream Hyperping project.
Operator-facing behavior changes at rollout
| Surface | Before (v1.8.1) | After (v1.8.2) |
|---|---|---|
hyperping_alerts |
stuck at 0 since v1.8.0 (silent decode of AlertHistory against a non-existent shape) |
reflects real alert count |
hyperping_monitor_mtta_seconds{period="24h"} (warm, projects with no acks) |
47 misleading zero-valued series for hyp_core |
absent |
list_recent_alerts warm-tick warnings |
78 failures / 12.7h fleet-wide ("invalid character 'M'") | gone |
hyperping_monitor_mtta_seconds{period in {7d,30d,90d,365d}} (cold) |
absent for projects with no acks | still absent until acks happen upstream |
hyperping_alerts was the bug the user reported — the warm-tick "invalid character 'M'" warning logged on every refresh. v0.7.1's nil-args + AlertHistory fixes unstick that path.
The MTTA series-set change is the operationally interesting one. Any absent()-based alert rule on hyperping_monitor_mtta_seconds needs review:
- Before:
absent(hyperping_monitor_mtta_seconds{period="24h"})always returned empty (47 series were emitted with value=0) - After: the same query fires for projects with no ack data
- Operator workaround if you want to keep "no MTTA = ok" semantic: predicate on the upstream condition explicitly (e.g., a manual
hyperping_project_has_acksindicator or just leave the metric optional in dashboards)
Why MTTA may still be absent after v1.8.2
This release fixes the wiring around MTTA emission. It does NOT manufacture MTTA values out of thin air. hyperping_monitor_mtta_seconds requires acknowledged alerts in the configured Hyperping project. If list_recent_alerts.rawAlerts[*].acknowledgedAt is null for every alert (no on-call / ack flow configured on the Hyperping side), MTTA will remain absent across every period regardless of any client-side change.
Self-check (against the live MCP):
# probe list_recent_alerts (now decodes correctly with v0.7.1)
# any rawAlert with acknowledgedAt != null means MTTA can populateOr equivalent: hyperping_alerts > 0 unless hyperping_monitor_mtta_seconds.
Tests
- 3 new warm MTTA regression tests including an explicit aggregate-leak guard (mock asymmetric per-monitor=100, aggregate=9999 → assert emitted value is 100, proving the aggregate field was not used).
- 318 total Go tests pass with
-race -count=1(up from 315). - Chart render harness all pass.
- 5 logical commits: deps bump → TDD failing tests → fix → chart bump → docs.
Backward compatibility
Patch release. No public API change. Two intentional behavior changes (alert count unsticks; warm MTTA zeros become absences) are documented above and were the target of this PR.
Chart
Chart 1.8.2 carries appVersion: "1.8.2". Values schema unchanged. No values.yaml change required for operators upgrading from chart 1.8.1.
Verification
| Check | Result |
|---|---|
go vet ./... |
clean |
go build ./... |
clean |
go test -race -count=1 ./... |
318 passed |
golangci-lint run ./... |
clean |
helm lint deploy/helm/hyperping-exporter |
clean |
python3 deploy/helm/hyperping-exporter/tests/render_test.py |
all pass |
Upstream
Consumes develeap/hyperping-go v0.7.1, which adds output-shape pinning to its schema contract test so this bug class is caught at PR time on the SDK side going forward.
PR
Full diff and review: #79.
Chart chart-v1.8.2
Fixed
hyperping_alertswas stuck at 0 across every project regardless of
the real upstream count. Thehyperping-gov0.7.0AlertHistory
struct declared{Alerts, Total}while the live MCP server response
shape is{timeGroups, totalAlerts, downAlerts, upAlerts, rawAlerts}.
The Go decoder silently produced an all-zero struct, so the exporter
faithfully reportedtotal = 0while alerts were happening upstream.
v1.8.2 bumps to hyperping-go v0.7.1 which corrects the shape and
exposes a nil-safeTotal()accessor; both exporter callsites
(legacycollector.goand tieredtiered.gowarm-tier) switch to
the method form. Behaviour change at rollout:hyperping_alerts
starts moving for projects with non-zero alert history. Alert rules
that treated this gauge as effectively-constant should be reviewed.- The MCP transport "invalid character 'M' looking for beginning of
value" warning on every warm tick stops. hyperping-go v0.7.1 fixes
CallToolto sendarguments: {}when the caller passes nil args
(the server rejected the malformed request with a textual
MCP error -32602: Input validation ...reply that the client tried
to JSON-decode, hence the noisy warning). - Warm-tier 24h
hyperping_monitor_mtta_secondsseries stop emitting
misleading zeros for projects without acknowledged alerts. The
warm-tier per-UUIDget_monitor_mttacall was reading the response's
top-levelmttaaggregate (which is 0 when the project has no acks
in the window) intores.mtta[uuid], producing one zero-valued
period="24h"series per monitor. The cold tier already handled this
shape correctly. v1.8.2 mirrors the cold-tier semantic in the warm
path: only record an entry when the response'smonitorsarray
carries a matching uuid, and read the per-monitor value from that
entry rather than the aggregate. Behaviour change at rollout: the
warm 24h MTTA series disappear for any project whose Hyperping
account does not acknowledge alerts. They reappear automatically
once acks start flowing upstream.
Changed
- Chart version + appVersion bumped to
1.8.2.
Verification
- All existing tests pass under
-race -count=1. Three new tests pin
the warm-tier emit-suppression contract (empty Monitors -> no entry;
populated Monitors -> per-monitor value, never aggregate; mixed
fixture -> only populated uuids end up in the snapshot). - Helm render tests pass with version pins moved to
1.8.2. - See README "MTTA precondition" for why this metric may still be
absent across every period after the fix lands (Layer 3 upstream
precondition: the project must actually acknowledge alerts).
Install
helm repo add develeap https://develeap.github.io/hyperping-exporter
helm repo update
helm install hyperping-exporter develeap/hyperping-exporter \
--version 1.8.2v1.8.1
What this fixes
Two bugs surfaced after the v1.8.0 rollout on cgk8s, both confirmed against the live exporter behavior and (for bug 1) the live MCP server response shape.
Bug 1: cold-tier MTTA fan-out was silently empty
The v1.8.0 release notes claimed cold-tier MTTA fan-out worked via the hyperping-go v0.7.0 empty-uuids semantic. That claim was wrong: the MCP server's get_monitor_mtta tool returns project-level aggregate only (monitors: [], plus a project mean) when called with empty monitor_uuids. Per-monitor data requires explicit UUIDs in the request body.
The exporter's cold MTTA path iterated the empty Monitors[] slice, populated an empty per-period map, and emitted zero series for every (uuid, cold-period) tuple. Operators with multi-period configs saw cold MTTR / SLA / downtime / outages fan out normally, but MTTA only emitted the 24h warm series.
Fix: Cold MTTA call now sources monitor UUIDs from the HOT-tier snapshot (always populated after HOT's eager startup refresh) and passes them explicitly. Still one MCP call per cold period. The misleading in-source comment is corrected.
Bug 2: WARM and COLD tiers had no eager startup refresh
HOT ran an eager in-band refresh at startup (preserves /readyz semantics). WARM and COLD waited for their first ticker fire at +warmTTL and +coldTTL respectively. On the cgk8s deploy (warmTTL=30m, coldTTL=1h) that meant dashboards were dark for 24h SLA up to 30m after every restart, and dark for 7d/30d/90d/365d up to 1h. For an executive SLA surface, that gap was conspicuous after every deploy / OOM / node drain / chart bump.
Fix: Each enabled tier's goroutine now runs one eager refresh before installing its ticker. HOT remains in-band (no /readyz semantic change). WARM and COLD eager refreshes are non-blocking on the caller — they run inside the existing tier goroutines so process startup is unaffected. Per-tier mutex (already present) covers the edge case where a slow eager refresh overlaps with the first ticker fire. Disabled tiers do NOT run eager refreshes (zero API calls; existing tier-disabled semantic preserved).
Behavior change at rollout
Operators with config.periods set to include 7d / 30d / 90d / 365d will see those hyperping_monitor_mtta_seconds series populate for the first time. Alert rules using absent() to tolerate the v1.8.0 silent absence will silently flip on this rollout and need to be reviewed before deploy.
No other operator-facing change. Default-config (no periods set) is unaffected.
Tests
- 7 new tests (3 cold-MTTA + 4 eager-prefetch); pinned mocks reflect real MCP semantic (empty uuids return empty
monitors[]; explicit uuids return populatedmonitors[]). TestColdMtta_FansOutAcrossPeriods— per-period series populated for every (uuid, cold-period) tuple.TestColdMtta_PassesExplicitUUIDs— regression guard: cold MTTA requestmonitor_uuidsis non-empty.TestColdMtta_SkipsWhenHotEmpty— no panic, no MCP call, when HOT snapshot is empty.TestTieredRefresher_EagerWarmPrefetch—refreshWarminvoked within a window much shorter than warmTTL.TestTieredRefresher_EagerColdPrefetch— same for cold.TestTieredRefresher_DisabledTierNoEagerRefresh— disabled warm/cold issues zero API calls.- 2 existing isolation tests updated for the new eager-prefetch behavior; pinned contracts unchanged.
- Total suite: 315 passed with
-race -count=1.
Backward compatibility
Patch release. No public API change. Default-config Desc snapshot guard (added in v1.8.0) still passes unchanged. Existing PromQL queries continue to work; new cold MTTA series simply start populating where they were absent in v1.8.0.
Verification
| Check | Result |
|---|---|
go vet ./... |
clean |
go build ./... |
clean |
go test -race -count=1 ./... |
315 passed |
golangci-lint run ./... |
clean |
helm lint deploy/helm/hyperping-exporter |
clean |
python3 deploy/helm/hyperping-exporter/tests/render_test.py |
all pass |
Chart
Chart 1.8.1 carries appVersion: "1.8.1". Values schema unchanged. Operators upgrading from chart 1.8.0 see no values-file change required.
PR
Full diff and review: #78.
v1.8.0
What this ships
Two things in one release:
-
Silent-zero MTTA bug fix. Pre-v1.8.0 the exporter's
hyperping_monitor_mtta_secondsseries have been emitting all-zero values for every monitor on every scrape since the multi-project rewrite. The pre-hyperping-go v0.7.0MCP client sent the wrong request-arg shape and decoded into a struct the server never returned. Bumping the upstream client restores real windowed MTTA values. Operators will see this metric flip from0to its real value at rollout. Any alert rule or recording rule whose threshold was tuned against the bogus0must be re-baselined before this image goes live in front of pagers. -
Multi-period metric emission. New per-project
config.periodsfield fans the seven period-bearing metrics across configured SLA report windows. Allowed tokens:24h,7d,30d,90d,365d. Absent or empty list defaults to["24h"], which keeps a chart 1.7.x values.yaml byte-identical on the wire. Period -> tier mapping is fixed:24his warm;7d,30d,90d,365dare cold. Cold-tier MTTA fan-out uses the new v0.7.0 empty-uuids semantic so adding a period costs +1 MCP call per cold tick, not +N.
Breaking changes (read these before rollout)
1. hyperping_monitor_mtta_seconds always carries a period label
Default-config series identity changes from:
hyperping_monitor_mtta_seconds{name=...,project=...,tenant=...,tier=...,uuid=...}
to:
hyperping_monitor_mtta_seconds{name=...,period="24h",project=...,tenant=...,tier=...,uuid=...}
Recording rules, alert expressions, and Grafana panels referencing the unlabelled form need a one-time update.
2. hyperping_monitor_mtta_seconds values flip from 0 to real
This is a value-level change, not a label-level one. See the headline. Re-baseline any thresholds.
3. hyperping_data_age_seconds gains a period label, single-emit per (tier, period)
HOT tier (no window) emits one series with period="". WARM and COLD tiers emit one series per configured period mapped to them (24h -> warm; 7d/30d/90d/365d -> cold). No empty-period legacy series is emitted for warm/cold. PromQL migration:
# before (chart 1.7.x)
sum(data_age_seconds{tier="warm"})
# after (chart 1.8.0): still works; counts the period(s) mapped to warm
sum(data_age_seconds{tier="warm"})
# explicit per-period query (new)
data_age_seconds{tier="warm", period="24h"}
For the default periods=["24h"] the scalar value of sum(data_age_seconds{tier="warm"}) is identical to pre-1.8.0.
Added
config.periodsper-project knob. Allowed tokens:"24h","7d","30d","90d","365d". Absent or empty list defaults to["24h"].- Period -> tier mapping (fixed):
24h-> warm;7d,30d,90d,365d-> cold. A period whose mapped tier is disabled on the project (viacache.warmEnabled: falseorcache.coldEnabled: false) emits no series for that window;hyperping_exporter_tier_disabledcovers the absence semantic. - Period fan-out on seven period-bearing metrics:
hyperping_monitor_sla_ratio,_downtime_seconds,_outages,_longest_outage_seconds,_mttr_seconds,_mtta_seconds, andhyperping_tenant_avg_sla_ratio. - Startup WARN log per
(project, period)whose mapped tier is disabled. Saves operators a debug round-trip when they ask "why is my 7d data missing?" - README section "Multi-period metric emission" with a copy-pastable YAML example.
Chart
deploy/helm/hyperping-exporterbumped 1.7.0 -> 1.8.0;appVersion1.7.0 -> 1.8.0.config.periodsexposed invalues.yamlwith allowed tokens, default, and docs.helm templatepasses the field through verbatim into the renderedprojects.yaml.- Three new render-test cases:
MP1(passthrough),MP2(absent-key byte-identical compat with chart 1.7.x),MP3(invalid-token chart-level passthrough; binary rejects at startup).
Backward compatibility (no config.periods set)
| Surface | Behaviour |
|---|---|
Chart values.yaml without config.periods |
Renders projects.yaml byte-identical to chart 1.7.x (asserted by render test MP2) |
| Series count for sla_ratio, downtime_seconds, outages, longest_outage_seconds, mttr_seconds, tenant_avg_sla_ratio | Unchanged; period="24h" only |
hyperping_monitor_mtta_seconds |
period="24h" label now ALWAYS present (documented breaking change); value flips from 0 to real |
hyperping_data_age_seconds |
Now {tier="hot", period=""} + {tier="warm", period="24h"}; sum() per tier is scalar-preserved for the default |
| API call volume per scrape | Unchanged when config.periods is absent or ["24h"] |
Rate-limit math
For hyp_core at 136 monitors, default tier TTLs (hot=60s, warm=5min, cold=15min). Units are explicit per row to avoid mixing instantaneous and smoothed numbers:
| Before (chart 1.7.x) | After 1.8.0 default ["24h"] |
After 1.8.0 full ["24h","7d","30d","90d","365d"] |
|
|---|---|---|---|
| REST calls/hr/project (smoothed) | 240 hot + 12 warm + 8 cold = 260 | identical | 240 hot + 12 warm + 16 cold = 268 |
| MCP calls/hr/project (smoothed) | ~4 908 warm | identical | 4 908 warm + 16 cold = 4 924 |
| MCP burst per cold tick (instantaneous) | 0 | 0 | 4 (one all-monitors MTTA call per cold period) |
| MCP burst per warm tick (instantaneous) | ~408 (3 calls/monitor × 136) | identical | identical |
Limits: 800/hr REST per project, 215/60s MCP burst. Full 5-period opt-in uses 33% of the REST budget and ~14% of the MCP burst budget. The new long-window MCP fetches use v0.7.0's empty-uuids "all monitors in one call" path so adding a period costs +1 MCP call per cold tick, not +N.
Tests
- 308/308 Go unit tests pass with
-race -count=1 - 12 new unit tests in
multi_period_test.go(main package):resolvePeriodsdefaulting, allowed tokens, invalid-token error wrapping, duplicates,periodToTiermapping,loadProjectsFileperiods parsing, plus 2 tests covering the dead-period WARN log - 6 new unit tests in
internal/collector/multi_period_test.go: MTTA period label, period-label-presence regression guard,data_age_secondssingle-emit semantics, warm/cold orphan empty-period regression guard, disabled cold tier + mapped periods no-orphan-series contract, and the v1.8.0 default-config registry Desc-set parity pin - 3 chart render-test cases (
MP1,MP2,MP3) - Race-detector clean
helm lint,golangci-lint,go vet,go build: all clean
Followups not in this release
- Per-period MTTA on the warm tier (only cold currently fans MTTA across cold-mapped windows; warm 24h MTTA still uses the legacy per-monitor loop because that same loop covers per-monitor anomaly_count / anomaly_score the all-monitors MTTA call does not).
- Tenant SLA average fan-out is implicit (the cold-tier loop emits one tenant series per cold period via
r.MTTR) but lacks a dedicated regression test asserting the per-period series count for arbitraryperiodslists.
Upstream
This release consumes develeap/hyperping-go v0.7.0, which fixes four MCP client methods that were silently returning all-zero values: GetMonitorMtta, GetMonitorMttr, GetMonitorResponseTime, GetMonitorUptime. The exporter calls Mtta and ResponseTime; only MTTA had observable broken behaviour because the response_time path also pulls per-monitor anomalies via a separate working call.
PR
Full diff and review history: #77.
Chart chart-v1.8.1
Fixed
- Cold-tier MTTA fan-out (
hyperping_monitor_mtta_secondswith
periodin7d/30d/90d/365d) was silently empty in v1.8.0.
The cold refresher called the MCPget_monitor_mttatool with an
emptymonitor_uuidsslice on the assumption that "empty meant
every monitor". The live server semantic is the opposite: empty
monitor_uuidsreturns the project-level aggregate only
(monitors: [],totalAcknowledged: 0,mtta: 0). The exporter
iterated the empty array and published an empty per-period map, so
no cold MTTA series were ever emitted. v1.8.1 sources monitor UUIDs
from the HOT snapshot and passes them explicitly as the
monitor_uuidsvariadic argument. Behaviour change at rollout:
operators with multi-period configs (e.g.
periods: ["24h", "7d", "30d"]) will start seeing populated
hyperping_monitor_mtta_secondsseries for the cold-mapped windows.
Alert rules that usedabsent()on the cold MTTA series to tolerate
the v1.8.0 silent absence should be reviewed. - Tiered-mode warm and cold tiers now perform an eager refresh at
startup so dashboards are not dark forwarmTTL/coldTTLafter a
pod restart. Pre-1.8.1 each tier built itstime.Ticker(d)and
waited+dfor the first refresh; on a deploy withwarmTTL=30m
andcoldTTL=1hthat meant no 24h SLA series for 30m after every
restart and no 7d/30d/90d/365d series for 1h. The eager refresh
runs inside the per-tier goroutine (not on the caller path) so HOT
remains the only tier that gates/readyz. Per-tier mutexes defend
the unlikely overlap between a slow eager refresh and the first
scheduled tick. Disabled tiers continue to launch no goroutine and
therefore do not run an eager refresh.
Changed
- Chart version + appVersion bumped to
1.8.1.
Verification
- All existing tests pass under
-race -count=1. New tests added for
the cold MTTA fan-out contract (3) and the eager warm/cold prefetch
contract (4). - README "Multi-period metric emission" section corrected: the prior
wording claimed the empty-uuids MCP call returned per-monitor
entries, which was the source of the v1.8.0 silent-empty bug.
Install
helm repo add develeap https://develeap.github.io/hyperping-exporter
helm repo update
helm install hyperping-exporter develeap/hyperping-exporter \
--version 1.8.1Chart chart-v1.8.0
Fixed
- BREAKING (silent-zero bug fix):
hyperping_monitor_mtta_secondswas
emitting all-zero values for every monitor on every scrape because
the pre-v0.7.0hyperping-goMCP client sent the wrong request-arg
shape and decoded into a struct the server never returned. Bumping
to hyperping-go v0.7.0 (canonical MCP signatures) restores real
windowed MTTA values. Operators upgrading from chart 1.7.x will see
this metric flip from 0 to its actual value at rollout; alert
thresholds that were tuned around the buggy 0 must be re-baselined. - The same v0.7.0 client correctness fix repairs three other windowed
MCP methods (GetMonitorMttr,GetMonitorResponseTime,
GetMonitorUptime) which were affected by the same shape mismatch.
The exporter only calls Mtta and ResponseTime today, so the
observable behaviour change is MTTA only.
Added
config.periodsfield on eachprojects:entry. Allowed tokens:
"24h","7d","30d","90d","365d". Absent or empty list
defaults to["24h"]so a chart 1.7.x values.yaml renders
byte-identical projects.yaml on the wire. Period -> tier mapping is
fixed:24his warm;7d,30d,90d,365dare cold. A period
whose mapped tier is disabled on the project emits no series for
that window (existinghyperping_exporter_tier_disabledself-metric
covers the absence semantic).- Period fan-out on the seven period-bearing metrics
(hyperping_monitor_sla_ratio,_downtime_seconds,_outages,
_longest_outage_seconds,_mttr_seconds,_mtta_seconds, and
hyperping_tenant_avg_sla_ratio). For configured periods mapped to
cold tier (7d/30d/90d/365d) the cold-tier refresher issues one
all-monitors MCP call per period (via v0.7.0's empty-uuids semantic)
rather than N-monitor fan-out, keeping the new long-window fetches
inside the MCP burst budget. - README section "Multi-period metric emission" with a copy-pastable
YAML example showing the full opt-in across all five periods. - Chart render tests covering both the present-and-set and
absent-key paths forconfig.periodsso the byte-identical
backward-compat claim is mechanically enforced.
Changed
-
BREAKING (series identity):
hyperping_monitor_mtta_secondsnow
ALWAYS carries aperiodlabel, defaulting toperiod="24h"for
projects that do not opt into additional windows. PromQL selectors
and recording rules that referenced the unlabelled form must add
period="24h"(or omit the explicit period to match the full
fan-out) during this rollout. Grafana panels keyed on this metric
should be reviewed. -
BREAKING (label scheme):
hyperping_data_age_secondsgains a
periodlabel alongside the existingtierlabel and switches to a
single-emit scheme per (tier, period) pair. The HOT tier carries no
window and continues to emit one series withperiod="". The WARM
and COLD tiers now emit one series per configured period that maps
to them (24h -> warm; 7d/30d/90d/365d -> cold) and NO empty-period
legacy series. PromQL migration:# before (chart 1.7.x) sum(data_age_seconds{tier="warm"}) # after (chart 1.8.0): still works; counts the period(s) mapped to warm sum(data_age_seconds{tier="warm"}) # explicit per-period query data_age_seconds{tier="warm", period="24h"}An aggregation like
sum(data_age_seconds{tier="warm"})returns the
same scalar as pre-1.8 for the defaultperiods=["24h"](one warm
series), and the sum across configured periods for multi-period
configs (which is the natural "tier-level age" answer). Prior to
this release the v1.8.0 draft dual-emitted a legacy empty-period
series alongside the new per-period series, which silently
double-counted undersum; that behaviour has been removed. -
github.com/develeap/hyperping-gopinned to v0.7.0 (was v0.6.3).
Beyond the silent-zero MTTA fix, this release adds canonical
windowed signaturesfunc (c *MCPClient) GetMonitorXxx(ctx, from, to, uuids ...string) (*MonitorXxxResponse, error)and renames the
response types (MttaReport->MonitorMttaResponse, etc). -
Chart bumped to 1.8.0; appVersion 1.8.0 (binary image tag follows).
Install
helm repo add develeap https://develeap.github.io/hyperping-exporter
helm repo update
helm install hyperping-exporter develeap/hyperping-exporter \
--version 1.8.0v1.7.1
What this fixes
Patch release unblocking production usage of v1.7.0.
The HTTP/2 ALPN bug from hyperping-go v0.6.2
v1.7.0 pinned hyperping-go v0.6.2, which had a critical HTTP/2 ALPN regression: every HTTPS API call to api.hyperping.io (or any non-localhost host) failed immediately with errors like
Unsolicited response received on idle HTTP channel starting with
"\x00\x00\x12\x04\x00\x00\x00\x00\x00..."
or
net/http: HTTP/1.x transport connection broken:
malformed HTTP response "\x00\x00\x12\x04..."
The byte pattern is an HTTP/2 SETTINGS frame being misread by Go's HTTP/1 parser. Affected both the REST cache refresh path and the MCP client.
v1.7.1 bumps to hyperping-go v0.6.3, which is the upstream fix. Full root-cause analysis: develeap/hyperping-go#37.
If you've been running v1.7.0 with GODEBUG=http2client=0 as a workaround, you can remove that env var after upgrading to v1.7.1.
Go stdlib CVE fix
Toolchain bumped from 1.26.3 to 1.26.4, resolving two stdlib vulnerabilities disclosed shortly before this release:
GO-2026-5039— arbitrary inputs unescaped innet/textprotoerrors (reached via the MCP transport's MIME header parsing).GO-2026-5037/CVE-2026-42504— inefficient candidate hostname parsing incrypto/x509(reached via TLS hostname verification).
Both fixed in stdlib 1.26.4.
What stayed the same
No behavior changes in the exporter binary itself. Same flags, same metrics, same multi-project fan-out as v1.7.0. Drop-in upgrade.
Upgrade
docker pull khaledsalhabdeveleap/hyperping-exporter:1.7.1Or in Helm:
image:
tag: "1.7.1"Chart version is unchanged (1.6.0); only the image tag needs to flip.
v1.7.0 — Multi-project exporter
Multi-project exporter (binary 1.7.0)
One exporter process now scrapes multiple Hyperping projects concurrently.
Added
--projects-file(envHYPERPING_PROJECTS_FILE): a YAML list of{id, apiKey|apiKeyFile, mcpUrl?, excludeNamePattern?}entries. The binary fans out onehyperping.Client+ transport +*collector.Collectorper project, each with its own refresh loop, so a rate-limit pause on one project does not stall the others.- A
projectconstLabel (value = the projectid) is injected on everyhyperping_*,hyperping_client_*, andhyperping_mcp_*series, so multi-project series coexist on one registry without collision. /readyzis OR across all configured projects; per-project readiness is exposed viahyperping_project_ready{project=<id>}.
Compatibility / cutover
- The legacy single-key path (
--api-key/--api-key-file/HYPERPING_API_KEY) is preserved and synthesises one project with iddefault(emittingproject="default"). - Downstream alerts/dashboards that match series without a
project=...matcher must add one. During cutover use transitional selectors likeproject=~"hyp_core|", and deploy in projects mode (not legacy) so series carry real ids (hyp_core,hyp_infra) rather thandefault.
Pairs with Helm chart 1.6.0 (tag chart-v1.6.0).
Chart 1.6.0 — Multi-project
Helm chart 1.6.0 — multi-project
Adds config.projects support for the multi-project exporter. appVersion 1.5.1 -> 1.7.0; chart 1.5.4 -> 1.6.0.
Added
config.projects(list): when non-empty, the chart renders--projects-file=/etc/hyperping/projects.yamland mounts a projected volume composing the chart-managed Secret with each project's key.- A single ExternalSecret materialises one Secret
<release>-projectscarrying oneapi-key-<id>data key per project. validateProjectshelper: enforces unique ids matching[a-zA-Z0-9._-]{1,64}, exactly one secret source per project, and mutual exclusion with the legacy top-levelapiKey/existingSecret/externalSecret.remoteRef.
Compatibility
- Legacy single-key deploys (
config.apiKey/existingSecret) render unchanged.
Cutover notes (downstream alerting)
- Deploy via
config.projects, NOT the legacyconfig.apiKey: the legacy path emitsproject="default", which the transitionalproject=~"hyp_core|"alert selectors do not match (fleet-wide alert dead-spot). - Set
config.cacheMode: tieredif the per-tierHyperpingDataStalealerts are expected to fire; the defaultlegacyemits onlytier="hot", so warm/cold staleness rules stay inert.
Install
helm repo add hyp-exporter https://develeap.github.io/hyperping-exporter
helm repo update
helm install hyperping-exporter hyp-exporter/hyperping-exporter --version 1.6.0
v1.6.0
What's New
Security hardening
This release lands the result of an independent security audit. Highlights:
- Go toolchain bumped to 1.26.3 (from 1.26.2), clearing eight stdlib CVEs (
GO-2026-4918HTTP/2 SETTINGS_MAX_FRAME_SIZE infinite loop,GO-2026-4971/4980/4981/4982, and friends). The release workflow now hard-gates ongovulncheck v1.3.0, so a vulnerable transitive dependency cannot ship to operators in a future release. - Label-bomb mitigation: every metric-label value (monitor name, healthcheck name) is truncated to 256 bytes at emit time via a shared, UTF-8-safe helper. A compromised tenant or operator with rename rights can no longer force the Prometheus side to ingest multi-kilobyte label values multiplied across every per-monitor series.
- Tenant label validation:
extractTenantnow rejects any character outside[a-zA-Z0-9._-]and bounds the resulting tag at 64 bytes. Tags with colons, slashes, spaces, or unicode characters now collapse to the empty string rather than flowing verbatim into the label set. /metricsstartup warning when binding any-interface (:port,0.0.0.0:port,[::]:port) without--web.config.file. The default bind is unchanged; this is a hint, not a hard fail, but the word "unauthenticated" appears in the log line so it is grep-able during incident response.- HTTP server hardening:
IdleTimeout(120s) andMaxHeaderBytes(1 MiB) explicitly set on the metricshttp.Serverto guard against keep-alive idle-connection DoS and header-bomb DoS. - SDK upgrade to hyperping-go v0.6.2, which broadens the credential redactor to cover
Authorization(every scheme, not just Bearer),Cookie,Set-Cookie,Proxy-Authorization, and theX-Api-Keyfamily. Closes the path by which a server-side error message could leak any of those headers throughAPIError.Error().
API key sourcing
--api-key-file <path>: read the Hyperping API key from a file rather than from argv or the environment. Recommended source for container deployments; the file can be owned by a dedicated user and is not visible viapsor/proc/<pid>/cmdline. Trailing CR/LF combinations are stripped (LF, CRLF, CR, and multi-newline tails all yield the same key).--api-keyCLI flag is deprecated and emits a stderr warning at startup. It still works for one cycle. PreferHYPERPING_API_KEYor--api-key-file; the CLI form leaks the secret into/proc/<pid>/cmdline.
Breaking changes for Prometheus operators
Three of the security fixes silently change emitted label values. If you have alerts or dashboards keyed on these, please audit them before upgrading.
Metric-label values capped at 256 bytes
Affects every series carrying a name label: hyperping_monitor_up, hyperping_monitor_response_time_seconds, hyperping_monitor_sla_ratio, hyperping_healthcheck_*. If any of your monitor or healthcheck names exceeds 256 bytes, the emitted series will no longer carry the full value. Audit selectors of the form:
hyperping_monitor_up{name="The full literal name longer than 256 bytes..."}
Either shorten the upstream name, or migrate to a prefix regex against the truncated form.
Tenant label rejects non-token characters
tenant label now matches ^[a-zA-Z0-9._-]{1,64}$ or is empty. Existing tags containing :, /, spaces, or unicode collapse to tenant="". Queries like:
sum by (tenant) (hyperping_monitor_up)
hyperping_tenant_health_score{tenant="ops:edge"}
bucket affected monitors under the empty-tenant series. Rename upstream tags to use only [a-zA-Z0-9._-] to restore the previous behaviour.
SLA name-label now stable across renames
hyperping_monitor_sla_ratio now derives its name label from the live monitor record rather than the per-report snapshot. Mid-window renames no longer fragment SLA series against base monitor series for the same uuid. If you joined SLA and base series on (uuid, name), switch the join to uuid only to keep the previous behaviour.
Container image
Multi-arch image built for linux/amd64 and linux/arm64, pushed to both registries:
docker.io/khaledsalhabdeveleap/hyperping-exporter:1.6.0ghcr.io/develeap/hyperping-exporter:1.6.0
Image digest: sha256:1fbdbedb5d92ced35d01e5d2df271f877c43d61a3f848b86b985c99ab8adb9d6
Both registry pushes are keyless-signed with cosign; transparency-log entries are in Sigstore Rekor (logIndex 1682206081 for Docker Hub, 1682206783 for GHCR). Verify with:
cosign verify \
--certificate-identity-regexp "https://github.com/develeap/hyperping-exporter/.github/workflows/release.yml@refs/tags/v1.6.0" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
ghcr.io/develeap/hyperping-exporter@sha256:1fbdbedb5d92ced35d01e5d2df271f877c43d61a3f848b86b985c99ab8adb9d6SBOMs for all 8 archive variants are attached to this release as *.sbom.json.
Upgrade
# Helm
image:
repository: ghcr.io/develeap/hyperping-exporter
tag: "1.6.0"# Docker Compose
image: ghcr.io/develeap/hyperping-exporter:1.6.0If you currently pass --api-key, plan to migrate to HYPERPING_API_KEY or --api-key-file before the deprecation lands as a removal in a future release.
Full Changelog
See CHANGELOG.md for the complete diff.