github robintra/perf-sentinel v0.25.5

latest release: chart-v0.25.5
3 hours ago

What's new in v0.25.5

v0.25.5 is about perf-sentinel reaching what sits behind a corporate network, and about two cases where it read less than it should. Outbound https:// calls ignored HTTPS_PROXY, verify-hash --url aside, and trusted only the bundled Mozilla roots, so a daemon or a CI job behind a proxy, or facing a TLS-inspecting one, could not reach Electricity Maps, Tempo, Jaeger, Prometheus, the Hub export or a Redfish BMC. jaeger-query --service failed with HTTP 404 against Jaeger 2.21, which removed the search endpoint it called. And on MySQL and MariaDB, a value between double quotes reached the templates, the reports and PerfSentinelHub in clear, because the tokenizer read it as an identifier.

One client, one proxy rule

Every https:// call of the daemon and of the CLI now goes through HTTPS_PROXY, or ALL_PROXY when HTTPS_PROXY is unset, empty or not a usable URL, over an HTTP CONNECT tunnel. NO_PROXY exempts host names, domains with their subdomains, IP addresses, CIDR ranges or *, and loopback only when it is listed. Credentials in the proxy URL become a Basic proxy authorization. Only an http:// proxy URL, or one without a scheme, is used: a SOCKS or https:// proxy URL logs one warning and the call connects directly, so it never receives a plaintext CONNECT or the credentials. http:// calls always connect directly and HTTP_PROXY is ignored, so a cluster-wide proxy does not divert internal endpoints.

The PEM certificates of SSL_CERT_FILE are trusted next to the bundled roots, for a proxy that inspects TLS or an internal PKI. An unreadable file, or one that holds no certificate, logs a warning and leaves the bundled roots alone.

verify-hash --url now downloads through the same client instead of ureq, which leaves the dependency tree. It still accepts only https://, refuses redirects and stops at 10 MiB. ureq read the proxy variables too, with other rules: ALL_PROXY before HTTPS_PROXY, HTTP_PROXY as a last resort, and https:// proxies. verify-hash --url now follows the rules above.

In the simulation lab, an origin serving a certificate from a throwaway CA sat behind a tinyproxy, on a Docker network the host cannot resolve, so a fetch could only succeed through the tunnel. verify-hash --url with HTTPS_PROXY and SSL_CERT_FILE verified the report's content hash, with the CONNECT in the proxy log, and so did ALL_PROXY alone. Without SSL_CERT_FILE it failed on the certificate, and with NO_PROXY naming the origin it connected directly and failed on DNS. It refused the 302 and stopped at the 10 MiB cap. The 0.25.4 binary went through the proxy too but failed on UnknownIssuer. A daemon serving TLS with a certificate from the same CA answered query --daemon https://localhost:<port> status only with SSL_CERT_FILE set.

The v3 search behind Jaeger 2.21

Jaeger 2.21 removed the v1 search, /api/traces?service=, and kept the per-trace read. When the v1 search answers 404, jaeger-query now retries it once through /api/v3/traces, with the same window as RFC 3339 bounds and --max-traces as query.search_depth, and parses the OTLP JSON results through the same path as an OTLP JSON file. A v3 search that matches nothing reports no traces found. A 404 without Jaeger's error body stays an HTTP error, after one extra request. Victoria Traces and Jaeger 2.20 and earlier keep the v1 search, and --trace-id is unchanged.

The lab replays the same Spring Boot capture into Jaeger 2.20.0 and 2.21.0. On 2.21.0, 0.25.4 failed with HTTP 404 on /api/traces, and 0.25.5 logged the v3 retry and found the same two n_plus_one_http findings as through 2.20.0 and the daemon, POST x6 and GET x7, with the same signatures across the six ingestion paths.

Double quotes are strings on MySQL and MariaDB

Both engines read "..." as a string literal in their default mode, where PostgreSQL and the SQL standard read an identifier. The tokenizer took the standard reading for every engine, so WHERE email = "alice@example.com" kept the address in the template. It now masks a double-quoted value like a single-quoted one when the engine is MySQL or MariaDB, taken from db.system.name or db.system, from db.type for dd-trace over OTLP, or from the operation field of native JSON. mysql-stat normalizes as MySQL. Every other engine, and an event that names no engine, keeps "..." as an identifier.

Detection groups by template, so the findings on these queries change too. Queries that split into one template per value now group, and an N+1 that only varied by such a value now shows up. A sanitized statement whose only literal was double-quoted no longer looks sanitized, so a heuristic N+1 on it can disappear. On a lab fixture of six-query loops, 0.25.4 found no N+1 on the MySQL and MariaDB traces and left the address 9 times in the JSON report and 9 times in the SARIF. 0.25.5 found one N+1 on each MySQL and MariaDB trace and no address, and kept SELECT "Name" FROM "Users" WHERE "Id" = ? verbatim on PostgreSQL.

An accurate non-loopback warning

A daemon listening on a non-loopback address warned that its endpoints have no authentication, which the ack and incident routes contradict once their API keys are set. The warning now reads OTLP ingest, /metrics and most read endpoints are never authenticated. Put a reverse proxy or a network policy in front.

Upgrade impact

  • MySQL and MariaDB findings whose SQL held a double-quoted value change template and signature, so their acknowledgments stop matching and PerfSentinelHub files them as new findings. Findings on such queries can appear or disappear, as described above. A MySQL server in ANSI_QUOTES mode loses its double-quoted identifiers to ?.
  • A process that inherits HTTPS_PROXY now uses it for its https:// calls. An https:// endpoint the proxy cannot reach, such as an in-cluster PerfSentinelHub, a Redfish BMC or a daemon queried over https://localhost, belongs in NO_PROXY.
  • verify-hash --url changes proxy rules: HTTPS_PROXY wins over ALL_PROXY, and an environment that only sets HTTP_PROXY, or names an https:// proxy, connects directly. A build without the daemon, tempo or jaeger-query feature can no longer fetch --url, it exits 4 and asks for --report. The released binaries carry all three.
  • The non-loopback listen warning changes wording, so a log rule that matches its old text needs updating.
  • perf-sentinel-core gains API: sentinel_core::http_client::ProxyConnector, fetch_get_limited and sentinel_core::normalize::sql::normalize_sql_for. The connector type of HttpClient and HttpClientWithBody becomes ProxyConnector, which only breaks code that spells the full client type.
  • No configuration key is added or removed, no route, metric name or wire format changes, the embedded reference data keeps its vintages, and MSRV stays 1.98.1.

Full detail in CHANGELOG.md.

Verifying this release

# Binary integrity via SLSA build provenance attestation (Build Level 2)
gh attestation verify perf-sentinel-linux-amd64 \
  --repo robintra/perf-sentinel

# A periodic disclosure produced by this binary
perf-sentinel verify-hash --report perf-sentinel-report.json \
  --expected-identity "https://github.com/robintra/perf-sentinel/.github/workflows/release.yml@refs/tags/v0.25.5" \
  --expected-issuer "https://token.actions.githubusercontent.com" \
  --verify-binary ./perf-sentinel-linux-amd64

gh CLI 2.49 or newer required for gh attestation verify.

Don't miss a new perf-sentinel release

NewReleases is sending notifications on new releases.