Skip to main content

ChainContent

Struct ChainContent 

Source
pub struct ChainContent<'a> {
    pub seq: u64,
    pub key_id: &'a str,
    pub transaction_id: &'a str,
    pub request_id: &'a str,
    pub request_hash: &'a str,
    pub action_name: &'a str,
    pub risk_level: RiskLevel,
    pub summary: &'a str,
    pub approval_id: Option<&'a str>,
    pub warnings_json: &'a str,
    pub created_at: &'a str,
}
Expand description

Immutable fields hashed into the chain. Status is intentionally absent — see module docs.

§Security contract — chain-content immutability

Every field in this struct is captured once at INSERT time and baked into chain_hash = ed25519_sign(canonical(self) || prev_chain_hash, key). After the row is written the hash is a one-time commitment: no field in this struct may ever be mutated in place.

summary is the field most likely to attract a future “let me just fix that typo” API. Do not add an update_summary (or similar) function. If a correction is genuinely needed, choose one of the two safe options:

  1. Insert a corrective row — a new transaction row that references the original transaction_id in its own summary, leaving the original row and its chain hash untouched.
  2. Extend the chain protocol — introduce a dedicated amendment record type with its own chain link, so that both the original commitment and the correction are auditable.

Any other approach silently breaks chain integrity: verify_chain will flag the modified row as Broken because the stored signature will no longer verify against the row’s content.

The canonical serialisation is stable across SQLite/Postgres backends. Each field is emitted as

    <tag-name> 0x1E <tag-value> 0x1F

where 0x1E is the tag/value separator within a single field and 0x1F is the field separator that terminates the field and introduces the next one. We use the ASCII C0 byte values RS (0x1E) and US (0x1F) because they are guaranteed not to appear in any normal text field, but our role assignment is the inverse of the ASCII C0 convention (where RS = “record separator” and US = “unit separator”). The names are kept in the source for byte-level traceability against the canonical buffer, not as a claim about ASCII semantics.

Inside a value, the four bytes \\, NUL, RS, US are escaped to \\\\, \\0, \\1E, \\1F respectively. The escape table is prefix-free (every escape starts with \\), so any value can be injected without ambiguity. See push_field for the implementation and tests for the round-trip.

Fields§

§seq: u64§key_id: &'a str§transaction_id: &'a str§request_id: &'a str§request_hash: &'a str§action_name: &'a str§risk_level: RiskLevel§summary: &'a str

Human-readable description of the planned action.

Immutable after insert. This field is included in the chain hash (see ChainContent struct-level doc). It MUST NOT be updated after the row is written — doing so silently invalidates chain_hash and will be detected as VerifyOutcome::Broken by sysknife audit verify. See the struct-level security contract for the only safe correction strategies.

§approval_id: Option<&'a str>

Signed receipt commitment for daemon-created previews. Legacy/imported rows may be None; serialised as empty for wire compatibility.

§warnings_json: &'a str

JSON-canonical (sorted keys) array of warning strings.

§created_at: &'a str

Implementations§

Source§

impl<'a> ChainContent<'a>

Source

pub fn canonical_bytes(&self) -> Vec<u8> ⓘ

Stable canonical encoding of every field. Within each field the 0x1E byte separates tag from value, and 0x1F terminates the field; raw NUL becomes the two-byte escape \0.

Trait Implementations§

Source§

impl<'a> Clone for ChainContent<'a>

Source§

fn clone(&self) -> ChainContent<'a>

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<'a> Debug for ChainContent<'a>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<'a> Eq for ChainContent<'a>

Source§

impl<'a> PartialEq for ChainContent<'a>

Source§

fn eq(&self, other: &ChainContent<'a>) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl<'a> StructuralPartialEq for ChainContent<'a>

Auto Trait Implementations§

§

impl<'a> Freeze for ChainContent<'a>

§

impl<'a> RefUnwindSafe for ChainContent<'a>

§

impl<'a> Send for ChainContent<'a>

§

impl<'a> Sync for ChainContent<'a>

§

impl<'a> Unpin for ChainContent<'a>

§

impl<'a> UnsafeUnpin for ChainContent<'a>

§

impl<'a> UnwindSafe for ChainContent<'a>

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> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

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

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

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
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
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.
Source§

impl<T> WithSubscriber for T

Source§

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
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

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