20261016 修复 Manifest failed-fetch 缓存与子树恢复
Some checks failed
ci / rust (push) Failing after 4s
ci / docker (push) Failing after 1m27s
ci / audit (push) Failing after 3s

This commit is contained in:
2026-10-16 15:53:40 +08:00
parent 5f46837b61
commit 2d7501db08
28 changed files with 1565 additions and 143 deletions

View File

@@ -4,6 +4,7 @@ use crate::output::report::Warning;
use crate::validation::manifest::PublicationPointSource;
use crate::validation::objects::{AspaAttestation, ObjectsOutput, RouterKeyPayload, Vrp};
use crate::validation::publication_point::PublicationPointSnapshot;
use serde::{Deserialize, Serialize};
use std::borrow::Cow;
use std::sync::{Arc, OnceLock};
@@ -41,11 +42,15 @@ pub(crate) fn next_allowed_ca_depth(config: &TreeRunConfig, parent_depth: usize)
ca_depth_is_allowed(config, child_depth).then_some(child_depth)
}
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum CaCertificateRef {
InlineDer(Vec<u8>),
/// A previously validated child reached through a failed-fetch cache edge.
/// Its entire branch must use cached results without repository requests.
CachedDer(Vec<u8>),
RepoBytes {
sha256_hex: String,
#[serde(skip)]
cached_der: Arc<OnceLock<Arc<[u8]>>>,
},
}
@@ -53,7 +58,8 @@ pub enum CaCertificateRef {
impl PartialEq for CaCertificateRef {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::InlineDer(left), Self::InlineDer(right)) => left == right,
(Self::InlineDer(left), Self::InlineDer(right))
| (Self::CachedDer(left), Self::CachedDer(right)) => left == right,
(
Self::RepoBytes {
sha256_hex: left, ..
@@ -83,7 +89,7 @@ impl CaCertificateRef {
pub fn sha256_hex(&self) -> Option<&str> {
match self {
Self::InlineDer(_) => None,
Self::InlineDer(_) | Self::CachedDer(_) => None,
Self::RepoBytes { sha256_hex, .. } => Some(sha256_hex.as_str()),
}
}
@@ -93,7 +99,7 @@ impl CaCertificateRef {
store: &crate::repository::storage::RocksStore,
) -> Result<Cow<'a, [u8]>, String> {
match self {
Self::InlineDer(bytes) => Ok(Cow::Borrowed(bytes.as_slice())),
Self::InlineDer(bytes) | Self::CachedDer(bytes) => Ok(Cow::Borrowed(bytes.as_slice())),
Self::RepoBytes {
sha256_hex,
cached_der,
@@ -116,7 +122,7 @@ impl CaCertificateRef {
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct CaInstanceHandle {
pub anchor_namespace: [u8; 32],
pub depth: usize,
@@ -142,6 +148,10 @@ pub struct CaInstanceHandle {
}
impl CaInstanceHandle {
pub fn is_cache_only(&self) -> bool {
matches!(self.ca_certificate, CaCertificateRef::CachedDer(_))
}
pub fn with_depth(mut self, depth: usize) -> Self {
self.depth = depth;
self
@@ -160,7 +170,7 @@ impl CaInstanceHandle {
pub fn ca_certificate_sha256_32(&self) -> Option<[u8; 32]> {
match &self.ca_certificate {
CaCertificateRef::InlineDer(bytes) => {
CaCertificateRef::InlineDer(bytes) | CaCertificateRef::CachedDer(bytes) => {
use sha2::Digest as _;
let digest = sha2::Sha256::digest(bytes);
Some(digest.into())
@@ -184,17 +194,18 @@ pub struct PublicationPointRunResult {
/// Candidate child CA instances to enqueue after this publication point completes.
///
/// - For `Fresh`, these are discovered from the current validated publication point.
/// - For failed synchronization, the result contains no child instances;
/// callers may retry the repository on a later run.
/// - For `FailedFetchCached`, these are cache-only edges: no descendant
/// acquisition or fresh validation is permitted during this run.
/// - Without usable cached results, this list is empty.
pub discovered_children: Vec<DiscoveredChildCaInstance>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct DiscoveredChildEntryProjection {
pub child_ski: String,
}
#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct DiscoveredChildCaInstance {
pub handle: CaInstanceHandle,
pub discovered_from: DiscoveredFrom,