pub struct CapabilityPolicy {Show 28 fields
pub network_allow: Vec<String>,
pub peer_fetch_allow: Vec<String>,
pub unix_sockets_allowed: bool,
pub filesystem_scope: Option<String>,
pub workdir_exec_allowed: bool,
pub read_only_paths: Vec<String>,
pub shell_allow: Vec<String>,
pub spawn_allow: Vec<String>,
pub spawn_workdir_snapshot: Vec<String>,
pub shell_strip_env: Vec<String>,
pub shell_baseline_env: Vec<String>,
pub shell_interpreter_runtime: Vec<InterpreterRuntimeGrant>,
pub shell_staged_runtime: Vec<StagedRuntimeGrant>,
pub shell_derived_interpreter_runtime: Vec<DerivedInterpreterRuntime>,
pub shell_trust_store: Vec<TrustStorePath>,
pub host_paths: Vec<HostPath>,
pub env_allow: Vec<String>,
pub limits: ExecutionLimits,
pub resources: HostResourceLimits,
pub declared_resources: ResourceCapabilities,
pub containment_floor: ContainmentClass,
pub state_declared: bool,
pub conversation_declared: bool,
pub plan_submit: bool,
pub install_skill: Vec<String>,
pub install_tool: Vec<String>,
pub install_from_sources: bool,
pub declared_deadline_seconds: Option<u64>,
}Fields§
§network_allow: Vec<String>§peer_fetch_allow: Vec<String>From capabilities.peer_fetch.allow: the peers this capsule may redeem a peer-file handle
against. Empty by default, which is deny — and which is also why no fetch-peer-file tool
manifest is written and the capsule’s model never sees the tool exists.
A separate list from Self::network_allow, enforced with the same rule matcher but
never merged into it. Ingesting a peer’s bytes lands a file in this capsule’s own workdir,
so it is a prompt-injection surface and deserves its own operator control; a destination
in network.allow is not redeemable unless it also appears here, and declaring it here
does not widen network.allow.
unix_sockets_allowed: boolFrom capabilities.network.unix_sockets. false by default, which makes the shell
subprocess tree’s socket(AF_UNIX, ...) calls fail with EACCES at the kernel level on
both Linux tiers — network_allow above governs IP destinations only and would otherwise
leave a local daemon socket (/var/run/docker.sock — host root) completely unmediated.
true simply omits that seccomp rule; it is capsule-wide, not per-socket-path. See
sandbox::denied_socket_domains.
filesystem_scope: Option<String>§workdir_exec_allowed: boolFrom capabilities.filesystem.workdir_exec. false by default, which withholds the
Landlock Execute right from the workdir’s own PathBeneath rule — see
sandbox::linux_enforce::workdir_access_rights. With it withheld the kernel refuses to exec
anything under the workdir on the resolved path itself, so shell_allow is enforced
completely: a binary copied or compiled into the workdir cannot run under any name.
true gives the right back for compile-and-run workflows and accepts, explicitly, that
shell_allow is then unenforceable for anything inside the workdir. That is why this field
is the one grant in this struct that also lowers the session’s achieved containment class
(see crate::containment::achieved_containment_class) — nothing else here can.
read_only_paths: Vec<String>From capabilities.filesystem.read_only: workdir subtrees the capsule may read but must
not write, in the same vocabulary Self::filesystem_scope uses. Empty by default, which
is the whole workdir writable.
Carried here as the declared strings and lowered once at staging into
crate::protected_paths::ProtectedPaths, which is what the dispatch check consults — so a
malformed entry refuses the launch rather than one call at a time. Unlike every other field
here this one grants nothing: it can only subtract from what the workdir preopen already
allows.
shell_allow: Vec<String>§spawn_allow: Vec<String>§spawn_workdir_snapshot: Vec<String>From capabilities.spawn.workdir_snapshot: the full names in Self::spawn_allow whose
every delegation starts in a copy of this session’s work folder, made by this runtime
before the child process starts. Empty by default, which starts every child in an empty
folder.
shell_strip_env: Vec<String>§shell_baseline_env: Vec<String>§shell_interpreter_runtime: Vec<InterpreterRuntimeGrant>Typed interpreter-runtime grants from capabilities.shell.interpreter_runtime: each
names an already-allowlisted binary and the exact host directories outside the workdir
its import machinery needs, with a per-directory list_dir enumerability flag. Empty
unless the manifest declares them. Consumed on KernelFull to add narrow Landlock
grants (see sandbox::resolve_interpreter_runtime_grants) and to fire W-SEC-009.
shell_staged_runtime: Vec<StagedRuntimeGrant>Typed staged-runtime grants from capabilities.shell.staged_runtime: each names an
already-allowlisted binary, the absolute host path of a pinned runtime tree, and the pin
identifying that tree’s build. Empty unless the manifest declares them.
Consumed at staging to enforce that declaring one requires an effective sealed floor (see
crate::staged_runtime::check_staged_runtime_floor) and to render the staged runtime
section of --explain-scope. Per-binary mutually exclusive with
Self::shell_interpreter_runtime, which the manifest parser already guarantees.
shell_derived_interpreter_runtime: Vec<DerivedInterpreterRuntime>The runtime directories of each shell_allow binary the runtime recognises as an
interpreter, as that interpreter reported them (see [crate::interpreter_runtime]). Not a
manifest field: empty from capability_policy_from_runtime_manifest, filled once by
stage_session and by mur run --explain-scope through
crate::interpreter_runtime::derive_interpreter_runtimes. Each becomes a readable,
non-executable Landlock grant (sandbox::resolve_derived_interpreter_grants) and, on
sealed, an optional composed-root bind.
shell_trust_store: Vec<TrustStorePath>The host’s TLS trust store, as staging found it for a capsule with a non-empty
shell_allow and a non-empty network_allow (see [crate::trust_store]). Not a manifest
field: empty from capability_policy_from_runtime_manifest, filled once by
stage_session and by mur run --explain-scope through
crate::trust_store::derive_trust_store. Each becomes a readable, non-executable
Landlock grant (sandbox::resolve_trust_store_grants), listable for a directory.
host_paths: Vec<HostPath>The host folders ~/.murmur/config.yaml‘s host_paths: lends every contained capsule on
this host, checked on this host, in config order (see crate::host_paths). Not a
manifest field: empty from capability_policy_from_runtime_manifest, filled by mur run
(and --explain-scope) from the global config alone. On landlock+seccomp each becomes a
Landlock rule for commands, plan shell steps and native tools; on sealed also a required
bind at its own path. Never executable. WASM tools’ preopens do not include them.
env_allow: Vec<String>Host env var names a WASM guest may observe, from capabilities.env.allow. Empty by
default: a guest sees only the runtime’s own MURMUR_* injection unless the manifest
names a variable here. shell_strip_env and the credential patterns still apply on
top, so a credential-shaped name declared here is stripped anyway.
limits: ExecutionLimitsExecution limits applied to every guest store in the session. Always fully
resolved — capability_policy_from_runtime_manifest substitutes a default for
each field capabilities.limits omits, so there is no “unset” state here and a
silent manifest yields ExecutionLimits::default rather than no limits.
resources: HostResourceLimitsOS-level bounds applied to every native subprocess the session spawns — rlimits, the
Linux cgroup v2 scope, and the workdir-size ceiling. Resolved on exactly the same terms
as limits above (each omitted capabilities.resources field replaced by its default,
no “unset” state), but a completely different subject: limits bounds a WASM guest
inside its wasmtime store, this bounds the processes the host forks. See
crate::resources.
declared_resources: ResourceCapabilitiesThe manifest’s own capabilities.resources block, every omitted field still None.
Self::resources is what a contained session applies; an unconfined session (a
Self::containment_floor of ContainmentClass::Unconfined) applies only what this
declares, creates a cgroup scope only when it declares a cgroup_* field and runs the
workdir guard only when it declares workdir_max_bytes.
containment_floor: ContainmentClassThe containment class this capsule asked for, from capabilities.containment.
Unlike every other field here it is a requirement, not a grant — and unlike
StageRequest::declared_containment_floor it is only the manifest’s own vote, before the
workspace config and --containment are folded in. stage_session overwrites it with the
combined floor as soon as that is known, so anything reading it off a StagedSession sees
the effective value; the manifest-only value exists so a CapabilityPolicy built straight
from a manifest is still self-consistent.
Read by sandbox::ShellEnforcement::resolve to decide whether a sealed-capable host
actually installs a composed root for this session — a capsule that declared scoped must
keep getting scoped’s mechanism. See sandbox::applied_tier.
state_declared: boolWhether the capsule’s own top-level capabilities.state block was declared.
Not a grant, and the only field here that is not: a durable state store is granted per
artifact, so a capsule-wide declaration reaches nothing at all. It is recorded so
stage_session can say that once (W-SEC-014) instead of leaving an operator to discover
an empty directory, and it is read by nothing else.
conversation_declared: boolRecorded for the same reason Self::state_declared is, and applied just as little: the
murmur:conversation/read grant is per artifact, so a capsule-wide declaration reaches
nothing and stage_session says so once (W-SEC-016).
plan_submit: boolFrom capabilities.plan.submit: whether this capsule’s model is offered the
runtime-provided submit-plan tool. false by default, which is deny — and which is also
why no submit-plan tool manifest is written and the capsule’s model never sees the tool
exists.
It grants no reach of its own: every step of a submitted plan runs through this same session’s tool dispatch, its shell allowlist and its spawn grant, so a plan reaches exactly what the model could already call one call at a time.
install_skill: Vec<String>From capabilities.install.skill: the entries naming which skill artifacts a pull
(manage.pull or the pull-artifact tool) may install into this session, verbatim and in
declaration order. Empty by default, which is deny. With Self::install_tool also
empty, every pull is refused.
A pulled skill gains no grant of its own; see install_grant.
install_tool: Vec<String>From capabilities.install.tool: the entries naming which tool artifacts, WASM or native,
a pull may install, verbatim and in declaration order. Empty by default, which is deny.
A pulled tool joins the session’s dispatch allowlist and dispatches on this policy’s own ceiling; it gains no grant of its own.
install_from_sources: boolFrom capabilities.install.from: true for [stores, sources], under which a pull the
stores cannot answer is fetched from the scope’s GitHub source. false by default.
declared_deadline_seconds: Option<u64>capabilities.limits.deadline_seconds exactly as the manifest declared it — None
when it declared nothing. Retained undefaulted alongside the fully-resolved limits
above purely so hook calls can apply their own, lower default without mistaking an
explicit 600 for silence. See Self::hook_limits.
Implementations§
Source§impl CapabilityPolicy
impl CapabilityPolicy
Sourcepub fn hook_limits(&self) -> ExecutionLimits
pub fn hook_limits(&self) -> ExecutionLimits
Execution limits for hook lifecycle calls — Self::limits with the hook-specific
deadline default substituted when the manifest declared none.
A hook call is one bounded piece of work, so it does not inherit the capsule-wide
ten-minute budget that exists for a capsule’s whole run: a wedged hook would
otherwise stall the session for most of that, every event. An explicitly declared
deadline_seconds still wins, for hooks as for every other guest.
Trait Implementations§
Source§impl Clone for CapabilityPolicy
impl Clone for CapabilityPolicy
Source§impl Debug for CapabilityPolicy
impl Debug for CapabilityPolicy
Source§impl Default for CapabilityPolicy
impl Default for CapabilityPolicy
impl Eq for CapabilityPolicy
Source§impl PartialEq for CapabilityPolicy
impl PartialEq for CapabilityPolicy
impl StructuralPartialEq for CapabilityPolicy
Auto Trait Implementations§
impl Freeze for CapabilityPolicy
impl RefUnwindSafe for CapabilityPolicy
impl Send for CapabilityPolicy
impl Sync for CapabilityPolicy
impl Unpin for CapabilityPolicy
impl UnsafeUnpin for CapabilityPolicy
impl UnwindSafe for CapabilityPolicy
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> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
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 moreSource§impl<T> NoneValue for Twhere
T: Default,
impl<T> NoneValue for Twhere
T: Default,
Source§type NoneType = T
type NoneType = T
NoneValue::null_value produces.