//! Ingest a directory of OSV JSON records and report what came out. //! //! Used to validate the parser against the real feed rather than against //! fixtures. Fixtures test the shape you expected; the feed tests the //! shape that ships. //! //! cargo run -p hound-defs --example ingest-osv -- [lookup-name] use hound_defs::{osv, Index}; fn main() { let mut args = std::env::args().skip(1); let Some(dir) = args.next() else { eprintln!("usage: ingest-osv [name-to-look-up]"); std::process::exit(2); }; let probe = args.next(); let mut files = 0usize; let mut unparsed = 0usize; let mut indicators = Vec::new(); let mut malicious = 0usize; for entry in std::fs::read_dir(&dir).expect("readable directory").flatten() { let path = entry.path(); if path.extension().is_none_or(|e| e != "json") { continue; } files += 1; let Ok(text) = std::fs::read_to_string(&path) else { continue }; let parsed = osv::parse_record(&text); if parsed.is_empty() { unparsed += 1; continue; } if parsed[0].id.starts_with("MAL-") { malicious += parsed.len(); } indicators.extend(parsed); } let mut ecosystems: std::collections::BTreeMap = Default::default(); let mut all_versions = 0usize; for i in &indicators { *ecosystems.entry(i.ecosystem.clone()).or_default() += 1; if i.versions == osv::Versions::All { all_versions += 1; } } println!("files read {files}"); println!("yielded nothing {unparsed}"); println!("indicators {}", indicators.len()); println!(" of those MAL- {malicious}"); println!(" all-versions {all_versions}"); println!("ecosystems {ecosystems:?}"); let index = Index::build(indicators); println!("index keys {}", index.len()); println!("filter {:.1} KB", index.filter_bytes() as f64 / 1024.0); if let Some(name) = probe { for eco in ["cratesio", "npm", "pypi"] { match index.any_version(eco, &name) { Some(hit) => println!("\nLOOKUP {eco}:{name} -> {} — {}", hit.id, hit.summary), None => println!("\nLOOKUP {eco}:{name} -> clean"), } } } }