rpki/tests/test_cir_peer_replay_m8.rs

229 lines
8.0 KiB
Rust

use std::path::{Path, PathBuf};
use std::process::Command;
use rpki::blob_store::ExternalRepoBytesDb;
use rpki::cir::{
CIR_VERSION_V3, CanonicalInputRepresentation, CirHashAlgorithm, CirTrustAnchor,
compute_reject_list_sha256, encode_cir, materialize_cir_from_repo_bytes, sha256,
};
fn skip_heavy_script_replay_test() -> bool {
std::env::var_os("RPKI_SKIP_HEAVY_SCRIPT_REPLAY_TESTS").is_some()
}
fn apnic_tal_path() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/tal/apnic-rfc7730-https.tal")
}
fn apnic_ta_path() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/ta/apnic-ta.cer")
}
fn build_ta_only_cir() -> (CanonicalInputRepresentation, Vec<u8>) {
let tal_bytes = std::fs::read(apnic_tal_path()).expect("read tal");
let ta_bytes = std::fs::read(apnic_ta_path()).expect("read ta");
let tal = rpki::data_model::tal::Tal::decode_bytes(&tal_bytes).expect("decode tal");
let ta_rsync_uri = tal
.ta_uris
.iter()
.find(|uri| uri.scheme() == "rsync")
.expect("tal has rsync uri")
.as_str()
.to_string();
(
CanonicalInputRepresentation {
version: CIR_VERSION_V3,
hash_alg: CirHashAlgorithm::Sha256,
validation_time: time::OffsetDateTime::parse(
"2026-04-07T00:00:00Z",
&time::format_description::well_known::Rfc3339,
)
.unwrap(),
objects: Vec::new(),
trust_anchors: vec![CirTrustAnchor {
ta_rsync_uri,
tal_uri: "https://example.test/root.tal".to_string(),
tal_bytes,
ta_certificate_sha256: sha256(&ta_bytes),
ta_certificate_der: ta_bytes.clone(),
}],
reject_list_sha256: compute_reject_list_sha256(std::iter::empty::<&str>()),
rejected_objects: Vec::new(),
},
ta_bytes,
)
}
fn write_repo_bytes(repo_bytes_db: &Path, bytes: &[u8]) {
use sha2::{Digest, Sha256};
let hash = hex::encode(Sha256::digest(bytes));
ExternalRepoBytesDb::open(repo_bytes_db)
.expect("open repo bytes")
.put_blob_bytes_batch(&[(hash, bytes.to_vec())])
.expect("write repo bytes");
}
fn prepare_reference_ccr(
work: &Path,
cir: &CanonicalInputRepresentation,
mirror_root: &Path,
) -> PathBuf {
let reference_ccr = work.join("reference.ccr");
let rpki_bin = env!("CARGO_BIN_EXE_rpki");
let wrapper = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("scripts/cir/cir-rsync-wrapper");
let tal_path = apnic_tal_path();
let ta_path = apnic_ta_path();
let out = Command::new(rpki_bin)
.env("REAL_RSYNC_BIN", "/usr/bin/rsync")
.env("CIR_MIRROR_ROOT", mirror_root)
.args([
"--db",
work.join("reference-db").to_string_lossy().as_ref(),
"--tal-path",
tal_path.to_string_lossy().as_ref(),
"--ta-path",
ta_path.to_string_lossy().as_ref(),
"--disable-rrdp",
"--rsync-command",
wrapper.to_string_lossy().as_ref(),
"--validation-time",
&cir.validation_time
.format(&time::format_description::well_known::Rfc3339)
.unwrap(),
"--max-depth",
"0",
"--max-instances",
"1",
"--ccr-out",
reference_ccr.to_string_lossy().as_ref(),
])
.output()
.expect("run reference rpki");
assert!(
out.status.success(),
"stderr={}",
String::from_utf8_lossy(&out.stderr)
);
reference_ccr
}
#[test]
fn cir_routinator_script_matches_reference_on_ta_only_cir() {
if skip_heavy_script_replay_test() {
return;
}
if !Path::new("/usr/bin/rsync").exists()
|| !Path::new("/home/yuyr/dev/rust_playground/routinator/target/debug/routinator").exists()
{
return;
}
let td = tempfile::tempdir().expect("tempdir");
let repo_bytes_db = td.path().join("repo-bytes.db");
let cir_path = td.path().join("sample.cir");
let mirror_root = td.path().join("mirror");
let out_dir = td.path().join("routinator-out");
let (cir, ta_bytes) = build_ta_only_cir();
std::fs::write(&cir_path, encode_cir(&cir).expect("encode cir")).expect("write cir");
write_repo_bytes(&repo_bytes_db, &ta_bytes);
materialize_cir_from_repo_bytes(&cir, &repo_bytes_db, &mirror_root, true).expect("materialize");
let reference_ccr = prepare_reference_ccr(td.path(), &cir, &mirror_root);
let script =
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("scripts/cir/run_cir_replay_routinator.sh");
let out = Command::new(script)
.env("CIR_MATERIALIZE_BIN", env!("CARGO_BIN_EXE_cir_materialize"))
.env(
"CIR_EXTRACT_INPUTS_BIN",
env!("CARGO_BIN_EXE_cir_extract_inputs"),
)
.env(
"CCR_TO_COMPARE_VIEWS_BIN",
env!("CARGO_BIN_EXE_ccr_to_compare_views"),
)
.args([
"--cir",
cir_path.to_string_lossy().as_ref(),
"--repo-bytes-db",
repo_bytes_db.to_string_lossy().as_ref(),
"--out-dir",
out_dir.to_string_lossy().as_ref(),
"--reference-ccr",
reference_ccr.to_string_lossy().as_ref(),
])
.output()
.expect("run routinator cir script");
assert!(
out.status.success(),
"stderr={}",
String::from_utf8_lossy(&out.stderr)
);
let summary: serde_json::Value = serde_json::from_slice(
&std::fs::read(out_dir.join("compare-summary.json")).expect("read summary"),
)
.expect("parse summary");
assert_eq!(summary["vrps"]["match"], true);
assert_eq!(summary["vaps"]["match"], true);
}
#[test]
fn cir_rpki_client_script_matches_reference_on_ta_only_cir() {
if skip_heavy_script_replay_test() {
return;
}
if !Path::new("/usr/bin/rsync").exists()
|| !Path::new("/home/yuyr/dev/rpki-client-9.7/build-m5/src/rpki-client").exists()
{
return;
}
let td = tempfile::tempdir().expect("tempdir");
let repo_bytes_db = td.path().join("repo-bytes.db");
let cir_path = td.path().join("sample.cir");
let mirror_root = td.path().join("mirror");
let out_dir = td.path().join("rpki-client-out");
let (cir, ta_bytes) = build_ta_only_cir();
std::fs::write(&cir_path, encode_cir(&cir).expect("encode cir")).expect("write cir");
write_repo_bytes(&repo_bytes_db, &ta_bytes);
materialize_cir_from_repo_bytes(&cir, &repo_bytes_db, &mirror_root, true).expect("materialize");
let reference_ccr = prepare_reference_ccr(td.path(), &cir, &mirror_root);
let script =
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("scripts/cir/run_cir_replay_rpki_client.sh");
let out = Command::new(script)
.env("CIR_MATERIALIZE_BIN", env!("CARGO_BIN_EXE_cir_materialize"))
.env(
"CIR_EXTRACT_INPUTS_BIN",
env!("CARGO_BIN_EXE_cir_extract_inputs"),
)
.env(
"CCR_TO_COMPARE_VIEWS_BIN",
env!("CARGO_BIN_EXE_ccr_to_compare_views"),
)
.args([
"--cir",
cir_path.to_string_lossy().as_ref(),
"--repo-bytes-db",
repo_bytes_db.to_string_lossy().as_ref(),
"--out-dir",
out_dir.to_string_lossy().as_ref(),
"--reference-ccr",
reference_ccr.to_string_lossy().as_ref(),
"--build-dir",
"/home/yuyr/dev/rpki-client-9.7/build-m5",
])
.output()
.expect("run rpki-client cir script");
assert!(
out.status.success(),
"stderr={}",
String::from_utf8_lossy(&out.stderr)
);
let summary: serde_json::Value = serde_json::from_slice(
&std::fs::read(out_dir.join("compare-summary.json")).expect("read summary"),
)
.expect("parse summary");
assert_eq!(summary["vrps"]["match"], true);
assert_eq!(summary["vaps"]["match"], true);
}