use rpki::ccr::{ CcrContentInfo, CcrDigestAlgorithm, TrustAnchorState, compute_state_hash, encode::{encode_content_info, encode_trust_anchor_state_payload_der}, }; use std::process::Command; fn sample_ccr_file() -> (tempfile::TempDir, std::path::PathBuf) { let dir = tempfile::tempdir().expect("tempdir"); let skis = vec![vec![0x11; 20]]; let skis_der = encode_trust_anchor_state_payload_der(&skis).expect("encode skis"); let ccr = CcrContentInfo::new(rpki::ccr::RpkiCanonicalCacheRepresentation { version: 0, hash_alg: CcrDigestAlgorithm::Sha256, produced_at: time::OffsetDateTime::parse( "2026-03-24T00:00:00Z", &time::format_description::well_known::Rfc3339, ) .expect("time"), mfts: None, vrps: None, vaps: None, tas: Some(TrustAnchorState { skis, hash: compute_state_hash(&skis_der) }), rks: None, }); let path = dir.path().join("sample.ccr"); std::fs::write(&path, encode_content_info(&ccr).expect("encode ccr")).expect("write ccr"); (dir, path) } #[test] fn ccr_dump_binary_prints_json_summary() { let (_dir, ccr_path) = sample_ccr_file(); let bin = env!("CARGO_BIN_EXE_ccr_dump"); let out = Command::new(bin) .args(["--ccr", ccr_path.to_string_lossy().as_ref()]) .output() .expect("run ccr_dump"); assert!(out.status.success(), "stderr={}", String::from_utf8_lossy(&out.stderr)); let json: serde_json::Value = serde_json::from_slice(&out.stdout).expect("parse json"); assert_eq!(json["version"], 0); assert_eq!(json["state_aspects"]["tas"]["ski_count"], 1); } #[test] fn ccr_verify_binary_prints_summary() { let (_dir, ccr_path) = sample_ccr_file(); let bin = env!("CARGO_BIN_EXE_ccr_verify"); let out = Command::new(bin) .args(["--ccr", ccr_path.to_string_lossy().as_ref()]) .output() .expect("run ccr_verify"); assert!(out.status.success(), "stderr={}", String::from_utf8_lossy(&out.stderr)); let json: serde_json::Value = serde_json::from_slice(&out.stdout).expect("parse json"); assert_eq!(json["version"], 0); assert_eq!(json["trust_anchor_ski_count"], 1); assert_eq!(json["state_hashes_ok"], true); } #[test] fn ccr_to_routinator_csv_binary_writes_vrp_csv() { use rpki::ccr::{ CcrContentInfo, CcrDigestAlgorithm, RpkiCanonicalCacheRepresentation, build_roa_payload_state, encode::encode_content_info, }; use rpki::validation::objects::Vrp; use rpki::data_model::roa::{IpPrefix, RoaAfi}; let dir = tempfile::tempdir().expect("tempdir"); let ccr_path = dir.path().join("vrp.ccr"); let csv_path = dir.path().join("out.csv"); let vrps = vec![Vrp { asn: 64496, prefix: IpPrefix { afi: RoaAfi::Ipv4, prefix_len: 24, addr: [203, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], }, max_length: 24, }]; let roa_state = build_roa_payload_state(&vrps).expect("build roa state"); let ccr = CcrContentInfo::new(RpkiCanonicalCacheRepresentation { version: 0, hash_alg: CcrDigestAlgorithm::Sha256, produced_at: time::OffsetDateTime::parse( "2026-03-25T00:00:00Z", &time::format_description::well_known::Rfc3339, ) .expect("time"), mfts: None, vrps: Some(roa_state), vaps: None, tas: None, rks: None, }); std::fs::write(&ccr_path, encode_content_info(&ccr).expect("encode ccr")).expect("write ccr"); let bin = env!("CARGO_BIN_EXE_ccr_to_routinator_csv"); let out = Command::new(bin) .args([ "--ccr", ccr_path.to_string_lossy().as_ref(), "--out", csv_path.to_string_lossy().as_ref(), "--trust-anchor", "apnic", ]) .output() .expect("run ccr_to_routinator_csv"); assert!(out.status.success(), "stderr={}", String::from_utf8_lossy(&out.stderr)); let csv = std::fs::read_to_string(csv_path).expect("read csv"); assert!(csv.contains("ASN,IP Prefix,Max Length,Trust Anchor")); assert!(csv.contains("AS64496,203.0.113.0/24,24,apnic")); } #[test] fn ccr_to_compare_views_binary_writes_vrp_and_vap_csvs() { use rpki::ccr::{ CcrContentInfo, CcrDigestAlgorithm, RpkiCanonicalCacheRepresentation, build_aspa_payload_state, build_roa_payload_state, encode::encode_content_info, }; use rpki::data_model::roa::{IpPrefix, RoaAfi}; use rpki::validation::objects::{AspaAttestation, Vrp}; let dir = tempfile::tempdir().expect("tempdir"); let ccr_path = dir.path().join("views.ccr"); let vrps_path = dir.path().join("vrps.csv"); let vaps_path = dir.path().join("vaps.csv"); let roa_state = build_roa_payload_state(&[Vrp { asn: 64496, prefix: IpPrefix { afi: RoaAfi::Ipv4, prefix_len: 24, addr: [198, 51, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], }, max_length: 24, }]) .expect("build roa state"); let aspa_state = build_aspa_payload_state(&[AspaAttestation { customer_as_id: 64496, provider_as_ids: vec![64498, 64497, 64498], }]) .expect("build aspa state"); let ccr = CcrContentInfo::new(RpkiCanonicalCacheRepresentation { version: 0, hash_alg: CcrDigestAlgorithm::Sha256, produced_at: time::OffsetDateTime::parse( "2026-03-30T00:00:00Z", &time::format_description::well_known::Rfc3339, ) .expect("time"), mfts: None, vrps: Some(roa_state), vaps: Some(aspa_state), tas: None, rks: None, }); std::fs::write(&ccr_path, encode_content_info(&ccr).expect("encode ccr")).expect("write ccr"); let bin = env!("CARGO_BIN_EXE_ccr_to_compare_views"); let out = Command::new(bin) .args([ "--ccr", ccr_path.to_string_lossy().as_ref(), "--vrps-out", vrps_path.to_string_lossy().as_ref(), "--vaps-out", vaps_path.to_string_lossy().as_ref(), "--trust-anchor", "apnic", ]) .output() .expect("run ccr_to_compare_views"); assert!(out.status.success(), "stderr={}", String::from_utf8_lossy(&out.stderr)); let vrps_csv = std::fs::read_to_string(vrps_path).expect("read vrps csv"); let vaps_csv = std::fs::read_to_string(vaps_path).expect("read vaps csv"); assert!(vrps_csv.contains("ASN,IP Prefix,Max Length,Trust Anchor")); assert!(vrps_csv.contains("AS64496,198.51.100.0/24,24,apnic")); assert!(vaps_csv.contains("Customer ASN,Providers,Trust Anchor")); assert!(vaps_csv.contains("AS64496,AS64497;AS64498,apnic")); } #[test] fn ccr_to_compare_views_binary_writes_header_only_vap_csv_when_absent() { use rpki::ccr::{ CcrContentInfo, CcrDigestAlgorithm, RpkiCanonicalCacheRepresentation, build_roa_payload_state, encode::encode_content_info, }; use rpki::data_model::roa::{IpPrefix, RoaAfi}; use rpki::validation::objects::Vrp; let dir = tempfile::tempdir().expect("tempdir"); let ccr_path = dir.path().join("views-no-vaps.ccr"); let vrps_path = dir.path().join("vrps.csv"); let vaps_path = dir.path().join("vaps.csv"); let roa_state = build_roa_payload_state(&[Vrp { asn: 64496, prefix: IpPrefix { afi: RoaAfi::Ipv4, prefix_len: 24, addr: [203, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], }, max_length: 24, }]) .expect("build roa state"); let ccr = CcrContentInfo::new(RpkiCanonicalCacheRepresentation { version: 0, hash_alg: CcrDigestAlgorithm::Sha256, produced_at: time::OffsetDateTime::parse( "2026-03-30T00:00:00Z", &time::format_description::well_known::Rfc3339, ) .expect("time"), mfts: None, vrps: Some(roa_state), vaps: None, tas: None, rks: None, }); std::fs::write(&ccr_path, encode_content_info(&ccr).expect("encode ccr")).expect("write ccr"); let bin = env!("CARGO_BIN_EXE_ccr_to_compare_views"); let out = Command::new(bin) .args([ "--ccr", ccr_path.to_string_lossy().as_ref(), "--vrps-out", vrps_path.to_string_lossy().as_ref(), "--vaps-out", vaps_path.to_string_lossy().as_ref(), "--trust-anchor", "apnic", ]) .output() .expect("run ccr_to_compare_views"); assert!(out.status.success(), "stderr={}", String::from_utf8_lossy(&out.stderr)); let vaps_csv = std::fs::read_to_string(vaps_path).expect("read vaps csv"); assert_eq!(vaps_csv, "Customer ASN,Providers,Trust Anchor\n"); }