pub struct AclEntry {Show 14 fields
pub did: String,
pub role: Role,
pub label: Option<String>,
pub allowed_contexts: Vec<String>,
pub created_at: u64,
pub created_by: String,
pub expires_at: Option<u64>,
pub kind: ConsumerKind,
pub capabilities: Vec<Capability>,
pub device: Option<DeviceBinding>,
pub version: u32,
pub step_up_approver: Option<String>,
pub step_up_require: Option<StepUpMode>,
pub approve_scope: ApproveScope,
}Expand description
An entry in the Access Control List.
Fields§
§did: String§role: Role§label: Option<String>§allowed_contexts: Vec<String>§created_at: u64§created_by: String§expires_at: Option<u64>Unix-epoch seconds at which this entry expires and should be pruned by
the background sweeper. None is permanent (existing pre-Phase-2
behavior; entries serialized before this field existed deserialize with
this default).
kind: ConsumerKindConsumer kind: Companion (user-driven) vs Service (headless). New in
M1 (vault-credential-manager design). #[serde(default)] ⇒ pre-M1
rows deserialise as Service { Daemon }.
capabilities: Vec<Capability>Fine-grained capability set. Empty Vec on legacy rows; the auth
layer falls back to derived_capabilities_for_role when this
is empty so existing behaviour stays byte-identical.
device: Option<DeviceBinding>Optional Companion/Service device-binding metadata. Populated by
the M4 device/register/0.1 flow; absent on legacy rows and on
pure ACL entries that don’t represent a registered device.
version: u32Optimistic-concurrency version. Incremented on every
successful update; the route layer’s If-Match header
compares against this and returns 409 Conflict on a
stale write. Closes M6 from the May 2026 security review
— two admins editing the same DID concurrently no longer
silently lose one update.
#[serde(default)] so pre-versioning rows deserialise
with version=0. The first update bumps it to 1.
step_up_approver: Option<String>VID authorized to ratify an AAL2 step-up for this subject — the
recipient the VTA addresses an auth/step-up/approve-request/0.1 to
when a gated operation resolves to delegated mode (the holder’s
mobile authenticator or browser companion). None means no delegated
approver is configured: under a delegated floor the operation
fail-closes (the subject can’t self-approve a delegated requirement).
Mirrors the spec’s AclEntry.stepUp.approver.
#[serde(default)] so pre-existing rows deserialise as None.
step_up_require: Option<StepUpMode>Per-entry step-up override raising the system floor for this subject —
the spec’s AclEntry.stepUp.require. ADDITIVE-ONLY: the effective mode
is the strictest of (system floor, this override), so an override weaker
than the floor is ignored (see StepUpMode::strictest). Restricted to
self / delegated (a per-subject override never relaxes to
delegated-any); the ACL op layer rejects other values.
#[serde(default)] so pre-existing rows deserialise as None (no
override; the system floor applies unchanged).
approve_scope: ApproveScopeAuthority to confer access via an approval, decoupled from the
authority to act. Read only by the two conferral paths
(compute_delegated_contexts, delegated_any_approver_covers); it
never feeds require_admin/has_context_access. Lets an approver be
least-privilege (act nowhere, authorize across contexts). #[serde(default)]
⇒ pre-existing rows deserialise as ApproveScope::None.
Implementations§
Source§impl AclEntry
impl AclEntry
Sourcepub fn new(
did: impl Into<String>,
role: Role,
created_by: impl Into<String>,
) -> Self
pub fn new( did: impl Into<String>, role: Role, created_by: impl Into<String>, ) -> Self
Create an entry with the required identity fields. Optional metadata
takes sensible defaults: no label, no allowed_contexts, never
expires, default ConsumerKind, no capabilities, no device
binding, version = 0, and created_at = now. Layer non-defaults on
with the with_* builder methods.
This is the single construction entry point — adding a new optional field here defaults it everywhere, so callers don’t churn.
Sourcepub fn with_created_at(self, created_at: u64) -> Self
pub fn with_created_at(self, created_at: u64) -> Self
Override created_at (defaults to now). Use when replaying a known
timestamp — bootstrap import, tests, migration.
Sourcepub fn with_label(self, label: Option<String>) -> Self
pub fn with_label(self, label: Option<String>) -> Self
Set the optional human-readable label.
Sourcepub fn with_contexts(self, allowed_contexts: Vec<String>) -> Self
pub fn with_contexts(self, allowed_contexts: Vec<String>) -> Self
Set the allowed-contexts (scope) list.
Sourcepub fn with_expires_at(self, expires_at: Option<u64>) -> Self
pub fn with_expires_at(self, expires_at: Option<u64>) -> Self
Set the optional expiry (unix seconds). None is permanent.
Sourcepub fn with_kind(self, kind: ConsumerKind) -> Self
pub fn with_kind(self, kind: ConsumerKind) -> Self
Set the consumer kind (Companion vs Service).
Sourcepub fn with_capabilities(self, capabilities: Vec<Capability>) -> Self
pub fn with_capabilities(self, capabilities: Vec<Capability>) -> Self
Set the fine-grained capability set.
Sourcepub fn with_device(self, device: Option<DeviceBinding>) -> Self
pub fn with_device(self, device: Option<DeviceBinding>) -> Self
Attach optional Companion/Service device-binding metadata.
Sourcepub fn with_step_up_approver(self, approver: Option<String>) -> Self
pub fn with_step_up_approver(self, approver: Option<String>) -> Self
Set the delegated step-up approver VID (stepUp.approver).
Sourcepub fn with_step_up_require(self, require: Option<StepUpMode>) -> Self
pub fn with_step_up_require(self, require: Option<StepUpMode>) -> Self
Set the per-entry step-up override (stepUp.require).
Sourcepub fn with_approve_scope(self, approve_scope: ApproveScope) -> Self
pub fn with_approve_scope(self, approve_scope: ApproveScope) -> Self
Set the approve-authority scope (what this DID may confer via approval, without any authority to act).
Sourcepub fn act_scope(&self) -> ActScope
pub fn act_scope(&self) -> ActScope
This entry’s authority to act, decoded from (role, allowed_contexts). Use this rather than reading allowed_contexts
directly — see ActScope for why.
Sourcepub fn can_act_in(&self, context_id: &str) -> bool
pub fn can_act_in(&self, context_id: &str) -> bool
Whether this entry may act in context_id, honouring context ancestry.
Sourcepub fn is_super_admin(&self) -> bool
pub fn is_super_admin(&self) -> bool
Whether this entry is a super-admin: an admin whose ActScope is
unrestricted, mirroring AuthClaims::is_super_admin.
Sourcepub fn with_version(self, version: u32) -> Self
pub fn with_version(self, version: u32) -> Self
Set the optimistic-concurrency version (defaults to 0).
Sourcepub fn is_expired(&self, now_unix: u64) -> bool
pub fn is_expired(&self, now_unix: u64) -> bool
Returns true if this entry has passed its configured expires_at.
Permanent entries (no expires_at) never expire.
Sourcepub fn etag(&self) -> String
pub fn etag(&self) -> String
Strong validator string suitable for the ETag response
header and the If-Match precondition on subsequent
updates. Combines the DID and the version so a moving
version increment can never accidentally validate against
the wrong row.
Format: W/"<did_hash>:<version>" — W/ because the
underlying ACL entry isn’t byte-identical between writes
(timestamps, label edits don’t change semantic content
but do change bytes); the did_hash is a 64-bit FxHash
to keep the header short.
Trait Implementations§
Source§impl<'de> Deserialize<'de> for AclEntry
impl<'de> Deserialize<'de> for AclEntry
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Auto Trait Implementations§
impl Freeze for AclEntry
impl RefUnwindSafe for AclEntry
impl Send for AclEntry
impl Sync for AclEntry
impl Unpin for AclEntry
impl UnsafeUnpin for AclEntry
impl UnwindSafe for AclEntry
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
Source§impl<T> BorrowUnordered for T
impl<T> BorrowUnordered for T
fn as_unordered(&self) -> &Unordered<T>
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
Source§impl<'de, T, C> DeserializeTyped<'de, C> for Twhere
T: Deserialize<'de>,
impl<'de, T, C> DeserializeTyped<'de, C> for Twhere
T: Deserialize<'de>,
fn deserialize_typed<S>(
_: &C,
deserializer: S,
) -> Result<T, <S as Deserializer<'de>>::Error>where
S: Deserializer<'de>,
impl<T, U> DeserializeTypedOwned<T> for Uwhere
U: for<'de> DeserializeTyped<'de, T>,
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, U, C> IntoWithContext<U, C> for Twhere
U: FromWithContext<T, C>,
impl<T, U, C> IntoWithContext<U, C> for Twhere
U: FromWithContext<T, C>,
Source§impl<T> Pointable for T
impl<T> Pointable for T
Source§impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> Read<Exclusive, BecauseExclusive> for Twhere
T: ?Sized,
Source§impl<T> ResourceProvider<()> for T
impl<T> ResourceProvider<()> for T
Source§fn get_resource(&self) -> &()
fn get_resource(&self) -> &()
T.