fix(buzz-audit): truncate created_at to microseconds before hashing#2678
Closed
Christian-Sidak wants to merge 1 commit into
Closed
fix(buzz-audit): truncate created_at to microseconds before hashing#2678Christian-Sidak wants to merge 1 commit into
Christian-Sidak wants to merge 1 commit into
Conversation
`Utc::now()` returns nanosecond precision but Postgres TIMESTAMPTZ stores only microseconds. `verify_chain` re-reads the truncated value and recomputes the digest, so the hashes never matched -- every chain failed verification on untampered data, making tamper detection useless. Fix: call `.trunc_subsecs(6)` in `log_inner` so the value hashed at write time is identical to what Postgres returns on read. Adds three Postgres-free regression tests to `hash.rs` documenting the invariant, the root cause, and the round-trip behaviour. Fixes block#2637 Signed-off-by: Christian-Sidak <61099993+Christian-Sidak@users.noreply.github.com>
Christian-Sidak
force-pushed
the
fix/issue-2637
branch
from
July 24, 2026 04:16
1be2e77 to
77e87e1
Compare
Member
|
🤖 hey — thanks for tracking this down, the diagnosis is exactly right (ns-precision |
Author
|
Makes sense, normalizing inside compute_hash is the more durable fix and the better test to carry. Closing in favor of #2638. Thanks for the quick review! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Utc::now()returns nanosecond precision but PostgresTIMESTAMPTZstores only microseconds;to_rfc3339()emits 9 vs 6 fractional digits, producing a different byte string and thus a different SHA-256 digestverify_chainrecomputes the hash from the stored (truncated) row and compares it to the written hash -- they never matched, so every chain failed verification on untampered dataAuditError::HashMismatchthe steady state, rendering tamper detection uselessFix: call
.trunc_subsecs(6)inlog_innerbefore computing the hash so the value hashed at write time is identical to what Postgres returns on read. One-line change at the single choke point (NewAuditEntrycarries no timestamp; all callers go throughlog_inner).Adds three Postgres-free regression tests to
hash.rs:nanosecond_and_microsecond_timestamps_hash_differently-- documents the root causehash_survives_microsecond_precision_round_trip-- proves the fix worksuntruncated_nanosecond_timestamp_fails_round_trip-- regression guardTest plan
cargo fmt -p buzz-auditpasses (no formatting changes)hash.rscover the invariant, the trap, and the round-trip#[ignore = "requires Postgres"]chain tests inservice.rsare expected to pass once run against a real database (per the issue, they fail on unpatched main and should pass with this fix)Fixes #2637