fix: retain Session recovery failures across real trust rejection
This commit is contained in:
Generated
+1
@@ -7580,6 +7580,7 @@ dependencies = [
|
||||
"content-history",
|
||||
"content-history-adapters",
|
||||
"content-history-store",
|
||||
"error-contract",
|
||||
"feature-storage",
|
||||
"flate2",
|
||||
"flow",
|
||||
|
||||
@@ -116,7 +116,7 @@ impl ProfileRuntimeWorkerFactory {
|
||||
.await;
|
||||
let mut worker = worker_result.map_err(|error| {
|
||||
self.retain_construction_failure(request, &error);
|
||||
cause(restore_worker_cause(&error))
|
||||
RuntimeRestoreFailure::from_worker(RuntimeRestoreStage::Recovery, error)
|
||||
})?;
|
||||
let tasks = worker.retain_startup_feature_cleanup();
|
||||
let sessions = worker.workdir_sessions();
|
||||
@@ -141,11 +141,13 @@ impl ProfileRuntimeWorkerFactory {
|
||||
.map_err(|_| cause("recovery Backend Job binding failed"))?;
|
||||
}
|
||||
worker
|
||||
.finalize_subjektiv_session_attribution(
|
||||
.finalize_subjektiv_session_attribution_retaining_startup_failure(
|
||||
request.request.subjektiv_attached,
|
||||
SubjektivSessionAttributionLifecycle::RestoredSession,
|
||||
)
|
||||
.map_err(|error| cause(restore_worker_cause(&error)))?;
|
||||
.map_err(|error| {
|
||||
RuntimeRestoreFailure::from_worker(RuntimeRestoreStage::Recovery, error)
|
||||
})?;
|
||||
if pending {
|
||||
worker::WorkerController::recover_pending_head(&mut worker, &root)
|
||||
.await
|
||||
@@ -161,21 +163,38 @@ impl ProfileRuntimeWorkerFactory {
|
||||
tasks
|
||||
.shutdown()
|
||||
.await
|
||||
.map_err(|_| cause("recovery Feature settlement failed"))?;
|
||||
.map_err(|_| RuntimeRestoreCleanupFailure::Feature)?;
|
||||
sessions
|
||||
.close_all()
|
||||
.await
|
||||
.map_err(|_| cause("recovery Workdir close failed"))?;
|
||||
.map_err(|_| RuntimeRestoreCleanupFailure::Workdir)?;
|
||||
if let Some(allocation) = allocation {
|
||||
allocation
|
||||
.release()
|
||||
.map_err(|_| cause("recovery allocation release failed"))?;
|
||||
.map_err(|_| RuntimeRestoreCleanupFailure::Allocation)?;
|
||||
}
|
||||
Ok::<_, RuntimeRestoreFailure>(())
|
||||
Ok::<_, RuntimeRestoreCleanupFailure>(())
|
||||
}
|
||||
.await;
|
||||
result?;
|
||||
cleanup?;
|
||||
match (result, cleanup) {
|
||||
(Err(mut primary), cleanup) => {
|
||||
primary.cleanup = match cleanup {
|
||||
Ok(()) => RuntimeRestoreCleanup::Confirmed,
|
||||
Err(failure) => {
|
||||
primary.cleanup_failure = Some(failure);
|
||||
RuntimeRestoreCleanup::Failed(failure)
|
||||
}
|
||||
};
|
||||
return Err(primary);
|
||||
}
|
||||
(Ok(()), Err(cleanup)) => {
|
||||
let mut failure = cause("restore recovery cleanup failed");
|
||||
failure.cleanup_failure = Some(cleanup);
|
||||
failure.cleanup = RuntimeRestoreCleanup::Failed(cleanup);
|
||||
return Err(failure);
|
||||
}
|
||||
(Ok(()), Ok(())) => {}
|
||||
}
|
||||
self.failed_restore_resources
|
||||
.lock()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner)
|
||||
|
||||
@@ -66,6 +66,7 @@ webauthn-rs = { workspace = true, features = ["conditional-ui"] }
|
||||
webauthn-rs-proto = "0.5.5"
|
||||
|
||||
[dev-dependencies]
|
||||
error-contract.workspace = true
|
||||
content-history.workspace = true
|
||||
content-history-store.workspace = true
|
||||
content-history-adapters.workspace = true
|
||||
|
||||
@@ -2365,9 +2365,21 @@ async fn connected_explicit_repair(scenario: ConnectedRepair) {
|
||||
assert_eq!(probe.activations.load(SeqCst), 0);
|
||||
assert_eq!(probe.publications.load(SeqCst), 0);
|
||||
assert_eq!(fixture.model.calls.load(SeqCst), model_before);
|
||||
assert!(
|
||||
matches!(metadata.read_by_name(&name).unwrap().unwrap().subjektiv_session_attribution,
|
||||
Some(session_store::SubjektivSessionAttributionState::Failed { session_id: id, .. }) if id == session_id)
|
||||
let saved_failure = metadata.read_by_name(&name).unwrap().unwrap();
|
||||
// Trust rejection occurs before the Session domain handler. An unsigned
|
||||
// legacy 401 attests neither a Session refusal nor absence of earlier effects.
|
||||
assert!(matches!(saved_failure.subjektiv_session_attribution,
|
||||
Some(session_store::SubjektivSessionAttributionState::OutcomeUnknown { session_id: id, .. }) if id == session_id));
|
||||
let session_store::worker_metadata::StartupFailureRead::Present(
|
||||
error_contract::DecodeFailure::Known(cause),
|
||||
) = saved_failure
|
||||
.decode_startup_failure::<protocol::session_failure::SessionRegistrationCause>()
|
||||
else {
|
||||
panic!("recovery must retain its typed Session unknown cause")
|
||||
};
|
||||
assert_eq!(
|
||||
*cause.facts().cause(),
|
||||
protocol::session_failure::SessionRegistrationCause::outcome_unknown()
|
||||
);
|
||||
let denied = record();
|
||||
assert_eq!(
|
||||
|
||||
Reference in New Issue
Block a user