20260410 完成五个rir 基于cir的三方回放,raw by hash 独立db,发现内存占用大,连续大rir 录制发生oom

This commit is contained in:
2026-04-11 11:24:32 +08:00
parent e083fe4daa
commit 77fc2f1a41
96 changed files with 5159 additions and 1720 deletions

View File

@@ -33,9 +33,13 @@ fn parse_args(argv: &[String]) -> Result<Args, String> {
fn main() -> Result<(), String> {
let args = parse_args(&std::env::args().collect::<Vec<_>>())?;
let ccr_path = args.ccr_path.as_ref().unwrap();
let bytes = std::fs::read(ccr_path).map_err(|e| format!("read ccr failed: {}: {e}", ccr_path.display()))?;
let bytes = std::fs::read(ccr_path)
.map_err(|e| format!("read ccr failed: {}: {e}", ccr_path.display()))?;
let json = dump_content_info_json_value(&bytes).map_err(|e| e.to_string())?;
println!("{}", serde_json::to_string_pretty(&json).map_err(|e| e.to_string())?);
println!(
"{}",
serde_json::to_string_pretty(&json).map_err(|e| e.to_string())?
);
Ok(())
}
@@ -45,9 +49,16 @@ mod tests {
#[test]
fn parse_args_accepts_ccr_path() {
let argv = vec!["ccr_dump".to_string(), "--ccr".to_string(), "a.ccr".to_string()];
let argv = vec![
"ccr_dump".to_string(),
"--ccr".to_string(),
"a.ccr".to_string(),
];
let args = parse_args(&argv).expect("parse");
assert_eq!(args.ccr_path.as_deref(), Some(std::path::Path::new("a.ccr")));
assert_eq!(
args.ccr_path.as_deref(),
Some(std::path::Path::new("a.ccr"))
);
}
#[test]

View File

@@ -94,7 +94,10 @@ mod tests {
"apnic".to_string(),
];
let args = parse_args(&argv).expect("parse args");
assert_eq!(args.ccr_path.as_deref(), Some(std::path::Path::new("a.ccr")));
assert_eq!(
args.ccr_path.as_deref(),
Some(std::path::Path::new("a.ccr"))
);
assert_eq!(
args.vrps_out_path.as_deref(),
Some(std::path::Path::new("vrps.csv"))

View File

@@ -49,7 +49,9 @@ fn parse_args(argv: &[String]) -> Result<Args, String> {
Ok(args)
}
fn collect_vrp_rows(bytes: &[u8]) -> Result<std::collections::BTreeSet<(u32, String, u16)>, String> {
fn collect_vrp_rows(
bytes: &[u8],
) -> Result<std::collections::BTreeSet<(u32, String, u16)>, String> {
let content_info = decode_content_info(bytes).map_err(|e| e.to_string())?;
extract_vrp_rows(&content_info).map_err(|e| e.to_string())
}
@@ -95,14 +97,24 @@ mod tests {
"apnic".to_string(),
];
let args = parse_args(&argv).expect("parse args");
assert_eq!(args.ccr_path.as_deref(), Some(std::path::Path::new("a.ccr")));
assert_eq!(args.out_path.as_deref(), Some(std::path::Path::new("out.csv")));
assert_eq!(
args.ccr_path.as_deref(),
Some(std::path::Path::new("a.ccr"))
);
assert_eq!(
args.out_path.as_deref(),
Some(std::path::Path::new("out.csv"))
);
assert_eq!(args.trust_anchor, "apnic");
}
#[test]
fn parse_args_rejects_missing_required_flags() {
let argv = vec!["ccr_to_routinator_csv".to_string(), "--ccr".to_string(), "a.ccr".to_string()];
let argv = vec![
"ccr_to_routinator_csv".to_string(),
"--ccr".to_string(),
"a.ccr".to_string(),
];
let err = parse_args(&argv).unwrap_err();
assert!(err.contains("--out is required"), "{err}");
}

View File

@@ -1,4 +1,7 @@
use rpki::ccr::{decode_content_info, verify::verify_content_info, verify_against_report_json_path, verify_against_vcir_store_path};
use rpki::ccr::{
decode_content_info, verify::verify_content_info, verify_against_report_json_path,
verify_against_vcir_store_path,
};
#[derive(Debug, Default, PartialEq, Eq)]
struct Args {
@@ -45,7 +48,8 @@ fn parse_args(argv: &[String]) -> Result<Args, String> {
fn main() -> Result<(), String> {
let args = parse_args(&std::env::args().collect::<Vec<_>>())?;
let ccr_path = args.ccr_path.as_ref().unwrap();
let bytes = std::fs::read(ccr_path).map_err(|e| format!("read ccr failed: {}: {e}", ccr_path.display()))?;
let bytes = std::fs::read(ccr_path)
.map_err(|e| format!("read ccr failed: {}: {e}", ccr_path.display()))?;
let ci = decode_content_info(&bytes).map_err(|e| e.to_string())?;
let summary = verify_content_info(&ci).map_err(|e| e.to_string())?;
if let Some(report_json) = args.report_json.as_ref() {
@@ -54,7 +58,10 @@ fn main() -> Result<(), String> {
if let Some(db_path) = args.db_path.as_ref() {
verify_against_vcir_store_path(&ci, db_path).map_err(|e| e.to_string())?;
}
println!("{}", serde_json::to_string_pretty(&summary).map_err(|e| e.to_string())?);
println!(
"{}",
serde_json::to_string_pretty(&summary).map_err(|e| e.to_string())?
);
Ok(())
}
@@ -74,8 +81,14 @@ mod tests {
"db".to_string(),
];
let args = parse_args(&argv).expect("parse");
assert_eq!(args.ccr_path.as_deref(), Some(std::path::Path::new("a.ccr")));
assert_eq!(args.report_json.as_deref(), Some(std::path::Path::new("report.json")));
assert_eq!(
args.ccr_path.as_deref(),
Some(std::path::Path::new("a.ccr"))
);
assert_eq!(
args.report_json.as_deref(),
Some(std::path::Path::new("report.json"))
);
assert_eq!(args.db_path.as_deref(), Some(std::path::Path::new("db")));
}

View File

@@ -1,12 +1,13 @@
use std::collections::{BTreeMap, BTreeSet};
use std::path::PathBuf;
use rpki::blob_store::{ExternalRawStoreDb, RawObjectStore};
use rpki::bundle::decode_ccr_compare_views;
use rpki::ccr::decode_content_info;
use rpki::cir::{decode_cir, resolve_static_pool_file};
use rpki::data_model::roa::RoaObject;
const USAGE: &str = "Usage: cir_drop_report --cir <path> --ccr <path> --report-json <path> --static-root <path> --json-out <path> --md-out <path>";
const USAGE: &str = "Usage: cir_drop_report --cir <path> --ccr <path> --report-json <path> (--static-root <path> | --raw-store-db <path>) --json-out <path> --md-out <path>";
#[derive(serde::Serialize)]
struct DroppedObjectRecord {
@@ -47,11 +48,25 @@ fn classify_reason(detail: Option<&str>, result: &str) -> String {
}
}
fn parse_args(argv: &[String]) -> Result<(PathBuf, PathBuf, PathBuf, PathBuf, PathBuf, PathBuf), String> {
fn parse_args(
argv: &[String],
) -> Result<
(
PathBuf,
PathBuf,
PathBuf,
Option<PathBuf>,
Option<PathBuf>,
PathBuf,
PathBuf,
),
String,
> {
let mut cir = None;
let mut ccr = None;
let mut report = None;
let mut static_root = None;
let mut raw_store_db = None;
let mut json_out = None;
let mut md_out = None;
let mut i = 1usize;
@@ -77,6 +92,12 @@ fn parse_args(argv: &[String]) -> Result<(PathBuf, PathBuf, PathBuf, PathBuf, Pa
argv.get(i).ok_or("--static-root requires a value")?,
));
}
"--raw-store-db" => {
i += 1;
raw_store_db = Some(PathBuf::from(
argv.get(i).ok_or("--raw-store-db requires a value")?,
));
}
"--json-out" => {
i += 1;
json_out = Some(PathBuf::from(
@@ -85,7 +106,9 @@ fn parse_args(argv: &[String]) -> Result<(PathBuf, PathBuf, PathBuf, PathBuf, Pa
}
"--md-out" => {
i += 1;
md_out = Some(PathBuf::from(argv.get(i).ok_or("--md-out requires a value")?));
md_out = Some(PathBuf::from(
argv.get(i).ok_or("--md-out requires a value")?,
));
}
"-h" | "--help" => return Err(USAGE.to_string()),
other => return Err(format!("unknown argument: {other}\n\n{USAGE}")),
@@ -96,7 +119,8 @@ fn parse_args(argv: &[String]) -> Result<(PathBuf, PathBuf, PathBuf, PathBuf, Pa
cir.ok_or_else(|| format!("--cir is required\n\n{USAGE}"))?,
ccr.ok_or_else(|| format!("--ccr is required\n\n{USAGE}"))?,
report.ok_or_else(|| format!("--report-json is required\n\n{USAGE}"))?,
static_root.ok_or_else(|| format!("--static-root is required\n\n{USAGE}"))?,
static_root,
raw_store_db,
json_out.ok_or_else(|| format!("--json-out is required\n\n{USAGE}"))?,
md_out.ok_or_else(|| format!("--md-out is required\n\n{USAGE}"))?,
))
@@ -104,7 +128,14 @@ fn parse_args(argv: &[String]) -> Result<(PathBuf, PathBuf, PathBuf, PathBuf, Pa
fn main() -> Result<(), String> {
let argv: Vec<String> = std::env::args().collect();
let (cir_path, ccr_path, report_path, static_root, json_out, md_out) = parse_args(&argv)?;
let (cir_path, ccr_path, report_path, static_root, raw_store_db, json_out, md_out) =
parse_args(&argv)?;
let backend_count = static_root.is_some() as u8 + raw_store_db.is_some() as u8;
if backend_count != 1 {
return Err(format!(
"must specify exactly one of --static-root or --raw-store-db\n\n{USAGE}"
));
}
let cir = decode_cir(&std::fs::read(&cir_path).map_err(|e| format!("read cir failed: {e}"))?)
.map_err(|e| format!("decode cir failed: {e}"))?;
@@ -112,11 +143,12 @@ fn main() -> Result<(), String> {
&std::fs::read(&ccr_path).map_err(|e| format!("read ccr failed: {e}"))?,
)
.map_err(|e| format!("decode ccr failed: {e}"))?;
let (vrps, vaps) =
decode_ccr_compare_views(&ccr, "unknown").map_err(|e| format!("decode compare views failed: {e}"))?;
let report: serde_json::Value =
serde_json::from_slice(&std::fs::read(&report_path).map_err(|e| format!("read report failed: {e}"))?)
.map_err(|e| format!("parse report failed: {e}"))?;
let (vrps, vaps) = decode_ccr_compare_views(&ccr, "unknown")
.map_err(|e| format!("decode compare views failed: {e}"))?;
let report: serde_json::Value = serde_json::from_slice(
&std::fs::read(&report_path).map_err(|e| format!("read report failed: {e}"))?,
)
.map_err(|e| format!("parse report failed: {e}"))?;
let mut object_hash_by_uri = BTreeMap::new();
for object in &cir.objects {
@@ -134,7 +166,9 @@ fn main() -> Result<(), String> {
let mut unknown_roa_objects = 0usize;
for pp in publication_points {
let publication_point = pp["publication_point_rsync_uri"].as_str().map(str::to_string);
let publication_point = pp["publication_point_rsync_uri"]
.as_str()
.map(str::to_string);
let manifest_uri = pp["manifest_rsync_uri"].as_str().map(str::to_string);
for obj in pp["objects"].as_array().into_iter().flatten() {
let result = obj["result"].as_str().unwrap_or("unknown");
@@ -155,39 +189,52 @@ fn main() -> Result<(), String> {
let mut derived_vrp_count = 0usize;
if kind == "roa" && !hash.is_empty() {
match resolve_static_pool_file(&static_root, &hash) {
Ok(path) => {
if let Ok(bytes) = std::fs::read(&path) {
if let Ok(roa) = RoaObject::decode_der(&bytes) {
for family in roa.roa.ip_addr_blocks {
for addr in family.addresses {
let prefix = match addr.prefix.afi {
rpki::data_model::roa::RoaAfi::Ipv4 => format!(
"{}.{}.{}.{}/{}",
addr.prefix.addr[0],
addr.prefix.addr[1],
addr.prefix.addr[2],
addr.prefix.addr[3],
let bytes_opt = if let Some(static_root) = static_root.as_ref() {
match resolve_static_pool_file(static_root, &hash) {
Ok(path) => std::fs::read(&path).ok(),
Err(_) => None,
}
} else if let Some(raw_store_db) = raw_store_db.as_ref() {
ExternalRawStoreDb::open(raw_store_db)
.ok()
.and_then(|store| store.get_raw_entry(&hash).ok().flatten())
.map(|entry| entry.bytes)
} else {
None
};
match bytes_opt {
Some(bytes) => {
if let Ok(roa) = RoaObject::decode_der(&bytes) {
for family in roa.roa.ip_addr_blocks {
for addr in family.addresses {
let prefix = match addr.prefix.afi {
rpki::data_model::roa::RoaAfi::Ipv4 => format!(
"{}.{}.{}.{}/{}",
addr.prefix.addr[0],
addr.prefix.addr[1],
addr.prefix.addr[2],
addr.prefix.addr[3],
addr.prefix.prefix_len
),
rpki::data_model::roa::RoaAfi::Ipv6 => {
let bytes: [u8; 16] = addr.prefix.addr;
format!(
"{}/{}",
std::net::Ipv6Addr::from(bytes),
addr.prefix.prefix_len
),
rpki::data_model::roa::RoaAfi::Ipv6 => {
let bytes: [u8; 16] = addr.prefix.addr;
format!("{}/{}", std::net::Ipv6Addr::from(bytes), addr.prefix.prefix_len)
}
};
let max_len = addr.max_length.unwrap_or(addr.prefix.prefix_len);
dropped_vrp_rows.insert((roa.roa.as_id, prefix, max_len));
derived_vrp_count += 1;
}
)
}
};
let max_len = addr.max_length.unwrap_or(addr.prefix.prefix_len);
dropped_vrp_rows.insert((roa.roa.as_id, prefix, max_len));
derived_vrp_count += 1;
}
} else {
unknown_roa_objects += 1;
}
} else {
unknown_roa_objects += 1;
}
}
Err(_) => unknown_roa_objects += 1,
None => unknown_roa_objects += 1,
}
}
@@ -227,22 +274,40 @@ fn main() -> Result<(), String> {
md.push_str("# CIR Drop Report\n\n");
md.push_str(&format!("- `final_vrp_count`: `{}`\n", vrps.len()));
md.push_str(&format!("- `final_vap_count`: `{}`\n", vaps.len()));
md.push_str(&format!("- `dropped_vrp_count`: `{}`\n", output["summary"]["droppedVrpCount"]));
md.push_str(&format!("- `dropped_object_count`: `{}`\n", output["summary"]["droppedObjectCount"]));
md.push_str(&format!(
"- `dropped_vrp_count`: `{}`\n",
output["summary"]["droppedVrpCount"]
));
md.push_str(&format!(
"- `dropped_object_count`: `{}`\n",
output["summary"]["droppedObjectCount"]
));
md.push_str(&format!(
"- `unknown_dropped_roa_objects`: `{}`\n\n",
output["summary"]["unknownDroppedRoaObjects"]
));
md.push_str("## Dropped By Kind\n\n");
for (kind, count) in output["summary"]["droppedByKind"].as_object().into_iter().flatten() {
for (kind, count) in output["summary"]["droppedByKind"]
.as_object()
.into_iter()
.flatten()
{
md.push_str(&format!("- `{kind}`: `{}`\n", count.as_u64().unwrap_or(0)));
}
md.push_str("\n## Dropped By Reason\n\n");
for (reason, count) in output["summary"]["droppedByReason"].as_object().into_iter().flatten() {
md.push_str(&format!("- `{reason}`: `{}`\n", count.as_u64().unwrap_or(0)));
for (reason, count) in output["summary"]["droppedByReason"]
.as_object()
.into_iter()
.flatten()
{
md.push_str(&format!(
"- `{reason}`: `{}`\n",
count.as_u64().unwrap_or(0)
));
}
if let Some(parent) = md_out.parent() {
std::fs::create_dir_all(parent).map_err(|e| format!("create markdown parent failed: {e}"))?;
std::fs::create_dir_all(parent)
.map_err(|e| format!("create markdown parent failed: {e}"))?;
}
std::fs::write(&md_out, md).map_err(|e| format!("write markdown failed: {e}"))?;

View File

@@ -26,11 +26,15 @@ fn run(argv: Vec<String>) -> Result<(), String> {
}
"--tals-dir" => {
i += 1;
tals_dir = Some(PathBuf::from(argv.get(i).ok_or("--tals-dir requires a value")?));
tals_dir = Some(PathBuf::from(
argv.get(i).ok_or("--tals-dir requires a value")?,
));
}
"--meta-json" => {
i += 1;
meta_json = Some(PathBuf::from(argv.get(i).ok_or("--meta-json requires a value")?));
meta_json = Some(PathBuf::from(
argv.get(i).ok_or("--meta-json requires a value")?,
));
}
other => return Err(format!("unknown argument: {other}\n\n{}", usage())),
}
@@ -76,4 +80,3 @@ fn run(argv: Vec<String>) -> Result<(), String> {
.map_err(|e| format!("write meta json failed: {}: {e}", meta_json.display()))?;
Ok(())
}

View File

@@ -1,7 +1,7 @@
use std::path::PathBuf;
fn usage() -> &'static str {
"Usage: cir_materialize --cir <path> --static-root <path> --mirror-root <path> [--keep-db]"
"Usage: cir_materialize --cir <path> (--static-root <path> | --raw-store-db <path>) --mirror-root <path> [--keep-db]"
}
fn main() {
@@ -14,6 +14,7 @@ fn main() {
fn run(argv: Vec<String>) -> Result<(), String> {
let mut cir_path: Option<PathBuf> = None;
let mut static_root: Option<PathBuf> = None;
let mut raw_store_db: Option<PathBuf> = None;
let mut mirror_root: Option<PathBuf> = None;
let mut keep_db = false;
@@ -31,6 +32,12 @@ fn run(argv: Vec<String>) -> Result<(), String> {
argv.get(i).ok_or("--static-root requires a value")?,
));
}
"--raw-store-db" => {
i += 1;
raw_store_db = Some(PathBuf::from(
argv.get(i).ok_or("--raw-store-db requires a value")?,
));
}
"--mirror-root" => {
i += 1;
mirror_root = Some(PathBuf::from(
@@ -44,16 +51,29 @@ fn run(argv: Vec<String>) -> Result<(), String> {
}
let cir_path = cir_path.ok_or_else(|| format!("--cir is required\n\n{}", usage()))?;
let static_root =
static_root.ok_or_else(|| format!("--static-root is required\n\n{}", usage()))?;
let mirror_root =
mirror_root.ok_or_else(|| format!("--mirror-root is required\n\n{}", usage()))?;
let backend_count = static_root.is_some() as u8 + raw_store_db.is_some() as u8;
if backend_count != 1 {
return Err(format!(
"must specify exactly one of --static-root or --raw-store-db\n\n{}",
usage()
));
}
let bytes = std::fs::read(&cir_path)
.map_err(|e| format!("read CIR failed: {}: {e}", cir_path.display()))?;
let cir = rpki::cir::decode_cir(&bytes).map_err(|e| e.to_string())?;
let result = rpki::cir::materialize_cir(&cir, &static_root, &mirror_root, true);
let result = if let Some(static_root) = static_root {
rpki::cir::materialize_cir(&cir, &static_root, &mirror_root, true)
.map_err(|e| e.to_string())
} else if let Some(raw_store_db) = raw_store_db {
rpki::cir::materialize_cir_from_raw_store(&cir, &raw_store_db, &mirror_root, true)
.map_err(|e| e.to_string())
} else {
unreachable!("validated backend count")
};
match result {
Ok(summary) => {
eprintln!(
@@ -74,4 +94,3 @@ fn run(argv: Vec<String>) -> Result<(), String> {
}
}
}

View File

@@ -1,11 +1,26 @@
use std::path::PathBuf;
use rpki::cir::{encode_cir, write_bytes_to_static_pool, CanonicalInputRepresentation, CirHashAlgorithm, CirObject, CirTal, CIR_VERSION_V1};
use rpki::cir::{
CIR_VERSION_V1, CanonicalInputRepresentation, CirHashAlgorithm, CirObject, CirTal, encode_cir,
write_bytes_to_static_pool,
};
use sha2::Digest;
const USAGE: &str = "Usage: cir_ta_only_fixture --tal-path <path> --ta-path <path> --tal-uri <url> --validation-time <rfc3339> --cir-out <path> --static-root <path>";
fn parse_args(argv: &[String]) -> Result<(PathBuf, PathBuf, String, time::OffsetDateTime, PathBuf, PathBuf), String> {
fn parse_args(
argv: &[String],
) -> Result<
(
PathBuf,
PathBuf,
String,
time::OffsetDateTime,
PathBuf,
PathBuf,
),
String,
> {
let mut tal_path = None;
let mut ta_path = None;
let mut tal_uri = None;
@@ -17,11 +32,15 @@ fn parse_args(argv: &[String]) -> Result<(PathBuf, PathBuf, String, time::Offset
match argv[i].as_str() {
"--tal-path" => {
i += 1;
tal_path = Some(PathBuf::from(argv.get(i).ok_or("--tal-path requires a value")?));
tal_path = Some(PathBuf::from(
argv.get(i).ok_or("--tal-path requires a value")?,
));
}
"--ta-path" => {
i += 1;
ta_path = Some(PathBuf::from(argv.get(i).ok_or("--ta-path requires a value")?));
ta_path = Some(PathBuf::from(
argv.get(i).ok_or("--ta-path requires a value")?,
));
}
"--tal-uri" => {
i += 1;
@@ -40,12 +59,15 @@ fn parse_args(argv: &[String]) -> Result<(PathBuf, PathBuf, String, time::Offset
}
"--cir-out" => {
i += 1;
cir_out = Some(PathBuf::from(argv.get(i).ok_or("--cir-out requires a value")?));
cir_out = Some(PathBuf::from(
argv.get(i).ok_or("--cir-out requires a value")?,
));
}
"--static-root" => {
i += 1;
static_root =
Some(PathBuf::from(argv.get(i).ok_or("--static-root requires a value")?));
static_root = Some(PathBuf::from(
argv.get(i).ok_or("--static-root requires a value")?,
));
}
"-h" | "--help" => return Err(USAGE.to_string()),
other => return Err(format!("unknown argument: {other}\n\n{USAGE}")),

View File

@@ -4,8 +4,7 @@ use std::path::PathBuf;
use rocksdb::{DB, IteratorMode, Options};
use rpki::storage::{
ALL_COLUMN_FAMILY_NAMES, CF_AUDIT_RULE_INDEX, CF_RAW_BY_HASH, CF_REPOSITORY_VIEW,
CF_RRDP_SOURCE, CF_RRDP_SOURCE_MEMBER, CF_RRDP_URI_OWNER, CF_VCIR,
column_family_descriptors,
CF_RRDP_SOURCE, CF_RRDP_SOURCE_MEMBER, CF_RRDP_URI_OWNER, CF_VCIR, column_family_descriptors,
};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
@@ -77,9 +76,7 @@ fn cf_group(cf_name: &str) -> CfGroup {
match cf_name {
CF_REPOSITORY_VIEW | CF_RAW_BY_HASH => CfGroup::CurrentRepositoryView,
CF_VCIR | CF_AUDIT_RULE_INDEX => CfGroup::CurrentValidationState,
CF_RRDP_SOURCE | CF_RRDP_SOURCE_MEMBER | CF_RRDP_URI_OWNER => {
CfGroup::CurrentRrdpState
}
CF_RRDP_SOURCE | CF_RRDP_SOURCE_MEMBER | CF_RRDP_URI_OWNER => CfGroup::CurrentRrdpState,
_ => CfGroup::LegacyCompatibility,
}
}

View File

@@ -56,10 +56,7 @@ fn parse_args() -> Result<Args, String> {
i += 1;
}
if out.bundle_root.is_none() || out.out.is_none() {
return Err(format!(
"--bundle-root and --out are required\n{}",
usage()
));
return Err(format!("--bundle-root and --out are required\n{}", usage()));
}
Ok(out)
}
@@ -188,10 +185,7 @@ fn real_main() -> Result<(), String> {
.as_array()
.ok_or("bundle missing deltaSequence.steps")?
{
let step_id = step["id"]
.as_str()
.ok_or("step missing id")?
.to_string();
let step_id = step["id"].as_str().ok_or("step missing id")?.to_string();
let step_dir = path_join(
&rir_dir,
step["relativePath"]
@@ -210,8 +204,9 @@ fn real_main() -> Result<(), String> {
.as_str()
.ok_or("step missing relativeTransitionLocksPath")?,
);
let validation_time = load_validation_time(&delta_locks)
.map_err(|e| format!("load step validation time failed for {rir}/{step_id}: {e}"))?;
let validation_time = load_validation_time(&delta_locks).map_err(|e| {
format!("load step validation time failed for {rir}/{step_id}: {e}")
})?;
let start = Instant::now();
let step_out = run_tree_from_tal_and_ta_der_payload_delta_replay_step_serial_audit(
&store,

View File

@@ -1,7 +1,7 @@
use rpki::bundle::{
RirBundleMetadata, RecordingHttpFetcher, RecordingRsyncFetcher,
build_single_rir_bundle_manifest, build_vap_compare_rows, build_vrp_compare_rows,
sha256_hex, write_json, write_live_base_replay_bundle_inputs, write_live_bundle_rir_readme,
RecordingHttpFetcher, RecordingRsyncFetcher, RirBundleMetadata,
build_single_rir_bundle_manifest, build_vap_compare_rows, build_vrp_compare_rows, sha256_hex,
write_json, write_live_base_replay_bundle_inputs, write_live_bundle_rir_readme,
write_live_bundle_top_readme, write_timing_json, write_vap_csv, write_vrp_csv,
};
use rpki::ccr::{build_ccr_from_run, verify_content_info, write_ccr_file};
@@ -54,15 +54,21 @@ fn parse_args(argv: &[String]) -> Result<Args, String> {
}
"--out-dir" => {
i += 1;
args.out_dir = Some(PathBuf::from(argv.get(i).ok_or("--out-dir requires a value")?));
args.out_dir = Some(PathBuf::from(
argv.get(i).ok_or("--out-dir requires a value")?,
));
}
"--tal-path" => {
i += 1;
args.tal_path = Some(PathBuf::from(argv.get(i).ok_or("--tal-path requires a value")?));
args.tal_path = Some(PathBuf::from(
argv.get(i).ok_or("--tal-path requires a value")?,
));
}
"--ta-path" => {
i += 1;
args.ta_path = Some(PathBuf::from(argv.get(i).ok_or("--ta-path requires a value")?));
args.ta_path = Some(PathBuf::from(
argv.get(i).ok_or("--ta-path requires a value")?,
));
}
"--validation-time" => {
i += 1;
@@ -90,8 +96,9 @@ fn parse_args(argv: &[String]) -> Result<Args, String> {
}
"--rsync-mirror-root" => {
i += 1;
args.rsync_mirror_root =
Some(PathBuf::from(argv.get(i).ok_or("--rsync-mirror-root requires a value")?));
args.rsync_mirror_root = Some(PathBuf::from(
argv.get(i).ok_or("--rsync-mirror-root requires a value")?,
));
}
"--max-depth" => {
i += 1;
@@ -113,7 +120,11 @@ fn parse_args(argv: &[String]) -> Result<Args, String> {
}
"--trust-anchor" => {
i += 1;
args.trust_anchor = Some(argv.get(i).ok_or("--trust-anchor requires a value")?.clone());
args.trust_anchor = Some(
argv.get(i)
.ok_or("--trust-anchor requires a value")?
.clone(),
);
}
other => return Err(format!("unknown argument: {other}\n{}", usage())),
}
@@ -147,11 +158,13 @@ fn run(args: Args) -> Result<PathBuf, String> {
fs::create_dir_all(&rir_dir)
.map_err(|e| format!("create rir dir failed: {}: {e}", rir_dir.display()))?;
let tal_bytes = fs::read(args.tal_path.as_ref().unwrap())
.map_err(|e| format!("read tal failed: {e}"))?;
let ta_bytes = fs::read(args.ta_path.as_ref().unwrap())
.map_err(|e| format!("read ta failed: {e}"))?;
let validation_time = args.validation_time.unwrap_or_else(time::OffsetDateTime::now_utc);
let tal_bytes =
fs::read(args.tal_path.as_ref().unwrap()).map_err(|e| format!("read tal failed: {e}"))?;
let ta_bytes =
fs::read(args.ta_path.as_ref().unwrap()).map_err(|e| format!("read ta failed: {e}"))?;
let validation_time = args
.validation_time
.unwrap_or_else(time::OffsetDateTime::now_utc);
let db_dir = out_root.join(".tmp").join(format!("{rir}-live-base-db"));
let replay_db_dir = out_root.join(".tmp").join(format!("{rir}-self-replay-db"));
@@ -205,8 +218,8 @@ fn run(args: Args) -> Result<PathBuf, String> {
.map_err(|e| format!("build ccr failed: {e}"))?;
let base_ccr_path = rir_dir.join("base.ccr");
write_ccr_file(&base_ccr_path, &ccr).map_err(|e| format!("write ccr failed: {e}"))?;
let ccr_bytes =
fs::read(&base_ccr_path).map_err(|e| format!("read written ccr failed: {}: {e}", base_ccr_path.display()))?;
let ccr_bytes = fs::read(&base_ccr_path)
.map_err(|e| format!("read written ccr failed: {}: {e}", base_ccr_path.display()))?;
let decoded = rpki::ccr::decode_content_info(&ccr_bytes)
.map_err(|e| format!("decode written ccr failed: {e}"))?;
let verify = verify_content_info(&decoded).map_err(|e| format!("verify ccr failed: {e}"))?;
@@ -235,8 +248,8 @@ fn run(args: Args) -> Result<PathBuf, String> {
&rsync.snapshot_fetches(),
)?;
let replay_store =
RocksStore::open(&replay_db_dir).map_err(|e| format!("open self replay rocksdb failed: {e}"))?;
let replay_store = RocksStore::open(&replay_db_dir)
.map_err(|e| format!("open self replay rocksdb failed: {e}"))?;
let replay_out = run_tree_from_tal_and_ta_der_payload_replay_serial_audit(
&replay_store,
&Policy::default(),
@@ -320,7 +333,11 @@ fn run(args: Args) -> Result<PathBuf, String> {
}),
)?;
write_live_bundle_top_readme(&out_root.join("README.md"), &rir_normalized)?;
write_live_bundle_rir_readme(&rir_dir.join("README.md"), &rir_normalized, &metadata.base_validation_time)?;
write_live_bundle_rir_readme(
&rir_dir.join("README.md"),
&rir_normalized,
&metadata.base_validation_time,
)?;
write_json(
&out_root.join("bundle-manifest.json"),
&build_single_rir_bundle_manifest(

View File

@@ -1,7 +1,7 @@
use rpki::bundle::{
RecordingHttpFetcher, RecordingRsyncFetcher, build_single_rir_bundle_manifest,
build_vap_compare_rows, build_vrp_compare_rows, copy_dir_all, load_validation_time,
sha256_hex, write_json, write_live_delta_replay_bundle_inputs, write_vap_csv, write_vrp_csv,
build_vap_compare_rows, build_vrp_compare_rows, copy_dir_all, load_validation_time, sha256_hex,
write_json, write_live_delta_replay_bundle_inputs, write_vap_csv, write_vrp_csv,
};
use rpki::ccr::{build_ccr_from_run, decode_content_info, verify_content_info, write_ccr_file};
use rpki::fetch::http::{BlockingHttpFetcher, HttpFetcherConfig};
@@ -54,12 +54,15 @@ fn parse_args(argv: &[String]) -> Result<Args, String> {
}
"--base-bundle-dir" => {
i += 1;
args.base_bundle_dir =
Some(PathBuf::from(argv.get(i).ok_or("--base-bundle-dir requires a value")?));
args.base_bundle_dir = Some(PathBuf::from(
argv.get(i).ok_or("--base-bundle-dir requires a value")?,
));
}
"--out-dir" => {
i += 1;
args.out_dir = Some(PathBuf::from(argv.get(i).ok_or("--out-dir requires a value")?));
args.out_dir = Some(PathBuf::from(
argv.get(i).ok_or("--out-dir requires a value")?,
));
}
"--validation-time" => {
i += 1;
@@ -87,8 +90,9 @@ fn parse_args(argv: &[String]) -> Result<Args, String> {
}
"--rsync-mirror-root" => {
i += 1;
args.rsync_mirror_root =
Some(PathBuf::from(argv.get(i).ok_or("--rsync-mirror-root requires a value")?));
args.rsync_mirror_root = Some(PathBuf::from(
argv.get(i).ok_or("--rsync-mirror-root requires a value")?,
));
}
"--max-depth" => {
i += 1;
@@ -110,7 +114,11 @@ fn parse_args(argv: &[String]) -> Result<Args, String> {
}
"--trust-anchor" => {
i += 1;
args.trust_anchor = Some(argv.get(i).ok_or("--trust-anchor requires a value")?.clone());
args.trust_anchor = Some(
argv.get(i)
.ok_or("--trust-anchor requires a value")?
.clone(),
);
}
other => return Err(format!("unknown argument: {other}\n{}", usage())),
}
@@ -193,7 +201,10 @@ fn run(args: Args) -> Result<PathBuf, String> {
let base_root = args.base_bundle_dir.as_ref().unwrap();
let base_rir_dir = base_root.join(&rir_normalized);
if !base_rir_dir.is_dir() {
return Err(format!("base bundle rir dir not found: {}", base_rir_dir.display()));
return Err(format!(
"base bundle rir dir not found: {}",
base_rir_dir.display()
));
}
if out_root.exists() {
fs::remove_dir_all(out_root)
@@ -206,12 +217,14 @@ fn run(args: Args) -> Result<PathBuf, String> {
.trust_anchor
.clone()
.unwrap_or_else(|| rir_normalized.clone());
let tal_bytes =
fs::read(rir_dir.join("tal.tal")).map_err(|e| format!("read tal from base bundle failed: {e}"))?;
let ta_bytes =
fs::read(rir_dir.join("ta.cer")).map_err(|e| format!("read ta from base bundle failed: {e}"))?;
let tal_bytes = fs::read(rir_dir.join("tal.tal"))
.map_err(|e| format!("read tal from base bundle failed: {e}"))?;
let ta_bytes = fs::read(rir_dir.join("ta.cer"))
.map_err(|e| format!("read ta from base bundle failed: {e}"))?;
let base_validation_time = load_validation_time(&rir_dir.join("base-locks.json"))?;
let target_validation_time = args.validation_time.unwrap_or_else(time::OffsetDateTime::now_utc);
let target_validation_time = args
.validation_time
.unwrap_or_else(time::OffsetDateTime::now_utc);
let target_store_dir = out_root.join(".tmp").join(format!("{rir}-live-target-db"));
let self_replay_dir = out_root.join(".tmp").join(format!("{rir}-self-delta-db"));
@@ -221,8 +234,8 @@ fn run(args: Args) -> Result<PathBuf, String> {
fs::create_dir_all(parent)
.map_err(|e| format!("create tmp dir failed: {}: {e}", parent.display()))?;
}
let target_store =
RocksStore::open(&target_store_dir).map_err(|e| format!("open target rocksdb failed: {e}"))?;
let target_store = RocksStore::open(&target_store_dir)
.map_err(|e| format!("open target rocksdb failed: {e}"))?;
let _base = run_tree_from_tal_and_ta_der_payload_replay_serial_audit(
&target_store,
@@ -282,17 +295,19 @@ fn run(args: Args) -> Result<PathBuf, String> {
)
.map_err(|e| format!("build delta ccr failed: {e}"))?;
let delta_ccr_path = rir_dir.join("delta.ccr");
write_ccr_file(&delta_ccr_path, &delta_ccr).map_err(|e| format!("write delta ccr failed: {e}"))?;
let delta_ccr_bytes =
fs::read(&delta_ccr_path).map_err(|e| format!("read delta ccr failed: {}: {e}", delta_ccr_path.display()))?;
let delta_decoded =
decode_content_info(&delta_ccr_bytes).map_err(|e| format!("decode delta ccr failed: {e}"))?;
write_ccr_file(&delta_ccr_path, &delta_ccr)
.map_err(|e| format!("write delta ccr failed: {e}"))?;
let delta_ccr_bytes = fs::read(&delta_ccr_path)
.map_err(|e| format!("read delta ccr failed: {}: {e}", delta_ccr_path.display()))?;
let delta_decoded = decode_content_info(&delta_ccr_bytes)
.map_err(|e| format!("decode delta ccr failed: {e}"))?;
let delta_verify =
verify_content_info(&delta_decoded).map_err(|e| format!("verify delta ccr failed: {e}"))?;
let delta_vrp_rows = build_vrp_compare_rows(&target_out.tree.vrps, &trust_anchor);
let delta_vap_rows = build_vap_compare_rows(&target_out.tree.aspas, &trust_anchor);
let (ccr_vrps, ccr_vaps) = rpki::bundle::decode_ccr_compare_views(&delta_decoded, &trust_anchor)?;
let (ccr_vrps, ccr_vaps) =
rpki::bundle::decode_ccr_compare_views(&delta_decoded, &trust_anchor)?;
if delta_vrp_rows != ccr_vrps {
return Err("record-delta.csv compare view does not match delta.ccr".to_string());
}
@@ -312,8 +327,8 @@ fn run(args: Args) -> Result<PathBuf, String> {
&rsync.snapshot_fetches(),
)?;
let self_store =
RocksStore::open(&self_replay_dir).map_err(|e| format!("open self replay db failed: {e}"))?;
let self_store = RocksStore::open(&self_replay_dir)
.map_err(|e| format!("open self replay db failed: {e}"))?;
let replay_out = run_tree_from_tal_and_ta_der_payload_delta_replay_serial_audit(
&self_store,
&Policy::default(),
@@ -355,7 +370,8 @@ fn run(args: Args) -> Result<PathBuf, String> {
)?;
let mut bundle_json: serde_json::Value = serde_json::from_slice(
&fs::read(rir_dir.join("bundle.json")).map_err(|e| format!("read base bundle.json failed: {e}"))?,
&fs::read(rir_dir.join("bundle.json"))
.map_err(|e| format!("read base bundle.json failed: {e}"))?,
)
.map_err(|e| format!("parse base bundle.json failed: {e}"))?;
bundle_json["deltaValidationTime"] = serde_json::Value::String(

View File

@@ -65,19 +65,27 @@ fn parse_args(argv: &[String]) -> Result<Args, String> {
}
"--out-dir" => {
i += 1;
args.out_dir = Some(PathBuf::from(argv.get(i).ok_or("--out-dir requires a value")?));
args.out_dir = Some(PathBuf::from(
argv.get(i).ok_or("--out-dir requires a value")?,
));
}
"--tal-path" => {
i += 1;
args.tal_path = Some(PathBuf::from(argv.get(i).ok_or("--tal-path requires a value")?));
args.tal_path = Some(PathBuf::from(
argv.get(i).ok_or("--tal-path requires a value")?,
));
}
"--ta-path" => {
i += 1;
args.ta_path = Some(PathBuf::from(argv.get(i).ok_or("--ta-path requires a value")?));
args.ta_path = Some(PathBuf::from(
argv.get(i).ok_or("--ta-path requires a value")?,
));
}
"--base-validation-time" => {
i += 1;
let value = argv.get(i).ok_or("--base-validation-time requires a value")?;
let value = argv
.get(i)
.ok_or("--base-validation-time requires a value")?;
args.base_validation_time = Some(
time::OffsetDateTime::parse(value, &Rfc3339)
.map_err(|e| format!("invalid --base-validation-time: {e}"))?,
@@ -117,8 +125,9 @@ fn parse_args(argv: &[String]) -> Result<Args, String> {
}
"--rsync-mirror-root" => {
i += 1;
args.rsync_mirror_root =
Some(PathBuf::from(argv.get(i).ok_or("--rsync-mirror-root requires a value")?));
args.rsync_mirror_root = Some(PathBuf::from(
argv.get(i).ok_or("--rsync-mirror-root requires a value")?,
));
}
"--max-depth" => {
i += 1;
@@ -140,7 +149,11 @@ fn parse_args(argv: &[String]) -> Result<Args, String> {
}
"--trust-anchor" => {
i += 1;
args.trust_anchor = Some(argv.get(i).ok_or("--trust-anchor requires a value")?.clone());
args.trust_anchor = Some(
argv.get(i)
.ok_or("--trust-anchor requires a value")?
.clone(),
);
}
"--keep-db" => args.keep_db = true,
"--capture-inputs-only" => args.capture_inputs_only = true,
@@ -164,7 +177,12 @@ fn parse_args(argv: &[String]) -> Result<Args, String> {
Ok(args)
}
fn write_v2_top_readme(path: &Path, rir: &str, delta_count: usize, delta_interval_secs: u64) -> Result<(), String> {
fn write_v2_top_readme(
path: &Path,
rir: &str,
delta_count: usize,
delta_interval_secs: u64,
) -> Result<(), String> {
if let Some(parent) = path.parent() {
fs::create_dir_all(parent)
.map_err(|e| format!("create parent failed: {}: {e}", parent.display()))?;
@@ -203,11 +221,19 @@ fn ensure_recorded_target_snapshots_for_locks(
previous_locks_path: &Path,
http: &RecordingHttpFetcher<BlockingHttpFetcher>,
) -> Result<(), String> {
let previous_locks: serde_json::Value = serde_json::from_slice(
&fs::read(previous_locks_path)
.map_err(|e| format!("read previous locks failed: {}: {e}", previous_locks_path.display()))?,
)
.map_err(|e| format!("parse previous locks failed: {}: {e}", previous_locks_path.display()))?;
let previous_locks: serde_json::Value =
serde_json::from_slice(&fs::read(previous_locks_path).map_err(|e| {
format!(
"read previous locks failed: {}: {e}",
previous_locks_path.display()
)
})?)
.map_err(|e| {
format!(
"parse previous locks failed: {}: {e}",
previous_locks_path.display()
)
})?;
let previous_rrdp = previous_locks
.get("rrdp")
.and_then(|v| v.as_object())
@@ -251,9 +277,7 @@ fn ensure_recorded_target_snapshots_for_locks(
if let Err(err) = http.fetch(snapshot_uri) {
eprintln!(
"[sequence] warning: fetch target snapshot failed notify_uri={} snapshot_uri={} err={}",
notify_uri,
snapshot_uri,
err
notify_uri, snapshot_uri, err
);
}
}
@@ -281,20 +305,30 @@ fn run(args: Args) -> Result<PathBuf, String> {
}
let rir_dir = out_root.join(&rir_normalized);
let delta_steps_root = rir_dir.join("delta-steps");
fs::create_dir_all(&delta_steps_root)
.map_err(|e| format!("create delta steps dir failed: {}: {e}", delta_steps_root.display()))?;
fs::create_dir_all(&delta_steps_root).map_err(|e| {
format!(
"create delta steps dir failed: {}: {e}",
delta_steps_root.display()
)
})?;
let tal_bytes = fs::read(args.tal_path.as_ref().unwrap())
.map_err(|e| format!("read tal failed: {e}"))?;
let ta_bytes = fs::read(args.ta_path.as_ref().unwrap())
.map_err(|e| format!("read ta failed: {e}"))?;
let tal_bytes =
fs::read(args.tal_path.as_ref().unwrap()).map_err(|e| format!("read tal failed: {e}"))?;
let ta_bytes =
fs::read(args.ta_path.as_ref().unwrap()).map_err(|e| format!("read ta failed: {e}"))?;
fs::write(rir_dir.join("tal.tal"), &tal_bytes).map_err(|e| format!("write tal failed: {e}"))?;
fs::write(rir_dir.join("ta.cer"), &ta_bytes).map_err(|e| format!("write ta failed: {e}"))?;
let base_validation_time = args.base_validation_time.unwrap_or_else(time::OffsetDateTime::now_utc);
let base_validation_time = args
.base_validation_time
.unwrap_or_else(time::OffsetDateTime::now_utc);
let work_db_dir = out_root.join(".tmp").join(format!("{rir}-sequence-work-db"));
let base_self_replay_dir = out_root.join(".tmp").join(format!("{rir}-sequence-base-self-replay-db"));
let work_db_dir = out_root
.join(".tmp")
.join(format!("{rir}-sequence-work-db"));
let base_self_replay_dir = out_root
.join(".tmp")
.join(format!("{rir}-sequence-base-self-replay-db"));
let _ = fs::remove_dir_all(&work_db_dir);
let _ = fs::remove_dir_all(&base_self_replay_dir);
if let Some(parent) = work_db_dir.parent() {
@@ -356,9 +390,7 @@ fn run(args: Args) -> Result<PathBuf, String> {
)?;
eprintln!(
"[sequence] base input materialization done rir={} rrdp_repos={} rsync_modules={}",
rir_normalized,
base_capture.rrdp_repo_count,
base_capture.rsync_module_count
rir_normalized, base_capture.rrdp_repo_count, base_capture.rsync_module_count
);
let base_ccr_path = rir_dir.join("base.ccr");
let base_vrps_path = rir_dir.join("base-vrps.csv");
@@ -402,8 +434,8 @@ fn run(args: Args) -> Result<PathBuf, String> {
.map_err(|e| format!("read base ccr failed: {}: {e}", base_ccr_path.display()))?;
let base_decoded = decode_content_info(&base_ccr_bytes)
.map_err(|e| format!("decode base ccr failed: {e}"))?;
let base_verify =
verify_content_info(&base_decoded).map_err(|e| format!("verify base ccr failed: {e}"))?;
let base_verify = verify_content_info(&base_decoded)
.map_err(|e| format!("verify base ccr failed: {e}"))?;
let base_vrp_rows = build_vrp_compare_rows(&base_out.tree.vrps, &trust_anchor);
let base_vap_rows = build_vap_compare_rows(&base_out.tree.aspas, &trust_anchor);
let (base_ccr_vrps, base_ccr_vaps) =
@@ -464,7 +496,9 @@ fn run(args: Args) -> Result<PathBuf, String> {
let mut delta_steps = Vec::new();
let mut previous_locks_path = rir_dir.join("base-locks.json");
let mut previous_ref = "base".to_string();
let sequence_self_replay_dir = out_root.join(".tmp").join(format!("{rir}-sequence-self-replay-db"));
let sequence_self_replay_dir = out_root
.join(".tmp")
.join(format!("{rir}-sequence-self-replay-db"));
let _ = fs::remove_dir_all(&sequence_self_replay_dir);
let sequence_replay_store = if args.capture_inputs_only {
None
@@ -499,7 +533,10 @@ fn run(args: Args) -> Result<PathBuf, String> {
fs::create_dir_all(&step_dir)
.map_err(|e| format!("create step dir failed: {}: {e}", step_dir.display()))?;
let step_validation_time = time::OffsetDateTime::now_utc();
eprintln!("[sequence] step live run start rir={} step={}", rir_normalized, step_id);
eprintln!(
"[sequence] step live run start rir={} step={}",
rir_normalized, step_id
);
let step_http = RecordingHttpFetcher::new(
BlockingHttpFetcher::new(HttpFetcherConfig {
timeout: Duration::from_secs(args.http_timeout_secs),
@@ -542,7 +579,10 @@ fn run(args: Args) -> Result<PathBuf, String> {
);
ensure_recorded_target_snapshots_for_locks(&store, &previous_locks_path, &step_http)?;
eprintln!("[sequence] step output generation phase start rir={} step={}", rir_normalized, step_id);
eprintln!(
"[sequence] step output generation phase start rir={} step={}",
rir_normalized, step_id
);
let delta_ccr_path = step_dir.join("delta.ccr");
let delta_vrps_path = step_dir.join("record-delta.csv");
let delta_vaps_path = step_dir.join("record-delta-vaps.csv");
@@ -550,8 +590,7 @@ fn run(args: Args) -> Result<PathBuf, String> {
if args.capture_inputs_only {
eprintln!(
"[sequence] step CCR/self-replay skipped rir={} step={}",
rir_normalized,
step_id
rir_normalized, step_id
);
(
String::new(),
@@ -573,7 +612,10 @@ fn run(args: Args) -> Result<PathBuf, String> {
false,
)
} else {
eprintln!("[sequence] step CCR/self-replay start rir={} step={}", rir_normalized, step_id);
eprintln!(
"[sequence] step CCR/self-replay start rir={} step={}",
rir_normalized, step_id
);
let delta_ccr = build_ccr_from_run(
&store,
&[step_out.discovery.trust_anchor.clone()],
@@ -597,31 +639,39 @@ fn run(args: Args) -> Result<PathBuf, String> {
let (ccr_vrps, ccr_vaps) =
rpki::bundle::decode_ccr_compare_views(&delta_decoded, &trust_anchor)?;
if delta_vrp_rows != ccr_vrps {
return Err(format!("{step_id} VRP compare view does not match delta.ccr"));
return Err(format!(
"{step_id} VRP compare view does not match delta.ccr"
));
}
if delta_vap_rows != ccr_vaps {
return Err(format!("{step_id} VAP compare view does not match delta.ccr"));
return Err(format!(
"{step_id} VAP compare view does not match delta.ccr"
));
}
write_vrp_csv(&delta_vrps_path, &delta_vrp_rows)?;
write_vap_csv(&delta_vaps_path, &delta_vap_rows)?;
let step_replay_out = run_tree_from_tal_and_ta_der_payload_delta_replay_step_serial_audit(
sequence_replay_store.as_ref().expect("sequence replay store"),
&Policy::default(),
&tal_bytes,
&ta_bytes,
None,
&step_dir.join("payload-delta-archive"),
&previous_locks_path,
&step_dir.join("locks-delta.json"),
step_validation_time,
&TreeRunConfig {
max_depth: args.max_depth,
max_instances: args.max_instances,
},
)
.map_err(|e| format!("sequence self replay failed for {step_id}: {e}"))?;
let step_replay_out =
run_tree_from_tal_and_ta_der_payload_delta_replay_step_serial_audit(
sequence_replay_store
.as_ref()
.expect("sequence replay store"),
&Policy::default(),
&tal_bytes,
&ta_bytes,
None,
&step_dir.join("payload-delta-archive"),
&previous_locks_path,
&step_dir.join("locks-delta.json"),
step_validation_time,
&TreeRunConfig {
max_depth: args.max_depth,
max_instances: args.max_instances,
},
)
.map_err(|e| format!("sequence self replay failed for {step_id}: {e}"))?;
let step_self_replay_ok =
build_vrp_compare_rows(&step_replay_out.tree.vrps, &trust_anchor) == delta_vrp_rows
build_vrp_compare_rows(&step_replay_out.tree.vrps, &trust_anchor)
== delta_vrp_rows
&& build_vap_compare_rows(&step_replay_out.tree.aspas, &trust_anchor)
== delta_vap_rows;
let output = (
@@ -631,11 +681,17 @@ fn run(args: Args) -> Result<PathBuf, String> {
delta_verify,
step_self_replay_ok,
);
eprintln!("[sequence] step CCR/self-replay done rir={} step={}", rir_normalized, step_id);
eprintln!(
"[sequence] step CCR/self-replay done rir={} step={}",
rir_normalized, step_id
);
output
};
eprintln!("[sequence] step input materialization start rir={} step={}", rir_normalized, step_id);
eprintln!(
"[sequence] step input materialization start rir={} step={}",
rir_normalized, step_id
);
let delta_capture = write_live_delta_replay_step_inputs(
&step_dir,
&rir_normalized,
@@ -816,7 +872,12 @@ fn run(args: Args) -> Result<PathBuf, String> {
}
}),
)?;
write_v2_top_readme(&out_root.join("README.md"), &rir_normalized, args.delta_count, args.delta_interval_secs)?;
write_v2_top_readme(
&out_root.join("README.md"),
&rir_normalized,
args.delta_count,
args.delta_interval_secs,
)?;
write_v2_rir_readme(
&rir_dir.join("README.md"),
&rir_normalized,

View File

@@ -48,35 +48,49 @@ fn parse_args(argv: &[String]) -> Result<Args, String> {
}
"--out-dir" => {
i += 1;
args.out_dir = Some(PathBuf::from(argv.get(i).ok_or("--out-dir requires a value")?));
args.out_dir = Some(PathBuf::from(
argv.get(i).ok_or("--out-dir requires a value")?,
));
}
"--tal-path" => {
i += 1;
args.tal_path = Some(PathBuf::from(argv.get(i).ok_or("--tal-path requires a value")?));
args.tal_path = Some(PathBuf::from(
argv.get(i).ok_or("--tal-path requires a value")?,
));
}
"--ta-path" => {
i += 1;
args.ta_path = Some(PathBuf::from(argv.get(i).ok_or("--ta-path requires a value")?));
args.ta_path = Some(PathBuf::from(
argv.get(i).ok_or("--ta-path requires a value")?,
));
}
"--payload-replay-archive" => {
i += 1;
args.payload_replay_archive =
Some(PathBuf::from(argv.get(i).ok_or("--payload-replay-archive requires a value")?));
args.payload_replay_archive = Some(PathBuf::from(
argv.get(i)
.ok_or("--payload-replay-archive requires a value")?,
));
}
"--payload-replay-locks" => {
i += 1;
args.payload_replay_locks =
Some(PathBuf::from(argv.get(i).ok_or("--payload-replay-locks requires a value")?));
args.payload_replay_locks = Some(PathBuf::from(
argv.get(i)
.ok_or("--payload-replay-locks requires a value")?,
));
}
"--payload-delta-archive" => {
i += 1;
args.payload_delta_archive =
Some(PathBuf::from(argv.get(i).ok_or("--payload-delta-archive requires a value")?));
args.payload_delta_archive = Some(PathBuf::from(
argv.get(i)
.ok_or("--payload-delta-archive requires a value")?,
));
}
"--payload-delta-locks" => {
i += 1;
args.payload_delta_locks =
Some(PathBuf::from(argv.get(i).ok_or("--payload-delta-locks requires a value")?));
args.payload_delta_locks = Some(PathBuf::from(
argv.get(i)
.ok_or("--payload-delta-locks requires a value")?,
));
}
"--validation-time" => {
i += 1;
@@ -106,7 +120,11 @@ fn parse_args(argv: &[String]) -> Result<Args, String> {
}
"--trust-anchor" => {
i += 1;
args.trust_anchor = Some(argv.get(i).ok_or("--trust-anchor requires a value")?.clone());
args.trust_anchor = Some(
argv.get(i)
.ok_or("--trust-anchor requires a value")?
.clone(),
);
}
other => return Err(format!("unknown argument: {other}\n{}", usage())),
}
@@ -155,7 +173,9 @@ fn sha256_hex(bytes: &[u8]) -> String {
fn copy_dir_all(src: &Path, dst: &Path) -> Result<(), String> {
fs::create_dir_all(dst)
.map_err(|e| format!("create directory failed: {}: {e}", dst.display()))?;
for entry in fs::read_dir(src).map_err(|e| format!("read_dir failed: {}: {e}", src.display()))? {
for entry in
fs::read_dir(src).map_err(|e| format!("read_dir failed: {}: {e}", src.display()))?
{
let entry = entry.map_err(|e| format!("read_dir entry failed: {}: {e}", src.display()))?;
let ty = entry
.file_type()
@@ -168,8 +188,13 @@ fn copy_dir_all(src: &Path, dst: &Path) -> Result<(), String> {
fs::create_dir_all(parent)
.map_err(|e| format!("create parent failed: {}: {e}", parent.display()))?;
}
fs::copy(entry.path(), &to)
.map_err(|e| format!("copy failed: {} -> {}: {e}", entry.path().display(), to.display()))?;
fs::copy(entry.path(), &to).map_err(|e| {
format!(
"copy failed: {} -> {}: {e}",
entry.path().display(),
to.display()
)
})?;
}
}
Ok(())
@@ -222,7 +247,10 @@ fn write_timing_json(
)
}
fn rewrite_delta_base_locks_sha(delta_root: &Path, emitted_base_locks_sha256: &str) -> Result<(), String> {
fn rewrite_delta_base_locks_sha(
delta_root: &Path,
emitted_base_locks_sha256: &str,
) -> Result<(), String> {
let delta_locks = delta_root.join("locks-delta.json");
if delta_locks.is_file() {
let mut json: serde_json::Value = serde_json::from_slice(
@@ -243,7 +271,8 @@ fn rewrite_delta_base_locks_sha(delta_root: &Path, emitted_base_locks_sha256: &s
if archive_root.is_dir() {
for path in walk_json_files_named(&archive_root, "base.json")? {
let mut json: serde_json::Value = serde_json::from_slice(
&fs::read(&path).map_err(|e| format!("read base.json failed: {}: {e}", path.display()))?,
&fs::read(&path)
.map_err(|e| format!("read base.json failed: {}: {e}", path.display()))?,
)
.map_err(|e| format!("parse base.json failed: {}: {e}", path.display()))?;
json.as_object_mut()
@@ -265,8 +294,11 @@ fn walk_json_files_named(root: &Path, name: &str) -> Result<Vec<PathBuf>, String
}
let mut stack = vec![root.to_path_buf()];
while let Some(dir) = stack.pop() {
for entry in fs::read_dir(&dir).map_err(|e| format!("read_dir failed: {}: {e}", dir.display()))? {
let entry = entry.map_err(|e| format!("read_dir entry failed: {}: {e}", dir.display()))?;
for entry in
fs::read_dir(&dir).map_err(|e| format!("read_dir failed: {}: {e}", dir.display()))?
{
let entry =
entry.map_err(|e| format!("read_dir entry failed: {}: {e}", dir.display()))?;
let path = entry.path();
let ty = entry
.file_type()
@@ -308,8 +340,10 @@ fn run(args: Args) -> Result<PathBuf, String> {
fs::create_dir_all(&rir_dir)
.map_err(|e| format!("create rir dir failed: {}: {e}", rir_dir.display()))?;
let tal_bytes = fs::read(tal_path).map_err(|e| format!("read tal failed: {}: {e}", tal_path.display()))?;
let ta_bytes = fs::read(ta_path).map_err(|e| format!("read ta failed: {}: {e}", ta_path.display()))?;
let tal_bytes =
fs::read(tal_path).map_err(|e| format!("read tal failed: {}: {e}", tal_path.display()))?;
let ta_bytes =
fs::read(ta_path).map_err(|e| format!("read ta failed: {}: {e}", ta_path.display()))?;
let db_dir = run_root.join(".tmp").join(format!("{rir}-base-db"));
if db_dir.exists() {
@@ -354,7 +388,8 @@ fn run(args: Args) -> Result<PathBuf, String> {
write_ccr_file(&base_ccr_path, &ccr).map_err(|e| format!("write ccr failed: {e}"))?;
let ccr_bytes = fs::read(&base_ccr_path)
.map_err(|e| format!("read written ccr failed: {}: {e}", base_ccr_path.display()))?;
let decoded = decode_content_info(&ccr_bytes).map_err(|e| format!("decode written ccr failed: {e}"))?;
let decoded =
decode_content_info(&ccr_bytes).map_err(|e| format!("decode written ccr failed: {e}"))?;
let verify = verify_content_info(&decoded).map_err(|e| format!("verify ccr failed: {e}"))?;
let vrp_rows = build_vrp_compare_rows(&out.tree.vrps, &trust_anchor);
@@ -385,10 +420,13 @@ fn run(args: Args) -> Result<PathBuf, String> {
);
let emitted_base_locks_path = rir_dir.join("base-locks.json");
write_json(&emitted_base_locks_path, &base_locks_json)?;
let emitted_base_locks_sha256 = sha256_hex(
&fs::read(&emitted_base_locks_path)
.map_err(|e| format!("read emitted base locks failed: {}: {e}", emitted_base_locks_path.display()))?,
);
let emitted_base_locks_sha256 =
sha256_hex(&fs::read(&emitted_base_locks_path).map_err(|e| {
format!(
"read emitted base locks failed: {}: {e}",
emitted_base_locks_path.display()
)
})?);
if let Some(delta_archive) = args.payload_delta_archive.as_ref() {
copy_dir_all(delta_archive, &rir_dir.join("payload-delta-archive"))?;
@@ -418,10 +456,8 @@ fn run(args: Args) -> Result<PathBuf, String> {
rewrite_delta_base_locks_sha(&rir_dir, &emitted_base_locks_sha256)?;
}
fs::write(rir_dir.join("tal.tal"), &tal_bytes)
.map_err(|e| format!("write tal failed: {e}"))?;
fs::write(rir_dir.join("ta.cer"), &ta_bytes)
.map_err(|e| format!("write ta failed: {e}"))?;
fs::write(rir_dir.join("tal.tal"), &tal_bytes).map_err(|e| format!("write tal failed: {e}"))?;
fs::write(rir_dir.join("ta.cer"), &ta_bytes).map_err(|e| format!("write ta failed: {e}"))?;
let mut metadata = RirBundleMetadata {
schema_version: "20260330-v1".to_string(),
@@ -484,15 +520,19 @@ fn run(args: Args) -> Result<PathBuf, String> {
) {
let delta_db_dir = run_root.join(".tmp").join(format!("{rir}-delta-db"));
if delta_db_dir.exists() {
fs::remove_dir_all(&delta_db_dir)
.map_err(|e| format!("remove old delta db failed: {}: {e}", delta_db_dir.display()))?;
fs::remove_dir_all(&delta_db_dir).map_err(|e| {
format!(
"remove old delta db failed: {}: {e}",
delta_db_dir.display()
)
})?;
}
if let Some(parent) = delta_db_dir.parent() {
fs::create_dir_all(parent)
.map_err(|e| format!("create delta db parent failed: {}: {e}", parent.display()))?;
}
let delta_store =
RocksStore::open(&delta_db_dir).map_err(|e| format!("open delta rocksdb failed: {e}"))?;
let delta_store = RocksStore::open(&delta_db_dir)
.map_err(|e| format!("open delta rocksdb failed: {e}"))?;
let delta_started = Instant::now();
let delta_out = run_tree_from_tal_and_ta_der_payload_delta_replay_serial_audit(
&delta_store,
@@ -527,16 +567,21 @@ fn run(args: Args) -> Result<PathBuf, String> {
let delta_ccr_path = rir_dir.join("delta.ccr");
write_ccr_file(&delta_ccr_path, &delta_ccr)
.map_err(|e| format!("write delta ccr failed: {e}"))?;
let delta_ccr_bytes = fs::read(&delta_ccr_path)
.map_err(|e| format!("read written delta ccr failed: {}: {e}", delta_ccr_path.display()))?;
let delta_ccr_bytes = fs::read(&delta_ccr_path).map_err(|e| {
format!(
"read written delta ccr failed: {}: {e}",
delta_ccr_path.display()
)
})?;
let delta_decoded = decode_content_info(&delta_ccr_bytes)
.map_err(|e| format!("decode written delta ccr failed: {e}"))?;
let delta_verify =
verify_content_info(&delta_decoded).map_err(|e| format!("verify delta ccr failed: {e}"))?;
let delta_verify = verify_content_info(&delta_decoded)
.map_err(|e| format!("verify delta ccr failed: {e}"))?;
let delta_vrp_rows = build_vrp_compare_rows(&delta_out.tree.vrps, &trust_anchor);
let delta_vap_rows = build_vap_compare_rows(&delta_out.tree.aspas, &trust_anchor);
let (delta_ccr_vrps, delta_ccr_vaps) = decode_ccr_compare_views(&delta_decoded, &trust_anchor)?;
let (delta_ccr_vrps, delta_ccr_vaps) =
decode_ccr_compare_views(&delta_decoded, &trust_anchor)?;
if delta_vrp_rows != delta_ccr_vrps {
return Err("record-delta.csv compare view does not match delta.ccr".to_string());
}
@@ -585,7 +630,11 @@ fn run(args: Args) -> Result<PathBuf, String> {
write_json(&rir_dir.join("bundle.json"), &metadata)?;
write_json(&rir_dir.join("verification.json"), &verification)?;
write_top_readme(&run_root.join("README.md"), rir)?;
write_rir_readme(&rir_dir.join("README.md"), rir, &metadata.base_validation_time)?;
write_rir_readme(
&rir_dir.join("README.md"),
rir,
&metadata.base_validation_time,
)?;
let bundle_manifest = BundleManifest {
schema_version: "20260330-v1".to_string(),
@@ -654,11 +703,8 @@ mod tests {
fn load_validation_time_reads_top_level_validation_time() {
let dir = tempdir().expect("tempdir");
let path = dir.path().join("locks.json");
std::fs::write(
&path,
r#"{"validationTime":"2026-03-16T11:49:15+08:00"}"#,
)
.expect("write locks");
std::fs::write(&path, r#"{"validationTime":"2026-03-16T11:49:15+08:00"}"#)
.expect("write locks");
let got = load_validation_time(&path).expect("load validation time");
assert_eq!(
got.format(&Rfc3339).expect("format"),
@@ -722,7 +768,12 @@ mod tests {
assert!(out_dir.join("apnic").join("base-vaps.csv").is_file());
assert!(out_dir.join("apnic").join("delta.ccr").is_file());
assert!(out_dir.join("apnic").join("record-delta.csv").is_file());
assert!(out_dir.join("apnic").join("record-delta-vaps.csv").is_file());
assert!(
out_dir
.join("apnic")
.join("record-delta-vaps.csv")
.is_file()
);
assert!(out_dir.join("apnic").join("verification.json").is_file());
let bundle_json: serde_json::Value = serde_json::from_slice(
&std::fs::read(out_dir.join("apnic").join("bundle.json")).expect("read bundle.json"),
@@ -734,11 +785,12 @@ mod tests {
assert!(bundle_json.get("baseCcrSha256").is_some());
assert!(bundle_json.get("deltaVrpCount").is_some());
assert!(bundle_json.get("deltaCcrSha256").is_some());
let base_locks_bytes =
std::fs::read(out_dir.join("apnic").join("base-locks.json")).expect("read emitted base locks");
let base_locks_bytes = std::fs::read(out_dir.join("apnic").join("base-locks.json"))
.expect("read emitted base locks");
let expected_base_locks_sha = sha256_hex(&base_locks_bytes);
let delta_locks_json: serde_json::Value = serde_json::from_slice(
&std::fs::read(out_dir.join("apnic").join("locks-delta.json")).expect("read delta locks"),
&std::fs::read(out_dir.join("apnic").join("locks-delta.json"))
.expect("read delta locks"),
)
.expect("parse delta locks");
assert_eq!(delta_locks_json["baseLocksSha256"], expected_base_locks_sha);

View File

@@ -177,16 +177,24 @@ fn materialize_rsync_module_from_store(
.strip_prefix("rsync://")
.ok_or_else(|| format!("invalid rsync module uri: {module_uri}"))?
.trim_end_matches('/');
fs::create_dir_all(tree_root.join(relative_root))
.map_err(|e| format!("create rsync tree root failed: {}: {e}", tree_root.join(relative_root).display()))?;
fs::create_dir_all(tree_root.join(relative_root)).map_err(|e| {
format!(
"create rsync tree root failed: {}: {e}",
tree_root.join(relative_root).display()
)
})?;
for (uri, bytes) in objects {
let rel = uri
.strip_prefix(module_uri)
.ok_or_else(|| format!("object uri {uri} does not belong to module {module_uri}"))?;
let path = tree_root.join(relative_root).join(rel);
if let Some(parent) = path.parent() {
fs::create_dir_all(parent)
.map_err(|e| format!("create rsync object parent failed: {}: {e}", parent.display()))?;
fs::create_dir_all(parent).map_err(|e| {
format!(
"create rsync object parent failed: {}: {e}",
parent.display()
)
})?;
}
fs::write(&path, bytes)
.map_err(|e| format!("write rsync object failed: {}: {e}", path.display()))?;
@@ -197,8 +205,8 @@ fn materialize_rsync_module_from_store(
fn copy_dir_all(src: &Path, dst: &Path) -> Result<(), String> {
fs::create_dir_all(dst)
.map_err(|e| format!("create directory failed: {}: {e}", dst.display()))?;
for entry in fs::read_dir(src)
.map_err(|e| format!("read directory failed: {}: {e}", src.display()))?
for entry in
fs::read_dir(src).map_err(|e| format!("read directory failed: {}: {e}", src.display()))?
{
let entry = entry.map_err(|e| format!("read entry failed: {}: {e}", src.display()))?;
let file_type = entry
@@ -252,8 +260,12 @@ fn keep_rsync_module(pp: &rpki::audit::PublicationPointAudit) -> Result<Option<S
if is_failed_fetch_source(&pp.source) {
return Ok(None);
}
let module_uri = canonical_rsync_module(&pp.rsync_base_uri)
.map_err(|e| format!("canonicalize rsync module failed for {}: {e}", pp.rsync_base_uri))?;
let module_uri = canonical_rsync_module(&pp.rsync_base_uri).map_err(|e| {
format!(
"canonicalize rsync module failed for {}: {e}",
pp.rsync_base_uri
)
})?;
if pp.rrdp_notification_uri.is_none() || pp.repo_sync_source.as_deref() == Some("rsync") {
return Ok(Some(module_uri));
}
@@ -317,8 +329,9 @@ fn repair_base_inputs(
for entry in fs::read_dir(&repos_dir)
.map_err(|e| format!("scan rrdp repo dir failed: {}: {e}", repos_dir.display()))?
{
let entry = entry
.map_err(|e| format!("read rrdp repo entry failed: {}: {e}", repos_dir.display()))?;
let entry = entry.map_err(|e| {
format!("read rrdp repo entry failed: {}: {e}", repos_dir.display())
})?;
let meta = entry.path().join("meta.json");
if !meta.exists() {
continue;
@@ -385,13 +398,13 @@ fn repair_base_inputs(
}
write_json_value(locks_path, &locks)?;
verification.base["capture"]["rrdpRepoCount"] = serde_json::Value::from(
locks.get("rrdp")
locks
.get("rrdp")
.and_then(|v| v.as_object())
.map(|m| m.len())
.unwrap_or(0),
);
verification.base["capture"]["rsyncModuleCount"] =
serde_json::Value::from(final_modules.len());
verification.base["capture"]["rsyncModuleCount"] = serde_json::Value::from(final_modules.len());
Ok(())
}
@@ -502,8 +515,9 @@ fn repair_delta_step_inputs(
for entry in fs::read_dir(&repos_dir)
.map_err(|e| format!("scan rrdp repo dir failed: {}: {e}", repos_dir.display()))?
{
let entry = entry
.map_err(|e| format!("read rrdp repo entry failed: {}: {e}", repos_dir.display()))?;
let entry = entry.map_err(|e| {
format!("read rrdp repo entry failed: {}: {e}", repos_dir.display())
})?;
let meta = entry.path().join("meta.json");
if !meta.exists() {
continue;
@@ -634,7 +648,8 @@ fn repair_delta_step_inputs(
.and_then(|v| v.get("session"))
.and_then(|v| v.as_str())
.or_else(|| {
entry.get("base")
entry
.get("base")
.and_then(|v| v.get("session"))
.and_then(|v| v.as_str())
});
@@ -645,7 +660,10 @@ fn repair_delta_step_inputs(
if session_dir.exists() {
continue;
}
let base_bucket_dir = base_capture_root.join("rrdp").join("repos").join(&bucket_hash);
let base_bucket_dir = base_capture_root
.join("rrdp")
.join("repos")
.join(&bucket_hash);
let base_session_dir = base_bucket_dir.join(session);
if !base_session_dir.exists() {
continue;
@@ -673,13 +691,13 @@ fn repair_delta_step_inputs(
write_json_value(&locks_path, &locks)?;
step_verification["capture"]["rrdpRepoCount"] = serde_json::Value::from(
locks.get("rrdp")
locks
.get("rrdp")
.and_then(|v| v.as_object())
.map(|m| m.len())
.unwrap_or(0),
);
step_verification["capture"]["rsyncModuleCount"] =
serde_json::Value::from(final_modules.len());
step_verification["capture"]["rsyncModuleCount"] = serde_json::Value::from(final_modules.len());
Ok(())
}
@@ -694,7 +712,12 @@ fn rewrite_delta_base_hash(step_dir: &Path, previous_locks_path: &Path) -> Resul
let locks_path = step_dir.join("locks-delta.json");
let mut locks = load_json(&locks_path)?;
let previous_locks = serde_json::from_slice::<serde_json::Value>(&previous_locks_bytes)
.map_err(|e| format!("parse previous locks failed: {}: {e}", previous_locks_path.display()))?;
.map_err(|e| {
format!(
"parse previous locks failed: {}: {e}",
previous_locks_path.display()
)
})?;
locks["baseLocksSha256"] = serde_json::Value::String(previous_locks_sha256.clone());
let capture = locks
.get("capture")
@@ -760,17 +783,33 @@ fn real_main() -> Result<(), String> {
let bundle_json_path = rir_dir.join("bundle.json");
let verification_path = rir_dir.join("verification.json");
let mut bundle: RirBundleMetadataV2Serde = serde_json::from_slice(
&fs::read(&bundle_json_path)
.map_err(|e| format!("read bundle.json failed: {}: {e}", bundle_json_path.display()))?,
)
.map_err(|e| format!("parse bundle.json failed: {}: {e}", bundle_json_path.display()))?;
let mut bundle: RirBundleMetadataV2Serde =
serde_json::from_slice(&fs::read(&bundle_json_path).map_err(|e| {
format!(
"read bundle.json failed: {}: {e}",
bundle_json_path.display()
)
})?)
.map_err(|e| {
format!(
"parse bundle.json failed: {}: {e}",
bundle_json_path.display()
)
})?;
let mut verification: VerificationV2 = serde_json::from_slice(
&fs::read(&verification_path)
.map_err(|e| format!("read verification.json failed: {}: {e}", verification_path.display()))?,
)
.map_err(|e| format!("parse verification.json failed: {}: {e}", verification_path.display()))?;
let mut verification: VerificationV2 =
serde_json::from_slice(&fs::read(&verification_path).map_err(|e| {
format!(
"read verification.json failed: {}: {e}",
verification_path.display()
)
})?)
.map_err(|e| {
format!(
"parse verification.json failed: {}: {e}",
verification_path.display()
)
})?;
let tal_bytes = fs::read(rir_dir.join("tal.tal"))
.map_err(|e| format!("read tal.tal failed: {}: {e}", rir_dir.display()))?;
@@ -787,7 +826,8 @@ fn real_main() -> Result<(), String> {
fs::create_dir_all(parent)
.map_err(|e| format!("create refresh db parent failed: {}: {e}", parent.display()))?;
}
let store = RocksStore::open(&work_db).map_err(|e| format!("open refresh rocksdb failed: {e}"))?;
let store =
RocksStore::open(&work_db).map_err(|e| format!("open refresh rocksdb failed: {e}"))?;
let base_archive = path_join(&rir_dir, &bundle.base.relative_archive_path);
let base_locks = path_join(&rir_dir, &bundle.base.relative_locks_path);
@@ -823,8 +863,8 @@ fn real_main() -> Result<(), String> {
.map_err(|e| format!("build base ccr failed: {e}"))?;
write_ccr_file(&base_ccr, &base_ccr_content)
.map_err(|e| format!("write base ccr failed: {}: {e}", base_ccr.display()))?;
let base_ccr_bytes =
fs::read(&base_ccr).map_err(|e| format!("read base ccr failed: {}: {e}", base_ccr.display()))?;
let base_ccr_bytes = fs::read(&base_ccr)
.map_err(|e| format!("read base ccr failed: {}: {e}", base_ccr.display()))?;
let base_decoded =
decode_content_info(&base_ccr_bytes).map_err(|e| format!("decode base ccr failed: {e}"))?;
let base_verify =
@@ -838,15 +878,18 @@ fn real_main() -> Result<(), String> {
bundle.base.vap_count = base_vap_rows.len();
verification.base["ccr"]["sha256"] = serde_json::Value::String(bundle.base.ccr_sha256.clone());
verification.base["ccr"]["stateHashesOk"] = serde_json::Value::Bool(base_verify.state_hashes_ok);
verification.base["ccr"]["stateHashesOk"] =
serde_json::Value::Bool(base_verify.state_hashes_ok);
verification.base["ccr"]["manifestInstances"] =
serde_json::Value::from(base_verify.manifest_instances);
verification.base["ccr"]["roaVrpCount"] = serde_json::Value::from(base_vrp_rows.len());
verification.base["ccr"]["aspaPayloadSets"] = serde_json::Value::from(base_vap_rows.len());
verification.base["ccr"]["routerKeyCount"] =
serde_json::Value::from(base_verify.router_key_count);
verification.base["compareViews"]["baseVrpCount"] = serde_json::Value::from(base_vrp_rows.len());
verification.base["compareViews"]["baseVapCount"] = serde_json::Value::from(base_vap_rows.len());
verification.base["compareViews"]["baseVrpCount"] =
serde_json::Value::from(base_vrp_rows.len());
verification.base["compareViews"]["baseVapCount"] =
serde_json::Value::from(base_vap_rows.len());
verification.base["capture"]["selfReplayOk"] = serde_json::Value::Bool(true);
repair_base_inputs(
&base_archive,
@@ -922,7 +965,8 @@ fn real_main() -> Result<(), String> {
step_verification["ccr"]["manifestInstances"] =
serde_json::Value::from(delta_verify.manifest_instances);
step_verification["ccr"]["roaVrpCount"] = serde_json::Value::from(delta_vrp_rows.len());
step_verification["ccr"]["aspaPayloadSets"] = serde_json::Value::from(delta_vap_rows.len());
step_verification["ccr"]["aspaPayloadSets"] =
serde_json::Value::from(delta_vap_rows.len());
step_verification["ccr"]["routerKeyCount"] =
serde_json::Value::from(delta_verify.router_key_count);
step_verification["compareViews"]["vrpCount"] =
@@ -931,28 +975,29 @@ fn real_main() -> Result<(), String> {
serde_json::Value::from(delta_vap_rows.len());
step_verification["selfReplayOk"] = serde_json::Value::Bool(true);
}
let step_verification_path = path_join(&rir_dir, &step.relative_path).join("verification.json");
let mut step_verification_json: serde_json::Value = serde_json::from_slice(
&fs::read(&step_verification_path).map_err(|e| {
let step_verification_path =
path_join(&rir_dir, &step.relative_path).join("verification.json");
let mut step_verification_json: serde_json::Value =
serde_json::from_slice(&fs::read(&step_verification_path).map_err(|e| {
format!(
"read step verification failed: {}: {e}",
step_verification_path.display()
)
})?,
)
.map_err(|e| {
format!(
"parse step verification failed: {}: {e}",
step_verification_path.display()
)
})?;
})?)
.map_err(|e| {
format!(
"parse step verification failed: {}: {e}",
step_verification_path.display()
)
})?;
step_verification_json["ccr"]["sha256"] =
serde_json::Value::String(step.delta_ccr_sha256.clone());
step_verification_json["ccr"]["stateHashesOk"] =
serde_json::Value::Bool(delta_verify.state_hashes_ok);
step_verification_json["ccr"]["manifestInstances"] =
serde_json::Value::from(delta_verify.manifest_instances);
step_verification_json["ccr"]["roaVrpCount"] = serde_json::Value::from(delta_vrp_rows.len());
step_verification_json["ccr"]["roaVrpCount"] =
serde_json::Value::from(delta_vrp_rows.len());
step_verification_json["ccr"]["aspaPayloadSets"] =
serde_json::Value::from(delta_vap_rows.len());
step_verification_json["ccr"]["routerKeyCount"] =

View File

@@ -1,5 +1,5 @@
use rocksdb::{DB, IteratorMode, Options};
use rpki::storage::{column_family_descriptors, CF_REPOSITORY_VIEW};
use rpki::storage::{CF_REPOSITORY_VIEW, column_family_descriptors};
use std::fs;
use std::path::{Path, PathBuf};

View File

@@ -64,12 +64,9 @@ fn main() {
println!("rule_hash={}", output.rule_hash);
println!("validation_path_hint={:?}", output.validation_path_hint);
if let Some(trace) = trace_rule_to_root(
&store,
AuditRuleKind::Roa,
&output.rule_hash,
)
.expect("trace rule")
if let Some(trace) =
trace_rule_to_root(&store, AuditRuleKind::Roa, &output.rule_hash)
.expect("trace rule")
{
println!(
"trace_leaf_manifest={}",
@@ -79,11 +76,17 @@ fn main() {
.map(|node| node.manifest_rsync_uri.as_str())
.unwrap_or("")
);
println!("trace_source_object_uri={}", trace.resolved_output.source_object_uri);
println!(
"trace_source_object_uri={}",
trace.resolved_output.source_object_uri
);
println!("trace_chain_len={}", trace.chain_leaf_to_root.len());
for (idx, node) in trace.chain_leaf_to_root.iter().enumerate() {
println!("chain[{idx}].manifest={}", node.manifest_rsync_uri);
println!("chain[{idx}].current_manifest={}", node.current_manifest_rsync_uri);
println!(
"chain[{idx}].current_manifest={}",
node.current_manifest_rsync_uri
);
println!("chain[{idx}].current_crl={}", node.current_crl_rsync_uri);
}
}