systemprompt_security/policy/registry.rs
1//! Inventory-based registration for governance policies.
2//!
3//! Companion to [`crate::authz::AuthzHookRegistration`]: policies register a
4//! factory at static-init time and [`super::GovernanceEngine::from_config`]
5//! resolves configured ids against the collected set. The four built-in
6//! policies in [`super::builtin`] self-register here; extensions add their own
7//! via [`crate::register_governance_policy!`] and enable them from the same
8//! `governance.policies` YAML sequence.
9//!
10//! Copyright (c) systemprompt.io — Business Source License 1.1.
11//! See <https://systemprompt.io> for licensing details.
12
13use serde_yaml::Value as YamlValue;
14
15use super::types::GovernancePolicy;
16
17/// Constructs one policy instance from its raw YAML config entry.
18///
19/// Runs once per [`super::GovernanceEngine::from_config`] call and must not
20/// block; a factory receives `YamlValue::Null` when the policy is absent from
21/// config. A rejected entry is an error the engine refuses to start on.
22pub type PolicyFactory =
23 fn(&YamlValue) -> Result<Box<dyn GovernancePolicy>, PolicyConfigurationError>;
24
25/// Why a policy factory rejected its YAML entry.
26#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
27#[error("{0}")]
28pub struct PolicyConfigurationError(pub String);
29
30/// One inventory submission per policy. `id` is the stable referent used in
31/// `governance.policies` YAML and in `governance_decisions.policy`.
32#[derive(Debug, Clone, Copy)]
33pub struct PolicyRegistration {
34 pub id: &'static str,
35 pub factory: PolicyFactory,
36}
37
38inventory::collect!(PolicyRegistration);
39
40#[doc(hidden)]
41pub use inventory;
42
43#[macro_export]
44macro_rules! register_governance_policy {
45 ($id:expr, $factory:expr) => {
46 $crate::policy::registry::inventory::submit! {
47 $crate::policy::PolicyRegistration {
48 id: $id,
49 factory: $factory,
50 }
51 }
52 };
53}