From 9032adcb1232e1760b96781c2020266a6df99e02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=94=90=E5=B0=8F=E9=B8=AD?= Date: Sat, 5 Sep 2026 17:40:50 +0800 Subject: [PATCH] fix(site-replication): judge service-account items against deletion marks too (backlog#2291) The service-account receive path used only the live record's timestamp; a deleted account left nothing to compare against, so a stale create from a snapshot or a delayed delivery could recreate it. Consult the recorded deletion mark when the record is absent, as the user path does. The site replicator account is managed by join/rotate and stays exempt. --- rustfs/src/admin/handlers/site_replication.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/rustfs/src/admin/handlers/site_replication.rs b/rustfs/src/admin/handlers/site_replication.rs index 2f1d40fcb..df667513c 100644 --- a/rustfs/src/admin/handlers/site_replication.rs +++ b/rustfs/src/admin/handlers/site_replication.rs @@ -6088,10 +6088,14 @@ async fn apply_iam_service_account_item( }; let envelope = change.oidc_service_account_envelope; if let Some(create) = change.create { - let local_updated_at = iam_sys - .get_user(&create.access_key) - .await - .map(|local| local.update_at.unwrap_or(OffsetDateTime::UNIX_EPOCH)); + // Like the user path: with the account already deleted here, the + // recorded deletion mark is the timestamp a stale create/update + // (a snapshot or a delayed delivery) has to beat (backlog#2291). + let local_updated_at = match iam_sys.get_user(&create.access_key).await { + Some(local) => Some(local.update_at.unwrap_or(OffsetDateTime::UNIX_EPOCH)), + None if create.access_key == SITE_REPLICATOR_SERVICE_ACCOUNT => None, + None => local_iam_deletion_mark(&[format!("svc-acc:{}", create.access_key)]).await, + }; let replicated_policy = if create.access_key == SITE_REPLICATOR_SERVICE_ACCOUNT { if local_updated_at.is_some_and(|local_updated_at| is_stale_update(local_updated_at, incoming_updated_at)) { return Ok(());