20260605 移除audit rule index和DB trace

This commit is contained in:
2026-06-05 16:02:25 +08:00
parent 9579f65501
commit e597c7c124
29 changed files with 4032 additions and 2298 deletions

View File

@@ -14,7 +14,10 @@ use crate::parallel::object_worker::{
};
use crate::policy::{Policy, SignedObjectFailurePolicy};
use crate::report::{RfcRef, Warning};
use crate::storage::{PackFile, PackTime, VcirLocalOutput, VcirOutputType};
use crate::storage::{
PackFile, PackTime, VcirLocalOutput, VcirLocalOutputPayload, VcirOutputType,
VcirSourceObjectType,
};
use crate::validation::cert_path::{CertPathError, validate_signed_object_ee_cert_path_fast};
use crate::validation::manifest::PublicationPointData;
use crate::validation::publication_point::PublicationPointSnapshot;
@@ -28,6 +31,13 @@ const RFC_CRLDP: &[RfcRef] = &[RfcRef("RFC 6487 §4.8.6")];
const RFC_CRLDP_AND_LOCKED_PACK: &[RfcRef] =
&[RfcRef("RFC 6487 §4.8.6"), RfcRef("RFC 9286 §4.2.1")];
fn sha256_hex_to_32(hex_value: &str) -> [u8; 32] {
let bytes = hex::decode(hex_value).expect("internal sha256 hex should decode");
let mut out = [0u8; 32];
out.copy_from_slice(&bytes);
out
}
fn decode_resource_certificate_with_policy(
der: &[u8],
policy: &Policy,
@@ -132,8 +142,6 @@ pub(crate) struct RoaTaskResult {
pub(crate) worker_index: usize,
pub(crate) queue_wait_ms: u64,
pub(crate) worker_ms: u64,
pub(crate) rsync_uri: String,
pub(crate) sha256_hex: String,
pub(crate) outcome: Result<RoaTaskOk, ObjectValidateError>,
}
@@ -418,8 +426,8 @@ pub fn process_publication_point_for_issuer_with_options<P: PublicationPointData
local_outputs_cache.extend(ok.local_outputs);
}
audit.push(ObjectAuditEntry {
rsync_uri: result.rsync_uri,
sha256_hex: result.sha256_hex,
rsync_uri: file.rsync_uri.clone(),
sha256_hex: sha256_hex_from_32(&file.sha256),
kind: AuditObjectKind::Roa,
result: AuditObjectResult::Ok,
detail: None,
@@ -428,8 +436,8 @@ pub fn process_publication_point_for_issuer_with_options<P: PublicationPointData
Err(e) => match policy.signed_object_failure_policy {
SignedObjectFailurePolicy::DropObject => {
audit.push(ObjectAuditEntry {
rsync_uri: result.rsync_uri.clone(),
sha256_hex: result.sha256_hex,
rsync_uri: file.rsync_uri.clone(),
sha256_hex: sha256_hex_from_32(&file.sha256),
kind: AuditObjectKind::Roa,
result: AuditObjectResult::Error,
detail: Some(e.to_string()),
@@ -437,24 +445,21 @@ pub fn process_publication_point_for_issuer_with_options<P: PublicationPointData
let mut refs = vec![RfcRef("RFC 6488 §3"), RfcRef("RFC 9582 §4-§5")];
refs.extend_from_slice(extra_rfc_refs_for_crl_selection(&e));
warnings.push(
Warning::new(format!(
"dropping invalid ROA: {}: {e}",
result.rsync_uri
))
.with_rfc_refs(&refs)
.with_context(&result.rsync_uri),
Warning::new(format!("dropping invalid ROA: {}: {e}", file.rsync_uri))
.with_rfc_refs(&refs)
.with_context(&file.rsync_uri),
)
}
SignedObjectFailurePolicy::DropPublicationPoint => {
stats.publication_point_dropped = true;
audit.push(ObjectAuditEntry {
rsync_uri: result.rsync_uri.clone(),
sha256_hex: result.sha256_hex,
rsync_uri: file.rsync_uri.clone(),
sha256_hex: sha256_hex_from_32(&file.sha256),
kind: AuditObjectKind::Roa,
result: AuditObjectResult::Error,
detail: Some(e.to_string()),
});
for f in locked_files.iter().skip(result.index + 1) {
for f in locked_files.iter().skip(idx + 1) {
if f.rsync_uri.ends_with(".roa") {
audit.push(ObjectAuditEntry {
rsync_uri: f.rsync_uri.clone(),
@@ -484,7 +489,7 @@ pub fn process_publication_point_for_issuer_with_options<P: PublicationPointData
warnings.push(
Warning::new(format!(
"dropping publication point due to invalid ROA: {}: {e}",
result.rsync_uri
file.rsync_uri
))
.with_rfc_refs(&refs)
.with_context(manifest_rsync_uri),
@@ -786,19 +791,24 @@ pub fn process_publication_point_for_issuer_parallel_roa_with_pool_options<
}
#[derive(Clone)]
pub(crate) struct OwnedRoaTask {
pub(crate) publication_point_id: u64,
index: usize,
file: PackFile,
manifest_rsync_uri: String,
pub(crate) struct RoaTaskShared {
locked_files: Arc<[PackFile]>,
manifest_rsync_uri: Arc<str>,
issuer_ca_der: Arc<[u8]>,
issuer_ca: Arc<ResourceCertificate>,
issuer_spki_der: Arc<[u8]>,
issuer_ca_rsync_uri: Option<String>,
issuer_ca_rsync_uri: Option<Arc<str>>,
crl_cache: Arc<Mutex<std::collections::HashMap<String, CachedIssuerCrl>>>,
issuer_resources_index: Arc<IssuerResourcesIndex>,
issuer_effective_ip: Option<crate::data_model::rc::IpResourceSet>,
issuer_effective_as: Option<crate::data_model::rc::AsResourceSet>,
issuer_effective_ip: Option<Arc<crate::data_model::rc::IpResourceSet>>,
issuer_effective_as: Option<Arc<crate::data_model::rc::AsResourceSet>>,
}
#[derive(Clone)]
pub(crate) struct OwnedRoaTask {
pub(crate) publication_point_id: u64,
index: usize,
shared: Arc<RoaTaskShared>,
validation_time: time::OffsetDateTime,
collect_vcir_local_outputs: bool,
strict_cms_der: bool,
@@ -862,8 +872,13 @@ fn validate_owned_roa_task(worker_index: usize, task: OwnedRoaTask) -> RoaTaskRe
.map(|submitted_at| worker_started.saturating_duration_since(submitted_at))
.map(|duration| duration.as_millis() as u64)
.unwrap_or(0);
let sha256_hex = sha256_hex_from_32(&task.file.sha256);
let issuer_spki = match SubjectPublicKeyInfo::from_der(task.issuer_spki_der.as_ref()) {
let shared = task.shared.as_ref();
let file = task
.shared
.locked_files
.get(task.index)
.expect("ROA task index must reference locked file");
let issuer_spki = match SubjectPublicKeyInfo::from_der(shared.issuer_spki_der.as_ref()) {
Ok((rem, spki)) if rem.is_empty() => spki,
Ok((rem, _)) => {
return RoaTaskResult {
@@ -872,8 +887,6 @@ fn validate_owned_roa_task(worker_index: usize, task: OwnedRoaTask) -> RoaTaskRe
worker_index,
queue_wait_ms,
worker_ms: worker_started.elapsed().as_millis() as u64,
rsync_uri: task.file.rsync_uri,
sha256_hex,
outcome: Err(ObjectValidateError::CertPath(
CertPathError::IssuerSpkiTrailingBytes(rem.len()),
)),
@@ -886,8 +899,6 @@ fn validate_owned_roa_task(worker_index: usize, task: OwnedRoaTask) -> RoaTaskRe
worker_index,
queue_wait_ms,
worker_ms: worker_started.elapsed().as_millis() as u64,
rsync_uri: task.file.rsync_uri,
sha256_hex,
outcome: Err(ObjectValidateError::CertPath(
CertPathError::IssuerSpkiParse(e.to_string()),
)),
@@ -895,16 +906,16 @@ fn validate_owned_roa_task(worker_index: usize, task: OwnedRoaTask) -> RoaTaskRe
}
};
let outcome = process_roa_with_issuer_parallel_cached(
&task.file,
task.manifest_rsync_uri.as_str(),
task.issuer_ca_der.as_ref(),
task.issuer_ca.as_ref(),
file,
shared.manifest_rsync_uri.as_ref(),
shared.issuer_ca_der.as_ref(),
shared.issuer_ca.as_ref(),
&issuer_spki,
task.issuer_ca_rsync_uri.as_deref(),
task.crl_cache.as_ref(),
task.issuer_resources_index.as_ref(),
task.issuer_effective_ip.as_ref(),
task.issuer_effective_as.as_ref(),
shared.issuer_ca_rsync_uri.as_deref(),
shared.crl_cache.as_ref(),
shared.issuer_resources_index.as_ref(),
shared.issuer_effective_ip.as_deref(),
shared.issuer_effective_as.as_deref(),
task.validation_time,
None,
task.collect_vcir_local_outputs,
@@ -922,8 +933,6 @@ fn validate_owned_roa_task(worker_index: usize, task: OwnedRoaTask) -> RoaTaskRe
worker_index,
queue_wait_ms,
worker_ms: worker_started.elapsed().as_millis() as u64,
rsync_uri: task.file.rsync_uri,
sha256_hex,
outcome,
}
}
@@ -935,16 +944,7 @@ pub(crate) enum ParallelObjectsPrepare {
pub(crate) struct ParallelObjectsStage {
pub(crate) publication_point_id: u64,
pub(crate) locked_files: Vec<PackFile>,
pub(crate) manifest_rsync_uri: String,
issuer_ca_der: Arc<[u8]>,
issuer_ca: Arc<ResourceCertificate>,
issuer_spki_der: Arc<[u8]>,
issuer_ca_rsync_uri: Option<String>,
crl_cache: Arc<Mutex<std::collections::HashMap<String, CachedIssuerCrl>>>,
issuer_resources_index: Arc<IssuerResourcesIndex>,
issuer_effective_ip: Option<crate::data_model::rc::IpResourceSet>,
issuer_effective_as: Option<crate::data_model::rc::AsResourceSet>,
shared: Arc<RoaTaskShared>,
validation_time: time::OffsetDateTime,
collect_vcir_local_outputs: bool,
strict_cms_der: bool,
@@ -955,31 +955,41 @@ pub(crate) struct ParallelObjectsStage {
}
impl ParallelObjectsStage {
#[cfg(test)]
pub(crate) fn build_roa_tasks(&self) -> Vec<OwnedRoaTask> {
self.locked_files
let mut tasks = Vec::with_capacity(self.roa_task_count());
self.extend_roa_tasks(|task| tasks.push(task));
tasks
}
pub(crate) fn append_roa_tasks_to(
&self,
pending: &mut std::collections::VecDeque<OwnedRoaTask>,
) {
self.extend_roa_tasks(|task| pending.push_back(task));
}
fn extend_roa_tasks<F>(&self, mut push: F)
where
F: FnMut(OwnedRoaTask),
{
let shared = self.shared.clone();
self.locked_files()
.iter()
.enumerate()
.filter(|(_, file)| file.rsync_uri.ends_with(".roa"))
.map(|(index, file)| OwnedRoaTask {
publication_point_id: self.publication_point_id,
index,
file: file.clone(),
manifest_rsync_uri: self.manifest_rsync_uri.clone(),
issuer_ca_der: self.issuer_ca_der.clone(),
issuer_ca: self.issuer_ca.clone(),
issuer_spki_der: self.issuer_spki_der.clone(),
issuer_ca_rsync_uri: self.issuer_ca_rsync_uri.clone(),
crl_cache: self.crl_cache.clone(),
issuer_resources_index: self.issuer_resources_index.clone(),
issuer_effective_ip: self.issuer_effective_ip.clone(),
issuer_effective_as: self.issuer_effective_as.clone(),
validation_time: self.validation_time,
collect_vcir_local_outputs: self.collect_vcir_local_outputs,
strict_cms_der: self.strict_cms_der,
strict_name: self.strict_name,
submitted_at: None,
})
.collect()
.for_each(|(index, _)| {
push(OwnedRoaTask {
publication_point_id: self.publication_point_id,
index,
shared: shared.clone(),
validation_time: self.validation_time,
collect_vcir_local_outputs: self.collect_vcir_local_outputs,
strict_cms_der: self.strict_cms_der,
strict_name: self.strict_name,
submitted_at: None,
});
});
}
pub(crate) fn roa_task_count(&self) -> usize {
@@ -991,7 +1001,11 @@ impl ParallelObjectsStage {
}
pub(crate) fn locked_file_count(&self) -> usize {
self.locked_files.len()
self.shared.locked_files.len()
}
fn locked_files(&self) -> &[PackFile] {
self.shared.locked_files.as_ref()
}
}
@@ -1212,19 +1226,21 @@ pub(crate) fn prepare_publication_point_for_parallel_roa<P: PublicationPointData
ParallelObjectsPrepare::Staged(ParallelObjectsStage {
publication_point_id,
locked_files: locked_files.to_vec(),
manifest_rsync_uri: manifest_rsync_uri.to_string(),
issuer_ca_der: Arc::<[u8]>::from(issuer_ca_der.to_vec()),
issuer_spki_der: Arc::<[u8]>::from(issuer_ca.tbs.subject_public_key_info.clone()),
issuer_ca: Arc::new(issuer_ca),
issuer_ca_rsync_uri: issuer_ca_rsync_uri.map(ToString::to_string),
crl_cache: Arc::new(Mutex::new(crl_cache)),
issuer_resources_index: Arc::new(build_issuer_resources_index(
issuer_effective_ip,
issuer_effective_as,
)),
issuer_effective_ip: issuer_effective_ip.cloned(),
issuer_effective_as: issuer_effective_as.cloned(),
shared: Arc::new(RoaTaskShared {
locked_files: Arc::<[PackFile]>::from(locked_files.to_vec()),
manifest_rsync_uri: Arc::<str>::from(manifest_rsync_uri),
issuer_ca_der: Arc::<[u8]>::from(issuer_ca_der.to_vec()),
issuer_spki_der: Arc::<[u8]>::from(issuer_ca.tbs.subject_public_key_info.clone()),
issuer_ca: Arc::new(issuer_ca),
issuer_ca_rsync_uri: issuer_ca_rsync_uri.map(Arc::<str>::from),
crl_cache: Arc::new(Mutex::new(crl_cache)),
issuer_resources_index: Arc::new(build_issuer_resources_index(
issuer_effective_ip,
issuer_effective_as,
)),
issuer_effective_ip: issuer_effective_ip.cloned().map(Arc::new),
issuer_effective_as: issuer_effective_as.cloned().map(Arc::new),
}),
validation_time,
collect_vcir_local_outputs,
strict_cms_der: policy.strict.cms_der,
@@ -1241,18 +1257,20 @@ pub(crate) fn reduce_parallel_roa_stage(
timing: Option<&TimingHandle>,
) -> Result<ObjectsOutput, String> {
roa_results.sort_by_key(|result| result.index);
let mut roa_by_index = roa_results
.into_iter()
.map(|result| (result.index, result))
.collect::<std::collections::HashMap<_, _>>();
let mut aspa_crl_cache = stage
let mut roa_results = roa_results.into_iter().peekable();
let shared = stage.shared.clone();
let mut aspa_crl_cache = shared
.crl_cache
.lock()
.expect("parallel ROA CRL cache lock")
.clone();
let issuer_spki = SubjectPublicKeyInfo::from_der(stage.issuer_spki_der.as_ref())
let issuer_spki = SubjectPublicKeyInfo::from_der(shared.issuer_spki_der.as_ref())
.map_err(|e| e.to_string())?
.1;
let collect_vcir_local_outputs = stage.collect_vcir_local_outputs;
let validation_time = stage.validation_time;
let strict_cms_der = stage.strict_cms_der;
let strict_name = stage.strict_name;
let mut stats = stage.stats;
let mut warnings = stage.warnings;
let mut audit = stage.audit;
@@ -1260,21 +1278,32 @@ pub(crate) fn reduce_parallel_roa_stage(
let mut aspas: Vec<AspaAttestation> = Vec::new();
let mut local_outputs_cache: Vec<VcirLocalOutput> = Vec::new();
for (idx, file) in stage.locked_files.iter().enumerate() {
for (idx, file) in shared.locked_files.iter().enumerate() {
if file.rsync_uri.ends_with(".roa") {
let result = roa_by_index
.remove(&idx)
.ok_or_else(|| format!("missing ROA task result for {}", file.rsync_uri))?;
let result = match roa_results.peek() {
Some(result) if result.index == idx => roa_results
.next()
.expect("peeked ROA task result must be present"),
Some(result) => {
return Err(format!(
"unexpected ROA task result index {} while reducing {} at index {}",
result.index, file.rsync_uri, idx
));
}
None => {
return Err(format!("missing ROA task result for {}", file.rsync_uri));
}
};
match result.outcome {
Ok(mut ok) => {
stats.roa_ok += 1;
vrps.append(&mut ok.vrps);
if stage.collect_vcir_local_outputs {
if collect_vcir_local_outputs {
local_outputs_cache.extend(ok.local_outputs);
}
audit.push(ObjectAuditEntry {
rsync_uri: result.rsync_uri,
sha256_hex: result.sha256_hex,
rsync_uri: file.rsync_uri.clone(),
sha256_hex: sha256_hex_from_32(&file.sha256),
kind: AuditObjectKind::Roa,
result: AuditObjectResult::Ok,
detail: None,
@@ -1282,8 +1311,8 @@ pub(crate) fn reduce_parallel_roa_stage(
}
Err(e) => {
audit.push(ObjectAuditEntry {
rsync_uri: result.rsync_uri.clone(),
sha256_hex: result.sha256_hex,
rsync_uri: file.rsync_uri.clone(),
sha256_hex: sha256_hex_from_32(&file.sha256),
kind: AuditObjectKind::Roa,
result: AuditObjectResult::Error,
detail: Some(e.to_string()),
@@ -1291,9 +1320,9 @@ pub(crate) fn reduce_parallel_roa_stage(
let mut refs = vec![RfcRef("RFC 6488 §3"), RfcRef("RFC 9582 §4-§5")];
refs.extend_from_slice(extra_rfc_refs_for_crl_selection(&e));
warnings.push(
Warning::new(format!("dropping invalid ROA: {}: {e}", result.rsync_uri))
Warning::new(format!("dropping invalid ROA: {}: {e}", file.rsync_uri))
.with_rfc_refs(&refs)
.with_context(&result.rsync_uri),
.with_context(&file.rsync_uri),
)
}
}
@@ -1301,20 +1330,20 @@ pub(crate) fn reduce_parallel_roa_stage(
let _t = timing.as_ref().map(|t| t.span_phase("objects_aspa_total"));
match process_aspa_with_issuer(
file,
&stage.manifest_rsync_uri,
stage.issuer_ca_der.as_ref(),
stage.issuer_ca.as_ref(),
shared.manifest_rsync_uri.as_ref(),
shared.issuer_ca_der.as_ref(),
shared.issuer_ca.as_ref(),
&issuer_spki,
stage.issuer_ca_rsync_uri.as_deref(),
shared.issuer_ca_rsync_uri.as_deref(),
&mut aspa_crl_cache,
stage.issuer_resources_index.as_ref(),
stage.issuer_effective_ip.as_ref(),
stage.issuer_effective_as.as_ref(),
stage.validation_time,
shared.issuer_resources_index.as_ref(),
shared.issuer_effective_ip.as_deref(),
shared.issuer_effective_as.as_deref(),
validation_time,
timing,
stage.collect_vcir_local_outputs,
stage.strict_cms_der,
stage.strict_name,
collect_vcir_local_outputs,
strict_cms_der,
strict_name,
) {
Ok((att, local_output)) => {
stats.aspa_ok += 1;
@@ -1349,6 +1378,12 @@ pub(crate) fn reduce_parallel_roa_stage(
}
}
}
if let Some(result) = roa_results.next() {
return Err(format!(
"unexpected trailing ROA task result at index {}",
result.index
));
}
Ok(ObjectsOutput {
vrps,
@@ -1388,8 +1423,9 @@ fn process_publication_point_for_issuer_parallel_roa_inner<P: PublicationPointDa
ParallelObjectsPrepare::Staged(stage) => stage,
};
let mut pending = std::collections::VecDeque::from(stage.build_roa_tasks());
let roa_task_count = stage.roa_task_count();
let mut pending = std::collections::VecDeque::with_capacity(roa_task_count);
stage.append_roa_tasks_to(&mut pending);
let mut worker_pool = pool
.pool
.lock()
@@ -1537,7 +1573,6 @@ pub(crate) fn validate_roa_task_serial(
strict_cms_der: bool,
strict_name: bool,
) -> RoaTaskResult {
let sha256_hex = sha256_hex_from_32(&task.file.sha256);
let outcome = process_roa_with_issuer(
task.file,
manifest_rsync_uri,
@@ -1566,15 +1601,13 @@ pub(crate) fn validate_roa_task_serial(
worker_index: 0,
queue_wait_ms: 0,
worker_ms: 0,
rsync_uri: task.file.rsync_uri.clone(),
sha256_hex,
outcome,
}
}
fn process_roa_with_issuer(
file: &PackFile,
manifest_rsync_uri: &str,
_manifest_rsync_uri: &str,
issuer_ca_der: &[u8],
issuer_ca: &ResourceCertificate,
issuer_spki: &SubjectPublicKeyInfo<'_>,
@@ -1659,12 +1692,6 @@ fn process_roa_with_issuer(
.iter()
.map(|vrp| {
let prefix = vrp_prefix_to_string(vrp);
let payload_json = serde_json::json!({
"asn": vrp.asn,
"prefix": prefix,
"max_length": vrp.max_length,
})
.to_string();
let rule_hash = crate::audit::sha256_hex(
format!(
"roa-rule:{}:{}:{}:{}",
@@ -1673,20 +1700,20 @@ fn process_roa_with_issuer(
.as_bytes(),
);
VcirLocalOutput {
output_id: rule_hash.clone(),
output_type: VcirOutputType::Vrp,
item_effective_until: item_effective_until.clone(),
source_object_uri: file.rsync_uri.clone(),
source_object_type: "roa".to_string(),
source_object_hash: source_object_hash.clone(),
source_ee_cert_hash: source_ee_cert_hash.clone(),
payload_json,
rule_hash,
validation_path_hint: vec![
manifest_rsync_uri.to_string(),
file.rsync_uri.clone(),
source_object_hash.clone(),
],
source_object_type: VcirSourceObjectType::Roa,
source_object_hash: file.sha256,
source_ee_cert_hash: sha256_hex_to_32(&source_ee_cert_hash),
payload: VcirLocalOutputPayload::Vrp {
asn: vrp.asn,
afi: vrp.prefix.afi,
prefix_len: vrp.prefix.prefix_len,
addr: vrp.prefix.addr,
max_length: vrp.max_length,
},
rule_hash: sha256_hex_to_32(&rule_hash),
}
})
.collect();
@@ -1696,7 +1723,7 @@ fn process_roa_with_issuer(
fn process_roa_with_issuer_parallel_cached(
file: &PackFile,
manifest_rsync_uri: &str,
_manifest_rsync_uri: &str,
issuer_ca_der: &[u8],
issuer_ca: &ResourceCertificate,
issuer_spki: &SubjectPublicKeyInfo<'_>,
@@ -1787,12 +1814,6 @@ fn process_roa_with_issuer_parallel_cached(
.iter()
.map(|vrp| {
let prefix = vrp_prefix_to_string(vrp);
let payload_json = serde_json::json!({
"asn": vrp.asn,
"prefix": prefix,
"max_length": vrp.max_length,
})
.to_string();
let rule_hash = crate::audit::sha256_hex(
format!(
"roa-rule:{}:{}:{}:{}",
@@ -1801,20 +1822,20 @@ fn process_roa_with_issuer_parallel_cached(
.as_bytes(),
);
VcirLocalOutput {
output_id: rule_hash.clone(),
output_type: VcirOutputType::Vrp,
item_effective_until: item_effective_until.clone(),
source_object_uri: file.rsync_uri.clone(),
source_object_type: "roa".to_string(),
source_object_hash: source_object_hash.clone(),
source_ee_cert_hash: source_ee_cert_hash.clone(),
payload_json,
rule_hash,
validation_path_hint: vec![
manifest_rsync_uri.to_string(),
file.rsync_uri.clone(),
source_object_hash.clone(),
],
source_object_type: VcirSourceObjectType::Roa,
source_object_hash: file.sha256,
source_ee_cert_hash: sha256_hex_to_32(&source_ee_cert_hash),
payload: VcirLocalOutputPayload::Vrp {
asn: vrp.asn,
afi: vrp.prefix.afi,
prefix_len: vrp.prefix.prefix_len,
addr: vrp.prefix.addr,
max_length: vrp.max_length,
},
rule_hash: sha256_hex_to_32(&rule_hash),
}
})
.collect();
@@ -1824,7 +1845,7 @@ fn process_roa_with_issuer_parallel_cached(
fn process_aspa_with_issuer(
file: &PackFile,
manifest_rsync_uri: &str,
_manifest_rsync_uri: &str,
issuer_ca_der: &[u8],
issuer_ca: &ResourceCertificate,
issuer_spki: &SubjectPublicKeyInfo<'_>,
@@ -1922,24 +1943,17 @@ fn process_aspa_with_issuer(
.as_bytes(),
);
let local_output = VcirLocalOutput {
output_id: rule_hash.clone(),
output_type: VcirOutputType::Aspa,
item_effective_until,
source_object_uri: file.rsync_uri.clone(),
source_object_type: "aspa".to_string(),
source_object_hash: source_object_hash.clone(),
source_ee_cert_hash,
payload_json: serde_json::json!({
"customer_as_id": attestation.customer_as_id,
"provider_as_ids": attestation.provider_as_ids,
})
.to_string(),
rule_hash,
validation_path_hint: vec![
manifest_rsync_uri.to_string(),
file.rsync_uri.clone(),
source_object_hash,
],
source_object_type: VcirSourceObjectType::Aspa,
source_object_hash: file.sha256,
source_ee_cert_hash: sha256_hex_to_32(&source_ee_cert_hash),
payload: VcirLocalOutputPayload::Aspa {
customer_as_id: attestation.customer_as_id,
provider_as_ids: attestation.provider_as_ids.clone(),
},
rule_hash: sha256_hex_to_32(&rule_hash),
};
Ok((attestation, Some(local_output)))
@@ -2965,6 +2979,54 @@ mod tests {
assert_eq!(roa_afi_to_string(RoaAfi::Ipv6), "ipv6");
}
#[test]
fn parallel_stage_roa_tasks_share_stage_owned_payloads() {
let stage = ParallelObjectsStage {
publication_point_id: 7,
shared: Arc::new(RoaTaskShared {
locked_files: Arc::<[PackFile]>::from(vec![
PackFile::from_bytes_with_sha256(
"rsync://example.test/repo/a.roa",
vec![1, 2, 3],
[1u8; 32],
),
PackFile::from_bytes_with_sha256(
"rsync://example.test/repo/b.roa",
vec![4, 5, 6],
[2u8; 32],
),
]),
manifest_rsync_uri: Arc::<str>::from("rsync://example.test/repo/manifest.mft"),
issuer_ca_der: Arc::from([0x01u8].as_slice()),
issuer_ca: Arc::new(
ResourceCertificate::decode_der(&fixture_bytes(
"tests/fixtures/ta/apnic-ta.cer",
))
.expect("decode fixture CA certificate"),
),
issuer_spki_der: Arc::from([0x02u8].as_slice()),
issuer_ca_rsync_uri: Some(Arc::<str>::from("rsync://example.test/repo/ca.cer")),
crl_cache: Arc::new(Mutex::new(HashMap::new())),
issuer_resources_index: Arc::new(IssuerResourcesIndex::default()),
issuer_effective_ip: None,
issuer_effective_as: None,
}),
validation_time: OffsetDateTime::now_utc(),
collect_vcir_local_outputs: false,
strict_cms_der: false,
strict_name: false,
warnings: Vec::new(),
stats: ObjectsStats {
roa_total: 2,
..ObjectsStats::default()
},
audit: Vec::new(),
};
let tasks = stage.build_roa_tasks();
assert_eq!(tasks.len(), 2);
assert!(Arc::ptr_eq(&tasks[0].shared, &tasks[1].shared));
}
#[test]
fn strict_name_manifest_decode_failure_drops_publication_point() {
let publication_point = PublicationPointSnapshot {