Skip to main content

ArgumentAllowlist

Struct ArgumentAllowlist 

Source
#[non_exhaustive]
pub struct ArgumentAllowlist { pub tool: String, pub argument: String, pub allowed: Vec<String>, pub required: bool, pub deny_unknown_arguments: bool, }
Expand description

Per-tool argument allowlist entry.

When the middleware sees a tools/call for tool, it extracts the string value at argument from the call’s arguments object and checks its first token against allowed. If the token is not in the list the call is rejected with 403.

§Scope: this is not the argument-validation layer

Argument validation belongs downstream, in the tool itself – its input schema and its handler. Only the tool knows its parameter types, value ranges, mutually exclusive options, and which combinations are meaningful. This crate deliberately does not attempt that, and cannot: it sees an untyped JSON object at an authorization boundary.

What an allowlist provides is a coarse, role-scoped gate answering “may this role invoke this tool in roughly this shape”. It is defence in depth layered on top of the tool’s own validation, never a replacement for it. Its deliberate limits follow from that:

  • Only the first shlex::split word of the value is checked. An allowlist of ["ls"] accepts "ls -la; id", because the first parsed word is ls; everything after it is unconstrained. The check therefore constrains only the first parsed word, not every program a shell might go on to execute.
  • Object- and array-valued arguments are denied rather than inspected wherever an allowlist or deny_unknown_arguments actually applies; there is no nested-path matching.
  • Basename matching is POSIX-only, so C:\bin\ls.exe will not match ls.

This division is also why presence enforcement is opt-in rather than imposed: whether omitting an argument is safe depends entirely on the tool’s schema and defaults, which are the consumer’s to declare.

By default this constrains the value only when the argument is present – omitting it entirely skips the check. Set required to also demand the argument be supplied. This default is permanent and deliberate: presence enforcement is opt-in, because an allowlist that constrains a supplied value is a legitimate configuration and the crate does not impose the stricter policy on existing deployments. Use ArgumentAllowlist::new_required whenever omitting the argument must fail closed – in particular when the tool substitutes its own default for a missing value, since that default is never checked.

Fields (Non-exhaustive)§

This struct is marked as non-exhaustive
Non-exhaustive structs could have additional fields added in future. Therefore, non-exhaustive structs cannot be constructed in external crates using the traditional Struct { .. } syntax; cannot be matched against without a wildcard ..; and struct update syntax will not work.
§tool: String

Tool name to match (exact or glob, e.g. "run_query").

§argument: String

Argument key whose value is checked (e.g. "cmd", "query").

§allowed: Vec<String>

Permitted first-token values. Empty means unrestricted.

§required: bool

Require the argument to be present and string-valued.

Defaults to false, preserving the historical semantics: an allowlist constrains the value when the argument is supplied, and a caller omitting it passes unchecked. That is safe when the tool’s input schema already marks the argument required, but fails open when the handler substitutes a default for a missing value.

When true, a call that omits the argument – or supplies a non-string – is denied with 403, independently of allowed. Setting required with an empty allowed therefore means “must be supplied as a string, any value accepted”.

§deny_unknown_arguments: bool

Reject any top-level argument that no allowlist for this (role, tool) names.

Defaults to false, preserving the historical semantics: allowlists constrain only the arguments they name, so {"cmd":"ls","danger":true} passes when only cmd is allowlisted. That is safe when the tool’s input schema rejects unknown keys, and fails open when it does not.

When true on ANY allowlist matching a (role, tool) pair, the permitted argument names become the union of every matching allowlist’s argument, and any other top-level key is denied with 403. Object- and array-valued arguments are also denied, because this crate has no nested-path allowlist to constrain their contents.

Implementations§

Source§

impl ArgumentAllowlist

Source

pub fn new( tool: impl Into<String>, argument: impl Into<String>, allowed: Vec<String>, ) -> Self

Create an argument allowlist for a tool.

The argument is optional: the allowed-value list is enforced only when the caller supplies it. Use new_required when omitting the argument must fail closed.

Source

pub fn new_required( tool: impl Into<String>, argument: impl Into<String>, allowed: Vec<String>, ) -> Self

Create an argument allowlist that requires the argument to be present.

This is the recommended constructor for new policies because it fails closed when the caller omits the constrained argument.

Source

pub const fn with_required(self, required: bool) -> Self

Require the argument to be present and string-valued.

Source

pub const fn with_deny_unknown_arguments(self, deny: bool) -> Self

Confine the tool to only the arguments its allowlists name.

Applies to the whole (role, tool) pair, not just this entry: see deny_unknown_arguments.

Trait Implementations§

Source§

impl Clone for ArgumentAllowlist

Source§

fn clone(&self) -> ArgumentAllowlist

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 Debug for ArgumentAllowlist

Source§

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

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

impl<'de> Deserialize<'de> for ArgumentAllowlist

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more

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<'a, T, E> AsTaggedExplicit<'a, E> for T
where T: 'a,

Source§

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

Source§

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

Source§

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<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

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<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

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

Source§

fn __clone_box(&self, _: Private) -> *mut ()

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

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

Source§

fn from_ref(input: &T) -> T

Converts to this type from a reference to the input type.
Source§

impl<A, B, T> HttpServerConnExec<A, B> for T
where B: Body,

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> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + 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
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + 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> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

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

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

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<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

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