gleamunison/capability

Types

A sandbox policy: the exact set of abilities a program may use, named by their content-addressed keys (“m_” + hash suffix). Anything not listed is denied — deny-by-default, never allow-by-default.

pub type Policy {
  Policy(allow: List(String))
}

Constructors

  • Policy(allow: List(String))

Values

pub fn allow(keys: List(String)) -> Policy
pub fn allows(policy: Policy, key: String) -> Bool
pub fn catch_all() -> fn(
  Int,
  List(dynamic.Dynamic),
  fn(dynamic.Dynamic) -> dynamic.Dynamic,
) -> dynamic.Dynamic

A bare catch-all handler for the bottom of the stack: any ability with no installed frame raises capability_denied instead of the runtime’s unhandled_ability. Install last so allowed frames always win.

pub fn check(
  policy: Policy,
  frames: List(effects.HandlerFrame),
) -> Result(Nil, List(String))

Pre-flight: which abilities in these frames does the policy deny? Ok(Nil) means every frame is allowed.

pub fn frame_key(frame: effects.HandlerFrame) -> String

The ability key a frame serves (the runtime’s own key derivation).

pub fn guard_frames(
  policy: Policy,
  frames: List(effects.HandlerFrame),
) -> List(effects.HandlerFrame)

Rewrite frames under a policy: allowed abilities pass through untouched; denied abilities keep their shape but every op raises a structured {capability_denied, key, op} instead of running. A denied op is a loud, matchable failure — never a fabricated result, never a silent skip.

pub fn run_scoped(
  policy: Policy,
  frames: List(effects.HandlerFrame),
  entry: fn() -> dynamic.Dynamic,
) -> dynamic.Dynamic

Run an entry thunk under a policy: allowed frames execute, denied frames raise structured denials, and the catch-all sits innermost so ambient authority (any ability without an explicit allowed frame) is impossible by construction.

✨ Search Document