github robintra/perf-sentinel v0.7.2

latest releases: chart-v0.9.3, v0.9.3, chart-v0.9.2...
one month ago

What's new in v0.7.2

v0.7.2 adds the perf-sentinel hash-bake subcommand and applies a defense-in-depth hardening pass across two parallel surfaces: terminal rendering and TOML config validation. No breaking change on the daemon, the disclose, verify-hash, or report JSON contracts published in v0.7.1.

New subcommand: hash-bake

perf-sentinel hash-bake --report <PATH> --output <PATH> [--allow-signed] reads the report, recomputes the canonical SHA-256 content_hash via the same compute_content_hash API the disclosure pipeline already uses, writes the hash into integrity.content_hash, and saves the result via an atomic temp+rename. Intended for test fixture generation and for debugging reports whose hash drifted from canonical after manual edits.

  • Exit codes: 0 (success), 1 (refused: report already signed and --allow-signed not passed), 3 (input error: unreadable, JSON invalid, oversized, temp file collision, write failure).
  • Atomic write hardened with OpenOptions::create_new(true) plus O_NOFOLLOW on unix. A stale or symlinked <output>.tmp aborts the bake with exit 3 instead of being silently clobbered. The temp filename appends .tmp to the output path rather than replacing the extension, so a path like report.tmp does not collide with itself.
  • 64 MiB input size cap enforced via fs::metadata precheck before allocation. Same cap mirrored on verify-hash --report <local> so both subcommands behave identically against a multi-GB JSON fed by a poisoned mirror or a recursive symlink target.
  • Refused signed reports by default: re-baking does not invalidate an existing signature (the canonical form blanks integrity.signature), but the default refusal guards against accidental overwrites of signed disclosures. Opt in with --allow-signed.

The output writes integrity.content_hash only. integrity.signature, integrity.binary_attestation, and report_metadata.integrity_level are not touched.

Defense-in-depth: C1 control range stripped at every terminal-bound surface

Two parallel ANSI injection vectors closed at once:

  • sentinel_core::text_safety::sanitize_for_terminal and safe_url now strip the C1 control range 0x80..=0x9F (CSI U+009B, ST U+009C, OSC U+009D honoured by VT-family terminals when 8-bit controls are enabled). The filter switched from a bytes() scan to a chars() scan to catch the multi-byte UTF-8 encoding of C1 codepoints. Workspace-wide impact, every render boundary in render.rs, tui.rs, ack.rs, query.rs, explain.rs, disclose.rs, verify_hash.rs, html.rs benefits transitively.
  • sentinel_core::config::has_control_char extended with the same range. A malicious .perf-sentinel.toml placing a C1 byte in disclose_output_path, auth_token, or any field that ends up formatted into a tracing::warn! line on stderr can no longer survive load-time validation. The TOML loader is the right gate, the warning emission path does not route through sanitize_for_terminal.

These two changes are independent of the hash-bake feature itself but ship together as part of the same release.

verify-hash consistency pass

verify-hash --report <local> previously had no size cap on the local file. Same 64 MiB cap as hash-bake now applies, gated by an fs::metadata precheck. Remote --url mode is unaffected, it keeps the tighter MAX_REMOTE_BYTES = 10 MiB cap. Error wording and path sanitisation are aligned between the two subcommands so an operator parsing stderr with grep "exceeds the .* cap\." gets consistent matching on either failure path. The cap value lives in a shared crates/sentinel-cli/src/limits.rs::MAX_LOCAL_REPORT_BYTES constant consumed by both modules.

Documentation

  • docs/REPORTING.md and docs/FR/REPORTING-FR.md: new section "Computing a canonical content hash with hash-bake (0.7.2+)" with the exit code table.
  • docs/design/10-SIGSTORE-ATTESTATION.md and FR mirror: new "Tooling: hash-bake" paragraph positioning the subcommand as a fixture and debug tool complementing the disclosure pipeline, not part of the signed-disclosure chain itself.
  • Example reports under docs/schemas/examples/ bump their binary_verification_url to v0.7.2.

Helm chart

charts/perf-sentinel 0.2.36 to 0.2.37, appVersion 0.7.1 to 0.7.2. The artifacthub.io/changes annotation surfaces the hash-bake addition on Artifact Hub. See chart-v0.2.37 release for the chart-side detail.

Why this is a patch and not a minor

The only externally-visible new capability is one additional subcommand. Every existing CLI surface (analyze, disclose, verify-hash, watch, report, inspect, tempo, jaeger-query, query, ack, pg-stat, bench, calibrate, diff, explain, completions, demo) is preserved byte-for-byte. The report JSON schema, the Helm chart manifests, the OTLP listener wire format, the Prometheus metrics surface, and the verify-hash exit code palette are unchanged. The defense-in-depth hardening tightens previously over-permissive validation, no legitimate input that was accepted in v0.7.1 is rejected by v0.7.2 (C1 control bytes are not part of any specified TOML or JSON form).

Verifying this release

# Binary integrity via SLSA Build L3 attestation
gh attestation verify perf-sentinel-linux-amd64 \
  --owner robintra --repo 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.7.2" \
  --expected-issuer "https://token.actions.githubusercontent.com"

# Bake the canonical hash of a hand-edited fixture
perf-sentinel hash-bake --report fixture.json --output fixture.json

gh CLI 2.49 or newer required for gh attestation verify (unchanged from v0.7.1).

Full Changelog: v0.7.1...v0.7.2

Don't miss a new perf-sentinel release

NewReleases is sending notifications on new releases.