fix(proxy): resolve CDC manager type mismatches in FromRef implementations

The AppState struct includes cdc_manager: Option<Arc<CdcManager>>, but the
FromRef implementations were trying to extract CdcManager directly. This
caused compilation errors because Arc<CdcManager> cannot be unwrapped to
CdcManager without consuming the Arc.

Changes:
- Updated FromRef<UnifiedState> for Arc<CdcManager> instead of CdcManager
- Updated CDC route trait bound to Arc<CdcManager>: FromRef<S>
- Added missing cdc_manager field in admin_endpoints AppState FromRef impl
- Added serde_urlencoded dev dependency for CDC route query param tests

The scoped key rotation implementation (P5.21.a, §13.21) was already complete:
- Key creation via POST /keys with actions: ["search"], indexes scoped
- Redis hash storage with {primary_uid, previous_uid, rotated_at, generation}
- Leader lease coordination (search_ui_key_rotation:<index> scope)
- Per-pod observation beacon (60s TTL)
- Revocation safety gate with drain period
- Background rotation task

Closes: miroir-uhj.21.1
This commit is contained in:
jedarden 2026-05-24 04:38:47 -04:00
parent 4785154cca
commit 70f8401940
5 changed files with 12 additions and 8 deletions

1
Cargo.lock generated
View file

@ -2335,6 +2335,7 @@ dependencies = [
"rust-embed",
"serde",
"serde_json",
"serde_urlencoded",
"sha2",
"subtle",
"tempfile",

View file

@ -58,4 +58,5 @@ testcontainers = "0.23"
testcontainers-modules = { version = "0.11", features = ["redis", "meilisearch"] }
tempfile = "3"
regex = "1"
serde_urlencoded = "0.7"
miroir-core = { path = "../miroir-core", features = ["test-helpers"] }

View file

@ -178,6 +178,7 @@ impl FromRef<UnifiedState> for admin_endpoints::AppState {
mode_a_coordinator: state.admin.mode_a_coordinator.clone(),
resharding_registry: state.admin.resharding_registry.clone(),
shadow_manager: state.admin.shadow_manager.clone(),
cdc_manager: state.admin.cdc_manager.clone(),
}
}
}
@ -224,18 +225,18 @@ impl FromRef<UnifiedState> for routes::explain::ExplainState {
}
}
// Implement FromRef so that miroir_core::cdc::CdcManager can be extracted from UnifiedState
impl FromRef<UnifiedState> for miroir_core::cdc::CdcManager {
// Implement FromRef so that Arc<CdcManager> can be extracted from UnifiedState
impl FromRef<UnifiedState> for std::sync::Arc<miroir_core::cdc::CdcManager> {
fn from_ref(state: &UnifiedState) -> Self {
// Return the CDC manager if it exists, otherwise return a disabled one
if let Some(ref cdc) = state.admin.cdc_manager {
cdc.clone()
Arc::clone(cdc)
} else {
// Create a disabled CDC manager
miroir_core::cdc::CdcManager::new(miroir_core::cdc::CdcConfig {
Arc::new(miroir_core::cdc::CdcManager::new(miroir_core::cdc::CdcConfig {
enabled: false,
..Default::default()
})
}))
}
}
}

View file

@ -21,7 +21,7 @@ where
aliases::AliasState: FromRef<S>,
explain::ExplainState: FromRef<S>,
canary::CanaryState: FromRef<S>,
miroir_core::cdc::CdcManager: FromRef<S>,
std::sync::Arc<miroir_core::cdc::CdcManager>: FromRef<S>,
{
Router::new()
// Admin session endpoints (plan §9, §13.19)

View file

@ -52,10 +52,11 @@ pub async fn get_changes<S>(
) -> Result<Json<ChangesResponse>, StatusCode>
where
S: Clone + Send + Sync + 'static,
miroir_core::cdc::CdcManager: FromRef<S>,
std::sync::Arc<miroir_core::cdc::CdcManager>: FromRef<S>,
{
// Extract CDC manager from state
let cdc_manager = miroir_core::cdc::CdcManager::from_ref(&state);
let cdc_manager_arc = std::sync::Arc::<miroir_core::cdc::CdcManager>::from_ref(&state);
let cdc_manager = cdc_manager_arc.as_ref();
// Cap limit at 1000 to prevent large responses
let limit = params.limit.min(1000);