v0.5.18
What's new in v0.5.18
v0.5.18 closes a cross-format gap that surfaced in the simulation-lab CI/CD validation work: the SARIF emitter now exposes the canonical finding signature so SARIF-aware tools (GitHub Code Scanning, GitLab SAST, Sonar) can match findings against .perf-sentinel-acknowledgments.toml without parsing the JSON output separately. The signature appears in two places per result, properties.signature for parity with the existing ack metadata in properties and fingerprints["perfsentinel/v1"] for SARIF v2.1.0 native deduplication. Both fields hold the same value, pick whichever one matches the ingestion model of the tool consuming the SARIF.
The release also tightens the canonical signature against Trojan Source spoofing (CVE-2021-42574). compute_signature now strips Unicode BiDi-override and invisible-format characters from service and source_endpoint before constructing the signature, so a hostile span attribute like service = "alice<RLO>@evil.com" cannot fork ack matching from a visually identical legitimate entry. The same sanitizer was already applied to ack metadata at SARIF emission time in 0.5.17, this release pulls it down to the signature construction site so the entire matching chain (TOML file, JSON output, SARIF output) shares the canonical form.
Finally, the docs/ci-templates/ reference templates (GitLab CI, GitHub Actions, Jenkins) had their PERF_SENTINEL_VERSION pin bumped from 0.5.8 to 0.5.17 after the 0.5.17 tag was cut. This release matches the published binary version to the templates so a fresh curl https://raw.githubusercontent.com/.../docs/ci-templates/github-actions.yml no longer pulls a stale pin.
Added
SarifProperties.signature: Option<String>field on the SARIF result properties bag, populated fromFinding.signaturewhen non-empty. Skipped viaserde(skip_serializing_if = "Option::is_none")on legacy baselines (pre-0.5.17 reports without the field).SarifResult.fingerprints: Option<BTreeMap<&'static str, String>>field on the SARIF result, single-entry map keyed by"perfsentinel/v1", value is the canonical signature. SARIF v2.1.0 section 3.27.17 fingerprint, used by GitHub Code Scanning and GitLab SAST for deduplication across runs.BTreeMapoverHashMapfor stable JSON ordering,&'static strkey over ownedStringto skip one allocation per finding.- Signature emission for acknowledged findings. When
--show-acknowledgedis set, each acked SARIF result carries the sameproperties.signatureandfingerprints["perfsentinel/v1"]so a tool that round-trips the SARIF output back into the ack file can copy-paste the value directly. docs/SARIF.mdanddocs/FR/SARIF-FR.mdnew dedicated reference for the SARIF format emitted by perf-sentinel: per-result fields, tool driver, schema URL, with cross-link toACKNOWLEDGMENTS.mdfor the cross-format ack matching workflow.- "SARIF integration" section in
docs/ACKNOWLEDGMENTS.mdanddocs/FR/ACKNOWLEDGMENTS-FR.mdexplaining the two emission sites and when to pickproperties.signaturevsfingerprints["perfsentinel/v1"]based on the consumer. - 5 new tests: 4 unit tests in
crates/sentinel-core/src/report/sarif.rs(signature in properties, signature in fingerprints, both omitted when empty, acked finding carries both), 1 e2e test incrates/sentinel-cli/tests/e2e.rs(cli_signature_consistent_across_json_and_sarif) that runsanalyzetwice on the same fixture in JSON and SARIF mode and assertsJSON.findings[i].signature == SARIF.results[i].properties.signature == SARIF.results[i].fingerprints["perfsentinel/v1"]. The e2e test guards against future format drift between the two emit paths. - 1 unit test in
crates/sentinel-core/src/acknowledgments.rs(compute_signature_strips_bidi_and_invisible_from_service_and_endpoint) verifying thatservice = "alice\u{202E}@evil.com"andservice = "alice@evil.com"produce the same canonical signature so a hostile span attribute cannot fork ack matching.
Changed
compute_signaturestrips BiDi and invisible-format characters fromserviceandsource_endpointbefore formatting the canonical signature. Reuses the existingstrip_bidi_and_invisiblehelper from the SARIF emitter, now exposed aspub(crate)so the discipline stays consistent across the matching chain. The hash component (template SHA-256 prefix) is unchanged. In practice no production service has BiDi characters in its name, the change is defense in depth.acknowledged_finding_to_resultmutatesSarifPropertiesin place instead of rebuilding the struct after the call tofinding_to_result. Saves one allocation per acknowledged finding and removes the duplicate signature-capture guard that would have drifted as new fields are added toSarifPropertiesover time.docs/ci-templates/PERF_SENTINEL_VERSIONpin bumped from0.5.8to0.5.17acrossgitlab-ci.yml,github-actions.yml,github-actions-baseline.yml, andjenkinsfile.groovy. Already merged in commite75166bafter the 0.5.17 tag was cut, materialized in this release so users curling the templates pull a recent binary by default.
Behavior
- Default behavior preserved. Active findings continue to render the same way in JSON, HTML, and terminal output. The new SARIF fields are additive and skipped when the source signature is empty, so existing SARIF consumers parse the output unchanged. The signature value itself is identical to 0.5.17 for any finding whose
serviceandsource_endpointare pure ASCII (the overwhelming majority of production setups). Acks created in 0.5.17 against ASCII-named services continue to match in 0.5.18 byte-for-byte. - Edge case for non-ASCII service names with BiDi characters. If a
.perf-sentinel-acknowledgments.tomlentry was created in 0.5.17 against a service whose name carried BiDi or zero-width format characters (extremely rare), the entry will not match in 0.5.18 because the new signature strips those characters. Re-runanalyze --format json | jq '.findings[].signature'to capture the new signature and update the TOML.
Documentation
docs/SARIF.mdanddocs/FR/SARIF-FR.mddocument the per-result fields emitted by perf-sentinel, including the newproperties.signatureandfingerprints["perfsentinel/v1"]. Reference for downstream tooling that consumes the SARIF output.docs/ACKNOWLEDGMENTS.mdanddocs/FR/ACKNOWLEDGMENTS-FR.mdgain a "SARIF integration" section explaining the two emission sites and the cross-format matching workflow. The doc clarifies that the signature value is identical between JSON and SARIF, so tools can pick whichever surface fits their ingestion path.README.mdandREADME-FR.mdsimplified the global-integration diagram to drop the dark-variant<picture>block in favor of a singlerendering. Cosmetic, no scope change.
Install
Prebuilt binaries (Linux amd64 / arm64, macOS arm64, Windows amd64):
curl -LO https://github.com/robintra/perf-sentinel/releases/download/v0.5.18/perf-sentinel-linux-amd64
chmod +x perf-sentinel-linux-amd64
sudo mv perf-sentinel-linux-amd64 /usr/local/bin/perf-sentinelLinux 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 --version 0.5.18Docker:
docker run --rm -p 4317:4317 -p 4318:4318 \
ghcr.io/robintra/perf-sentinel:0.5.18 watch --listen-address 0.0.0.0Also available on Docker Hub: robintrassard/perf-sentinel:0.5.18.
Helm (chart 0.2.21 ships 0.5.18 as its appVersion default):
helm install perf-sentinel oci://ghcr.io/robintra/charts/perf-sentinel \
--version 0.2.21 \
--namespace observability --create-namespaceVerify the binary against SHA256SUMS.txt:
curl -LO https://github.com/robintra/perf-sentinel/releases/download/v0.5.18/SHA256SUMS.txt
sha256sum -c SHA256SUMS.txt --ignore-missingFull diff: v0.5.17...v0.5.18