Skip to main content

PermissionRegistry

Struct PermissionRegistry 

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

Registry for managing permission grants and requests.

This registry implements the new grant-based permission system with:

  • Hierarchical permission levels (Admin > Execute > Write > Read > None)
  • Path-based grants with optional recursion
  • Domain and command pattern grants
  • Batch permission request handling

§Lock Ordering

This struct contains multiple async mutexes. To prevent deadlocks, all methods follow these rules:

  1. Never hold multiple locks simultaneously - each method acquires locks in separate scopes, releasing one before acquiring the next
  2. Release locks before async operations - locks are released before sending to channels or awaiting other async calls
  3. Sequential ordering when multiple locks needed:
    • pending_requests or pending_batches first (for request lookup)
    • session_grants second (for grant operations)

Example pattern used throughout:

// Good: sequential lock acquisition in separate scopes
let request = {
    let mut pending = self.pending_requests.lock().await;
    pending.remove(id)?
}; // lock released here
self.add_grant(session_id, grant).await; // acquires session_grants

Implementations§

Source§

impl PermissionRegistry

Source

pub fn new(event_tx: Sender<ControllerEvent>) -> PermissionRegistry

Creates a new PermissionRegistry.

§Arguments
  • event_tx - Channel to send events when permissions are requested.
Source

pub async fn add_grant(&self, session_id: i64, grant: Grant)

Adds a grant for a session.

§Arguments
  • session_id - Session to add the grant to.
  • grant - The grant to add.
Source

pub async fn add_grants(&self, session_id: i64, new_grants: Vec<Grant>)

Adds multiple grants for a session.

§Arguments
  • session_id - Session to add the grants to.
  • new_grants - The grants to add.
Source

pub async fn cleanup_expired(&self, session_id: i64)

Removes expired grants from a session.

Source

pub async fn revoke_grants( &self, session_id: i64, target: &GrantTarget, ) -> usize

Revokes all grants matching a specific target for a session.

§Arguments
  • session_id - Session to revoke grants from.
  • target - Target to match for revocation.
§Returns

Number of grants revoked.

Source

pub async fn get_grants(&self, session_id: i64) -> Vec<Grant>

Gets all grants for a session.

§Arguments
  • session_id - Session to query.
§Returns

List of grants for the session (empty if none).

Source

pub async fn clear_grants(&self, session_id: i64)

Clears all grants for a session.

§Arguments
  • session_id - Session to clear.
Source

pub async fn check(&self, session_id: i64, request: &PermissionRequest) -> bool

Checks if a permission request is satisfied by existing grants.

This checks if any grant in the session satisfies the request based on:

  1. Target coverage (grant target covers request target)
  2. Level hierarchy (grant level >= required level)
  3. Grant not expired
§Arguments
  • session_id - Session to check.
  • request - The permission request to check.
§Returns

true if permission is granted, false otherwise.

Source

pub async fn check_batch( &self, session_id: i64, requests: &[PermissionRequest], ) -> HashSet<String>

Checks multiple permission requests and returns which are already granted.

§Arguments
  • session_id - Session to check.
  • requests - The permission requests to check.
§Returns

Set of request IDs that are already granted.

Source

pub async fn find_satisfying_grant( &self, session_id: i64, request: &PermissionRequest, ) -> Option<Grant>

Finds which grant (if any) satisfies a request.

§Arguments
  • session_id - Session to check.
  • request - The permission request to check.
§Returns

The grant that satisfies the request, if any.

Source

pub async fn request_permission( &self, session_id: i64, request: PermissionRequest, turn_id: Option<TurnId>, ) -> Result<Receiver<PermissionPanelResponse>, PermissionError>

Registers an individual permission request.

If the request is already satisfied by existing grants, returns an auto-approved response immediately. Otherwise, registers the request, emits an event, and returns a receiver to await the response.

§Arguments
  • session_id - Session requesting permission.
  • request - The permission request.
  • turn_id - Optional turn ID for UI context.
§Returns

A receiver that will receive a PermissionPanelResponse.

Source

pub async fn respond_to_request( &self, request_id: &str, response: PermissionPanelResponse, ) -> Result<(), PermissionError>

Responds to an individual permission request.

§Arguments
  • request_id - ID of the request to respond to.
  • response - The user’s response (grant/deny with optional persistent grant).
§Returns

Ok(()) if successful.

Source

pub async fn cancel(&self, request_id: &str) -> Result<(), PermissionError>

Cancels a pending permission request.

This is called by the UI when the user closes the permission dialog without responding. Dropping the sender will cause the tool to receive a RecvError.

§Arguments
  • request_id - ID of the request to cancel.
§Returns

Ok(()) if the request was found and cancelled.

Source

pub async fn pending_for_session( &self, session_id: i64, ) -> Vec<PendingPermissionInfo>

Gets all pending permission requests for a session.

§Arguments
  • session_id - Session ID to query.
§Returns

List of pending permission info for the session.

Source

pub async fn is_granted( &self, session_id: i64, request: &PermissionRequest, ) -> bool

Check if permission is already granted for the session.

This is a convenience method that wraps check(). Uses the Grant::satisfies method from the permission system.

§Arguments
  • session_id - Session to check.
  • request - The permission request to check.
§Returns

True if permission was previously granted for the session.

Source

pub async fn register_batch( &self, session_id: i64, requests: Vec<PermissionRequest>, turn_id: Option<TurnId>, ) -> Result<Receiver<BatchPermissionResponse>, PermissionError>

Registers a batch of permission requests.

Requests that are already satisfied by existing grants are auto-approved and not included in the batch sent to the UI.

§Arguments
  • session_id - Session requesting permissions.
  • requests - The permission requests.
  • turn_id - Optional turn ID for UI context.
§Returns

A receiver that will receive the batch response.

Source

pub async fn respond_to_batch( &self, batch_id: &str, response: BatchPermissionResponse, ) -> Result<(), PermissionError>

Responds to a batch permission request.

§Arguments
  • batch_id - ID of the batch to respond to.
  • response - The batch response with approved grants and denied requests.
§Returns

Ok(()) if successful.

Source

pub async fn cancel_batch(&self, batch_id: &str) -> Result<(), PermissionError>

Cancels a pending batch permission request.

This is called by the UI when the user closes the batch permission dialog without responding. Dropping the sender will cause the tools to receive errors.

§Arguments
  • batch_id - ID of the batch to cancel.
§Returns

Ok(()) if the batch was found and cancelled.

Source

pub async fn cancel_session(&self, session_id: i64)

Cancels all pending requests for a session.

This drops the response channels, causing receivers to get errors.

§Arguments
  • session_id - Session to cancel.
Source

pub async fn clear_session(&self, session_id: i64)

Clears all state for a session (grants and pending requests).

§Arguments
  • session_id - Session to clear.
Source

pub async fn has_pending(&self, session_id: i64) -> bool

Checks if there are any pending requests for a session.

§Arguments
  • session_id - Session to check.
§Returns

true if there are pending requests.

Source

pub async fn pending_count(&self) -> usize

Gets count of pending requests across all sessions.

Source

pub async fn pending_request_ids(&self, session_id: i64) -> Vec<String>

Gets pending request IDs for a session.

Source

pub async fn pending_batch_ids(&self, session_id: i64) -> Vec<String>

Gets pending batch IDs for a session.

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