use rpki::validation::from_tal::discover_root_ca_instance_from_tal_and_ta_der; use rpki::validation::run_tree_from_tal::root_handle_from_trust_anchor; use rpki::validation::run_tree_from_tal::{ run_tree_from_tal_and_ta_der_serial, run_tree_from_tal_and_ta_der_serial_audit, run_tree_from_tal_url_serial, run_tree_from_tal_url_serial_audit, }; use rpki::validation::tree::TreeRunConfig; use std::collections::HashMap; struct MapHttpFetcher { map: HashMap>, } impl rpki::sync::rrdp::Fetcher for MapHttpFetcher { fn fetch(&self, uri: &str) -> Result, String> { self.map .get(uri) .cloned() .ok_or_else(|| format!("no fixture mapped for {uri}")) } } struct EmptyRsyncFetcher; impl rpki::fetch::rsync::RsyncFetcher for EmptyRsyncFetcher { fn fetch_objects( &self, _rsync_base_uri: &str, ) -> Result)>, rpki::fetch::rsync::RsyncFetchError> { Ok(Vec::new()) } } #[test] fn root_handle_is_constructible_from_fixture_tal_and_ta() { let tal_bytes = std::fs::read("tests/fixtures/tal/apnic-rfc7730-https.tal") .expect("read apnic tal fixture"); let ta_der = std::fs::read("tests/fixtures/ta/apnic-ta.cer").expect("read apnic ta fixture"); let discovery = discover_root_ca_instance_from_tal_and_ta_der(&tal_bytes, &ta_der, None).expect("discover"); let root = root_handle_from_trust_anchor(&discovery.trust_anchor, None, &discovery.ca_instance); assert_eq!(root.depth, 0); assert_eq!( root.manifest_rsync_uri, discovery.ca_instance.manifest_rsync_uri ); assert_eq!(root.rsync_base_uri, discovery.ca_instance.rsync_base_uri); assert!( root.ca_certificate_der.len() > 100, "TA der should be non-empty" ); } #[test] fn run_tree_from_tal_url_entry_executes_and_records_failure_when_repo_empty() { let tal_url = "mock:apnic.tal"; let tal_bytes = std::fs::read("tests/fixtures/tal/apnic-rfc7730-https.tal") .expect("read apnic tal fixture"); let ta_der = std::fs::read("tests/fixtures/ta/apnic-ta.cer").expect("read apnic ta fixture"); let mut map = HashMap::new(); map.insert(tal_url.to_string(), tal_bytes); map.insert( "https://rpki.apnic.net/repository/apnic-rpki-root-iana-origin.cer".to_string(), ta_der.clone(), ); map.insert( "rsync://rpki.apnic.net/repository/apnic-rpki-root-iana-origin.cer".to_string(), ta_der.clone(), ); let http = MapHttpFetcher { map }; let rsync = EmptyRsyncFetcher; let temp = tempfile::tempdir().expect("tempdir"); let store = rpki::storage::RocksStore::open(temp.path()).expect("open rocksdb"); let policy = rpki::policy::Policy { sync_preference: rpki::policy::SyncPreference::RsyncOnly, ..rpki::policy::Policy::default() }; let out = run_tree_from_tal_url_serial( &store, &policy, tal_url, &http, &rsync, time::OffsetDateTime::now_utc(), &TreeRunConfig { max_depth: Some(0), max_instances: Some(1), }, ) .expect("run tree"); assert_eq!(out.tree.instances_processed, 0); assert_eq!(out.tree.instances_failed, 1); assert!( out.tree .warnings .iter() .any(|w| w.message.contains("publication point failed")), "expected failure warning" ); } #[test] fn run_tree_from_tal_and_ta_der_entry_executes_and_records_failure_when_repo_empty() { let tal_bytes = std::fs::read("tests/fixtures/tal/apnic-rfc7730-https.tal") .expect("read apnic tal fixture"); let ta_der = std::fs::read("tests/fixtures/ta/apnic-ta.cer").expect("read apnic ta fixture"); let http = MapHttpFetcher { map: HashMap::new(), }; let rsync = EmptyRsyncFetcher; let temp = tempfile::tempdir().expect("tempdir"); let store = rpki::storage::RocksStore::open(temp.path()).expect("open rocksdb"); let policy = rpki::policy::Policy { sync_preference: rpki::policy::SyncPreference::RsyncOnly, ..rpki::policy::Policy::default() }; let out = run_tree_from_tal_and_ta_der_serial( &store, &policy, &tal_bytes, &ta_der, None, &http, &rsync, time::OffsetDateTime::now_utc(), &TreeRunConfig { max_depth: Some(0), max_instances: Some(1), }, ) .expect("run tree"); assert_eq!(out.tree.instances_processed, 0); assert_eq!(out.tree.instances_failed, 1); assert!( out.tree .warnings .iter() .any(|w| w.message.contains("publication point failed")), "expected failure warning" ); } #[test] fn run_tree_from_tal_url_audit_entry_collects_no_publication_points_when_repo_empty() { let tal_url = "mock:apnic.tal"; let tal_bytes = std::fs::read("tests/fixtures/tal/apnic-rfc7730-https.tal") .expect("read apnic tal fixture"); let ta_der = std::fs::read("tests/fixtures/ta/apnic-ta.cer").expect("read apnic ta fixture"); let mut map = HashMap::new(); map.insert(tal_url.to_string(), tal_bytes); map.insert( "https://rpki.apnic.net/repository/apnic-rpki-root-iana-origin.cer".to_string(), ta_der.clone(), ); map.insert( "rsync://rpki.apnic.net/repository/apnic-rpki-root-iana-origin.cer".to_string(), ta_der.clone(), ); let http = MapHttpFetcher { map }; let rsync = EmptyRsyncFetcher; let temp = tempfile::tempdir().expect("tempdir"); let store = rpki::storage::RocksStore::open(temp.path()).expect("open rocksdb"); let policy = rpki::policy::Policy { sync_preference: rpki::policy::SyncPreference::RsyncOnly, ..rpki::policy::Policy::default() }; let out = run_tree_from_tal_url_serial_audit( &store, &policy, tal_url, &http, &rsync, time::OffsetDateTime::now_utc(), &TreeRunConfig { max_depth: Some(0), max_instances: Some(1), }, ) .expect("run tree audit"); assert_eq!(out.tree.instances_processed, 0); assert_eq!(out.tree.instances_failed, 1); assert!(out.publication_points.is_empty()); } #[test] fn run_tree_from_tal_and_ta_der_audit_entry_collects_no_publication_points_when_repo_empty() { let tal_bytes = std::fs::read("tests/fixtures/tal/apnic-rfc7730-https.tal") .expect("read apnic tal fixture"); let ta_der = std::fs::read("tests/fixtures/ta/apnic-ta.cer").expect("read apnic ta fixture"); let http = MapHttpFetcher { map: HashMap::new(), }; let rsync = EmptyRsyncFetcher; let temp = tempfile::tempdir().expect("tempdir"); let store = rpki::storage::RocksStore::open(temp.path()).expect("open rocksdb"); let policy = rpki::policy::Policy { sync_preference: rpki::policy::SyncPreference::RsyncOnly, ..rpki::policy::Policy::default() }; let out = run_tree_from_tal_and_ta_der_serial_audit( &store, &policy, &tal_bytes, &ta_der, None, &http, &rsync, time::OffsetDateTime::now_utc(), &TreeRunConfig { max_depth: Some(0), max_instances: Some(1), }, ) .expect("run tree audit"); assert_eq!(out.tree.instances_processed, 0); assert_eq!(out.tree.instances_failed, 1); assert!(out.publication_points.is_empty()); }