Skip to main content

vyre_libs/dataflow/
mod.rs

1//! Compatibility facade for shared dataflow soundness contracts.
2//!
3//! `vyre-libs::dataflow` remains as a stable import path for older consumers,
4//! but platform crates must not re-export downstream analysis engines. Concrete
5//! IFDS, SSA, reaching-definition, callgraph, slicing, range, and related
6//! analyses live in their owning engine crates and consume these shared
7//! contracts from `vyre-foundation`.
8
9use serde::{Deserialize, Serialize};
10
11pub use vyre_foundation::soundness::{
12    validate_dynamic_pipeline, validate_dynamic_primitive, validate_pipeline, validate_primitive,
13    DynamicPrimitiveSoundness, DynamicSoundnessViolation, PrecisionContract, PrimitiveSoundness,
14    Soundness, SoundnessTagged, SoundnessViolation,
15};
16
17/// Shared fact-schema version for security, borrowck, and Weir/Vyre bridges.
18pub const SHARED_FACT_SCHEMA_VERSION: u16 = 1;
19
20/// Cross-engine fact families accepted by the shared dataflow schema.
21#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
22pub enum SharedFactKind {
23    /// Attacker-controlled or analysis source fact.
24    Source,
25    /// Security sink fact.
26    Sink,
27    /// Taint/dataflow reachability fact.
28    Taint,
29    /// Sanitizer or kill-set fact.
30    Sanitizer,
31    /// Program graph edge or call/control edge fact.
32    GraphEdge,
33    /// Rust borrow loan fact.
34    BorrowLoan,
35    /// Rust origin/region fact.
36    BorrowOrigin,
37    /// Rust origin subset/outlives fact.
38    BorrowSubset,
39    /// Dominance or authorization-guard fact.
40    Dominance,
41    /// Numeric range or bounds fact.
42    Range,
43    /// Source-to-sink witness/path fact.
44    Witness,
45}
46
47impl SharedFactKind {
48    /// Stable wire tag used by columnar schemas and release evidence.
49    #[must_use]
50    pub const fn wire_tag(self) -> &'static str {
51        match self {
52            Self::Source => "source",
53            Self::Sink => "sink",
54            Self::Taint => "taint",
55            Self::Sanitizer => "sanitizer",
56            Self::GraphEdge => "graph_edge",
57            Self::BorrowLoan => "borrow_loan",
58            Self::BorrowOrigin => "borrow_origin",
59            Self::BorrowSubset => "borrow_subset",
60            Self::Dominance => "dominance",
61            Self::Range => "range",
62            Self::Witness => "witness",
63        }
64    }
65}
66
67/// Minimal cross-engine fact header.
68#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
69pub struct SharedFactHeader {
70    /// Schema version, currently [`SHARED_FACT_SCHEMA_VERSION`].
71    pub schema_version: u16,
72    /// Producer id such as `c-c11`, `rustc-nll`, or `weir`.
73    pub producer: String,
74    /// Shared fact family.
75    pub kind: SharedFactKind,
76    /// Stable producer-local fact id.
77    pub fact_id: u64,
78    /// Primary subject id.
79    pub subject: u64,
80    /// Optional object id.
81    pub object: Option<u64>,
82    /// Optional auxiliary id, usually a point, edge kind, or relation id.
83    pub aux: Option<u64>,
84    /// Stable file id, or zero when not source-spanned.
85    pub file_id: u32,
86    /// Start byte offset, inclusive.
87    pub start_byte: u32,
88    /// End byte offset, exclusive.
89    pub end_byte: u32,
90    /// Soundness label for the fact.
91    pub soundness: Soundness,
92}
93
94impl SharedFactHeader {
95    /// Build one shared fact header.
96    #[must_use]
97    pub fn new(
98        producer: impl Into<String>,
99        kind: SharedFactKind,
100        fact_id: u64,
101        subject: u64,
102        soundness: Soundness,
103    ) -> Self {
104        Self {
105            schema_version: SHARED_FACT_SCHEMA_VERSION,
106            producer: producer.into(),
107            kind,
108            fact_id,
109            subject,
110            object: None,
111            aux: None,
112            file_id: 0,
113            start_byte: 0,
114            end_byte: 0,
115            soundness,
116        }
117    }
118
119    /// Attach an object id.
120    #[must_use]
121    pub const fn with_object(mut self, object: u64) -> Self {
122        self.object = Some(object);
123        self
124    }
125
126    /// Attach an auxiliary relation id.
127    #[must_use]
128    pub const fn with_aux(mut self, aux: u64) -> Self {
129        self.aux = Some(aux);
130        self
131    }
132
133    /// Attach a byte span.
134    #[must_use]
135    pub const fn with_span(mut self, file_id: u32, start_byte: u32, end_byte: u32) -> Self {
136        self.file_id = file_id;
137        self.start_byte = start_byte;
138        self.end_byte = end_byte;
139        self
140    }
141
142    /// Render the stable compact header used by schema contract tests.
143    #[must_use]
144    pub fn wire_header(&self) -> String {
145        format!(
146            "schema=v{};producer={};kind={};fact_id={};subject={};object={};aux={};file={};start={};end={};soundness={:?}",
147            self.schema_version,
148            self.producer,
149            self.kind.wire_tag(),
150            self.fact_id,
151            self.subject,
152            self.object.unwrap_or(0),
153            self.aux.unwrap_or(0),
154            self.file_id,
155            self.start_byte,
156            self.end_byte,
157            self.soundness
158        )
159    }
160}
161
162#[cfg(test)]
163mod tests {
164    use super::*;
165
166    #[test]
167    fn c_security_source_fact_header_is_exact() {
168        let header = SharedFactHeader::new("c-c11", SharedFactKind::Source, 1, 42, Soundness::Exact)
169            .with_span(7, 100, 120);
170
171        assert_eq!(
172            header.wire_header(),
173            "schema=v1;producer=c-c11;kind=source;fact_id=1;subject=42;object=0;aux=0;file=7;start=100;end=120;soundness=Exact"
174        );
175    }
176
177    #[test]
178    fn rust_borrow_subset_fact_header_is_exact() {
179        let header = SharedFactHeader::new(
180            "rustc-nll",
181            SharedFactKind::BorrowSubset,
182            9,
183            3,
184            Soundness::Exact,
185        )
186        .with_object(5)
187        .with_aux(11);
188
189        assert_eq!(
190            header.wire_header(),
191            "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"
192        );
193    }
194
195    #[test]
196    fn weir_witness_fact_header_is_exact() {
197        let header = SharedFactHeader::new("weir", SharedFactKind::Witness, 13, 21, Soundness::Exact)
198            .with_object(34)
199            .with_aux(55);
200
201        assert_eq!(
202            header.wire_header(),
203            "schema=v1;producer=weir;kind=witness;fact_id=13;subject=21;object=34;aux=55;file=0;start=0;end=0;soundness=Exact"
204        );
205    }
206}