audit_trail/lib.rs
1//! # audit-trail
2//!
3//! Tamper-evident audit logging via cryptographically chained records.
4//!
5//! Every audited event becomes a [`Record`] capturing the canonical
6//! who / what / when / where / result tuple, together with the hash of the
7//! preceding record. Any modification to a past record breaks the chain at
8//! that point and is trivially detectable on re-verification.
9//!
10//! ## Public surface
11//!
12//! - [`Record`] — the audited event (5W + chain links).
13//! - [`Chain`] — the append-only chain that wires a [`Hasher`], a [`Sink`],
14//! and a [`Clock`].
15//! - [`Hasher`] — pluggable hash function (SHA-256, BLAKE3, …).
16//! - [`Sink`] — pluggable backend that persists each record.
17//! - [`Clock`] — pluggable time source.
18//! - [`Verifier`] — replays a chain and proves it is untampered.
19//! - [`codec`] — stable binary record encoding (`alloc` feature).
20//! - [`FileSink`] / [`FileReader`] — append-only file persistence
21//! (`std` feature).
22//!
23//! ## Optional features
24//!
25//! - `std` (default) — enables `std`-dependent items ([`FileSink`],
26//! [`FileReader`]) and `std::error::Error` impls. Implies `alloc`.
27//! - `alloc` — enables owned-record and in-memory sink types
28//! ([`OwnedRecord`], [`MemorySink`]) plus the [`codec`] module for
29//! serialising records to bytes.
30//! - `sha2` — enables the reference `Sha256Hasher` backed by the `sha2`
31//! crate.
32//! - `blake3` — enables the reference `Blake3Hasher` backed by the
33//! `blake3` crate.
34//!
35//! Without any optional features, the crate ships traits, the `Chain`,
36//! and the `Verifier` only — callers supply their own hasher, sink, and
37//! clock.
38//!
39//! ## Design principles
40//!
41//! - **Zero-allocation hot path.** Records borrow their string fields; the
42//! append path never touches the heap.
43//! - **No async runtime dependency.** The append API is synchronous.
44//! - **`no_std` capable.** Enable with `default-features = false`.
45//!
46//! See `.dev/ROADMAP.md` for the path to 1.0.
47//!
48//! ## License
49//!
50//! Dual-licensed under Apache-2.0 OR MIT.
51
52#![doc(html_root_url = "https://docs.rs/audit-trail")]
53#![cfg_attr(docsrs, feature(doc_cfg))]
54#![cfg_attr(not(feature = "std"), no_std)]
55#![deny(missing_docs)]
56#![deny(unsafe_op_in_unsafe_fn)]
57#![deny(unused_must_use)]
58#![deny(unused_results)]
59#![deny(clippy::unwrap_used)]
60#![deny(clippy::expect_used)]
61#![deny(clippy::todo)]
62#![deny(clippy::unimplemented)]
63#![deny(clippy::print_stdout)]
64#![deny(clippy::print_stderr)]
65#![deny(clippy::dbg_macro)]
66#![deny(clippy::undocumented_unsafe_blocks)]
67#![deny(clippy::missing_safety_doc)]
68
69#[cfg(feature = "alloc")]
70extern crate alloc;
71
72/// Crate version string, populated by Cargo at build time.
73pub const VERSION: &str = env!("CARGO_PKG_VERSION");
74
75mod canonical;
76mod chain;
77mod clock;
78mod error;
79mod hash;
80mod record;
81mod sink;
82mod verify;
83
84#[cfg(feature = "alloc")]
85pub mod codec;
86#[cfg(feature = "alloc")]
87mod owned;
88#[cfg(feature = "std")]
89mod readers;
90#[cfg(feature = "alloc")]
91mod sinks;
92
93#[cfg(any(feature = "sha2", feature = "blake3"))]
94mod hashers;
95
96pub use chain::Chain;
97#[cfg(feature = "std")]
98#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
99pub use clock::SystemClock;
100pub use clock::{Clock, Timestamp};
101pub use error::{Error, Result, SinkError};
102pub use hash::{Digest, HASH_LEN, Hasher};
103pub use record::{Action, Actor, Outcome, Record, RecordId, Target};
104pub use sink::Sink;
105pub use verify::Verifier;
106
107#[cfg(feature = "alloc")]
108#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
109pub use owned::OwnedRecord;
110
111#[cfg(feature = "alloc")]
112#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
113pub use sinks::MemorySink;
114
115#[cfg(feature = "std")]
116#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
117pub use readers::FileReader;
118
119#[cfg(feature = "std")]
120#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
121pub use sinks::FileSink;
122
123#[cfg(feature = "blake3")]
124#[cfg_attr(docsrs, doc(cfg(feature = "blake3")))]
125pub use hashers::Blake3Hasher;
126
127#[cfg(feature = "sha2")]
128#[cfg_attr(docsrs, doc(cfg(feature = "sha2")))]
129pub use hashers::Sha256Hasher;