pub struct TierPermissionHandler { /* private fields */ }Expand description
Bridges a car_policy::PermissionGate into the authorization
pipeline’s permission stage.
This is where the permission-tier model (survey §3.4.3, §5.2.5) meets
the existing pipeline: the gate classifies each action’s risk tier,
compares it to the session’s granted standing authority, and consults
the durable approval ledger. Its decision maps onto the pipeline’s
existing vocabulary — Allow proceeds, NeedsApproval becomes
AskUser (autonomy suspended pending a human decision), and a prior
rejection becomes Deny. Every decision is audited to the event log
as a PermissionDecision event so the tier reasoning is inspectable
rather than implicit.
§Two axes on one event
The audited event carries reversibility alongside required_tier,
from car_policy::classify_reversibility — the independent answer to
can this be undone? The gate itself does not consult it and its
decision does not depend on it; the field is recorded because the two
questions used to be fused inside PermissionTier and an audit trail
that reports only the ladder cannot tell a git push (recoverable) from
a charged card (not) — both arrive as full_access / needs_approval.
Splitting them at the point of record is what lets a later gate, a
reviewer, or a post-hoc analysis distinguish the two without re-deriving
the classification from a tool name months later. See
docs/proposals/shepherd-substrate-adoption.md.
Implementations§
Source§impl TierPermissionHandler
impl TierPermissionHandler
pub fn new(gate: Arc<RwLock<PermissionGate>>) -> Self
Sourcepub fn with_event_log(self, log: Arc<Mutex<EventLog>>) -> Self
pub fn with_event_log(self, log: Arc<Mutex<EventLog>>) -> Self
Audit each gate decision to this event log as a PermissionDecision.
Sourcepub async fn record_approval(
&self,
action: &Action,
approve: bool,
reviewer: &str,
reason: &str,
evidence: Option<String>,
) -> Result<ApprovalRecord>
pub async fn record_approval( &self, action: &Action, approve: bool, reviewer: &str, reason: &str, evidence: Option<String>, ) -> Result<ApprovalRecord>
Record a durable human-in-the-loop decision through the gate and
emit it to the event log as an ApprovalRecorded event — the
auditable state transition §5.2.5 calls for (“who approved/rejected
what, when, on what evidence”). approve=false records a rejection.
Errs when the ledger journal write fails — the decision was NOT
recorded, and no ApprovalRecorded event is emitted (review A7).
Trait Implementations§
Source§impl PermissionHandler for TierPermissionHandler
impl PermissionHandler for TierPermissionHandler
Source§fn check<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
_tool_name: &'life1 str,
action: &'life2 Action,
) -> Pin<Box<dyn Future<Output = AuthzDecision> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn check<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
_tool_name: &'life1 str,
action: &'life2 Action,
) -> Pin<Box<dyn Future<Output = AuthzDecision> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Auto Trait Implementations§
impl !RefUnwindSafe for TierPermissionHandler
impl !UnwindSafe for TierPermissionHandler
impl Freeze for TierPermissionHandler
impl Send for TierPermissionHandler
impl Sync for TierPermissionHandler
impl Unpin for TierPermissionHandler
impl UnsafeUnpin for TierPermissionHandler
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
impl<T> ErasedDestructor for Twhere
T: 'static,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
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 moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
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