github robintra/perf-sentinel v0.5.5

latest releases: chart-v0.2.53, v0.8.8, chart-v0.2.52...
one month ago

What's new in v0.5.5

OTLP ingest hardening. Three independent bugs in v0.5.4 made the default OTel Collector setup harder than it should have been: framework-aware suggestions never fired on JPA, EF Core or Diesel stacks because perf-sentinel only read code.* from the I/O span itself; the OTLP/HTTP endpoint rejected the gzip-compressed exports the OTel Collector ships by default; and the new stable semconv v1.33.0 attribute names (code.function.name, code.file.path, code.line.number) were silently ignored. v0.5.5 fixes all three. As a side effect of the audit pass, the OTLP hot path also got a single-pass attribute classifier (~13x fewer key comparisons per span) and a wire-level cap on compressed bodies that bounds attacker decompression CPU.

After upgrading, an OTel Collector with default gzip works out of the box, JPA and Hibernate findings carry actionable suggested_fix again, and agents emitting either legacy or stable code.* are both supported.

Fixed

  • Walk parent span chain to recover code.* attributes. OTel auto-instrumentation typically attaches code.namespace, code.function and friends to the user-frame span (controller, service), not to the inner JDBC or HTTP-client span. perf-sentinel previously read these only from the I/O span itself, so JAVA_RULES, CSHARP_RULES and RUST_RULES never fired on stacks that delegate I/O to a driver. The walk is bounded at depth 8 to stay safe on malformed parent chains. suggested_fix now appears on JPA, Hibernate, EF Core and Diesel findings even when the agent emits nothing on the leaf span.
  • Accept gzip-compressed OTLP/HTTP exports on POST /v1/traces. The OTel Collector ships gzip by default, which previously triggered HTTP 400 on every export and forced users to set compression: none in the Collector config. perf-sentinel now wires tower-http's RequestDecompressionLayer outside the existing DefaultBodyLimit, so Bytes extraction caps the decompressed payload at [daemon] max_payload_size and tower-http streams the decode with backpressure (no gzip-bomb amplification). Uncompressed clients keep working unchanged. The OTLP/gRPC path was already covered by tonic and is not affected.

Changed

  • Read OpenTelemetry semconv v1.33.0 stable code attribute names (code.function.name, code.file.path, code.line.number) with a fallback to the legacy names (code.function, code.filepath, code.lineno, code.namespace). When only the stable FQ function name is present, the namespace is derived by splitting on the last ., which keeps JAVA_RULES's segment-anchored substring matching firing on org.springframework.data.jpa and friends. An explicit legacy code.namespace always wins over the derived value. The legacy code.function (documented as a bare function name) is deliberately not fed into the namespace derivation, to avoid surfacing false positives on agents that pack a dotted value into the legacy attribute.
  • Single-pass span attribute classifier on the OTLP hot path. convert_span previously ran ~14 separate linear scans over the attribute list (one per get_str_attribute lookup). It now classifies the full set in a single iteration with a match on the key. At typical 30-attribute HTTP spans the saving is ~13x fewer key comparisons per span. The parent walk for code.* no longer re-scans the leaf span attributes, since classification already produced them.

Security

  • Compressed body wire-cap on OTLP/HTTP. A new RequestBodyLimitLayer is layered as the outermost middleware on /v1/traces, so the request flow is now RequestBodyLimit (compressed wire bytes) -> RequestDecompression -> DefaultBodyLimit (decompressed bytes via the Bytes extractor) -> handler. With Content-Length set, compressed bodies above max_payload_size get a clean 413 before any decompression CPU is spent. Closes the amplification path where a relaxed max_payload_size could let an attacker burn ~100 ms of decompress CPU per request with a near-pathological compression ratio.
  • Drop code.* span attributes containing control characters. ANSI escapes, NULs, newlines and other ASCII control bytes inside code_function, code_filepath or code_namespace are now silently dropped at the canonical sanitize_span_event boundary, mirroring the existing posture for cloud.region. Closes a defense-in-depth gap where attacker-controlled ancestor spans could feed control bytes into code.* (now read via the parent walk) and surface them in TUI/CLI output or tracing logs.

Docs

  • OTLP/HTTP gzip support documented in docs/INSTRUMENTATION.md and docs/FR/INSTRUMENTATION-FR.md under "Production: via OpenTelemetry Collector". Notes that perf-sentinel accepts gzip natively, no compression: none workaround required, and that the decompressed body still respects [daemon] max_payload_size.
  • Helm chart 0.2.8 bumps appVersion and the default daemon image tag to 0.5.5.

Install

Prebuilt binaries (Linux amd64 / arm64, macOS arm64, Windows amd64):

curl -LO https://github.com/robintra/perf-sentinel/releases/download/v0.5.5/perf-sentinel-linux-amd64
chmod +x perf-sentinel-linux-amd64
sudo mv perf-sentinel-linux-amd64 /usr/local/bin/perf-sentinel

Linux binaries are statically linked against musl and run on any distribution (Alpine, Debian, RHEL, Ubuntu any version) regardless of glibc version, and inside FROM scratch images.

From crates.io:

cargo install perf-sentinel

Docker:

docker run --rm -p 4317:4317 -p 4318:4318 \
  ghcr.io/robintra/perf-sentinel:0.5.5 watch --listen-address 0.0.0.0

Also available on Docker Hub: robintrassard/perf-sentinel:0.5.5.

Helm (chart 0.2.8 ships 0.5.5 as its appVersion default):

helm install perf-sentinel oci://ghcr.io/robintra/charts/perf-sentinel \
  --version 0.2.8 \
  --namespace observability --create-namespace

Verify the binary against SHA256SUMS.txt:

curl -LO https://github.com/robintra/perf-sentinel/releases/download/v0.5.5/SHA256SUMS.txt
sha256sum -c SHA256SUMS.txt --ignore-missing

Full diff: v0.5.4...v0.5.5

Don't miss a new perf-sentinel release

NewReleases is sending notifications on new releases.