forensicnomicon_data/
evidence.rs1pub use forensicnomicon_core::evidence::EvidenceStrength;
14
15pub fn evidence_for(artifact_id: &str) -> Option<&'static crate::catalog::ArtifactDescriptor> {
21 crate::catalog::CATALOG
22 .by_id(artifact_id)
23 .filter(|d| d.evidence_strength.is_some())
24}
25
26pub fn artifacts_with_strength(
28 min_strength: EvidenceStrength,
29) -> Vec<&'static crate::catalog::ArtifactDescriptor> {
30 crate::catalog::CATALOG
31 .list()
32 .iter()
33 .filter(|d| d.evidence_strength.is_some_and(|s| s >= min_strength))
34 .collect()
35}
36
37#[cfg(test)]
38mod tests {
39 use super::*;
40 use crate::catalog::{TriagePriority, CATALOG};
41
42 #[test]
43 fn evidence_for_returns_descriptor() {
44 let result: Option<&crate::catalog::ArtifactDescriptor> = evidence_for("shimcache");
45 assert!(result.is_some());
46 }
47
48 #[test]
49 fn prefetch_is_definitive() {
50 let e = evidence_for("prefetch_file").expect("prefetch_file must be assessed");
51 assert_eq!(e.evidence_strength, Some(EvidenceStrength::Definitive));
52 }
53
54 #[test]
55 fn bash_history_is_circumstantial() {
56 let e = evidence_for("linux_bash_history").expect("linux_bash_history must be assessed");
57 assert_eq!(e.evidence_strength, Some(EvidenceStrength::Circumstantial));
58 }
59
60 #[test]
61 fn definitive_entries_have_caveats() {
62 for d in CATALOG.list() {
63 if d.evidence_strength == Some(EvidenceStrength::Definitive) {
64 assert!(
65 !d.evidence_caveats.is_empty(),
66 "{} is Definitive but has no caveats documented",
67 d.id
68 );
69 }
70 }
71 }
72
73 #[test]
74 fn filter_by_strength_returns_subset() {
75 let definitive = artifacts_with_strength(EvidenceStrength::Definitive);
76 let all = artifacts_with_strength(EvidenceStrength::Unreliable);
77 assert!(definitive.len() < all.len());
78 assert!(definitive
79 .iter()
80 .all(|d| d.evidence_strength == Some(EvidenceStrength::Definitive)));
81 }
82
83 #[test]
84 fn unknown_artifact_returns_none() {
85 assert!(evidence_for("this_does_not_exist").is_none());
86 }
87
88 #[test]
89 fn critical_triage_artifacts_have_evidence_entries() {
90 let missing: Vec<&str> = CATALOG
91 .for_triage()
92 .into_iter()
93 .filter(|d| d.triage_priority == TriagePriority::Critical)
94 .filter(|d| evidence_for(d.id).is_none())
95 .map(|d| d.id)
96 .collect();
97 assert!(
98 missing.is_empty(),
99 "Critical-priority artifacts missing from evidence table: {missing:?}"
100 );
101 }
102}