pub struct ScopeReport {Show 51 fields
pub declared_containment: ContainmentClass,
pub achieved_containment: ContainmentClass,
pub host_containment: ContainmentClass,
pub floor_met: bool,
pub shortfall_reason: Option<String>,
pub enforcement_tier: &'static str,
pub routes: Vec<RouteReport>,
pub userns_grant: Option<UsernsGrant>,
pub landlock_abi: Option<u8>,
pub filesystem_scope: Option<String>,
pub workdir_exec: bool,
pub read_only_paths: Vec<String>,
pub read_only_advisory_for: Vec<String>,
pub preopens: Vec<PreopenReport>,
pub network_allow: Vec<String>,
pub unix_sockets: bool,
pub shell_allow: Vec<String>,
pub spawn_allow: Vec<String>,
pub spawn_workdir_snapshot: Vec<String>,
pub parent_workdir: Option<ParentWorkdirReport>,
pub images: Option<ImagesReport>,
pub env_allow: Vec<String>,
pub plan_submit: bool,
pub install_skill: Vec<String>,
pub install_tool: Vec<String>,
pub install_from: Vec<String>,
pub interpreter_runtime_grants: Vec<String>,
pub derived_interpreter_runtime: Vec<String>,
pub trust_store: Vec<String>,
pub declared_needs: Vec<DeclaredNeedsReport>,
pub pinned_programs: Vec<PinnedProgramReport>,
pub name_resolution: Vec<String>,
pub host_paths: Vec<HostPathReport>,
pub exports_files: Option<ExportsFilesReport>,
pub peer_files: Option<PeerFilesReport>,
pub peer_tasks: bool,
pub peer_fetch_allow: Vec<String>,
pub state_stores: Vec<StateStoreReport>,
pub configured_artifacts: Vec<String>,
pub staged_runtime_grants: Vec<String>,
pub runtime_writes: Vec<RuntimeWriteReport>,
pub manifest_files: Vec<ManifestFileReport>,
pub io_max: IoMaxReport,
pub cgroup_scope: CgroupScopeReport,
pub filesystem_boundary: FilesystemBoundaryReport,
pub runtime_dir: RuntimeDirReport,
pub records_dir: RuntimeDirReport,
pub temp_dir: TempDirReport,
pub process_view: ProcessViewReport,
pub unconfined: Option<UnconfinedReport>,
pub harness: Option<HarnessReport>,
}Expand description
Read-only answer to “what would this capsule actually be allowed to do on this host?”.
Built from the already-parsed CapabilityPolicy plus one ContainmentDecision. Nothing
here stages artifacts, touches a registry, creates a workdir or resolves DNS — it is a
diagnostic, so it reports even when Self::floor_met is false.
Fields§
§declared_containment: ContainmentClassStrongest class any source asked for (manifest / workspace config / --containment).
achieved_containment: ContainmentClassThe class this session’s commands run under: the class of Self::enforcement_tier,
capped at advisory by workdir_exec or a runtime directory inside the workdir. From
ContainmentDecision::achieved.
host_containment: ContainmentClassThe class this host could back for a capsule declaring sealed, never what this session
runs on: a capsule declaring less runs on a weaker tier, and Self::achieved_containment
says which. From ContainmentDecision::host_containment. Always serialized.
floor_met: boolachieved_containment >= declared_containment. false means mur run would refuse.
shortfall_reason: Option<String>The missing mechanism when floor_met is false; absent otherwise.
enforcement_tier: &'static strThe tier this session installs, as a stable wire name: the host’s tier capped by the
declared floor, from ContainmentDecision::enforcement_tier.
routes: Vec<RouteReport>Every route this capsule could run code on, and what holds each: one RouteReport row per
Route::ALL entry, in that order, from route_table. A route the session’s class
covers names Self::enforcement_tier; one it does not names HOST_PROCESS_MECHANISM
and says what it does run under.
Always serialized, every row, on every tier and platform: an absent key identifies a
runtime that predates it. Set again through Self::with_routes by the caller that knows
the inference transport.
userns_grant: Option<UsernsGrant>Where this host’s permission to create an unprivileged user namespace comes from, as
UsernsGrant::wire_name, or null off Linux, where AppArmor does not exist and the
question has no answer.
Always serialized, on the same terms as Self::workdir_exec: the key’s absence
identifies a runtime that predates it, not a host that was not asked. Reported because
three very different hosts — no AppArmor, hardening switched off host-wide, and the shipped
profile confining mur — otherwise produce byte-identical reports while differing enormously
in what else on the machine can create a user namespace.
landlock_abi: Option<u8>The Landlock ABI this session’s ruleset is built at: the kernel’s, capped at
[crate::sandbox::LANDLOCK_TARGET_ABI], or null when no Landlock domain is installed —
a tier below landlock+seccomp, or a kernel without Landlock.
Keyed on the session’s applied tier, like Self::filesystem_boundary, and computed
by the same [crate::sandbox::ruleset_landlock_abi] the shell child builds at, so the
trace records the ruleset that was installed. Always serialized, on the same terms as
Self::userns_grant. Below 2 a file cannot be moved or hard-linked between two folders
of the workdir; below 3 truncating a host file outside it is not refused.
filesystem_scope: Option<String>capabilities.filesystem.scope, verbatim.
workdir_exec: boolcapabilities.filesystem.workdir_exec. Always present (never skipped when false), so a
consumer can tell “declared false” from “this runtime predates the key” by the field’s
presence rather than by its value.
true is the only manifest declaration that lowers Self::achieved_containment, which is
why it is reported next to the grants rather than buried: reading achieved: advisory on a
Landlock-capable host makes sense only alongside it.
read_only_paths: Vec<String>capabilities.filesystem.read_only, verbatim — the workdir subtrees the capsule may read
but must not write. Empty when the capsule declares none, which is the whole workdir
writable. Always serialized as an array (never skipped), on the same terms as
Self::state_stores: an absent key identifies a runtime that predates the field, not a
capsule that declared nothing.
The one field here that subtracts rather than grants, which is why it is reported beside
Self::read_only_advisory_for rather than alone: a protection stated without its
qualification reads as a boundary the capsule does not have.
read_only_advisory_for: Vec<String>The entries of Self::shell_allow that Self::read_only_paths is only advisory
against — the same set W-SEC-017 fires for, resolved by the same
read_only_advisory_for both this report and mur doctor call.
Empty means the declaration is enforced for every readable call. Non-empty names the
binaries whose own file I/O the dispatch-time write-intent analyser cannot read, so the
report cannot claim more than W-SEC-017 already qualifies. Always serialized as an array
(never skipped), on the same terms as Self::read_only_paths, and always empty when
that list is: nothing is advisory against a protection that was never declared.
preopens: Vec<PreopenReport>The filesystem surface every guest-bearing artifact in this capsule is preopened into, one
entry per runtime: tool, runtime: driver and runtime: hook entry, in manifest order.
Empty when the capsule declares only skills. Always serialized as an array (never skipped),
on the same terms as Self::state_stores: an absent key identifies a runtime that
predates the field, not a capsule with no guest artifacts.
This is the field that answers “what can this tool read and write?”.
Self::filesystem_scope above does not: it is the capsule-wide declaration, and it is
joined into no preopen root.
Copied through untouched, exactly as the reports beside it are — resolving a preopen changes no class, no floor and no tier.
network_allow: Vec<String>capabilities.network.allow, verbatim — declared destinations, not resolved IPs.
unix_sockets: boolcapabilities.network.unix_sockets.
shell_allow: Vec<String>capabilities.shell.allow, verbatim.
spawn_allow: Vec<String>capabilities.spawn.allow, verbatim.
spawn_workdir_snapshot: Vec<String>capabilities.spawn.workdir_snapshot, verbatim: the entries of Self::spawn_allow whose
every delegation starts in a copy of this session’s work folder. Always serialized, []
when undeclared.
parent_workdir: Option<ParentWorkdirReport>What this session’s work folder started with, when a delegating parent copied its own
into it, and what keeps this session’s commands off the parent’s real folder on its tier:
null for every session but such a child. Always serialized.
A report of what the launching parent did, from mur run --parent-workdir-snapshot, never
a grant: it opens nothing and changes no class, floor or tier. Its restriction is
Self::filesystem_boundary’s, keyed on the same applied tier.
images: Option<ImagesReport>The context.images limits this session applies, and whether keep applies at all. Set
by the caller that knows the transport, through Self::with_images; null until then.
Always serialized.
env_allow: Vec<String>capabilities.env.allow, verbatim.
plan_submit: boolcapabilities.plan.submit — whether the model is offered the submit-plan tool. Always
serialized (never skipped when false), on the same terms as Self::workdir_exec: an
absent key identifies a runtime that predates the grant, not a capsule that declined it.
It opens no host resource of its own. It is reported beside the grants because it changes how much of every other grant one model turn can reach: a plan runs many steps against this capsule’s own tools, shell allowlist and spawn grant without a turn in between.
install_skill: Vec<String>capabilities.install.skill, verbatim: which skill artifacts a pull (manage.pull,
pull-artifact) may install into the session. Always serialized, an empty list included,
on Self::plan_submit’s terms: an absent key identifies a runtime that predates the
grant.
It opens no host resource of its own. A pulled skill adds text to what the model reads and gains no grant.
install_tool: Vec<String>capabilities.install.tool, verbatim: which tool artifacts a pull may install. Always
serialized, on Self::install_skill’s terms. A pulled tool joins the dispatch allowlist,
runs on this capsule’s own grants and gains none of its own.
install_from: Vec<String>capabilities.install.from: ["stores"], or ["stores", "sources"] when a pull the
stores cannot answer is fetched from the scope’s GitHub source. [] for a capsule with no
install grant, which pulls from nowhere. Always serialized, on Self::install_skill’s
terms.
interpreter_runtime_grants: Vec<String>Every host directory a capabilities.shell.interpreter_runtime grant opens, rendered as
<binary>: <dir>[ (list_dir)]. These are the paths outside the workdir that stay
reachable even at scoped.
derived_interpreter_runtime: Vec<String>Every host path staging derived from a recognised shell.allow interpreter’s own import
path, rendered <binary>: <dir> (list_dir) for a directory and <binary>: <path> for a zip
archive or an extension-module library. Each is readable and none is executable. Always
serialized, [] when no allowlisted binary is a recognised interpreter.
trust_store: Vec<String>Every host trust-store path staging found for a capsule whose commands reach the network,
rendered <path> (list_dir) for a directory and <path> for a CA bundle file. Each is
readable and none is executable. Always serialized, [] when shell.allow or
network.allow is empty or the host has none of the locations
[crate::trust_store] checks.
declared_needs: Vec<DeclaredNeedsReport>What the host programs the capsule’s tools run need, one element per (artifact, program)
with at least one need, as crate::declared_needs resolved it: each granted need with
its paths, each missing one with why. Always serialized, [] when no tool pinned with an
operator lock origin declares a need for a program shell.allow grants.
pinned_programs: Vec<PinnedProgramReport>Which copy of each program a tool pins a download of runs, one element per (artifact,
program) gated as Self::declared_needs and with a download for this host’s platform,
as crate::pinned_programs chose it. Always serialized, [] when none applies.
name_resolution: Vec<String>The host files a command reads to resolve localhost and the other names /etc/hosts
carries, granted read-only by the tier: /etc/hosts and /etc/nsswitch.conf on the
Landlock tiers (scoped, sealed), [] on every other. Always serialized.
host_paths: Vec<HostPathReport>Every host folder ~/.murmur/config.yaml’s host_paths: lends this session, in config
order, with what the applied tier does with it (see crate::host_paths). Always
serialized, [] with none. A grant from the operator’s global config, never the manifest,
and it changes no class, floor or tier.
exports_files: Option<ExportsFilesReport>The read-only file surface exports.files declares, or null when the capsule declares
none. Always serialized (never skipped), so a consumer can tell “this runtime predates
exports” from “this capsule declined to export anything” by the field’s presence rather
than by its value — the same terms Self::workdir_exec is reported on.
An export is a disclosure, not a grant: it never appears in
Self::achieved_containment, and declaring one cannot change any other field of this
report. It is printed beside the grants because it is the other direction of the same
question — what crosses the capsule boundary, and which way.
peer_files: Option<PeerFilesReport>The peer-handoff surface exports.peer_files declares, or null when the capsule
declares none. Always serialized, on the same terms as Self::exports_files.
A separate authoriser from exports.files, over a separate subtree: a capsule may declare
either, both or neither, and this field says nothing about the other. Like every export it
is a disclosure rather than a grant, and declaring it cannot change
Self::achieved_containment, Self::enforcement_tier or Self::floor_met.
peer_tasks: boolWhether the door serves tasks from peer capsules: exports.peer_tasks.accept, with an
absent block reported as false. Always serialized.
Like every export it opens a surface rather than granting the guest anything, and it cannot
change Self::achieved_containment, Self::enforcement_tier or Self::floor_met.
peer_fetch_allow: Vec<String>capabilities.peer_fetch.allow, verbatim — the peers this capsule may redeem a handle
against. Empty when the block is absent, which is deny.
A separate list from Self::network_allow and never an alias for it: a destination
reachable by send is not redeemable unless it also appears here, because ingesting a
peer’s bytes into this workdir is a different question from being allowed to talk to it.
state_stores: Vec<StateStoreReport>Every durable state store this session’s artifacts declare, one entry per declaring
artifact, empty when none does. Always serialized as an array (never skipped), on the same
terms as Self::exports_files: an absent key identifies a runtime that predates state
stores, not a capsule that declined one.
Declaring a store cannot change Self::achieved_containment, Self::floor_met or
Self::enforcement_tier — it is copied through untouched, exactly as the export reports
beside it are. It is reported because it is the one grant that opens a path outside every
workdir, which nothing else in this block would reveal.
configured_artifacts: Vec<String>Every artifact whose manifest entry declares a config: block, in manifest order, empty
when none does. Always serialized as an array (never skipped), on the same terms as
Self::state_stores: an absent key identifies a runtime that predates artifact config,
not a capsule that declined it.
Names only. What an artifact is configured with is operator-authored plaintext that
belongs in the manifest and in nothing this report — or trace.jsonl, which carries this
report verbatim — writes out.
Declaring config cannot change Self::achieved_containment, Self::floor_met or
Self::enforcement_tier: it adds one environment variable to one guest and reaches no
grant. Reported because a variable an artifact silently depends on is otherwise invisible
to an operator reading the capsule’s scope.
staged_runtime_grants: Vec<String>Every capabilities.shell.staged_runtime grant, rendered as
<binary>: <source_path> (pin: <pin>). These are host runtime trees a sealed capsule
asks to have bind-mounted read-only into its composed root.
Reported whatever the floor and whatever this host can back — a capsule that declares a
staged runtime and cannot run here is exactly the case an operator is inspecting when they
reach for --explain-scope, so hiding the grant behind a met floor would blank out the
diagnostic in the one case it is for.
runtime_writes: Vec<RuntimeWriteReport>Every path the runtime itself writes inside the capsule’s workdir, so a consumer for whom
that workdir is the deliverable can subtract them and be left with what the capsule
changed. Always serialized as an array (never skipped), on the same terms as
Self::state_stores: an absent key identifies a runtime that predates the declaration,
not a runtime that writes nothing.
The one field here that describes what the runtime does rather than what the capsule may
do. It is reported beside the grants because it answers the other half of “what is this
workdir”, and because a consumer that has to maintain its own list of runtime entries
silently falls behind every time the set changes — enabling sealed being exactly that
case.
The same set whatever Self::enforcement_tier and Self::achieved_containment say:
no row turns on the tier. See crate::workdir_writes.
manifest_files: Vec<ManifestFileReport>Every path the manifest names a file by — inference.system_prompt_file,
inference.compaction.system_prompt_file, each local-source artifacts[].source — and
where it is read from: the manifest folder, the installed package, or the host path itself.
Always serialized as an array (never skipped), on the same terms as
Self::state_stores; [] when the manifest names no file.
Reports where a path resolves, not whether the file is there: nothing is read to build it.
Changes no class and no floor. Set through Self::with_manifest_files from
crate::manifest_files::manifest_file_reports.
io_max: IoMaxReportThe declared capabilities.resources.cgroup_io_bytes_per_sec ceiling, and whether it is
actually on this session’s cgroup scope.
Always serialized (never skipped), on the same terms as Self::workdir_exec and
Self::state_stores: an absent key identifies a runtime that predates the field, not a
host that was not asked. IoMaxStatus::NotProbed is what “not asked” looks like, and it
is a value in the report rather than a missing key.
The one field here filled from a performed operation rather than from the policy: at
launch it carries the outcome of the real io.max write, established before session_start
is written so trace.jsonl cannot claim a ceiling the kernel refused; under
--explain-scope it carries the outcome of the same write against a throwaway cgroup that
is created and removed. Declaring a ceiling that does not apply changes no class and refuses
no launch — io.max is the one non-fatal cgroup limit — so this field is the only place
the shortfall appears.
cgroup_scope: CgroupScopeReportWhether this session’s subprocesses get a delegated cgroup v2 scope.
Always serialized. At launch it is delegated or not-required, from
[crate::cgroup::prepare_scope]’s real outcome: a launch that cannot get a scope it needs
is refused with E-RUN-012 and writes no session_start. Under --explain-scope it is
crate::cgroup::probe_scope’s answer, and unavailable there is that refusal predicted,
with the reason it would print. Changes no class and no floor: a refused capsule runs under
no class at all. Set through Self::with_cgroup_scope; not-probed until then.
filesystem_boundary: FilesystemBoundaryReportWhat this session’s filesystem mechanism does not restrict — the block --explain-scope
prints as Not protected here, directly under Containment.
Always serialized (never skipped), on the same terms as Self::state_stores: an absent
key identifies a runtime that predates the field, and an empty
FilesystemBoundaryReport::not_protected identifies a session with nothing to disclaim.
Derived in [filesystem_boundary] from the tier Self::enforcement_tier names, and
from no CapabilityPolicy field: workdir_exec caps Self::achieved_containment
without changing what the mechanism restricts. It stands beside the grants rather than
among them because it qualifies every one at once.
runtime_dir: RuntimeDirReportWhat the session’s runtime directory is to its commands, from [runtime_dir_report] on
the applied tier, Self::landlock_abi and where the directory lies. Always serialized.
When it is not read-only, its reason is also a FilesystemBoundaryReport::not_protected
statement.
records_dir: RuntimeDirReportWhat the session’s records directory is to its commands, from [records_dir_report] on
the same inputs. Always serialized; its reason, when set, is also a
FilesystemBoundaryReport::not_protected statement.
temp_dir: TempDirReportThe session’s temporary folder and whether a literal /tmp reaches it, from
[temp_dir_report] on the session’s [crate::temp_dir::temp_mapping] answer — the one
its enforcement installs. Always serialized.
process_view: ProcessViewReportWhich /proc the session’s commands see, from crate::proc_view::process_view_report
on the view the session’s probe decided (Self::with_process_view) — the one its
enforcement installs. Always serialized.
unconfined: Option<UnconfinedReport>Who the capsule’s subprocesses run as when the session is unconfined; null on every
contained session. Always serialized.
harness: Option<HarnessReport>What a transport: process capsule’s harness needs beyond its class, and where the manifest
allows it: the driver, the harness binary and interpreter, and each path, host and env need
with its status. null on every capsule whose transport is not process. Always
serialized. Set through Self::with_harness by the caller that resolved the driver’s
needs against the manifest; session_start.effective_grants.harness carries it byte for
byte, and --explain-scope computes it the same way from the installed driver.
Implementations§
Source§impl ScopeReport
impl ScopeReport
Source§impl ScopeReport
impl ScopeReport
Sourcepub fn with_images(
self,
images: ContextImagesConfig,
transport: Option<&str>,
) -> Self
pub fn with_images( self, images: ContextImagesConfig, transport: Option<&str>, ) -> Self
This report with Self::images set from images, for a capsule on transport; None
is a capsule with no inference: block.
Sourcepub fn with_routes(self, transport: Option<&str>) -> Self
pub fn with_routes(self, transport: Option<&str>) -> Self
This report with Self::routes built again by route_table, now that the caller
knows the inference transport (None for a capsule with no inference: block).
Reads Self::preopens for the capsule’s tool, driver and hook entries, and the grants
beside them, so the table and the rest of the report describe one capsule.
Sourcepub fn with_harness(self, report: Option<HarnessReport>) -> Self
pub fn with_harness(self, report: Option<HarnessReport>) -> Self
This report with Self::harness set to report, the process harness’s resolved needs.
None leaves it null, for a capsule whose transport is not process.
Sourcepub fn with_declared_needs(self, needs: &[ResolvedProgramNeeds]) -> Self
pub fn with_declared_needs(self, needs: &[ResolvedProgramNeeds]) -> Self
This report with Self::declared_needs built from needs: what staging derives after
it has read every tool’s manifest, which is after the report is first built.
Sourcepub fn with_pinned_programs(self, programs: &[ResolvedPinnedProgram]) -> Self
pub fn with_pinned_programs(self, programs: &[ResolvedPinnedProgram]) -> Self
This report with Self::pinned_programs built from programs, staging’s source choice
for each pinned program download.
Sourcepub fn with_manifest_files(self, rows: Vec<ManifestFileReport>) -> Self
pub fn with_manifest_files(self, rows: Vec<ManifestFileReport>) -> Self
This report with Self::manifest_files set to rows.
Sourcepub fn with_process_view(self, view: &ProcView) -> Self
pub fn with_process_view(self, view: &ProcView) -> Self
This report with Self::process_view stating view, the /proc the session’s probe
decided its commands see.
Sourcepub fn with_cgroup_scope(self, cgroup_scope: CgroupScopeReport) -> Self
pub fn with_cgroup_scope(self, cgroup_scope: CgroupScopeReport) -> Self
This report with Self::cgroup_scope set from cgroup_scope.
Sourcepub fn with_parent_workdir(self, snapshot: Option<WorkdirSnapshot>) -> Self
pub fn with_parent_workdir(self, snapshot: Option<WorkdirSnapshot>) -> Self
This report with Self::parent_workdir set from snapshot, the restriction read off
Self::filesystem_boundary so the two cannot disagree about one tier. None leaves it
null.
Trait Implementations§
Source§impl Clone for ScopeReport
impl Clone for ScopeReport
Source§impl Debug for ScopeReport
impl Debug for ScopeReport
impl Eq for ScopeReport
Source§impl PartialEq for ScopeReport
impl PartialEq for ScopeReport
Source§impl Serialize for ScopeReport
impl Serialize for ScopeReport
impl StructuralPartialEq for ScopeReport
Auto Trait Implementations§
impl Forget for ScopeReport
impl Freeze for ScopeReport
impl Move for ScopeReport
impl RefUnwindSafe for ScopeReport
impl Send for ScopeReport
impl Sync for ScopeReport
impl Unpin for ScopeReport
impl UnsafeUnpin for ScopeReport
impl UnwindSafe for ScopeReport
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 more