allow_core/
lane_posture.rs1use crate::{CargoAllowError, FindingKind};
2use std::collections::BTreeMap;
3use std::str::FromStr;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
6pub enum LaneEnforcementMode {
7 Advisory,
8 Shadow,
9 #[default]
10 Blocking,
11}
12
13impl LaneEnforcementMode {
14 pub const ALL: &[Self] = &[Self::Advisory, Self::Shadow, Self::Blocking];
15
16 pub fn as_str(self) -> &'static str {
17 match self {
18 Self::Advisory => "advisory",
19 Self::Shadow => "shadow",
20 Self::Blocking => "blocking",
21 }
22 }
23
24 pub fn blocks_check_failure(self) -> bool {
25 matches!(self, Self::Blocking)
26 }
27}
28
29impl FromStr for LaneEnforcementMode {
30 type Err = CargoAllowError;
31
32 fn from_str(value: &str) -> Result<Self, Self::Err> {
33 let trimmed = value.trim();
34 let normalized = trimmed.to_ascii_lowercase();
35 match normalized.as_str() {
36 "advisory" => Ok(Self::Advisory),
37 "shadow" => Ok(Self::Shadow),
38 "blocking" => Ok(Self::Blocking),
39 _ => Err(CargoAllowError::new(format!(
40 "unsupported lane enforcement mode `{trimmed}`; valid values: advisory, shadow, blocking"
41 ))),
42 }
43 }
44}
45
46#[derive(Debug, Clone, PartialEq, Eq)]
47pub struct LaneConfig {
48 pub mode: LaneEnforcementMode,
49}
50
51pub fn lane_enforcement_mode_for_kind(
52 lanes: &BTreeMap<String, LaneConfig>,
53 kind: FindingKind,
54) -> LaneEnforcementMode {
55 lanes
56 .get(kind.as_str())
57 .map(|lane| lane.mode)
58 .unwrap_or(LaneEnforcementMode::Blocking)
59}
60
61pub fn effective_lane_posture_for_findings(
62 lanes: &BTreeMap<String, LaneConfig>,
63 kinds: impl IntoIterator<Item = FindingKind>,
64) -> BTreeMap<String, LaneEnforcementMode> {
65 let mut effective = lanes
66 .iter()
67 .map(|(name, lane)| (name.clone(), lane.mode))
68 .collect::<BTreeMap<_, _>>();
69 for kind in kinds {
70 effective
71 .entry(kind.as_str().to_string())
72 .or_insert(LaneEnforcementMode::Blocking);
73 }
74 effective
75}
76
77#[cfg(test)]
78#[path = "lane_posture_tests.rs"]
79mod tests;