openvet-policy 0.6.0

Requirement language and Kleene evaluator for OpenVet audit policies.
Documentation
//! # Requirement language and policy evaluator for OpenVet
//!
//! Turns a project's TOML-defined policy and the audits collected
//! for a single subject into a pass-or-fail [`Verdict`] with
//! per-requirement diagnostics. The wire format and evaluator
//! semantics are specified in `spec/policy.md`.
//!
//! # Requirements, claims, expressions
//!
//! A *claim* is a `(name, bool)` pair emitted by an audit (e.g.
//! `memory-unsafe-code: true`). OpenVet's canonical claim
//! vocabulary (`spec/vocabulary.md`) is deliberately atomic: each
//! claim is an observable property of the code, rather than a
//! context-sensitive judgement.
//!
//! A *requirement* is a boolean expression over claim names that
//! the consumer wants to hold for every dependency, e.g.
//! `(not memory-unsafe-code) or reviewed-unsafe`. Expressions
//! support `and`, `or`, `not`, and parentheses with standard
//! precedence; claim names are `[a-zA-Z_][a-zA-Z0-9_-]*`. See
//! [`expr::Expr`] and [`expr::parse`].
//!
//! # TOML shape
//!
//! ```toml
//! # Bare form: default-on requirement, value is the expression.
//! [requirement]
//! safe-to-deploy = "(not memory-unsafe-code) or reviewed-unsafe"
//!
//! # Table form: opt-in by overriding into the requirement set.
//! [requirement.fuzz-tested]
//! condition = "has-fuzz-tests"
//! default = false
//!
//! # Per-subject overrides. Matcher fields are AND'd; "*" or omitted
//! # is a wildcard.
//! [[override]]
//! registry = "cargo"
//! package = "libc"
//! requirements = { add = ["fuzz-tested"], remove = ["safe-to-deploy"] }
//!
//! [[override]]
//! package = "serde"
//! requirements = ["safe-to-deploy"]   # replace form
//!
//! # Cross-log claim renames: "log:claim" → canonical name.
//! [alias]
//! reviewed-unsafe = ["mozilla:audited-unsafe", "google:unsafe-verified"]
//! ```
//!
//! # Overrides and aliases
//!
//! The effective requirement set for a subject is computed by
//! walking the `[[override]]` blocks in declaration order: each
//! override whose matcher matches the subject either replaces the
//! working set or patches it, depending on whether `requirements`
//! is a plain list (replace) or an `{ add = [...], remove = [...] }`
//! table (patch). [`config::Override`], [`config::SubjectMatcher`],
//! and [`config::OverrideOp`] carry the parsed shapes.
//!
//! Aliases let a consumer treat differently-named claims from
//! different logs as the same canonical claim. They apply at
//! claim-lookup time; an audit from a log not listed under an
//! alias falls through to the canonical name unchanged. See
//! [`config::Alias`].
//!
//! # Evaluation
//!
//! Three-valued Kleene logic per audit ([`expr::Tri`]) with
//! standard short-circuiting: `False` short-circuits `and`, `True`
//! short-circuits `or`, and `not Unknown == Unknown`. The
//! `Unknown` branch is load-bearing: an audit can perfectly well
//! not have an opinion on a claim, and that is not the same as
//! actively asserting it false.
//!
//! A requirement passes for a subject iff at least one audit
//! returns `True` and no audit returns `False`. Fail variants
//! distinguish "nobody had enough info"
//! ([`eval::FailureKind::NotAsserted`]) from "an audit explicitly
//! disagrees" ([`eval::FailureKind::Contradicted`]); the latter
//! carries a snapshot of the relevant claims so the failure
//! message can show why. A subject passes iff all of its effective
//! requirements pass.
//!
//! # Usage
//!
//! ```rust,ignore
//! use openvet_policy::{parse_str, evaluate};
//!
//! let policy = parse_str(r#"
//!     [requirement]
//!     safe-to-deploy = "(not memory-unsafe-code) or reviewed-unsafe"
//! "#)?;
//! let verdict = evaluate(&policy, &subject, &[("alice", &audit)]);
//! println!("{verdict}");
//! # Ok::<(), openvet_policy::PolicyError>(())
//! ```
//!
//! [`Verdict`]'s `Display` impl produces the human-readable
//! explanation `openvet check` prints; programmatic consumers can
//! walk the [`Verdict::Fail`] variant's [`eval::FailureReason`]s
//! directly.

pub mod config;
pub(crate) mod error;
pub mod eval;
pub mod explain;
pub mod expr;

pub use config::{Policy, parse, parse_str};
pub use error::{PolicyError, Result};
pub use eval::{Verdict, evaluate};