Skip to main content

ContextChain

Struct ContextChain 

Source
pub struct ContextChain { /* private fields */ }
Expand description

Error chain for tracking causality across system boundaries.

§Purpose

Honeypot systems often need to track error propagation across multiple subsystems while maintaining public/internal separation at each hop.

This type provides:

  • Stack-like error accumulation
  • Causality timestamps
  • Cross-boundary sanitization

§Security

Each link in the chain maintains its own public/internal separation. Exposing the chain to external systems only reveals public contexts.

§Clone Policy

⚠️ This type does NOT implement Clone.

Cloning error chains would:

  • Duplicate sensitive internal contexts across memory
  • Create multiple zeroization sites with unpredictable drop order
  • Violate threat model assumptions about data lifetime

If you need to share chain information:

  • Use borrowing (&ContextChain) for read-only access
  • Use external_summary() for public-safe string representation
  • Use safe_clone_public() to create a sanitized clone (see method docs)

This is a deliberate design decision to prevent accidental security violations via casual .clone() calls.

§Example

use palisade_errors::{ContextChain, DualContextError, OperationCategory};

let root = DualContextError::with_lie(
    "Operation failed",
    "Database connection refused",
    OperationCategory::IO,
);

let mut chain = ContextChain::new(root);

let retry_failed = DualContextError::with_lie(
    "Retry failed",
    "Max retries (3) exceeded",
    OperationCategory::System,
);

chain.push(retry_failed);

assert_eq!(chain.depth(), 2);

Implementations§

Source§

impl ContextChain

Source

pub fn new(root: DualContextError) -> Self

Create a new chain with a root error.

Source

pub fn push(&mut self, error: DualContextError)

Add a new error to the chain (as the new head).

§Example
let mut chain = ContextChain::new(root);

let next_error = DualContextError::with_lie(
    "Propagated error",
    "Original error: connection refused",
    OperationCategory::System,
);

chain.push(next_error);
Source

pub fn root(&self) -> &DualContextError

Get the root cause error (first in chain).

Source

pub fn head(&self) -> &DualContextError

Get the final error (last in chain).

Source

pub fn depth(&self) -> usize

Get the chain depth (number of errors).

Source

pub fn iter(&self) -> impl Iterator<Item = &DualContextError>

Iterate over the error chain from root to head.

Source

pub fn external_summary(&self) -> String

Get external representation of the entire chain (public contexts only).

§Returns

A string showing the public message progression from root to head.

§Use Case

This method exists as the safe alternative to cloning for most scenarios:

  • Logging to external systems
  • User-facing error messages
  • Telemetry and alerting

If you need the chain structure itself without internal contexts, consider whether you actually need the structure or just the narrative flow. In most cases, this string representation is sufficient.

§Performance

Pre-calculates capacity to avoid multiple allocations during formatting.

§Example
let external = chain.external_summary();
// Output: "Database error → Retry failed"

Trait Implementations§

Source§

impl Drop for ContextChain

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

impl Zeroize for ContextChain

Source§

fn zeroize(&mut self)

Zero out this object from memory using Rust intrinsics which ensure the zeroization operation is not “optimized away” by the compiler.

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.

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, 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.