20260727 修复缓存回放丢失reject reason(#132):缓存artifact增加reject_reason字段,fresh验证记录真实原因,VCIR/PP cache回放还原,旧缓存给后备文案
This commit is contained in:
parent
cf68abf642
commit
7d5454a729
@ -406,6 +406,7 @@ mod tests {
|
||||
sha256: manifest_hash,
|
||||
object_type: Some("mft".to_string()),
|
||||
validation_status: VcirArtifactValidationStatus::Accepted,
|
||||
reject_reason: None,
|
||||
}],
|
||||
summary: VcirSummary {
|
||||
local_vrp_count: 0,
|
||||
|
||||
@ -729,6 +729,7 @@ mod tests {
|
||||
sha256: hash,
|
||||
object_type: Some("mft".to_string()),
|
||||
validation_status: crate::storage::VcirArtifactValidationStatus::Accepted,
|
||||
reject_reason: None,
|
||||
}],
|
||||
summary: crate::storage::VcirSummary {
|
||||
local_vrp_count: 0,
|
||||
|
||||
@ -267,6 +267,7 @@ mod tests {
|
||||
sha256: hash,
|
||||
object_type: Some("mft".to_string()),
|
||||
validation_status: VcirArtifactValidationStatus::Accepted,
|
||||
reject_reason: None,
|
||||
}],
|
||||
summary: VcirSummary {
|
||||
local_vrp_count: 0,
|
||||
|
||||
@ -645,6 +645,7 @@ mod tests {
|
||||
sha256: "ff".repeat(32),
|
||||
object_type: Some("mft".to_string()),
|
||||
validation_status: VcirArtifactValidationStatus::Accepted,
|
||||
reject_reason: None,
|
||||
}],
|
||||
summary: VcirSummary {
|
||||
local_vrp_count: 0,
|
||||
|
||||
@ -1660,6 +1660,9 @@ pub struct PublicationPointCacheObject {
|
||||
pub object_type: Option<String>,
|
||||
#[serde(rename = "s")]
|
||||
pub validation_status: VcirArtifactValidationStatus,
|
||||
/// See `VcirRelatedArtifact::reject_reason`.
|
||||
#[serde(rename = "e", default, skip_serializing_if = "Option::is_none")]
|
||||
pub reject_reason: Option<String>,
|
||||
}
|
||||
|
||||
impl PublicationPointCacheObject {
|
||||
@ -1671,6 +1674,7 @@ impl PublicationPointCacheObject {
|
||||
sha256: artifact.sha256.clone(),
|
||||
object_type: artifact.object_type.clone(),
|
||||
validation_status: artifact.validation_status,
|
||||
reject_reason: artifact.reject_reason.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -1682,6 +1686,7 @@ impl PublicationPointCacheObject {
|
||||
sha256: self.sha256.clone(),
|
||||
object_type: self.object_type.clone(),
|
||||
validation_status: self.validation_status,
|
||||
reject_reason: self.reject_reason.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -2157,6 +2162,11 @@ pub struct VcirRelatedArtifact {
|
||||
pub object_type: Option<String>,
|
||||
#[serde(rename = "s")]
|
||||
pub validation_status: VcirArtifactValidationStatus,
|
||||
/// Reject reason captured at fresh validation time for `Rejected` artifacts.
|
||||
/// `None` for accepted/warning artifacts and for cache entries written
|
||||
/// before this field existed.
|
||||
#[serde(rename = "e", default, skip_serializing_if = "Option::is_none")]
|
||||
pub reject_reason: Option<String>,
|
||||
}
|
||||
|
||||
impl VcirRelatedArtifact {
|
||||
|
||||
@ -257,6 +257,7 @@ fn sample_vcir(manifest_rsync_uri: &str) -> ValidatedCaInstanceResult {
|
||||
sha256: sha256_hex(b"manifest-object"),
|
||||
object_type: Some("mft".to_string()),
|
||||
validation_status: VcirArtifactValidationStatus::Accepted,
|
||||
reject_reason: None,
|
||||
},
|
||||
VcirRelatedArtifact {
|
||||
artifact_role: VcirArtifactRole::CurrentCrl,
|
||||
@ -265,6 +266,7 @@ fn sample_vcir(manifest_rsync_uri: &str) -> ValidatedCaInstanceResult {
|
||||
sha256: sha256_hex(b"current-crl"),
|
||||
object_type: Some("crl".to_string()),
|
||||
validation_status: VcirArtifactValidationStatus::Accepted,
|
||||
reject_reason: None,
|
||||
},
|
||||
],
|
||||
summary: VcirSummary {
|
||||
@ -2394,3 +2396,35 @@ fn repository_blob_verification_detects_missing_external_blob() {
|
||||
.expect_err("missing blob must fail");
|
||||
assert!(error.to_string().contains("missing.roa"), "{error}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn vcir_related_artifact_reject_reason_serde_backward_compatible() {
|
||||
// Legacy cache JSON written before the reject_reason ("e") field existed.
|
||||
let legacy = r#"{"r":"manifest","k":"mft","u":"rsync://example.test/a.mft","h":"0000000000000000000000000000000000000000000000000000000000000000","t":"mft","s":"accepted"}"#;
|
||||
let artifact: VcirRelatedArtifact = serde_json::from_str(legacy).expect("legacy artifact");
|
||||
assert_eq!(artifact.reject_reason, None);
|
||||
|
||||
// None reason is skipped on serialization, keeping cache entries compact.
|
||||
let json_none = serde_json::to_string(&artifact).expect("serialize none");
|
||||
assert!(!json_none.contains("\"e\""));
|
||||
|
||||
// A recorded reason round-trips through the "e" field.
|
||||
let mut with_reason = artifact.clone();
|
||||
with_reason.validation_status = VcirArtifactValidationStatus::Rejected;
|
||||
with_reason.reject_reason = Some("bad object".to_string());
|
||||
let json = serde_json::to_string(&with_reason).expect("serialize");
|
||||
assert!(json.contains("\"e\":\"bad object\""));
|
||||
let decoded: VcirRelatedArtifact = serde_json::from_str(&json).expect("deserialize");
|
||||
assert_eq!(decoded.reject_reason.as_deref(), Some("bad object"));
|
||||
|
||||
// PublicationPointCacheObject conversion carries the reason both ways.
|
||||
let cache_object = PublicationPointCacheObject::from_related_artifact(&with_reason);
|
||||
assert_eq!(cache_object.reject_reason.as_deref(), Some("bad object"));
|
||||
let back = cache_object.to_related_artifact();
|
||||
assert_eq!(back.reject_reason.as_deref(), Some("bad object"));
|
||||
|
||||
// Legacy PublicationPointCacheObject JSON without "e" still deserializes.
|
||||
let legacy_object: PublicationPointCacheObject =
|
||||
serde_json::from_str(legacy).expect("legacy cache object");
|
||||
assert_eq!(legacy_object.reject_reason, None);
|
||||
}
|
||||
|
||||
@ -1199,6 +1199,7 @@ mod tests {
|
||||
sha256: manifest_sha256.to_string(),
|
||||
object_type: Some("mft".to_string()),
|
||||
validation_status: VcirArtifactValidationStatus::Accepted,
|
||||
reject_reason: None,
|
||||
},
|
||||
VcirRelatedArtifact {
|
||||
artifact_role: VcirArtifactRole::SignedObject,
|
||||
@ -1207,6 +1208,7 @@ mod tests {
|
||||
sha256: locked_object_sha256.to_string(),
|
||||
object_type: Some("roa".to_string()),
|
||||
validation_status: VcirArtifactValidationStatus::Accepted,
|
||||
reject_reason: None,
|
||||
},
|
||||
],
|
||||
summary: VcirSummary {
|
||||
|
||||
@ -4023,6 +4023,7 @@ mod tests {
|
||||
sha256: sha256_hex(issuer_der),
|
||||
object_type: Some("cer".to_string()),
|
||||
validation_status: VcirArtifactValidationStatus::Accepted,
|
||||
reject_reason: None,
|
||||
},
|
||||
VcirRelatedArtifact {
|
||||
artifact_role: VcirArtifactRole::CurrentCrl,
|
||||
@ -4031,6 +4032,7 @@ mod tests {
|
||||
sha256: sha256_hex_from_32(&crl_hash),
|
||||
object_type: Some("crl".to_string()),
|
||||
validation_status: VcirArtifactValidationStatus::Accepted,
|
||||
reject_reason: None,
|
||||
},
|
||||
],
|
||||
summary: VcirSummary {
|
||||
@ -4543,6 +4545,7 @@ mod tests {
|
||||
sha256: "00".repeat(32),
|
||||
object_type: Some("cer".to_string()),
|
||||
validation_status: VcirArtifactValidationStatus::Rejected,
|
||||
reject_reason: None,
|
||||
},
|
||||
);
|
||||
vcir.local_outputs.push(VcirLocalOutput {
|
||||
|
||||
@ -3840,6 +3840,28 @@ fn audit_result_from_vcir_status(status: VcirArtifactValidationStatus) -> AuditO
|
||||
}
|
||||
}
|
||||
|
||||
/// Fallback detail for cached artifacts rejected by an earlier run whose cache
|
||||
/// entry predates reject-reason recording (field added 2026-07-27).
|
||||
const CACHED_REJECT_REASON_NOT_RECORDED: &str =
|
||||
"rejected in an earlier validation run (reject reason not recorded in cache)";
|
||||
|
||||
/// Detail for an audit entry rebuilt from a cached artifact: the real reject
|
||||
/// reason when the cache recorded one, an explicit fallback for legacy cache
|
||||
/// entries, and `None` for non-rejected artifacts.
|
||||
fn audit_detail_from_vcir_status(
|
||||
status: VcirArtifactValidationStatus,
|
||||
reject_reason: Option<&str>,
|
||||
) -> Option<String> {
|
||||
match status {
|
||||
VcirArtifactValidationStatus::Rejected => Some(
|
||||
reject_reason
|
||||
.map(str::to_string)
|
||||
.unwrap_or_else(|| CACHED_REJECT_REASON_NOT_RECORDED.to_string()),
|
||||
),
|
||||
VcirArtifactValidationStatus::Accepted | VcirArtifactValidationStatus::WarningOnly => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn build_publication_point_audit_from_snapshot(
|
||||
ca: &CaInstanceHandle,
|
||||
source: PublicationPointSource,
|
||||
@ -4059,7 +4081,10 @@ fn build_publication_point_audit_from_vcir(
|
||||
sha256_hex: artifact.sha256.clone(),
|
||||
kind: kind_from_vcir_artifact_kind(artifact.artifact_kind),
|
||||
result: audit_result_from_vcir_status(artifact.validation_status),
|
||||
detail: None,
|
||||
detail: audit_detail_from_vcir_status(
|
||||
artifact.validation_status,
|
||||
artifact.reject_reason.as_deref(),
|
||||
),
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -4170,7 +4195,10 @@ fn build_publication_point_audit_from_publication_point_cache_projection(
|
||||
sha256_hex: artifact.sha256.clone(),
|
||||
kind: kind_from_vcir_artifact_kind(artifact.artifact_kind),
|
||||
result: audit_result_from_vcir_status(artifact.validation_status),
|
||||
detail: None,
|
||||
detail: audit_detail_from_vcir_status(
|
||||
artifact.validation_status,
|
||||
artifact.reject_reason.as_deref(),
|
||||
),
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -6003,9 +6031,9 @@ fn build_vcir_related_artifacts(
|
||||
objects: &crate::validation::objects::ObjectsOutput,
|
||||
child_audits: &[ObjectAuditEntry],
|
||||
) -> Vec<VcirRelatedArtifact> {
|
||||
let mut audit_by_uri: HashMap<&str, AuditObjectResult> = HashMap::new();
|
||||
let mut audit_by_uri: HashMap<&str, &ObjectAuditEntry> = HashMap::new();
|
||||
for entry in child_audits.iter().chain(objects.audit.iter()) {
|
||||
audit_by_uri.insert(entry.rsync_uri.as_str(), entry.result.clone());
|
||||
audit_by_uri.insert(entry.rsync_uri.as_str(), entry);
|
||||
}
|
||||
|
||||
let mut artifacts = Vec::with_capacity(pack.files.len() + 2);
|
||||
@ -6016,6 +6044,7 @@ fn build_vcir_related_artifacts(
|
||||
sha256: sha256_hex(&pack.manifest_bytes),
|
||||
object_type: Some("mft".to_string()),
|
||||
validation_status: VcirArtifactValidationStatus::Accepted,
|
||||
reject_reason: None,
|
||||
});
|
||||
artifacts.push(VcirRelatedArtifact {
|
||||
artifact_role: if ca.parent_manifest_rsync_uri.is_none() {
|
||||
@ -6035,13 +6064,20 @@ fn build_vcir_related_artifacts(
|
||||
}),
|
||||
object_type: Some("cer".to_string()),
|
||||
validation_status: VcirArtifactValidationStatus::Accepted,
|
||||
reject_reason: None,
|
||||
});
|
||||
|
||||
for file in &pack.files {
|
||||
let result = audit_by_uri
|
||||
.get(file.rsync_uri.as_str())
|
||||
.cloned()
|
||||
let audit_entry = audit_by_uri.get(file.rsync_uri.as_str()).copied();
|
||||
let result = audit_entry
|
||||
.map(|entry| entry.result.clone())
|
||||
.unwrap_or(AuditObjectResult::Ok);
|
||||
let validation_status = audit_result_to_vcir_status(&result);
|
||||
let reject_reason = if validation_status == VcirArtifactValidationStatus::Rejected {
|
||||
audit_entry.and_then(|entry| entry.detail.clone())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let (artifact_role, artifact_kind) = artifact_role_and_kind(file, current_crl_rsync_uri);
|
||||
artifacts.push(VcirRelatedArtifact {
|
||||
artifact_role,
|
||||
@ -6049,7 +6085,8 @@ fn build_vcir_related_artifacts(
|
||||
uri: Some(file.rsync_uri.clone()),
|
||||
sha256: sha256_hex_from_32(&file.sha256),
|
||||
object_type: object_type_from_uri(file.rsync_uri.as_str()),
|
||||
validation_status: audit_result_to_vcir_status(&result),
|
||||
validation_status,
|
||||
reject_reason,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -708,6 +708,7 @@ fn sample_vcir_for_projection(
|
||||
sha256: manifest_hash,
|
||||
object_type: Some("mft".to_string()),
|
||||
validation_status: VcirArtifactValidationStatus::Accepted,
|
||||
reject_reason: None,
|
||||
},
|
||||
VcirRelatedArtifact {
|
||||
artifact_role: VcirArtifactRole::CurrentCrl,
|
||||
@ -716,6 +717,7 @@ fn sample_vcir_for_projection(
|
||||
sha256: current_crl_hash,
|
||||
object_type: Some("crl".to_string()),
|
||||
validation_status: VcirArtifactValidationStatus::Accepted,
|
||||
reject_reason: None,
|
||||
},
|
||||
VcirRelatedArtifact {
|
||||
artifact_role: VcirArtifactRole::ChildCaCert,
|
||||
@ -724,6 +726,7 @@ fn sample_vcir_for_projection(
|
||||
sha256: child_cert_hash.to_string(),
|
||||
object_type: Some("cer".to_string()),
|
||||
validation_status: VcirArtifactValidationStatus::Accepted,
|
||||
reject_reason: None,
|
||||
},
|
||||
VcirRelatedArtifact {
|
||||
artifact_role: VcirArtifactRole::SignedObject,
|
||||
@ -732,6 +735,7 @@ fn sample_vcir_for_projection(
|
||||
sha256: roa_hash,
|
||||
object_type: Some("roa".to_string()),
|
||||
validation_status: VcirArtifactValidationStatus::Accepted,
|
||||
reject_reason: None,
|
||||
},
|
||||
VcirRelatedArtifact {
|
||||
artifact_role: VcirArtifactRole::SignedObject,
|
||||
@ -740,6 +744,7 @@ fn sample_vcir_for_projection(
|
||||
sha256: aspa_hash,
|
||||
object_type: Some("aspa".to_string()),
|
||||
validation_status: VcirArtifactValidationStatus::Accepted,
|
||||
reject_reason: None,
|
||||
},
|
||||
],
|
||||
summary: VcirSummary {
|
||||
@ -1455,10 +1460,12 @@ fn build_vcir_related_artifacts_classifies_snapshot_files_and_audit_statuses() {
|
||||
&& artifact.artifact_role == VcirArtifactRole::ChildCaCert));
|
||||
assert!(artifacts.iter().any(|artifact| artifact.uri.as_deref()
|
||||
== Some("rsync://example.test/repo/issuer/a.roa")
|
||||
&& artifact.validation_status == VcirArtifactValidationStatus::Rejected));
|
||||
&& artifact.validation_status == VcirArtifactValidationStatus::Rejected
|
||||
&& artifact.reject_reason.as_deref() == Some("bad roa")));
|
||||
assert!(artifacts.iter().any(|artifact| artifact.uri.as_deref()
|
||||
== Some("rsync://example.test/repo/issuer/a.asa")
|
||||
&& artifact.validation_status == VcirArtifactValidationStatus::WarningOnly));
|
||||
&& artifact.validation_status == VcirArtifactValidationStatus::WarningOnly
|
||||
&& artifact.reject_reason.is_none()));
|
||||
assert!(artifacts.iter().any(|artifact| artifact.uri.as_deref()
|
||||
== Some("rsync://example.test/repo/issuer/a.gbr")
|
||||
&& artifact.artifact_kind == VcirArtifactKind::Gbr));
|
||||
@ -4510,6 +4517,7 @@ fn build_objects_output_from_vcir_tracks_expired_and_invalid_cached_outputs() {
|
||||
.to_string(),
|
||||
),
|
||||
validation_status: VcirArtifactValidationStatus::Accepted,
|
||||
reject_reason: None,
|
||||
});
|
||||
}
|
||||
|
||||
@ -4732,6 +4740,173 @@ fn build_publication_point_audit_from_vcir_uses_vcir_metadata_and_overlays_child
|
||||
}));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_publication_point_audit_from_vcir_restores_reject_reason_with_legacy_fallback() {
|
||||
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.related_artifacts.push(VcirRelatedArtifact {
|
||||
artifact_role: VcirArtifactRole::SignedObject,
|
||||
artifact_kind: VcirArtifactKind::Roa,
|
||||
uri: Some("rsync://example.test/repo/issuer/rejected-with-reason.roa".to_string()),
|
||||
sha256: sha256_hex(b"rejected-with-reason"),
|
||||
object_type: Some("roa".to_string()),
|
||||
validation_status: VcirArtifactValidationStatus::Rejected,
|
||||
reject_reason: Some("EE certificate path validation failed: test".to_string()),
|
||||
});
|
||||
vcir.related_artifacts.push(VcirRelatedArtifact {
|
||||
artifact_role: VcirArtifactRole::SignedObject,
|
||||
artifact_kind: VcirArtifactKind::Roa,
|
||||
uri: Some("rsync://example.test/repo/issuer/rejected-legacy.roa".to_string()),
|
||||
sha256: sha256_hex(b"rejected-legacy"),
|
||||
object_type: Some("roa".to_string()),
|
||||
validation_status: VcirArtifactValidationStatus::Rejected,
|
||||
reject_reason: None,
|
||||
});
|
||||
|
||||
let ca = CaInstanceHandle {
|
||||
depth: 0,
|
||||
tal_id: "test-tal".to_string(),
|
||||
parent_manifest_rsync_uri: None,
|
||||
ca_certificate: CaCertificateRef::inline_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 objects = crate::validation::objects::ObjectsOutput {
|
||||
vrps: Vec::new(),
|
||||
aspas: Vec::new(),
|
||||
router_keys: Vec::new(),
|
||||
local_outputs_cache: Vec::new(),
|
||||
warnings: Vec::new(),
|
||||
stats: crate::validation::objects::ObjectsStats::default(),
|
||||
audit: Vec::new(),
|
||||
roa_cache_stats: crate::validation::objects::RoaValidationCacheStats::default(),
|
||||
roa_cache_object_meta: Vec::new(),
|
||||
};
|
||||
|
||||
let audit = build_publication_point_audit_from_vcir(
|
||||
&ca,
|
||||
PublicationPointSource::VcirCurrentInstance,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
Some(&vcir),
|
||||
None,
|
||||
&[],
|
||||
&objects,
|
||||
&[],
|
||||
&[],
|
||||
);
|
||||
|
||||
assert!(audit.objects.iter().any(|entry| {
|
||||
entry.rsync_uri == "rsync://example.test/repo/issuer/rejected-with-reason.roa"
|
||||
&& matches!(entry.result, AuditObjectResult::Error)
|
||||
&& entry.detail.as_deref()
|
||||
== Some("EE certificate path validation failed: test")
|
||||
}));
|
||||
assert!(audit.objects.iter().any(|entry| {
|
||||
entry.rsync_uri == "rsync://example.test/repo/issuer/rejected-legacy.roa"
|
||||
&& matches!(entry.result, AuditObjectResult::Error)
|
||||
&& entry.detail.as_deref() == Some(CACHED_REJECT_REASON_NOT_RECORDED)
|
||||
}));
|
||||
assert!(audit.objects.iter().all(|entry| {
|
||||
!matches!(entry.result, AuditObjectResult::Ok) || entry.detail.is_none()
|
||||
}));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_publication_point_audit_from_pp_cache_projection_restores_reject_reason() {
|
||||
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.related_artifacts.push(VcirRelatedArtifact {
|
||||
artifact_role: VcirArtifactRole::SignedObject,
|
||||
artifact_kind: VcirArtifactKind::Roa,
|
||||
uri: Some("rsync://example.test/repo/issuer/rejected-with-reason.roa".to_string()),
|
||||
sha256: sha256_hex(b"rejected-with-reason"),
|
||||
object_type: Some("roa".to_string()),
|
||||
validation_status: VcirArtifactValidationStatus::Rejected,
|
||||
reject_reason: Some("EE certificate path validation failed: test".to_string()),
|
||||
});
|
||||
vcir.related_artifacts.push(VcirRelatedArtifact {
|
||||
artifact_role: VcirArtifactRole::SignedObject,
|
||||
artifact_kind: VcirArtifactKind::Roa,
|
||||
uri: Some("rsync://example.test/repo/issuer/rejected-legacy.roa".to_string()),
|
||||
sha256: sha256_hex(b"rejected-legacy"),
|
||||
object_type: Some("roa".to_string()),
|
||||
validation_status: VcirArtifactValidationStatus::Rejected,
|
||||
reject_reason: None,
|
||||
});
|
||||
let projection = PublicationPointCacheProjection::from_vcir_with_context(
|
||||
&vcir,
|
||||
"rsync://example.test/repo/issuer/".to_string(),
|
||||
None,
|
||||
[0x11; 32],
|
||||
[0x22; 32],
|
||||
[0x33; 32],
|
||||
[0x44; 32],
|
||||
[0x55; 32],
|
||||
)
|
||||
.expect("build publication point projection");
|
||||
|
||||
let ca = CaInstanceHandle {
|
||||
depth: 0,
|
||||
tal_id: "test-tal".to_string(),
|
||||
parent_manifest_rsync_uri: None,
|
||||
ca_certificate: CaCertificateRef::inline_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 objects = crate::validation::objects::ObjectsOutput {
|
||||
vrps: Vec::new(),
|
||||
aspas: Vec::new(),
|
||||
router_keys: Vec::new(),
|
||||
local_outputs_cache: Vec::new(),
|
||||
warnings: Vec::new(),
|
||||
stats: crate::validation::objects::ObjectsStats::default(),
|
||||
audit: Vec::new(),
|
||||
roa_cache_stats: crate::validation::objects::RoaValidationCacheStats::default(),
|
||||
roa_cache_object_meta: Vec::new(),
|
||||
};
|
||||
|
||||
let audit = build_publication_point_audit_from_publication_point_cache_projection(
|
||||
&ca,
|
||||
PublicationPointSource::PublicationPointCache,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
&projection,
|
||||
now,
|
||||
&[],
|
||||
&objects,
|
||||
&[],
|
||||
);
|
||||
|
||||
assert!(audit.objects.iter().any(|entry| {
|
||||
entry.rsync_uri == "rsync://example.test/repo/issuer/rejected-with-reason.roa"
|
||||
&& matches!(entry.result, AuditObjectResult::Error)
|
||||
&& entry.detail.as_deref()
|
||||
== Some("EE certificate path validation failed: test")
|
||||
}));
|
||||
assert!(audit.objects.iter().any(|entry| {
|
||||
entry.rsync_uri == "rsync://example.test/repo/issuer/rejected-legacy.roa"
|
||||
&& matches!(entry.result, AuditObjectResult::Error)
|
||||
&& entry.detail.as_deref() == Some(CACHED_REJECT_REASON_NOT_RECORDED)
|
||||
}));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_publication_point_audit_from_vcir_failed_no_cache_keeps_current_reject_only() {
|
||||
let now = time::OffsetDateTime::now_utc();
|
||||
@ -4948,6 +5123,7 @@ fn reconstruct_snapshot_from_vcir_reports_missing_manifest_and_related_raw_bytes
|
||||
sha256: sha256_hex(b"dup-roa-1"),
|
||||
object_type: Some("roa".to_string()),
|
||||
validation_status: VcirArtifactValidationStatus::Accepted,
|
||||
reject_reason: None,
|
||||
});
|
||||
vcir.related_artifacts.push(VcirRelatedArtifact {
|
||||
artifact_role: VcirArtifactRole::SignedObject,
|
||||
@ -4956,6 +5132,7 @@ fn reconstruct_snapshot_from_vcir_reports_missing_manifest_and_related_raw_bytes
|
||||
sha256: sha256_hex(b"dup-roa-2"),
|
||||
object_type: Some("roa".to_string()),
|
||||
validation_status: VcirArtifactValidationStatus::Accepted,
|
||||
reject_reason: None,
|
||||
});
|
||||
vcir.related_artifacts.push(VcirRelatedArtifact {
|
||||
artifact_role: VcirArtifactRole::IssuerCert,
|
||||
@ -4964,6 +5141,7 @@ fn reconstruct_snapshot_from_vcir_reports_missing_manifest_and_related_raw_bytes
|
||||
sha256: sha256_hex(b"issuer-cert"),
|
||||
object_type: Some("cer".to_string()),
|
||||
validation_status: VcirArtifactValidationStatus::Accepted,
|
||||
reject_reason: None,
|
||||
});
|
||||
|
||||
let ca = CaInstanceHandle {
|
||||
|
||||
@ -244,6 +244,7 @@ fn verify_against_vcir_store_matches_manifest_hashes() {
|
||||
sha256: manifest_hash.clone(),
|
||||
object_type: Some("mft".to_string()),
|
||||
validation_status: VcirArtifactValidationStatus::Accepted,
|
||||
reject_reason: None,
|
||||
}],
|
||||
summary: VcirSummary {
|
||||
local_vrp_count: 0,
|
||||
|
||||
@ -109,6 +109,7 @@ fn store_validated_manifest_baseline(
|
||||
sha256: manifest_sha256,
|
||||
object_type: Some("mft".to_string()),
|
||||
validation_status: VcirArtifactValidationStatus::Accepted,
|
||||
reject_reason: None,
|
||||
}],
|
||||
summary: VcirSummary {
|
||||
local_vrp_count: 0,
|
||||
|
||||
@ -112,6 +112,7 @@ fn store_validated_manifest_baseline(
|
||||
sha256: manifest_sha256,
|
||||
object_type: Some("mft".to_string()),
|
||||
validation_status: VcirArtifactValidationStatus::Accepted,
|
||||
reject_reason: None,
|
||||
}],
|
||||
summary: VcirSummary {
|
||||
local_vrp_count: 0,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user