SigilGuard. Policy behaviour
(SigilGuard v0.2.0)
View Source
Risk classification and trust-gated policy enforcement for the SIGIL protocol.
Maps actions to risk levels and evaluates whether a given trust level is sufficient to proceed. Supports configurable risk mappings, confirmation flow for borderline cases, and rate limiting.
Matches the sigil-protocol Rust crate's RiskLevel enum (v0.1.5).
Risk Level Hierarchy
:low < :medium < :high- low — Read-only, within workspace. Requires
:lowtrust. - medium — State-modifying but recoverable. Requires
:mediumtrust. - high — Destructive or irreversible. Requires
:hightrust.
Default Trust Thresholds
| Risk Level | Minimum Trust Required |
|---|---|
:low | :low |
:medium | :medium |
:high | :high |
Custom Policy Implementation
defmodule MyApp.StrictPolicy do
@behaviour SigilGuard.Policy
@impl true
def evaluate(action, trust_level, opts) do
# Custom logic
end
@impl true
def classify_risk(action, opts) do
# Custom risk classification
end
end
Summary
Callbacks
Classify the risk level of an action.
Evaluate an action against a trust level and return a verdict.
Functions
Classify the risk level of an action based on pattern matching.
Compare two risk levels.
Ensure the ETS table used by rate_check/2 exists.
Evaluate an action against a trust level.
Perform a rate check for an identity performing an action.
Return all risk levels in ascending order.
Return the default trust threshold for a risk level.
Types
@type risk_level() :: :low | :medium | :high
@type verdict() :: :allowed | :blocked | {:confirm, String.t()}
Callbacks
@callback classify_risk(action :: String.t(), opts :: keyword()) :: risk_level()
Classify the risk level of an action.
@callback evaluate( action :: String.t(), trust_level :: SigilGuard.Identity.trust_level(), opts :: keyword() ) :: verdict()
Evaluate an action against a trust level and return a verdict.
Functions
@spec classify_risk( String.t(), keyword() ) :: risk_level()
Classify the risk level of an action based on pattern matching.
Uses :risk_mappings option or falls back to built-in heuristics based on
action name prefixes.
Built-in Risk Heuristics
"delete_","drop_","destroy_","execute_","run_"→:high"write_","update_","create_","modify_","send_"→:medium"read_","get_","list_","search_"→:low- Everything else →
:medium
@spec compare_risk(risk_level(), risk_level()) :: :lt | :eq | :gt
Compare two risk levels.
Examples
iex> SigilGuard.Policy.compare_risk(:low, :high)
:lt
iex> SigilGuard.Policy.compare_risk(:high, :medium)
:gt
@spec ensure_rate_table(atom()) :: :ok
Ensure the ETS table used by rate_check/2 exists.
The default table is created automatically at application start; call
this only to pre-create a custom :rate_store table from a process that
outlives the callers (the table is owned by the process that creates it).
Safe to call concurrently — creation races resolve to the existing table.
@spec evaluate(String.t(), SigilGuard.Identity.trust_level(), keyword()) :: verdict()
Evaluate an action against a trust level.
Returns :allowed if trust is sufficient, {:confirm, reason} if the caller
is one trust level below the threshold (allowing interactive confirmation),
or :blocked otherwise.
Options
:risk_level— override the risk classification (default: look up via:risk_mappings):risk_mappings— map of action pattern to risk level:trust_thresholds— override default trust thresholds per risk level
Examples
iex> SigilGuard.Policy.evaluate("read_file", :medium)
:allowed
iex> SigilGuard.Policy.evaluate("delete_database", :low)
:blocked
Perform a rate check for an identity performing an action.
Returns :ok if within limits, or {:error, :rate_limited} if exceeded.
This is a fixed-window counter: an identity's first request opens a
window, requests within :window_ms count against :max_requests, and
the next request after the window expires opens a fresh one. Two limits
follow from that design — suitable for coarse abuse protection, not
strict quotas:
- Check and increment are separate ETS operations, so concurrent
callers can slightly exceed
:max_requestsunder contention. - Up to
2 × max_requestscan pass in a burst straddling a window boundary, as with any fixed-window scheme.
For strict guarantees, implement the SigilGuard.Policy behaviour with
a dedicated rate limiter backend.
Options
:max_requests— maximum requests per window (default: 100):window_ms— time window in milliseconds (default: 60_000):rate_store— ETS table name for rate tracking (default::sigil_guard_rates)
The default table is created at application start and lives as long as
the application. A custom :rate_store table is created on first use
and owned by the first calling process — its rate state is lost if that
process exits.
@spec risk_levels() :: [risk_level(), ...]
Return all risk levels in ascending order.
Examples
iex> SigilGuard.Policy.risk_levels()
[:low, :medium, :high]
@spec trust_threshold(risk_level()) :: SigilGuard.Identity.trust_level()
Return the default trust threshold for a risk level.
Examples
iex> SigilGuard.Policy.trust_threshold(:high)
:high
iex> SigilGuard.Policy.trust_threshold(:low)
:low