From d13a5d3abce823f2921f1362b0aac499f0629196 Mon Sep 17 00:00:00 2001 From: GatewayJ <18332154+GatewayJ@users.noreply.github.com> Date: Wed, 22 Jul 2026 20:34:27 +0800 Subject: [PATCH] fix(rbac): migrate unlabeled tenant resources --- src/reconcile/phases.rs | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/reconcile/phases.rs b/src/reconcile/phases.rs index d3013d6..19f7ab4 100644 --- a/src/reconcile/phases.rs +++ b/src/reconcile/phases.rs @@ -274,13 +274,23 @@ fn operator_resource_owned_by_tenant_or_predecessor( .iter() .any(|owner| owner.controller == Some(true) && !owner_matches_tenant(owner))) }); + let current_owner_matches = tenant.meta().uid.as_ref().is_some_and(|tenant_uid| { + metadata.owner_references.as_ref().is_some_and(|owners| { + owners.iter().any(|owner| { + owner_matches_tenant(owner) && owner.uid.as_str() == tenant_uid.as_str() + }) + }) + }); let legacy_manager_matches = metadata.managed_fields.as_ref().is_some_and(|fields| { fields .iter() .any(|field| field.manager.as_deref() == Some("rustfs-operator")) }); - labels_match && legacy_manager_matches && owner_scope_matches + // Early Operator releases created Tenant resources before common labels were added. An exact + // current Tenant owner UID plus the legacy SSA manager is sufficient provenance for those + // resources, while stale unlabeled resources remain untouched. + legacy_manager_matches && owner_scope_matches && (labels_match || current_owner_matches) } fn security_patch_metadata( @@ -1455,13 +1465,25 @@ mod tests { &tenant )); - let missing_labels = ObjectMeta { + let unlabeled_current_owned = ObjectMeta { owner_references: Some(vec![tenant.new_owner_ref()]), managed_fields: Some(operator_managed_fields()), ..Default::default() }; + assert!(operator_resource_owned_by_tenant_or_predecessor( + &unlabeled_current_owned, + &tenant + )); + + let mut stale_unlabeled_owner = tenant.new_owner_ref(); + stale_unlabeled_owner.uid = "previous-tenant-uid".to_string(); + let unlabeled_stale_owned = ObjectMeta { + owner_references: Some(vec![stale_unlabeled_owner]), + managed_fields: Some(operator_managed_fields()), + ..Default::default() + }; assert!(!operator_resource_owned_by_tenant_or_predecessor( - &missing_labels, + &unlabeled_stale_owned, &tenant ));