Skip to main content

AuditLogger

Struct AuditLogger 

Source
pub struct AuditLogger {
    config: AuditConfig,
    entries: Mutex<Vec<AuditEntry>>,
    last_hmac: Mutex<String>,
}
Expand description

Audit logger for SOC2/GDPR compliance.

§HMAC Chain Integrity

When configured with an HMAC key, the logger maintains a cryptographic chain where each entry’s signature includes the previous entry’s signature. This creates an append-only log that detects tampering or deletion.

The chain starts with GENESIS_HMAC as the “previous” value for the first entry. Each subsequent entry includes the HMAC of the previous entry.

Fields§

§config: AuditConfig§entries: Mutex<Vec<AuditEntry>>§last_hmac: Mutex<String>

Last HMAC in the chain (for signing new entries).

Implementations§

Source§

impl AuditLogger

Source

pub fn new() -> Self

Creates a new audit logger with default config.

Source

pub fn with_config(config: AuditConfig) -> Self

Creates a new audit logger with custom config.

Source

pub fn log(&self, event: &MemoryEvent)

Logs an audit event.

Source

pub fn log_entry(&self, entry: AuditEntry)

Logs a custom audit entry.

If an HMAC key is configured, the entry is signed and chained to the previous entry before storage.

Source

fn sign_entry(&self, entry: AuditEntry) -> AuditEntry

Signs an entry with HMAC if configured, updating chain state.

Source

pub fn log_capture(&self, memory_id: &str, namespace: &str)

Logs a capture event.

Source

pub fn log_recall(&self, query: &str, result_count: usize)

Logs a search/recall event.

Source

pub fn log_sync(&self, pushed: usize, pulled: usize)

Logs a sync event.

Source

pub fn log_redaction(&self, memory_id: &str, redaction_types: &[String])

Logs a redaction event.

Source

pub fn log_pii_detection(&self, pii_types: &[String], context: Option<&str>)

Logs a PII detection event for GDPR/SOC2 compliance.

Records when PII is detected in content, including the types of PII found and the count. The actual PII values are NOT logged to avoid storing sensitive data in audit logs.

Source

pub fn log_pii_disclosure( &self, destination: &str, pii_types: &[String], data_subject_id: Option<&str>, purpose: &str, legal_basis: &str, )

Logs a PII disclosure event for GDPR/SOC2 compliance.

Records when data containing PII is disclosed to external systems such as:

  • LLM providers (Anthropic, OpenAI, Ollama, etc.)
  • Remote sync destinations
  • External APIs

The actual PII values are NOT logged to avoid storing sensitive data. Only metadata about the disclosure is recorded.

§Arguments
  • destination - The external system receiving the data (e.g., “anthropic”, “openai”)
  • pii_types - Types of PII being disclosed
  • data_subject_id - Optional identifier of the data subject (anonymized)
  • purpose - The purpose of the disclosure
  • legal_basis - Legal basis for disclosure (e.g., “consent”, “legitimate_interest”)
Source

pub fn log_bulk_pii_disclosure( &self, destination: &str, record_count: usize, pii_categories: &[String], purpose: &str, legal_basis: &str, )

Logs a bulk PII disclosure event for batch operations.

Similar to log_pii_disclosure but for bulk operations involving multiple data subjects or records.

§Arguments
  • destination - The external system receiving the data
  • record_count - Number of records being disclosed
  • pii_categories - Categories of PII being disclosed
  • purpose - The purpose of the disclosure
  • legal_basis - Legal basis for disclosure
Source

pub fn log_denied(&self, action: &str, reason: &str)

Logs an access denied event.

Source

pub fn recent_entries(&self, limit: usize) -> Vec<AuditEntry>

Returns recent audit entries.

Source

pub fn entries_since(&self, since: DateTime<Utc>) -> Vec<AuditEntry>

Returns all entries since a given timestamp.

Source

pub fn cleanup(&self)

Clears old entries beyond retention period.

Source

pub fn verify_chain(&self) -> Result<()>

Verifies the HMAC chain integrity of all entries.

Returns Ok(()) if all entries are valid and properly chained, or an error describing the first invalid entry found.

§Errors

Returns an error if:

  • No HMAC key is configured
  • An entry has an invalid or missing signature
  • The chain is broken (entry’s previous_hmac doesn’t match prior signature)
Source

pub const fn is_signing_enabled(&self) -> bool

Returns whether HMAC signing is enabled.

Source

fn event_to_entry(&self, event: &MemoryEvent) -> AuditEntry

Converts a MemoryEvent to an AuditEntry.

Source

fn append_to_file(&self, path: &Path, entry: &AuditEntry) -> Result<()>

Appends an entry to the log file.

§Security
  • Path canonicalization is performed to prevent TOCTOU race conditions where a symlink could be modified between path validation and file open.
  • On Unix, file permissions are set atomically to 0o600 (owner read/write only) at file creation time using OpenOptionsExt::mode() to prevent race conditions.
Source

fn canonicalize_path(path: &Path) -> Result<PathBuf>

Canonicalizes a path, handling non-existent files by canonicalizing the parent.

Source§

impl AuditLogger

Source

pub fn generate_access_review( &self, period_start: DateTime<Utc>, period_end: DateTime<Utc>, ) -> AccessReviewReport

Generates an access review report for the specified period.

§Arguments
  • period_start - Start of the review period
  • period_end - End of the review period
§Example
use chrono::{Duration, Utc};
use subcog::security::AuditLogger;

let logger = AuditLogger::new();
let end = Utc::now();
let start = end - Duration::days(30);

let report = logger.generate_access_review(start, end);
println!("Total events: {}", report.total_events);

Trait Implementations§

Source§

impl Default for AuditLogger

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> FutureExt for T

§

fn with_context(self, otel_cx: Context) -> WithContext<Self>

Attaches the provided Context to this type, returning a WithContext wrapper. Read more
§

fn with_current_context(self) -> WithContext<Self>

Attaches the current Context to this type, returning a WithContext wrapper. Read more
§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
§

impl<T> IntoRequest<T> for T

§

fn into_request(self) -> Request<T>

Wrap the input message T in a tonic::Request
§

impl<L> LayerExt<L> for L

§

fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>
where L: Layer<S>,

Applies the layer to a service and wraps it in [Layered].
§

impl<T> Pointable for T

§

const ALIGN: usize

The alignment of pointer.
§

type Init = T

The type for initializers.
§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
§

impl<T> PolicyExt for T
where T: ?Sized,

§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] only if self and other return Action::Follow. Read more
§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

impl<T> Allocation for T
where T: RefUnwindSafe + Send + Sync,