Normandy.Behaviours.PolicyEngine.Ruleset (normandy v2.2.0)

View Source

PolicyEngine that evaluates an ordered list of in-memory rules, first match wins, with a configurable default action. The ruleset is supplied as a keyword list on ctx.opts (the opts half of the bundle's {module, opts} ref — always a keyword list by construction):

  • :rules (required) — list of %{match, action, rule_id, rationale} maps. match (required) is a tool-name glob: "*" (matches all), "prefix_*" (trailing * only — prefix match), or an exact name. action (required) is :allow | :deny | :require_approval.
  • :default_action (required) — action when no rule matches. There is no implicit :allow: a policy states what an unmatched call gets.

A rule sees the tool's name only. An MCP server or a remote A2A agent chooses its own tools' names, so match those on the prefix you gave them ("srv__*", see Normandy.MCP.ToolWrapper's "Tool names and policy rules"), never on a name such as "read_*" that a server can choose to match.

A malformed ruleset raises ArgumentError: when the agent is built (validate_opts!/1), and again in check/2, which the dispatch chokepoint turns into a denial. It never fails open.

A YAML-file loader is intentionally deferred — YAML is only a serialization of this in-memory shape.