pub struct SecurityConfig {
pub allow_seed_commands: bool,
pub allow_local_network: bool,
pub allow_env_vars: Vec<String>,
pub allow_blueprint_read_paths: bool,
pub read_paths: Vec<String>,
pub credential_store: CredentialStoreKind,
}Expand description
[security] in ~/.leviath/config.toml.
Distinct from a blueprint’s [security] block, which configures taint
tracking for one agent - this one holds machine-wide switches.
Fields§
§allow_seed_commands: boolWhether a blueprint’s seed = { command = "..." } regions may run.
On by default. A command seed executes at spawn - before the first
inference, and therefore before any tool-approval prompt - so it is the
one place a manifest can run something without the user being asked.
It is still confined to the run’s workdir, routed through the entry
stage’s sandbox when the agent declares one, and capped by
[limits] script_shell_timeout_secs. Set this to false to refuse them
machine-wide, or pass --no-seed-commands for a single run. Inspect an
agent’s command seeds before installing it with lev validate <path>.
allow_local_network: boolWhether agent-driven fetches may reach loopback, private, and link-local addresses.
Off by default. An agent’s web_fetch URL is chosen by the model out
of context an attacker can influence - a search result, a page fetched a
moment ago, an issue body - so an unrestricted fetch makes the agent a
confused deputy inside the user’s network. The concrete targets are
http://169.254.169.254/… (cloud metadata, which returns instance
credentials), http://127.0.0.1:3000/api/… (the user’s own lev serve),
and anything on the LAN.
Turn this on when the agent is genuinely meant to talk to something local -
a self-hosted model, a dev server under test. It applies to the script
host’s http_get/http_post and to redirect following; see
leviath_core::net.
allow_env_vars: Vec<String>Credential-shaped environment variables that agent scripts may read.
A Rhai script tool or script provider calling env_var("NAME") gets any
ordinary variable - PATH, TZ, an app’s own config. A name that looks
like a credential (see leviath_core::secrets::is_sensitive_env_name)
is refused unless it appears here, because a two-line script tool reading
ANTHROPIC_API_KEY and POSTing it elsewhere was otherwise a working
exfiltration path with no prompt anywhere in it.
List the exact names a script legitimately needs - typically the key for a custom provider script:
[security]
allow_env_vars = ["MY_PROVIDER_KEY"]Matching is case-insensitive and exact. There is no wildcard: "*" is
read as a variable literally named *, not as “allow everything”.
allow_blueprint_read_paths: boolWhether a blueprint’s [read_paths] declarations are honored as-is.
Off by default. A [read_paths] block travels inside the
agent.leviath you installed, and a manifest may only tighten what
your config allows, never widen it - otherwise any agent package could
read ~/.ssh, this very config file (your API keys), or a password
store by shipping one TOML line. With this off, an agent’s declared
read paths are inert until you grant them via Self::read_paths or
[agent_read_paths.<name>]. Turning it on says “any blueprint I run
may read every path it declares” - reads only, each access still
resolves symlinks and must land inside a declared entry, but prefer
the per-agent grant for anything you did not author yourself.
read_paths: Vec<String>Machine-wide read grants for agents that declare [read_paths].
Entries use the same three forms as a blueprint’s [read_paths] allow:
an exact path (grants its subtree), glob: and regex: patterns
(matched against the symlink-resolved real path, written with / on
every OS, regex auto-anchored). ~/ expands to your home; a relative
entry resolves against the run’s workdir.
[security]
read_paths = ["~/.leviath/runs", "glob:~/design-docs/**"]A grant only takes effect for a path the running blueprint also declares - by itself it grants nothing, so listing a directory here does not open it to agents that never asked.
credential_store: CredentialStoreKindWhere provider API keys and MCP OAuth tokens are kept.
file by default - ~/.leviath/config.toml and
~/.leviath/mcp-auth.json, both created 0600 so they are never even
briefly world-readable. This is what Claude Code and Codex do, and it is
the only backend that works headless, in a container, over SSH, and on a
CI runner.
Set it to keychain to move secrets into the OS credential store (macOS
Keychain, Windows Credential Manager, Secret Service elsewhere), so a
stolen ~/.leviath directory yields nothing:
[security]
credential_store = "keychain"Then run lev auth migrate to move the secrets you already have. It is
opt-in rather than the default because an unavailable keychain is not a
degraded experience but a broken one - every inference fails at once -
and the environments Leviath is most useful in are the least likely to
have a working credential store. lev auth status reports whether this
machine actually has one.
Trait Implementations§
Source§impl Clone for SecurityConfig
impl Clone for SecurityConfig
Source§fn clone(&self) -> SecurityConfig
fn clone(&self) -> SecurityConfig
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for SecurityConfig
impl Debug for SecurityConfig
Source§impl Default for SecurityConfig
impl Default for SecurityConfig
Source§impl<'de> Deserialize<'de> for SecurityConfig
impl<'de> Deserialize<'de> for SecurityConfig
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>,
impl Eq for SecurityConfig
Source§impl PartialEq for SecurityConfig
impl PartialEq for SecurityConfig
Source§impl Serialize for SecurityConfig
impl Serialize for SecurityConfig
impl StructuralPartialEq for SecurityConfig
Auto Trait Implementations§
impl Freeze for SecurityConfig
impl RefUnwindSafe for SecurityConfig
impl Send for SecurityConfig
impl Sync for SecurityConfig
impl Unpin for SecurityConfig
impl UnsafeUnpin for SecurityConfig
impl UnwindSafe for SecurityConfig
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
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> ConditionalSend for Twhere
T: Send,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>, which can then be
downcast into Box<dyn ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>, which can then be further
downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> DowncastSend for T
impl<T> DowncastSend for T
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<T> FromTemplate for T
impl<T> FromTemplate for T
Source§impl<T> FromWorld for Twhere
T: Default,
impl<T> FromWorld for Twhere
T: Default,
Source§fn from_world(_world: &mut World) -> T
fn from_world(_world: &mut World) -> T
Creates Self using default().
Source§impl<T> FutureExt for T
impl<T> FutureExt for T
Source§fn with_context(self, otel_cx: Context) -> WithContext<Self>
fn with_context(self, otel_cx: Context) -> WithContext<Self>
Source§fn with_current_context(self) -> WithContext<Self>
fn with_current_context(self) -> WithContext<Self>
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> IntoResult<T> for T
impl<T> IntoResult<T> for T
Source§fn into_result(self) -> Result<T, RunSystemError>
fn into_result(self) -> Result<T, RunSystemError>
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> Serialize for T
impl<T> Serialize for T
fn erased_serialize(&self, serializer: &mut dyn Serializer) -> Result<(), Error>
fn do_erased_serialize( &self, serializer: &mut dyn Serializer, ) -> Result<(), ErrorImpl>
Source§impl<T> Template for T
impl<T> Template for T
Source§fn build_template(
&self,
_context: &mut TemplateContext<'_, '_>,
) -> Result<<T as Template>::Output, BevyError>
fn build_template( &self, _context: &mut TemplateContext<'_, '_>, ) -> Result<<T as Template>::Output, BevyError>
entity context to produce a Template::Output.Source§fn clone_template(&self) -> T
fn clone_template(&self) -> T
Clone.