20260420_2 完成输出report和ccr优化,snapshot耗时优化到70多秒
This commit is contained in:
@@ -4,7 +4,7 @@ use crate::data_model::signed_object::SignedObjectVerifyError;
|
||||
use crate::policy::{CaFailedFetchPolicy, Policy};
|
||||
use crate::report::{RfcRef, Warning};
|
||||
use crate::storage::{PackFile, PackTime, RocksStore, StorageError, VcirArtifactRole};
|
||||
use crate::validation::cert_path::{CertPathError, validate_signed_object_ee_cert_path_fast};
|
||||
use crate::validation::cert_path::{validate_signed_object_ee_cert_path_fast, CertPathError};
|
||||
use crate::validation::publication_point::PublicationPointSnapshot;
|
||||
use sha2::Digest;
|
||||
use std::cmp::Ordering;
|
||||
@@ -398,11 +398,10 @@ pub fn process_manifest_publication_point_after_repo_sync(
|
||||
Err(ManifestProcessError::StopAllOutput(fresh_err))
|
||||
}
|
||||
CaFailedFetchPolicy::ReuseCurrentInstanceVcir => {
|
||||
let mut warnings = vec![
|
||||
Warning::new(format!("manifest failed fetch: {fresh_err}"))
|
||||
let mut warnings =
|
||||
vec![Warning::new(format!("manifest failed fetch: {fresh_err}"))
|
||||
.with_rfc_refs(&[RfcRef("RFC 9286 §6.6")])
|
||||
.with_context(manifest_rsync_uri),
|
||||
];
|
||||
.with_context(manifest_rsync_uri)];
|
||||
|
||||
match load_current_instance_vcir_publication_point(
|
||||
store,
|
||||
@@ -932,7 +931,8 @@ mod tests {
|
||||
use crate::storage::{
|
||||
PackFile, PackTime, RawByHashEntry, RocksStore, ValidatedCaInstanceResult,
|
||||
ValidatedManifestMeta, VcirArtifactKind, VcirArtifactRole, VcirArtifactValidationStatus,
|
||||
VcirAuditSummary, VcirInstanceGate, VcirRelatedArtifact, VcirSummary,
|
||||
VcirAuditSummary, VcirCcrManifestProjection, VcirInstanceGate, VcirRelatedArtifact,
|
||||
VcirSummary,
|
||||
};
|
||||
use std::path::Path;
|
||||
|
||||
@@ -1039,6 +1039,19 @@ mod tests {
|
||||
) -> ValidatedCaInstanceResult {
|
||||
let gate_time =
|
||||
PackTime::from_utc_offset_datetime(validation_time + time::Duration::hours(1));
|
||||
let ccr_manifest_projection = VcirCcrManifestProjection {
|
||||
manifest_rsync_uri: manifest_rsync_uri.to_string(),
|
||||
manifest_sha256: hex::decode(manifest_sha256).expect("decode manifest sha256"),
|
||||
manifest_size: 2048,
|
||||
manifest_ee_aki: vec![0x11; 20],
|
||||
manifest_number_be: vec![1],
|
||||
manifest_this_update: PackTime::from_utc_offset_datetime(validation_time),
|
||||
manifest_sia_locations_der: vec![vec![
|
||||
0x30, 0x11, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x05, 0x86, 0x05,
|
||||
b'r', b's', b'y', b'n', b'c',
|
||||
]],
|
||||
subordinate_skis: Vec::new(),
|
||||
};
|
||||
ValidatedCaInstanceResult {
|
||||
manifest_rsync_uri: manifest_rsync_uri.to_string(),
|
||||
parent_manifest_rsync_uri: None,
|
||||
@@ -1054,6 +1067,7 @@ mod tests {
|
||||
validated_manifest_this_update: PackTime::from_utc_offset_datetime(validation_time),
|
||||
validated_manifest_next_update: gate_time.clone(),
|
||||
},
|
||||
ccr_manifest_projection,
|
||||
instance_gate: VcirInstanceGate {
|
||||
manifest_next_update: gate_time.clone(),
|
||||
current_crl_next_update: gate_time.clone(),
|
||||
@@ -1313,12 +1327,10 @@ mod tests {
|
||||
.apply_repository_view_entries(&entries)
|
||||
.expect("apply current index");
|
||||
|
||||
assert!(
|
||||
store
|
||||
.get_repository_view_entry(&manifest_rsync_uri)
|
||||
.expect("get repository view")
|
||||
.is_none()
|
||||
);
|
||||
assert!(store
|
||||
.get_repository_view_entry(&manifest_rsync_uri)
|
||||
.expect("get repository view")
|
||||
.is_none());
|
||||
|
||||
let (fresh, _timing) = try_build_fresh_publication_point_with_timing(
|
||||
&store,
|
||||
|
||||
@@ -77,6 +77,7 @@ pub fn run_publication_point_once(
|
||||
repo_sync_runtime: None,
|
||||
parallel_phase2_config: None,
|
||||
parallel_roa_worker_pool: None,
|
||||
ccr_accumulator: None,
|
||||
};
|
||||
|
||||
let result = runner
|
||||
|
||||
@@ -3,6 +3,7 @@ use url::Url;
|
||||
use crate::analysis::timing::TimingHandle;
|
||||
use crate::audit::PublicationPointAudit;
|
||||
use crate::audit_downloads::DownloadLogHandle;
|
||||
use crate::ccr::CcrAccumulator;
|
||||
use crate::current_repo_index::{CurrentRepoIndexHandle, CurrentRepoObject};
|
||||
use crate::data_model::ta::TrustAnchor;
|
||||
use crate::parallel::config::{ParallelPhase1Config, ParallelPhase2Config};
|
||||
@@ -90,6 +91,7 @@ pub struct RunTreeFromTalAuditOutput {
|
||||
pub downloads: Vec<crate::audit::AuditDownloadEvent>,
|
||||
pub download_stats: crate::audit::AuditDownloadStats,
|
||||
pub current_repo_objects: Vec<CurrentRepoObject>,
|
||||
pub ccr_accumulator: Option<CcrAccumulator>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
@@ -118,6 +120,7 @@ fn make_live_runner<'a>(
|
||||
current_repo_index: Option<CurrentRepoIndexHandle>,
|
||||
repo_sync_runtime: Option<Arc<dyn RepoSyncRuntime>>,
|
||||
parallel_phase2_config: Option<ParallelPhase2Config>,
|
||||
ccr_accumulator: Option<CcrAccumulator>,
|
||||
) -> Rpkiv1PublicationPointRunner<'a> {
|
||||
let parallel_roa_worker_pool = parallel_phase2_config
|
||||
.as_ref()
|
||||
@@ -140,6 +143,7 @@ fn make_live_runner<'a>(
|
||||
repo_sync_runtime,
|
||||
parallel_phase2_config,
|
||||
parallel_roa_worker_pool,
|
||||
ccr_accumulator: ccr_accumulator.map(Mutex::new),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -291,6 +295,7 @@ pub fn run_tree_from_tal_url_serial(
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
);
|
||||
|
||||
let root = root_handle_from_trust_anchor(
|
||||
@@ -327,6 +332,7 @@ pub fn run_tree_from_tal_url_serial_audit(
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
);
|
||||
|
||||
let root = root_handle_from_trust_anchor(
|
||||
@@ -350,6 +356,7 @@ pub fn run_tree_from_tal_url_serial_audit(
|
||||
downloads,
|
||||
download_stats,
|
||||
current_repo_objects: Vec::new(),
|
||||
ccr_accumulator: None,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -379,6 +386,7 @@ pub fn run_tree_from_tal_url_serial_audit_with_timing(
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
);
|
||||
|
||||
let root = root_handle_from_trust_anchor(
|
||||
@@ -403,6 +411,7 @@ pub fn run_tree_from_tal_url_serial_audit_with_timing(
|
||||
downloads,
|
||||
download_stats,
|
||||
current_repo_objects: Vec::new(),
|
||||
ccr_accumulator: None,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -446,6 +455,7 @@ where
|
||||
Some(current_repo_index),
|
||||
Some(runtime),
|
||||
phase2_config,
|
||||
phase2_enabled.then(|| CcrAccumulator::new(vec![discovery.trust_anchor.clone()])),
|
||||
);
|
||||
|
||||
let root = root_handle_from_trust_anchor(
|
||||
@@ -472,6 +482,9 @@ where
|
||||
downloads,
|
||||
download_stats,
|
||||
current_repo_objects: snapshot_current_repo_objects(Some(¤t_repo_index_for_output)),
|
||||
ccr_accumulator: phase2_enabled
|
||||
.then(|| runner.ccr_accumulator_snapshot())
|
||||
.flatten(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -532,6 +545,14 @@ where
|
||||
Some(current_repo_index),
|
||||
Some(runtime),
|
||||
phase2_config,
|
||||
phase2_enabled.then(|| {
|
||||
CcrAccumulator::new(
|
||||
discoveries
|
||||
.iter()
|
||||
.map(|item| item.trust_anchor.clone())
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
}),
|
||||
);
|
||||
|
||||
let TreeRunAuditOutput {
|
||||
@@ -552,6 +573,9 @@ where
|
||||
downloads,
|
||||
download_stats,
|
||||
current_repo_objects: snapshot_current_repo_objects(Some(¤t_repo_index_for_output)),
|
||||
ccr_accumulator: phase2_enabled
|
||||
.then(|| runner.ccr_accumulator_snapshot())
|
||||
.flatten(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -792,6 +816,7 @@ pub fn run_tree_from_tal_and_ta_der_serial(
|
||||
repo_sync_runtime: None,
|
||||
parallel_phase2_config: None,
|
||||
parallel_roa_worker_pool: None,
|
||||
ccr_accumulator: None,
|
||||
};
|
||||
|
||||
let root = root_handle_from_trust_anchor(
|
||||
@@ -842,6 +867,7 @@ pub fn run_tree_from_tal_bytes_serial_audit(
|
||||
repo_sync_runtime: None,
|
||||
parallel_phase2_config: None,
|
||||
parallel_roa_worker_pool: None,
|
||||
ccr_accumulator: None,
|
||||
};
|
||||
|
||||
let root = root_handle_from_trust_anchor(
|
||||
@@ -865,6 +891,7 @@ pub fn run_tree_from_tal_bytes_serial_audit(
|
||||
downloads,
|
||||
download_stats,
|
||||
current_repo_objects: Vec::new(),
|
||||
ccr_accumulator: None,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -908,6 +935,7 @@ pub fn run_tree_from_tal_bytes_serial_audit_with_timing(
|
||||
repo_sync_runtime: None,
|
||||
parallel_phase2_config: None,
|
||||
parallel_roa_worker_pool: None,
|
||||
ccr_accumulator: None,
|
||||
};
|
||||
|
||||
let root = root_handle_from_trust_anchor(
|
||||
@@ -933,6 +961,7 @@ pub fn run_tree_from_tal_bytes_serial_audit_with_timing(
|
||||
downloads,
|
||||
download_stats,
|
||||
current_repo_objects: Vec::new(),
|
||||
ccr_accumulator: None,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -969,6 +998,7 @@ pub fn run_tree_from_tal_and_ta_der_serial_audit(
|
||||
repo_sync_runtime: None,
|
||||
parallel_phase2_config: None,
|
||||
parallel_roa_worker_pool: None,
|
||||
ccr_accumulator: None,
|
||||
};
|
||||
|
||||
let root = root_handle_from_trust_anchor(
|
||||
@@ -992,6 +1022,7 @@ pub fn run_tree_from_tal_and_ta_der_serial_audit(
|
||||
downloads,
|
||||
download_stats,
|
||||
current_repo_objects: Vec::new(),
|
||||
ccr_accumulator: None,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1031,6 +1062,7 @@ pub fn run_tree_from_tal_and_ta_der_serial_audit_with_timing(
|
||||
repo_sync_runtime: None,
|
||||
parallel_phase2_config: None,
|
||||
parallel_roa_worker_pool: None,
|
||||
ccr_accumulator: None,
|
||||
};
|
||||
|
||||
let root = root_handle_from_trust_anchor(
|
||||
@@ -1055,6 +1087,7 @@ pub fn run_tree_from_tal_and_ta_der_serial_audit_with_timing(
|
||||
downloads,
|
||||
download_stats,
|
||||
current_repo_objects: Vec::new(),
|
||||
ccr_accumulator: None,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1100,6 +1133,7 @@ pub fn run_tree_from_tal_and_ta_der_payload_replay_serial(
|
||||
repo_sync_runtime: None,
|
||||
parallel_phase2_config: None,
|
||||
parallel_roa_worker_pool: None,
|
||||
ccr_accumulator: None,
|
||||
};
|
||||
|
||||
let root = root_handle_from_trust_anchor(
|
||||
@@ -1156,6 +1190,7 @@ pub fn run_tree_from_tal_and_ta_der_payload_replay_serial_audit(
|
||||
repo_sync_runtime: None,
|
||||
parallel_phase2_config: None,
|
||||
parallel_roa_worker_pool: None,
|
||||
ccr_accumulator: None,
|
||||
};
|
||||
|
||||
let root = root_handle_from_trust_anchor(
|
||||
@@ -1179,6 +1214,7 @@ pub fn run_tree_from_tal_and_ta_der_payload_replay_serial_audit(
|
||||
downloads,
|
||||
download_stats,
|
||||
current_repo_objects: Vec::new(),
|
||||
ccr_accumulator: None,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1228,6 +1264,7 @@ pub fn run_tree_from_tal_and_ta_der_payload_replay_serial_audit_with_timing(
|
||||
repo_sync_runtime: None,
|
||||
parallel_phase2_config: None,
|
||||
parallel_roa_worker_pool: None,
|
||||
ccr_accumulator: None,
|
||||
};
|
||||
|
||||
let root = root_handle_from_trust_anchor(
|
||||
@@ -1252,6 +1289,7 @@ pub fn run_tree_from_tal_and_ta_der_payload_replay_serial_audit_with_timing(
|
||||
downloads,
|
||||
download_stats,
|
||||
current_repo_objects: Vec::new(),
|
||||
ccr_accumulator: None,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1283,6 +1321,7 @@ fn build_payload_replay_runner<'a>(
|
||||
repo_sync_runtime: None,
|
||||
parallel_phase2_config: None,
|
||||
parallel_roa_worker_pool: None,
|
||||
ccr_accumulator: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1314,6 +1353,7 @@ fn build_payload_delta_replay_runner<'a>(
|
||||
repo_sync_runtime: None,
|
||||
parallel_phase2_config: None,
|
||||
parallel_roa_worker_pool: None,
|
||||
ccr_accumulator: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1345,6 +1385,7 @@ fn build_payload_delta_replay_current_store_runner<'a>(
|
||||
repo_sync_runtime: None,
|
||||
parallel_phase2_config: None,
|
||||
parallel_roa_worker_pool: None,
|
||||
ccr_accumulator: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1461,6 +1502,7 @@ fn run_payload_delta_replay_audit_inner(
|
||||
downloads,
|
||||
download_stats,
|
||||
current_repo_objects: Vec::new(),
|
||||
ccr_accumulator: None,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1605,6 +1647,7 @@ fn run_payload_delta_replay_step_audit_inner(
|
||||
downloads,
|
||||
download_stats,
|
||||
current_repo_objects: Vec::new(),
|
||||
ccr_accumulator: None,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -4,11 +4,12 @@ use crate::audit::{
|
||||
ObjectAuditEntry, PublicationPointAudit,
|
||||
};
|
||||
use crate::audit_downloads::DownloadLogHandle;
|
||||
use crate::ccr::CcrAccumulator;
|
||||
use crate::current_repo_index::CurrentRepoIndexHandle;
|
||||
use crate::data_model::aspa::AspaObject;
|
||||
use crate::data_model::crl::RpkixCrl;
|
||||
use crate::data_model::manifest::ManifestObject;
|
||||
use crate::data_model::rc::ResourceCertificate;
|
||||
use crate::data_model::rc::{AccessDescription, ResourceCertificate, SubjectInfoAccess};
|
||||
use crate::data_model::roa::{RoaAfi, RoaObject};
|
||||
use crate::data_model::router_cert::{
|
||||
BgpsecRouterCertificate, BgpsecRouterCertificateDecodeError, BgpsecRouterCertificatePathError,
|
||||
@@ -23,8 +24,9 @@ use crate::replay::delta_archive::ReplayDeltaArchiveIndex;
|
||||
use crate::report::{RfcRef, Warning};
|
||||
use crate::storage::{
|
||||
PackFile, PackTime, RawByHashEntry, RocksStore, ValidatedCaInstanceResult, VcirArtifactKind,
|
||||
VcirArtifactRole, VcirArtifactValidationStatus, VcirAuditSummary, VcirChildEntry,
|
||||
VcirInstanceGate, VcirLocalOutput, VcirOutputType, VcirRelatedArtifact, VcirSummary,
|
||||
VcirArtifactRole, VcirArtifactValidationStatus, VcirAuditSummary, VcirCcrManifestProjection,
|
||||
VcirChildEntry, VcirInstanceGate, VcirLocalOutput, VcirOutputType, VcirRelatedArtifact,
|
||||
VcirSummary,
|
||||
};
|
||||
use crate::sync::repo::{
|
||||
sync_publication_point, sync_publication_point_replay, sync_publication_point_replay_delta,
|
||||
@@ -49,6 +51,7 @@ use crate::validation::publication_point::PublicationPointSnapshot;
|
||||
use crate::validation::tree::{
|
||||
CaInstanceHandle, DiscoveredChildCaInstance, PublicationPointRunResult, PublicationPointRunner,
|
||||
};
|
||||
use sha2::Digest;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
@@ -134,9 +137,47 @@ pub struct Rpkiv1PublicationPointRunner<'a> {
|
||||
pub repo_sync_runtime: Option<Arc<dyn RepoSyncRuntime>>,
|
||||
pub parallel_phase2_config: Option<ParallelPhase2Config>,
|
||||
pub parallel_roa_worker_pool: Option<ParallelRoaWorkerPool>,
|
||||
pub ccr_accumulator: Option<Mutex<CcrAccumulator>>,
|
||||
}
|
||||
|
||||
impl<'a> Rpkiv1PublicationPointRunner<'a> {
|
||||
pub(crate) fn ccr_accumulator_snapshot(&self) -> Option<CcrAccumulator> {
|
||||
self.ccr_accumulator
|
||||
.as_ref()
|
||||
.and_then(|accumulator| accumulator.lock().ok().map(|guard| guard.clone()))
|
||||
}
|
||||
|
||||
pub(crate) fn append_ccr_manifest_projection(
|
||||
&self,
|
||||
projection: &VcirCcrManifestProjection,
|
||||
) -> Result<(), String> {
|
||||
if let Some(accumulator) = self.ccr_accumulator.as_ref() {
|
||||
accumulator
|
||||
.lock()
|
||||
.map_err(|_| "lock CCR accumulator failed".to_string())?
|
||||
.append_manifest_projection(projection)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn append_ccr_manifest_projection_from_reuse(
|
||||
&self,
|
||||
projection: &VcirReuseProjection,
|
||||
) -> Result<(), String> {
|
||||
match projection.source {
|
||||
PublicationPointSource::Fresh => Err(
|
||||
"invalid reuse projection source: fresh does not belong to failed-fetch reuse"
|
||||
.to_string(),
|
||||
),
|
||||
PublicationPointSource::VcirCurrentInstance => self.append_ccr_manifest_projection(
|
||||
projection.ccr_manifest_projection.as_ref().ok_or_else(|| {
|
||||
"vcir current-instance reuse is missing CCR manifest projection".to_string()
|
||||
})?,
|
||||
),
|
||||
PublicationPointSource::FailedFetchNoCache => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn stage_fresh_publication_point_after_repo_ready(
|
||||
&self,
|
||||
ca: &CaInstanceHandle,
|
||||
@@ -237,6 +278,14 @@ impl<'a> Rpkiv1PublicationPointRunner<'a> {
|
||||
.map_err(|e| format!("persist VCIR failed: {e}"))?;
|
||||
let persist_vcir_ms = persist_vcir_started.elapsed().as_millis() as u64;
|
||||
|
||||
if self.ccr_accumulator.is_some() {
|
||||
let child_entries =
|
||||
build_vcir_child_entries(&discovered_children, self.validation_time)?;
|
||||
let ccr_manifest_projection =
|
||||
build_vcir_ccr_manifest_projection_from_fresh(ca, &pack, &child_entries)?;
|
||||
self.append_ccr_manifest_projection(&ccr_manifest_projection)?;
|
||||
}
|
||||
|
||||
let audit_build_started = std::time::Instant::now();
|
||||
let audit = build_publication_point_audit_from_snapshot(
|
||||
ca,
|
||||
@@ -745,6 +794,7 @@ impl<'a> PublicationPointRunner for Rpkiv1PublicationPointRunner<'a> {
|
||||
self.validation_time,
|
||||
)
|
||||
.map_err(|e| format!("failed fetch VCIR projection failed: {e}"))?;
|
||||
self.append_ccr_manifest_projection_from_reuse(&projection)?;
|
||||
let projection_ms = projection_started.elapsed().as_millis() as u64;
|
||||
warnings.extend(projection.warnings.clone());
|
||||
let audit_build_started = std::time::Instant::now();
|
||||
@@ -888,6 +938,7 @@ enum CachedIssuerCrl {
|
||||
struct VcirReuseProjection {
|
||||
source: PublicationPointSource,
|
||||
vcir: Option<ValidatedCaInstanceResult>,
|
||||
ccr_manifest_projection: Option<VcirCcrManifestProjection>,
|
||||
snapshot: Option<PublicationPointSnapshot>,
|
||||
objects: crate::validation::objects::ObjectsOutput,
|
||||
child_audits: Vec<ObjectAuditEntry>,
|
||||
@@ -1872,6 +1923,19 @@ fn empty_objects_output() -> crate::validation::objects::ObjectsOutput {
|
||||
}
|
||||
}
|
||||
|
||||
fn reuse_ccr_manifest_projection_from_vcir(
|
||||
ca: &CaInstanceHandle,
|
||||
vcir: &ValidatedCaInstanceResult,
|
||||
) -> Result<VcirCcrManifestProjection, String> {
|
||||
if vcir.ccr_manifest_projection.manifest_rsync_uri != ca.manifest_rsync_uri {
|
||||
return Err(format!(
|
||||
"vcir CCR manifest projection URI mismatch: expected {}, got {}",
|
||||
ca.manifest_rsync_uri, vcir.ccr_manifest_projection.manifest_rsync_uri
|
||||
));
|
||||
}
|
||||
Ok(vcir.ccr_manifest_projection.clone())
|
||||
}
|
||||
|
||||
fn project_current_instance_vcir_on_failed_fetch(
|
||||
store: &RocksStore,
|
||||
ca: &CaInstanceHandle,
|
||||
@@ -1896,6 +1960,7 @@ fn project_current_instance_vcir_on_failed_fetch(
|
||||
return Ok(VcirReuseProjection {
|
||||
source: PublicationPointSource::FailedFetchNoCache,
|
||||
vcir: None,
|
||||
ccr_manifest_projection: None,
|
||||
snapshot: None,
|
||||
objects: empty_objects_output(),
|
||||
child_audits: Vec::new(),
|
||||
@@ -1915,6 +1980,7 @@ fn project_current_instance_vcir_on_failed_fetch(
|
||||
return Ok(VcirReuseProjection {
|
||||
source: PublicationPointSource::FailedFetchNoCache,
|
||||
vcir: Some(vcir),
|
||||
ccr_manifest_projection: None,
|
||||
snapshot: None,
|
||||
objects: empty_objects_output(),
|
||||
child_audits: Vec::new(),
|
||||
@@ -1936,6 +2002,7 @@ fn project_current_instance_vcir_on_failed_fetch(
|
||||
return Ok(VcirReuseProjection {
|
||||
source: PublicationPointSource::FailedFetchNoCache,
|
||||
vcir: Some(vcir),
|
||||
ccr_manifest_projection: None,
|
||||
snapshot: None,
|
||||
objects: empty_objects_output(),
|
||||
child_audits: Vec::new(),
|
||||
@@ -1950,6 +2017,7 @@ fn project_current_instance_vcir_on_failed_fetch(
|
||||
.with_context(&ca.manifest_rsync_uri),
|
||||
);
|
||||
|
||||
let ccr_manifest_projection = reuse_ccr_manifest_projection_from_vcir(ca, &vcir)?;
|
||||
let snapshot = reconstruct_snapshot_from_vcir(store, ca, &vcir, &mut warnings);
|
||||
let objects = build_objects_output_from_vcir(&vcir, validation_time, &mut warnings);
|
||||
let (discovered_children, child_audits) =
|
||||
@@ -1958,6 +2026,7 @@ fn project_current_instance_vcir_on_failed_fetch(
|
||||
Ok(VcirReuseProjection {
|
||||
source: PublicationPointSource::VcirCurrentInstance,
|
||||
vcir: Some(vcir),
|
||||
ccr_manifest_projection: Some(ccr_manifest_projection),
|
||||
snapshot,
|
||||
objects,
|
||||
child_audits,
|
||||
@@ -2510,6 +2579,8 @@ fn build_vcir_from_fresh_result_with_timing(
|
||||
child_audits,
|
||||
);
|
||||
timing.related_artifacts_ms = related_artifacts_started.elapsed().as_millis() as u64;
|
||||
let ccr_manifest_projection =
|
||||
build_vcir_ccr_manifest_projection_from_fresh(ca, pack, &child_entries)?;
|
||||
let accepted_object_count = related_artifacts
|
||||
.iter()
|
||||
.filter(|artifact| artifact.validation_status == VcirArtifactValidationStatus::Accepted)
|
||||
@@ -2552,6 +2623,7 @@ fn build_vcir_from_fresh_result_with_timing(
|
||||
validated_manifest_this_update: pack.this_update.clone(),
|
||||
validated_manifest_next_update: pack.next_update.clone(),
|
||||
},
|
||||
ccr_manifest_projection,
|
||||
instance_gate: VcirInstanceGate {
|
||||
manifest_next_update: pack.next_update.clone(),
|
||||
current_crl_next_update: PackTime::from_utc_offset_datetime(
|
||||
@@ -2598,6 +2670,138 @@ fn build_vcir_from_fresh_result_with_timing(
|
||||
Ok((vcir, timing))
|
||||
}
|
||||
|
||||
fn build_vcir_ccr_manifest_projection_from_fresh(
|
||||
ca: &CaInstanceHandle,
|
||||
pack: &PublicationPointSnapshot,
|
||||
child_entries: &[VcirChildEntry],
|
||||
) -> Result<VcirCcrManifestProjection, String> {
|
||||
let manifest = ManifestObject::decode_der(&pack.manifest_bytes)
|
||||
.map_err(|e| format!("decode manifest for VCIR CCR projection failed: {e}"))?;
|
||||
let ee = &manifest.signed_object.signed_data.certificates[0].resource_cert;
|
||||
let manifest_ee_aki = ee
|
||||
.tbs
|
||||
.extensions
|
||||
.authority_key_identifier
|
||||
.clone()
|
||||
.ok_or_else(|| "manifest EE certificate missing AuthorityKeyIdentifier".to_string())?;
|
||||
let manifest_sia_locations_der = match ee
|
||||
.tbs
|
||||
.extensions
|
||||
.subject_info_access
|
||||
.as_ref()
|
||||
.ok_or_else(|| "manifest EE certificate missing Subject Information Access".to_string())?
|
||||
{
|
||||
SubjectInfoAccess::Ee(ee_sia) => ee_sia
|
||||
.access_descriptions
|
||||
.iter()
|
||||
.map(encode_access_description_der_for_vcir_ccr_projection)
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
SubjectInfoAccess::Ca(_) => {
|
||||
return Err(
|
||||
"manifest EE certificate Subject Information Access has CA variant".to_string(),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
let mut subordinate_skis = child_entries
|
||||
.iter()
|
||||
.map(|child| {
|
||||
hex::decode(&child.child_ski)
|
||||
.map_err(|e| format!("decode child_ski for VCIR CCR projection failed: {e}"))
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
subordinate_skis.sort();
|
||||
subordinate_skis.dedup();
|
||||
|
||||
Ok(VcirCcrManifestProjection {
|
||||
manifest_rsync_uri: ca.manifest_rsync_uri.clone(),
|
||||
manifest_sha256: sha2::Sha256::digest(&pack.manifest_bytes).to_vec(),
|
||||
manifest_size: pack.manifest_bytes.len() as u64,
|
||||
manifest_ee_aki,
|
||||
manifest_number_be: pack.manifest_number_be.clone(),
|
||||
manifest_this_update: pack.this_update.clone(),
|
||||
manifest_sia_locations_der,
|
||||
subordinate_skis,
|
||||
})
|
||||
}
|
||||
|
||||
fn encode_access_description_der_for_vcir_ccr_projection(
|
||||
access_description: &AccessDescription,
|
||||
) -> Result<Vec<u8>, String> {
|
||||
let oid = encode_oid_der_for_vcir_ccr_projection(&access_description.access_method_oid)?;
|
||||
let uri = encode_tlv_for_vcir_ccr_projection(
|
||||
0x86,
|
||||
access_description.access_location.as_bytes().to_vec(),
|
||||
);
|
||||
Ok(encode_sequence_for_vcir_ccr_projection(&[oid, uri]))
|
||||
}
|
||||
|
||||
fn encode_oid_der_for_vcir_ccr_projection(oid: &str) -> Result<Vec<u8>, String> {
|
||||
let arcs = oid
|
||||
.split('.')
|
||||
.map(|part| {
|
||||
part.parse::<u64>()
|
||||
.map_err(|_| format!("unsupported accessMethod OID: {oid}"))
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
if arcs.len() < 2 {
|
||||
return Err(format!("unsupported accessMethod OID: {oid}"));
|
||||
}
|
||||
if arcs[0] > 2 || (arcs[0] < 2 && arcs[1] >= 40) {
|
||||
return Err(format!("unsupported accessMethod OID: {oid}"));
|
||||
}
|
||||
let mut body = Vec::new();
|
||||
body.push((arcs[0] * 40 + arcs[1]) as u8);
|
||||
for arc in &arcs[2..] {
|
||||
encode_base128_for_vcir_ccr_projection(*arc, &mut body);
|
||||
}
|
||||
Ok(encode_tlv_for_vcir_ccr_projection(0x06, body))
|
||||
}
|
||||
|
||||
fn encode_base128_for_vcir_ccr_projection(mut value: u64, out: &mut Vec<u8>) {
|
||||
let mut tmp = vec![(value & 0x7F) as u8];
|
||||
value >>= 7;
|
||||
while value > 0 {
|
||||
tmp.push(((value & 0x7F) as u8) | 0x80);
|
||||
value >>= 7;
|
||||
}
|
||||
tmp.reverse();
|
||||
out.extend_from_slice(&tmp);
|
||||
}
|
||||
|
||||
fn encode_sequence_for_vcir_ccr_projection(elements: &[Vec<u8>]) -> Vec<u8> {
|
||||
let total_len: usize = elements.iter().map(Vec::len).sum();
|
||||
let mut buf = Vec::with_capacity(total_len);
|
||||
for element in elements {
|
||||
buf.extend_from_slice(element);
|
||||
}
|
||||
encode_tlv_for_vcir_ccr_projection(0x30, buf)
|
||||
}
|
||||
|
||||
fn encode_tlv_for_vcir_ccr_projection(tag: u8, value: Vec<u8>) -> Vec<u8> {
|
||||
let mut out = Vec::with_capacity(1 + 9 + value.len());
|
||||
out.push(tag);
|
||||
encode_length_for_vcir_ccr_projection(value.len(), &mut out);
|
||||
out.extend_from_slice(&value);
|
||||
out
|
||||
}
|
||||
|
||||
fn encode_length_for_vcir_ccr_projection(len: usize, out: &mut Vec<u8>) {
|
||||
if len < 0x80 {
|
||||
out.push(len as u8);
|
||||
return;
|
||||
}
|
||||
let mut bytes = Vec::new();
|
||||
let mut value = len;
|
||||
while value > 0 {
|
||||
bytes.push((value & 0xFF) as u8);
|
||||
value >>= 8;
|
||||
}
|
||||
bytes.reverse();
|
||||
out.push(0x80 | (bytes.len() as u8));
|
||||
out.extend_from_slice(&bytes);
|
||||
}
|
||||
|
||||
struct CurrentCrlRef<'a> {
|
||||
file: &'a PackFile,
|
||||
crl: RpkixCrl,
|
||||
@@ -3048,6 +3252,32 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
fn sample_runner_with_ccr_accumulator<'a>(
|
||||
store: &'a RocksStore,
|
||||
policy: &'a Policy,
|
||||
) -> Rpkiv1PublicationPointRunner<'a> {
|
||||
Rpkiv1PublicationPointRunner {
|
||||
store,
|
||||
policy,
|
||||
http_fetcher: &NeverHttpFetcher,
|
||||
rsync_fetcher: &FailingRsyncFetcher,
|
||||
validation_time: time::OffsetDateTime::now_utc(),
|
||||
timing: None,
|
||||
download_log: None,
|
||||
replay_archive_index: None,
|
||||
replay_delta_index: None,
|
||||
rrdp_dedup: false,
|
||||
rrdp_repo_cache: Mutex::new(HashMap::new()),
|
||||
rsync_dedup: false,
|
||||
rsync_repo_cache: Mutex::new(HashMap::new()),
|
||||
current_repo_index: None,
|
||||
repo_sync_runtime: None,
|
||||
parallel_phase2_config: None,
|
||||
parallel_roa_worker_pool: None,
|
||||
ccr_accumulator: Some(Mutex::new(CcrAccumulator::new(Vec::new()))),
|
||||
}
|
||||
}
|
||||
|
||||
fn openssl_available() -> bool {
|
||||
Command::new("openssl")
|
||||
.arg("version")
|
||||
@@ -3509,6 +3739,19 @@ authorityKeyIdentifier = keyid:always
|
||||
let router_hash = sha256_hex(b"router-bytes");
|
||||
let ee_hash = sha256_hex(b"ee-cert-bytes");
|
||||
let gate_until = PackTime::from_utc_offset_datetime(now + time::Duration::hours(1));
|
||||
let ccr_manifest_projection = VcirCcrManifestProjection {
|
||||
manifest_rsync_uri: manifest_uri.clone(),
|
||||
manifest_sha256: hex::decode(&manifest_hash).expect("decode manifest hash"),
|
||||
manifest_size: 2048,
|
||||
manifest_ee_aki: vec![0x11; 20],
|
||||
manifest_number_be: vec![1],
|
||||
manifest_this_update: PackTime::from_utc_offset_datetime(now),
|
||||
manifest_sia_locations_der: vec![vec![
|
||||
0x30, 0x11, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x05, 0x86, 0x05,
|
||||
b'r', b's', b'y', b'n', b'c',
|
||||
]],
|
||||
subordinate_skis: vec![vec![0x33; 20]],
|
||||
};
|
||||
ValidatedCaInstanceResult {
|
||||
manifest_rsync_uri: manifest_uri.clone(),
|
||||
parent_manifest_rsync_uri: None,
|
||||
@@ -3524,6 +3767,7 @@ authorityKeyIdentifier = keyid:always
|
||||
validated_manifest_this_update: PackTime::from_utc_offset_datetime(now),
|
||||
validated_manifest_next_update: gate_until.clone(),
|
||||
},
|
||||
ccr_manifest_projection,
|
||||
instance_gate: VcirInstanceGate {
|
||||
manifest_next_update: gate_until.clone(),
|
||||
current_crl_next_update: gate_until.clone(),
|
||||
@@ -3901,6 +4145,22 @@ authorityKeyIdentifier = keyid:always
|
||||
.expect("vcir exists");
|
||||
assert_eq!(vcir.manifest_rsync_uri, pack.manifest_rsync_uri);
|
||||
assert_eq!(vcir.summary.local_vrp_count as usize, objects.vrps.len());
|
||||
assert_eq!(
|
||||
vcir.ccr_manifest_projection.manifest_rsync_uri,
|
||||
pack.manifest_rsync_uri
|
||||
);
|
||||
assert_eq!(
|
||||
vcir.ccr_manifest_projection.manifest_number_be,
|
||||
pack.manifest_number_be
|
||||
);
|
||||
assert_eq!(
|
||||
vcir.ccr_manifest_projection.manifest_this_update,
|
||||
pack.this_update
|
||||
);
|
||||
assert_eq!(
|
||||
vcir.ccr_manifest_projection.manifest_size,
|
||||
pack.manifest_bytes.len() as u64
|
||||
);
|
||||
let first_output = vcir.local_outputs.first().expect("local outputs stored");
|
||||
assert!(store
|
||||
.get_audit_rule_index_entry(crate::storage::AuditRuleKind::Roa, &first_output.rule_hash)
|
||||
@@ -3908,6 +4168,81 @@ authorityKeyIdentifier = keyid:always
|
||||
.is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_vcir_ccr_manifest_projection_from_fresh_real_snapshot_matches_manifest_contents() {
|
||||
let (pack, issuer_ca_der, validation_time) =
|
||||
cernet_publication_point_snapshot_for_vcir_tests();
|
||||
let issuer_ca = ResourceCertificate::decode_der(&issuer_ca_der).expect("decode issuer ca");
|
||||
let ca = CaInstanceHandle {
|
||||
depth: 0,
|
||||
tal_id: "test-tal".to_string(),
|
||||
parent_manifest_rsync_uri: None,
|
||||
ca_certificate_der: issuer_ca_der,
|
||||
ca_certificate_rsync_uri: Some(
|
||||
"rsync://rpki.apnic.net/repository/B527EF581D6611E2BB468F7C72FD1FF2/BfycW4hQb3wNP4YsiJW-1n6fjro.cer".to_string(),
|
||||
),
|
||||
effective_ip_resources: issuer_ca.tbs.extensions.ip_resources.clone(),
|
||||
effective_as_resources: issuer_ca.tbs.extensions.as_resources.clone(),
|
||||
rsync_base_uri: pack.publication_point_rsync_uri.clone(),
|
||||
manifest_rsync_uri: pack.manifest_rsync_uri.clone(),
|
||||
publication_point_rsync_uri: pack.publication_point_rsync_uri.clone(),
|
||||
rrdp_notification_uri: None,
|
||||
};
|
||||
let child_discovery =
|
||||
discover_children_from_fresh_snapshot_with_audit(&ca, &pack, validation_time, None)
|
||||
.expect("discover children");
|
||||
let child_entries = build_vcir_child_entries(&child_discovery.children, validation_time)
|
||||
.expect("build child entries");
|
||||
|
||||
let projection = build_vcir_ccr_manifest_projection_from_fresh(&ca, &pack, &child_entries)
|
||||
.expect("build ccr manifest projection");
|
||||
let manifest = ManifestObject::decode_der(&pack.manifest_bytes).expect("decode manifest");
|
||||
let expected_locations = match manifest.signed_object.signed_data.certificates[0]
|
||||
.resource_cert
|
||||
.tbs
|
||||
.extensions
|
||||
.subject_info_access
|
||||
.as_ref()
|
||||
.expect("manifest sia")
|
||||
{
|
||||
SubjectInfoAccess::Ee(ee_sia) => ee_sia
|
||||
.access_descriptions
|
||||
.iter()
|
||||
.map(encode_access_description_der_for_vcir_ccr_projection)
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.expect("encode locations"),
|
||||
SubjectInfoAccess::Ca(_) => panic!("manifest ee SIA should not be CA variant"),
|
||||
};
|
||||
|
||||
assert_eq!(projection.manifest_rsync_uri, pack.manifest_rsync_uri);
|
||||
assert_eq!(
|
||||
projection.manifest_sha256,
|
||||
sha2::Sha256::digest(&pack.manifest_bytes).to_vec()
|
||||
);
|
||||
assert_eq!(projection.manifest_size, pack.manifest_bytes.len() as u64);
|
||||
assert_eq!(
|
||||
projection.manifest_ee_aki,
|
||||
manifest.signed_object.signed_data.certificates[0]
|
||||
.resource_cert
|
||||
.tbs
|
||||
.extensions
|
||||
.authority_key_identifier
|
||||
.clone()
|
||||
.expect("manifest aki")
|
||||
);
|
||||
assert_eq!(
|
||||
projection.manifest_number_be,
|
||||
manifest.manifest.manifest_number.bytes_be
|
||||
);
|
||||
assert_eq!(projection.manifest_this_update, pack.this_update);
|
||||
assert_eq!(projection.manifest_sia_locations_der, expected_locations);
|
||||
let expected_subordinate_skis = child_entries
|
||||
.iter()
|
||||
.map(|child| hex::decode(&child.child_ski).expect("decode child ski"))
|
||||
.collect::<Vec<_>>();
|
||||
assert_eq!(projection.subordinate_skis, expected_subordinate_skis);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_vcir_related_artifacts_classifies_snapshot_files_and_audit_statuses() {
|
||||
let manifest_bytes = std::fs::read(
|
||||
@@ -4243,6 +4578,7 @@ authorityKeyIdentifier = keyid:always
|
||||
repo_sync_runtime: None,
|
||||
parallel_phase2_config: None,
|
||||
parallel_roa_worker_pool: None,
|
||||
ccr_accumulator: None,
|
||||
};
|
||||
|
||||
// For this fixture-driven smoke, we provide the correct issuer CA certificate (the CA for
|
||||
@@ -4404,6 +4740,7 @@ authorityKeyIdentifier = keyid:always
|
||||
repo_sync_runtime: None,
|
||||
parallel_phase2_config: None,
|
||||
parallel_roa_worker_pool: None,
|
||||
ccr_accumulator: None,
|
||||
};
|
||||
|
||||
let first = runner.run_publication_point(&handle).expect("first run ok");
|
||||
@@ -4515,6 +4852,7 @@ authorityKeyIdentifier = keyid:always
|
||||
repo_sync_runtime: None,
|
||||
parallel_phase2_config: None,
|
||||
parallel_roa_worker_pool: None,
|
||||
ccr_accumulator: None,
|
||||
};
|
||||
|
||||
let first = runner.run_publication_point(&handle).expect("first run ok");
|
||||
@@ -4629,6 +4967,7 @@ authorityKeyIdentifier = keyid:always
|
||||
repo_sync_runtime: None,
|
||||
parallel_phase2_config: None,
|
||||
parallel_roa_worker_pool: None,
|
||||
ccr_accumulator: None,
|
||||
};
|
||||
|
||||
let first = runner.run_publication_point(&handle).expect("first run ok");
|
||||
@@ -4715,6 +5054,7 @@ authorityKeyIdentifier = keyid:always
|
||||
repo_sync_runtime: None,
|
||||
parallel_phase2_config: None,
|
||||
parallel_roa_worker_pool: None,
|
||||
ccr_accumulator: None,
|
||||
};
|
||||
let first = ok_runner
|
||||
.run_publication_point(&handle)
|
||||
@@ -4744,6 +5084,7 @@ authorityKeyIdentifier = keyid:always
|
||||
repo_sync_runtime: None,
|
||||
parallel_phase2_config: None,
|
||||
parallel_roa_worker_pool: None,
|
||||
ccr_accumulator: None,
|
||||
};
|
||||
let second = bad_runner
|
||||
.run_publication_point(&handle)
|
||||
@@ -5274,6 +5615,10 @@ authorityKeyIdentifier = keyid:always
|
||||
projection.discovered_children[0].handle.manifest_rsync_uri,
|
||||
"rsync://example.test/repo/child/child.mft"
|
||||
);
|
||||
assert_eq!(
|
||||
projection.ccr_manifest_projection.as_ref(),
|
||||
Some(&vcir.ccr_manifest_projection)
|
||||
);
|
||||
assert!(
|
||||
projection.snapshot.is_some(),
|
||||
"expected reconstructed snapshot"
|
||||
@@ -5325,6 +5670,7 @@ authorityKeyIdentifier = keyid:always
|
||||
projection.source,
|
||||
PublicationPointSource::FailedFetchNoCache
|
||||
);
|
||||
assert!(projection.ccr_manifest_projection.is_none());
|
||||
assert!(projection.objects.vrps.is_empty());
|
||||
assert!(projection.objects.aspas.is_empty());
|
||||
assert!(projection.discovered_children.is_empty());
|
||||
@@ -5364,6 +5710,7 @@ authorityKeyIdentifier = keyid:always
|
||||
PublicationPointSource::FailedFetchNoCache
|
||||
);
|
||||
assert!(projection.vcir.is_none());
|
||||
assert!(projection.ccr_manifest_projection.is_none());
|
||||
assert!(projection.snapshot.is_none());
|
||||
assert!(projection.objects.audit.is_empty());
|
||||
assert!(projection.discovered_children.is_empty());
|
||||
@@ -5414,6 +5761,7 @@ authorityKeyIdentifier = keyid:always
|
||||
PublicationPointSource::FailedFetchNoCache
|
||||
);
|
||||
assert!(projection.vcir.is_some());
|
||||
assert!(projection.ccr_manifest_projection.is_none());
|
||||
assert!(projection.snapshot.is_none());
|
||||
assert!(projection.discovered_children.is_empty());
|
||||
assert!(projection.warnings.iter().any(|warning| {
|
||||
@@ -5423,6 +5771,144 @@ authorityKeyIdentifier = keyid:always
|
||||
}));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn project_current_instance_vcir_rejects_mismatched_ccr_projection_uri() {
|
||||
let now = time::OffsetDateTime::now_utc();
|
||||
let child_cert_hash = sha256_hex(b"child-cert");
|
||||
let mut vcir = sample_vcir_for_projection(now, &child_cert_hash);
|
||||
vcir.ccr_manifest_projection.manifest_rsync_uri =
|
||||
"rsync://example.test/repo/issuer/other.mft".to_string();
|
||||
|
||||
let store_dir = tempfile::tempdir().expect("store dir");
|
||||
let store = RocksStore::open(store_dir.path()).expect("open rocksdb");
|
||||
store.put_vcir(&vcir).expect("put vcir");
|
||||
|
||||
let ca = CaInstanceHandle {
|
||||
depth: 0,
|
||||
tal_id: "test-tal".to_string(),
|
||||
parent_manifest_rsync_uri: None,
|
||||
ca_certificate_der: Vec::new(),
|
||||
ca_certificate_rsync_uri: None,
|
||||
effective_ip_resources: None,
|
||||
effective_as_resources: None,
|
||||
rsync_base_uri: "rsync://example.test/repo/issuer/".to_string(),
|
||||
manifest_rsync_uri: vcir.manifest_rsync_uri.clone(),
|
||||
publication_point_rsync_uri: "rsync://example.test/repo/issuer/".to_string(),
|
||||
rrdp_notification_uri: None,
|
||||
};
|
||||
|
||||
let err = project_current_instance_vcir_on_failed_fetch(
|
||||
&store,
|
||||
&ca,
|
||||
&ManifestFreshError::RepoSyncFailed {
|
||||
detail: "synthetic".to_string(),
|
||||
},
|
||||
now,
|
||||
)
|
||||
.unwrap_err();
|
||||
|
||||
assert!(
|
||||
err.contains("vcir CCR manifest projection URI mismatch"),
|
||||
"{err}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fresh_and_reuse_paths_produce_equivalent_ccr_manifest_projection() {
|
||||
let (pack, issuer_ca_der, validation_time) =
|
||||
cernet_publication_point_snapshot_for_vcir_tests();
|
||||
let ca = CaInstanceHandle {
|
||||
depth: 0,
|
||||
tal_id: "test-tal".to_string(),
|
||||
parent_manifest_rsync_uri: None,
|
||||
ca_certificate_der: issuer_ca_der,
|
||||
ca_certificate_rsync_uri: Some("rsync://rpki.apnic.net/repository/B527EF581D6611E2BB468F7C72FD1FF2/BfycW4hQb3wNP4YsiJW-1n6fjro.cer".to_string()),
|
||||
effective_ip_resources: None,
|
||||
effective_as_resources: None,
|
||||
rsync_base_uri: pack.publication_point_rsync_uri.clone(),
|
||||
manifest_rsync_uri: pack.manifest_rsync_uri.clone(),
|
||||
publication_point_rsync_uri: pack.publication_point_rsync_uri.clone(),
|
||||
rrdp_notification_uri: None,
|
||||
};
|
||||
let child_discovery =
|
||||
discover_children_from_fresh_snapshot_with_audit(&ca, &pack, validation_time, None)
|
||||
.expect("discover children");
|
||||
let fresh_vcir = build_vcir_from_fresh_result(
|
||||
&ca,
|
||||
&pack,
|
||||
&empty_objects_output(),
|
||||
&[],
|
||||
&child_discovery.audits,
|
||||
&child_discovery.children,
|
||||
validation_time,
|
||||
)
|
||||
.expect("build fresh vcir");
|
||||
|
||||
let reuse_projection = reuse_ccr_manifest_projection_from_vcir(&ca, &fresh_vcir)
|
||||
.expect("reuse projection from vcir");
|
||||
|
||||
assert_eq!(fresh_vcir.ccr_manifest_projection, reuse_projection);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn append_ccr_manifest_projection_from_reuse_requires_projection_for_current_instance() {
|
||||
let store_dir = tempfile::tempdir().expect("store dir");
|
||||
let store = RocksStore::open(store_dir.path()).expect("open rocksdb");
|
||||
let policy = Policy::default();
|
||||
let runner = sample_runner_with_ccr_accumulator(&store, &policy);
|
||||
|
||||
let err = runner
|
||||
.append_ccr_manifest_projection_from_reuse(&VcirReuseProjection {
|
||||
source: PublicationPointSource::VcirCurrentInstance,
|
||||
vcir: None,
|
||||
ccr_manifest_projection: None,
|
||||
snapshot: None,
|
||||
objects: empty_objects_output(),
|
||||
child_audits: Vec::new(),
|
||||
discovered_children: Vec::new(),
|
||||
warnings: Vec::new(),
|
||||
})
|
||||
.unwrap_err();
|
||||
|
||||
assert!(err.contains("missing CCR manifest projection"), "{err}");
|
||||
assert_eq!(
|
||||
runner
|
||||
.ccr_accumulator_snapshot()
|
||||
.expect("ccr accumulator snapshot")
|
||||
.manifest_count(),
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn append_ccr_manifest_projection_from_reuse_skips_failed_fetch_no_cache() {
|
||||
let store_dir = tempfile::tempdir().expect("store dir");
|
||||
let store = RocksStore::open(store_dir.path()).expect("open rocksdb");
|
||||
let policy = Policy::default();
|
||||
let runner = sample_runner_with_ccr_accumulator(&store, &policy);
|
||||
|
||||
runner
|
||||
.append_ccr_manifest_projection_from_reuse(&VcirReuseProjection {
|
||||
source: PublicationPointSource::FailedFetchNoCache,
|
||||
vcir: None,
|
||||
ccr_manifest_projection: None,
|
||||
snapshot: None,
|
||||
objects: empty_objects_output(),
|
||||
child_audits: Vec::new(),
|
||||
discovered_children: Vec::new(),
|
||||
warnings: Vec::new(),
|
||||
})
|
||||
.expect("failed-fetch no-cache should not append");
|
||||
|
||||
assert_eq!(
|
||||
runner
|
||||
.ccr_accumulator_snapshot()
|
||||
.expect("ccr accumulator snapshot")
|
||||
.manifest_count(),
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_snapshot_time_value_reports_invalid_timestamp() {
|
||||
let err = parse_snapshot_time_value(&PackTime {
|
||||
@@ -5919,6 +6405,7 @@ authorityKeyIdentifier = keyid:always
|
||||
repo_sync_runtime: None,
|
||||
parallel_phase2_config: None,
|
||||
parallel_roa_worker_pool: None,
|
||||
ccr_accumulator: None,
|
||||
};
|
||||
let first = runner_rrdp
|
||||
.run_publication_point(&handle)
|
||||
@@ -5951,6 +6438,7 @@ authorityKeyIdentifier = keyid:always
|
||||
repo_sync_runtime: None,
|
||||
parallel_phase2_config: None,
|
||||
parallel_roa_worker_pool: None,
|
||||
ccr_accumulator: None,
|
||||
};
|
||||
let third = runner_rsync
|
||||
.run_publication_point(&handle)
|
||||
|
||||
Reference in New Issue
Block a user