use serde::{Deserialize, Serialize};
pub use vyre_foundation::soundness::{
validate_dynamic_pipeline, validate_dynamic_primitive, validate_pipeline, validate_primitive,
DynamicPrimitiveSoundness, DynamicSoundnessViolation, PrecisionContract, PrimitiveSoundness,
Soundness, SoundnessTagged, SoundnessViolation,
};
pub const SHARED_FACT_SCHEMA_VERSION: u16 = 1;
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
pub enum SharedFactKind {
Source,
Sink,
Taint,
Sanitizer,
GraphEdge,
BorrowLoan,
BorrowOrigin,
BorrowSubset,
Dominance,
Range,
Witness,
}
impl SharedFactKind {
#[must_use]
pub const fn wire_tag(self) -> &'static str {
match self {
Self::Source => "source",
Self::Sink => "sink",
Self::Taint => "taint",
Self::Sanitizer => "sanitizer",
Self::GraphEdge => "graph_edge",
Self::BorrowLoan => "borrow_loan",
Self::BorrowOrigin => "borrow_origin",
Self::BorrowSubset => "borrow_subset",
Self::Dominance => "dominance",
Self::Range => "range",
Self::Witness => "witness",
}
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct SharedFactHeader {
pub schema_version: u16,
pub producer: String,
pub kind: SharedFactKind,
pub fact_id: u64,
pub subject: u64,
pub object: Option<u64>,
pub aux: Option<u64>,
pub file_id: u32,
pub start_byte: u32,
pub end_byte: u32,
pub soundness: Soundness,
}
impl SharedFactHeader {
#[must_use]
pub fn new(
producer: impl Into<String>,
kind: SharedFactKind,
fact_id: u64,
subject: u64,
soundness: Soundness,
) -> Self {
Self {
schema_version: SHARED_FACT_SCHEMA_VERSION,
producer: producer.into(),
kind,
fact_id,
subject,
object: None,
aux: None,
file_id: 0,
start_byte: 0,
end_byte: 0,
soundness,
}
}
#[must_use]
pub const fn with_object(mut self, object: u64) -> Self {
self.object = Some(object);
self
}
#[must_use]
pub const fn with_aux(mut self, aux: u64) -> Self {
self.aux = Some(aux);
self
}
#[must_use]
pub const fn with_span(mut self, file_id: u32, start_byte: u32, end_byte: u32) -> Self {
self.file_id = file_id;
self.start_byte = start_byte;
self.end_byte = end_byte;
self
}
#[must_use]
pub fn wire_header(&self) -> String {
format!(
"schema=v{};producer={};kind={};fact_id={};subject={};object={};aux={};file={};start={};end={};soundness={:?}",
self.schema_version,
self.producer,
self.kind.wire_tag(),
self.fact_id,
self.subject,
self.object.unwrap_or(0),
self.aux.unwrap_or(0),
self.file_id,
self.start_byte,
self.end_byte,
self.soundness
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn c_security_source_fact_header_is_exact() {
let header = SharedFactHeader::new("c-c11", SharedFactKind::Source, 1, 42, Soundness::Exact)
.with_span(7, 100, 120);
assert_eq!(
header.wire_header(),
"schema=v1;producer=c-c11;kind=source;fact_id=1;subject=42;object=0;aux=0;file=7;start=100;end=120;soundness=Exact"
);
}
#[test]
fn rust_borrow_subset_fact_header_is_exact() {
let header = SharedFactHeader::new(
"rustc-nll",
SharedFactKind::BorrowSubset,
9,
3,
Soundness::Exact,
)
.with_object(5)
.with_aux(11);
assert_eq!(
header.wire_header(),
"schema=v1;producer=rustc-nll;kind=borrow_subset;fact_id=9;subject=3;object=5;aux=11;file=0;start=0;end=0;soundness=Exact"
);
}
#[test]
fn weir_witness_fact_header_is_exact() {
let header = SharedFactHeader::new("weir", SharedFactKind::Witness, 13, 21, Soundness::Exact)
.with_object(34)
.with_aux(55);
assert_eq!(
header.wire_header(),
"schema=v1;producer=weir;kind=witness;fact_id=13;subject=21;object=34;aux=55;file=0;start=0;end=0;soundness=Exact"
);
}
}