pub mod host;
pub use praxis_policy;
pub use praxis_policy::*;
#[cfg(feature = "python-host")]
pub use cpex_hosts_python;
#[cfg(feature = "python-host")]
pub use cpex_hosts_python::{IsolatedVenvFactory, KIND as ISOLATED_VENV_KIND};
#[cfg(test)]
mod tests {
use super::*;
use praxis_policy_core::config::parse_config;
use std::sync::Arc;
#[test]
fn install_builtins_runs_without_panic() {
let engine = Arc::new(PolicyEngine::default());
install_builtins(&engine);
}
#[test]
fn policy_config_parses_through_the_facade() {
let config = parse_config(
r#"
plugins:
- name: jwt
kind: identity/jwt
hooks: [identity.resolve]
"#,
)
.expect("valid config");
assert_eq!(config.plugins.len(), 1);
assert_eq!(config.plugins[0].hooks, vec!["identity.resolve".to_owned()]);
}
#[test]
fn legacy_hook_name_is_rejected() {
let engine = Arc::new(PolicyEngine::default());
install_builtins(&engine);
let err = engine
.load_config_yaml(
r#"
plugins:
- name: jwt
kind: identity/jwt
hooks: [tool_pre_invoke]
"#,
)
.expect_err("legacy hook names are removed");
let err = err.to_string();
assert!(err.contains("'cmf.tool_pre_invoke'"), "{err}");
}
}
#[cfg(all(test, feature = "python-host"))]
mod python_host_tests {
use super::*;
use praxis_policy_core::config::parse_config;
use praxis_policy_core::factory::PluginFactoryRegistry;
fn minimal_config_yaml() -> &'static str {
r#"
engine_settings:
dispatch: hooks
plugins:
- name: pii-filter
kind: isolated_venv
hooks: [cmf.tool_pre_invoke]
config:
class_name: my_pkg.filters.PiiFilter
"#
}
#[test]
fn from_config_instantiates_the_python_host() {
let config = parse_config(minimal_config_yaml()).expect("valid YAML");
let mut factories = PluginFactoryRegistry::new();
factories.register(ISOLATED_VENV_KIND, Box::new(IsolatedVenvFactory));
let engine = PolicyEngine::from_config(config, &factories)
.expect("isolated_venv factory is registered, so instantiation succeeds");
assert_eq!(engine.plugin_count(), 1);
assert!(engine.has_hooks_for("cmf.tool_pre_invoke"));
}
#[test]
fn register_factory_then_load_yaml_wires_the_python_host() {
let engine = std::sync::Arc::new(PolicyEngine::default());
engine.register_factory(ISOLATED_VENV_KIND, Box::new(IsolatedVenvFactory));
engine
.load_config_yaml(
r#"
engine_settings:
dispatch: hooks
plugins:
- name: py-identity
kind: isolated_venv
hooks: [identity.resolve, token.delegate, cmf.tool_pre_invoke]
config:
class_name: my_pkg.Resolver
"#,
)
.expect("the isolated_venv kind resolves through the facade");
for hook in ["identity.resolve", "token.delegate", "cmf.tool_pre_invoke"] {
assert!(engine.has_hooks_for(hook), "no handler on {hook}");
}
}
}