feat(s3): implement count_by_tenant so deregistered tenants stay discoverable#362
Merged
Conversation
…overable The tenant-maintenance page discovers tenants from ResourceStorage::count_by_tenant; the S3 backend inherited the empty trait default, so deregistering a tenant without purge made its objects invisible in the UI while they remained in the bucket, purgeable only with direct bucket access. PrefixPerTenant mode: one delimiter LIST enumerates tenant prefixes, then paginated LISTs count each tenant's current-pointer objects under resources/. LIST-only by design — no per-object GETs — so delete tombstones count too: a tombstone is still purgeable data, which is what this count exists to surface. Non-tenant top-level groups (registry, settings, bulk-submit state) have no resources/ subtree and drop out at zero. BucketPerTenant stays unsupported, matching the tenant-registry carve-out for that mode. Covered by a mock-client unit test (history versions don't inflate counts, tombstones count, registered-but-empty tenants don't appear) and a MinIO integration test exercising the SDK delimiter path through a register-seed-deregister flow. Closes #330
Code reviewNo issues found. Checked for bugs and CLAUDE.md compliance. |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
smunini
approved these changes
Jul 23, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #330: the S3 backend inherited
count_by_tenant's empty trait default, so a tenant deregistered without purge vanished from the tenant-maintenance page while its objects (~1.4k seeded conformance resources plus any real data) stayed in the bucket — orphaned, purgeable only with direct bucket access. Found by the #290 browser matrix.Implementation
As sketched in the issue:
CommonPrefixes) enumerates tenant prefixes under the base prefix; paginated LISTs then count each tenant's current-pointer objects underresources/.resources/subtree and drop out at zero.S3Api::list_common_prefixeson both the AWS client (paginatedlist_objects_v2+ delimiter) and the mock.CompositeStorage already delegates
count_by_tenantto its primary, so no changes there.Verification
test_minio_count_by_tenant_survives_deregistration) exercising the real SDK delimiter path through a register → seed → deregister flow. Deliberately named outside thetest_minio_settingsfilter so the conditional-write count guard is untouched.Follow-up
Once this is in a build the browser matrix tests against, the #290 e2e deregister assertion tightens back to expecting the
unregisteredrow on every backend — that change goes on the e2e branch.