ManifestCache

Struct ManifestCache 

Source
pub struct ManifestCache {
    rollouts_dir: PathBuf,
    fleet_dir: PathBuf,
    trust_path: PathBuf,
    freshness_window: Duration,
}

Fields§

§rollouts_dir: PathBuf§fleet_dir: PathBuf§trust_path: PathBuf§freshness_window: Duration

Implementations§

Source§

impl ManifestCache

Source

pub fn new(state_dir: &Path, trust_path: &Path) -> Self

Source

pub fn new_with_freshness( state_dir: &Path, trust_path: &Path, freshness_window: Duration, ) -> Self

Tunable-freshness constructor. Tests with fixed-signedAt fixtures pass a longer window so old signed bytes still verify; production uses Self::new which pins DEFAULT_FRESHNESS_WINDOW_SECS.

Source

pub fn new_default(state_dir: &Path) -> Self

Construct a ManifestCache rooted under state_dir/{rollouts,fleet}/ and pointed at the conventional DEFAULT_TRUST_PATH. The longpoll worker uses this; tests use Self::new to inject a tempdir-rooted trust file.

Source

fn manifest_path(&self, rollout_id: &str) -> PathBuf

Source

fn signature_path(&self, rollout_id: &str) -> PathBuf

Source

fn fleet_path(&self) -> PathBuf

Source

fn fleet_sig_path(&self) -> PathBuf

Source

pub fn read_cached_bytes(&self, rollout_id: &str) -> Option<(Vec<u8>, Vec<u8>)>

Reads (manifest, sig) bytes if both exist; does NOT verify.

Source

fn load_trust_roots( &self, now: DateTime<Utc>, ) -> Result<(Vec<TrustedPubkey>, Option<DateTime<Utc>>)>

Source

fn validate_rollout_id_for_path(rollout_id: &str) -> Result<(), ManifestError>

Path-traversal sanity check on the rollout_id string before it is embedded in any filesystem path. Mirrors the CP route validator’s shape (RFC-0008 §6.3 canonical format "channel@channel_ref"); both layers refuse / and .. so neither side can be coerced into reading a file outside its rollouts directory.

Source

fn verify_bytes( &self, manifest_bytes: &[u8], signature_bytes: &[u8], advertised_rollout_id: &str, ) -> Result<VerifiedRolloutManifest, ManifestError>

Source

fn assert_rollout_id_matches( manifest: &RolloutManifest, advertised_rollout_id: &str, ) -> Result<(), ManifestError>

Discriminator per RFC-0008 §6.3: the canonical identity is "{channel}@{channel_ref}" derived from the parsed manifest’s fields. Defense-in-depth that the advertised id matches the manifest’s actual identity; the signature verify above already authenticates the bytes, so this catches filename / advertised-id substitution attacks where attacker-signed bytes carrying a different (channel, channel_ref) arrive at a path claiming the canonical id of a different rollout.

Source

fn assert_membership( manifest: &RolloutManifest, hostname: &str, wave_index: u32, ) -> Result<(), ManifestError>

Source

fn assert_target_closure( manifest: &RolloutManifest, hostname: &str, expected_target_closure: &str, ) -> Result<(), ManifestError>

RFC-0005 §4.1 advisory-payload contract: agent acts on a Dispatch only if the dispatched target_closure matches the manifest’s declared target_closure for this host. Pure function; tested in isolation. The dispatch path’s canonical entry composes this with [fetch_or_load] via [ensure_for_dispatch].

Source

fn write_cache( &self, rollout_id: &str, manifest_bytes: &[u8], sig_bytes: &[u8], ) -> Result<()>

Source

pub async fn fetch_or_load( &self, client: &Client, cp_url: &str, rollout_id: &str, ) -> Result<VerifiedRolloutManifest, ManifestError>

Disk-cache hit re-verifies bytes (defense in depth); miss OR cache verify-failure fetches from CP, verifies, writes through. Public so the periodic manifest_poll worker can fetch rollouts independently of any dispatch arrival (agent-side feed).

LOADBEARING: verify-failure falls through to fetch. Returning the verify error directly would leave a stale cached manifest permanently stuck on freshness/signature errors without ever attempting a CP refresh.

Source

pub async fn ensure( &self, client: &Client, cp_url: &str, rollout_id: &str, hostname: &str, wave_index: u32, ) -> Result<VerifiedRolloutManifest, ManifestError>

Fetch + verify a manifest, then assert (hostname, wave_index) membership. Used by callers that need the explicit wave-index sanity check; the dispatch path uses Self::ensure_for_dispatch instead.

Source

pub async fn ensure_for_dispatch( &self, client: &Client, cp_url: &str, rollout_id: &str, hostname: &str, expected_target_closure: &str, ) -> Result<VerifiedRolloutManifest, ManifestError>

Canonical dispatch entry: fetch + verify the manifest, then assert the dispatched target_closure matches the manifest’s declaration for this host (RFC-0005 §4.1). The longpoll worker’s only path from a DispatchResponse into the reducer.

Source

fn read_cached_fleet_bytes(&self) -> Option<(Vec<u8>, Vec<u8>)>

Source

fn write_fleet_cache( &self, artifact_bytes: &[u8], sig_bytes: &[u8], ) -> Result<()>

Source

fn verify_fleet_bytes( &self, artifact_bytes: &[u8], signature_bytes: &[u8], ) -> Result<VerifiedFleet, ManifestError>

Source

pub async fn fetch_or_load_fleet( &self, client: &Client, cp_url: &str, ) -> Result<(VerifiedFleet, String), ManifestError>

Disk-cache hit re-verifies bytes; miss OR cache verify-failure fetches /v1/fleet.resolved + /sig from CP, verifies, writes through. Returns the verified struct paired with canonical_hash_from_bytes(artifact_bytes) so the periodic manifest_poll worker can cross-check each fetched rollout’s fleet_resolved_hash against this anchor (per the architect’s amendment to the d010-feed plan, restated under Option C: discriminator moves from this function’s signature into the worker’s tick logic as a cross-consistency check between the two signed sources).

LOADBEARING: verify-failure falls through to fetch. Returning the cache’s verify Err without attempting CP refresh would leave an aged-out cached manifest permanently stuck — every manifest_poll tick re-verifying the same stale bytes, returning Stale, and the reducer’s advance_tick pass-gate would have no fresh manifest to consult.

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
§

impl<'a, T, E> AsTaggedExplicit<'a, E> for T
where T: 'a,

§

fn explicit(self, class: Class, tag: u32) -> TaggedParser<'a, Explicit, Self, E>

§

impl<'a, T, E> AsTaggedImplicit<'a, E> for T
where T: 'a,

§

fn implicit( self, class: Class, constructed: bool, tag: u32, ) -> TaggedParser<'a, Implicit, Self, E>

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

§

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