diff --git a/crates/didbot-policy/src/evaluate.rs b/crates/didbot-policy/src/evaluate.rs index 299ee275..286a4099 100644 --- a/crates/didbot-policy/src/evaluate.rs +++ b/crates/didbot-policy/src/evaluate.rs @@ -9,9 +9,9 @@ //! Only which reason is reported, when several outcomes tie for the worst //! severity, depends on order. +use crate::index::PolicyTree; use crate::outcome::Outcome; use crate::policy::PolicyId; -use crate::index::PolicyTree; use crate::subject::Subject; /// The result of evaluating a subject against every candidate policy. @@ -163,7 +163,7 @@ mod tests { #[test] fn shuffling_outcomes_cannot_change_the_verdict_severity() { use Outcome::*; - let base = vec![ + let base = [ (pid(0), Allow), (pid(1), reject("a")), (pid(2), Allow), diff --git a/crates/didbot-policy/src/index.rs b/crates/didbot-policy/src/index.rs index 22e415e4..8e865dd3 100644 --- a/crates/didbot-policy/src/index.rs +++ b/crates/didbot-policy/src/index.rs @@ -209,8 +209,9 @@ impl PolicyTree { /// The ordered candidate policies this subject may be decided by. /// - /// For a write matching nothing, this costs only the tree walk - /// [`WriteIndex::candidates`] documents — no evaluator is invoked. + /// For a write matching nothing, this costs only a tree walk bounded by + /// the write's own changed paths, never by how many policies are + /// registered — no evaluator is invoked. pub fn decision_candidates(&self, subject: &Subject<'_>) -> Vec { match subject { Subject::Write { @@ -222,9 +223,7 @@ impl PolicyTree { .index .write_decision .candidates(collection, *action, diff.changed_paths), - Subject::Grant { client_id, .. } => { - self.index.grant_decision.candidates(client_id) - } + Subject::Grant { client_id, .. } => self.index.grant_decision.candidates(client_id), } } @@ -244,9 +243,7 @@ impl PolicyTree { .index .write_observation .candidates(collection, *action, diff.changed_paths), - Subject::Grant { client_id, .. } => { - self.index.grant_observation.candidates(client_id) - } + Subject::Grant { client_id, .. } => self.index.grant_observation.candidates(client_id), } } } @@ -293,8 +290,18 @@ impl PolicyTreeBuilder { for (i, decl) in self.declarations.iter().enumerate() { let policy = PolicyId(i as u32); policy_evaluator.push(decl.evaluator); - insert(&mut index.write_decision, &mut index.grant_decision, policy, &decl.applicability); - insert(&mut index.write_observation, &mut index.grant_observation, policy, &decl.observes); + insert( + &mut index.write_decision, + &mut index.grant_decision, + policy, + &decl.applicability, + ); + insert( + &mut index.write_observation, + &mut index.grant_observation, + policy, + &decl.observes, + ); } PolicyTree { evaluators: self.evaluators, diff --git a/crates/didbot-policy/src/lib.rs b/crates/didbot-policy/src/lib.rs index 3de37382..9097afab 100644 --- a/crates/didbot-policy/src/lib.rs +++ b/crates/didbot-policy/src/lib.rs @@ -4,7 +4,7 @@ //! This is the core `plan/policy.md` describes — not a policy language, not //! an evaluator, not I/O. Two sibling crates use it: `didbot-policy-regex` //! is a deterministic in-process [`Evaluator`], and `didbot-pds`'s write -//! path drives [`evaluate`] per write, outside its store lock, and turns a +//! path drives [`evaluate()`] per write, outside its store lock, and turns a //! [`Verdict::Freeze`] into the queue-draining behaviour `plan/policy.md` //! describes under "Outcomes" — this crate produces the verdict and stops //! there. @@ -22,7 +22,7 @@ //! subject's own diff, not by how many policies are registered. //! - [`Outcome`], [`Staleness`], [`Observed`], [`Lifecycle`], [`EvalError`] //! and the [`Evaluator`] trait — the contract every evaluator implements. -//! - [`Verdict`], [`combine`] and [`evaluate`] — ordered evaluation with +//! - [`Verdict`], [`combine`] and [`evaluate()`] — ordered evaluation with //! deny-only semantics. [`combine`] is where monotonicity is structural //! rather than conventional: see its doc comment. //! @@ -81,7 +81,11 @@ mod tests { } impl Evaluator for Fixed { - fn evaluate(&self, _subject: &Subject<'_>, _policy: PolicyId) -> Result { + fn evaluate( + &self, + _subject: &Subject<'_>, + _policy: PolicyId, + ) -> Result { self.calls.fetch_add(1, Ordering::SeqCst); Ok(self.outcome.clone()) } @@ -235,7 +239,10 @@ mod tests { WriteAction::Update, &["displayName"], ); - assert!(matches!(evaluate(&name_edit, &tree), Verdict::Reject { .. })); + assert!(matches!( + evaluate(&name_edit, &tree), + Verdict::Reject { .. } + )); } /// The observation surface is independent of the decision surface: a