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-signednot passed), 3 (input error: unreadable, JSON invalid, oversized, temp file collision, write failure). - Atomic write hardened with
OpenOptions::create_new(true)plusO_NOFOLLOWon unix. A stale or symlinked<output>.tmpaborts the bake with exit 3 instead of being silently clobbered. The temp filename appends.tmpto the output path rather than replacing the extension, so a path likereport.tmpdoes not collide with itself. - 64 MiB input size cap enforced via
fs::metadataprecheck before allocation. Same cap mirrored onverify-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_terminalandsafe_urlnow strip the C1 control range0x80..=0x9F(CSIU+009B, STU+009C, OSCU+009Dhonoured by VT-family terminals when 8-bit controls are enabled). The filter switched from abytes()scan to achars()scan to catch the multi-byte UTF-8 encoding of C1 codepoints. Workspace-wide impact, every render boundary inrender.rs,tui.rs,ack.rs,query.rs,explain.rs,disclose.rs,verify_hash.rs,html.rsbenefits transitively.sentinel_core::config::has_control_charextended with the same range. A malicious.perf-sentinel.tomlplacing a C1 byte indisclose_output_path,auth_token, or any field that ends up formatted into atracing::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 throughsanitize_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.mdanddocs/FR/REPORTING-FR.md: new section "Computing a canonical content hash withhash-bake(0.7.2+)" with the exit code table.docs/design/10-SIGSTORE-ATTESTATION.mdand 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 theirbinary_verification_urlto 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.jsongh CLI 2.49 or newer required for gh attestation verify (unchanged from v0.7.1).
Full Changelog: v0.7.1...v0.7.2