pub fn analyze(
old: &PolicyBundle,
new: &PolicyBundle,
replay: &[ReplayRequest],
clock: &dyn Clock,
) -> Result<BlastRadiusReport, String>Expand description
Replay the corpus against both bundles and classify the changes.
Each ReplayRequest is evaluated by the old Authorizer and the new
Authorizer. The pair of decisions is classified; samples of
AllowToDeny and DenyToAllow flips are retained (capped at
SAMPLE_CAP) for debugging and audit.
§Errors
Returns an error string if either bundle’s schema or policy set fails
to parse. The replay engine itself is infallible (the cedar
Authorizer::authorize does not return an error for a well-formed
request — cedar policy evaluation is total).
§Examples
use agentguard_policy::blast_radius::{analyze, ReplayRequest};
use agentguard_policy::{NamedPolicy, PolicyBundle};
use agentguard_policy::version::PolicyVersion;
use agentguard_core::AgentRequestBuilder;
use agentguard_core::{Principal, AgentAction, Resource, AgentContext};
use agentguard_core::ttl::SystemClock;
let schema = r#"entity User;
entity Mailbox;
action "ToolCall::send_email" appliesTo { principal: [User], resource: [Mailbox] };"#;
let bundle = |src: &str| PolicyBundle {
version: PolicyVersion::new(1),
tenant_id: "test".into(),
schema_hash: [0u8; 32],
policies_hash: [0u8; 32],
created_at: 0,
created_by: "test".into(),
signature: None,
schema_source: schema.into(),
policies: vec![NamedPolicy { id: "p".into(), source: src.into() }],
};
let req = ReplayRequest {
request: Box::new(
AgentRequestBuilder::new(Principal::user("alice"))
.action(AgentAction::tool("send_email"))
.resource(Resource::new("Mailbox", "alice@acme"))
.context(AgentContext::new())
.build()
.unwrap()
),
entities: vec![],
old_effect: "allow".into(),
};
let report = analyze(
&bundle(r#"permit (principal in User::"alice", action == Action::"ToolCall::send_email", resource == Mailbox::"alice@acme");"#),
&bundle(r#"forbid (principal, action, resource);"#),
&[req],
&SystemClock,
)
.unwrap();
assert_eq!(report.allow_to_deny, 1);