Skip to content

feat: Add shared-bucket multitenancy support for OSS attachments#767

Draft
Schmarvinius wants to merge 6 commits intomainfrom
feat/mt-shared-bucket
Draft

feat: Add shared-bucket multitenancy support for OSS attachments#767
Schmarvinius wants to merge 6 commits intomainfrom
feat/mt-shared-bucket

Conversation

@Schmarvinius
Copy link
Copy Markdown
Collaborator

Description:

Summary

  • Tenant-prefixed object keys ({tenantId}/{contentId}) for shared-bucket mode across AWS, Azure, and GCP
  • deleteContentByPrefix on all OSClient implementations for tenant cleanup on unsubscribe
  • Input validation for tenantId and contentId to prevent path traversal
  • Google Cloud: fixed N+1 list query in prefix deletion (single call with versions(true))
  • AWS: partial failure logging for batch deletes
  • Azure: parallel deletion using executor

Test plan

  • 9 integration tests in MultiTenantIsolationTest (tenant isolation, path traversal, null tenant)
  • Unit tests for all three client implementations (pagination, versioning, error handling)
  • TenantCleanupHandler and Registration tests for wiring
  • All 449 tests pass (378 core + 71 OSS)

@hyperspace-insights
Copy link
Copy Markdown
Contributor

Summary

The following content is AI-generated and provides a summary of the pull request:


Add Shared-Bucket Multitenancy Support for OSS Attachments

New Features

✨ Introduces shared-bucket multitenancy support for the OSS attachments feature across AWS S3, Azure Blob Storage, and Google Cloud Storage. In shared mode, object keys are prefixed with {tenantId}/{contentId} to provide logical tenant isolation within a single bucket. A new TenantCleanupHandler automatically removes all tenant data when a tenant unsubscribes.

Key additions:

  • Tenant-prefixed object keys in shared mode for all CRUD operations
  • Input validation for tenant IDs and content IDs to prevent path traversal attacks
  • deleteContentByPrefix on all three OSClient implementations for bulk tenant data cleanup
  • TenantCleanupHandler wired to the DeploymentService unsubscribe event

Changes

  • OSClient.java: Added deleteContentByPrefix(String prefix) as a default method (throws UnsupportedOperationException if not overridden).
  • AWSClient.java: Implemented deleteContentByPrefix with paginated listObjectsV2 + batch deleteObjects, with warning logs for partial failures.
  • AzureClient.java: Implemented deleteContentByPrefix using listBlobs with prefix filtering and parallel deletion via the executor.
  • GoogleClient.java: Implemented deleteContentByPrefix using a single storage.list call with versions(true) to avoid N+1 queries, deleting each blob by generation.
  • OSSAttachmentsServiceHandler.java: Added multitenancyEnabled and objectStoreKind fields; introduced buildObjectKey, getTenant, validateTenantId, and validateContentId helpers; updated all attachment operations to use the computed object key in shared mode. Constructor signature updated accordingly.
  • TenantCleanupHandler.java (new): Event handler that listens to EVENT_UNSUBSCRIBE and calls deleteContentByPrefix to clean up all objects for the unsubscribing tenant.
  • Registration.java: Updated to read cds.multitenancy.enabled and cds.attachments.objectStore.kind from the environment; registers TenantCleanupHandler when shared multitenancy mode is active. Fixed Javadoc typo ("filesystem" → "object store").
  • MultiTenantIsolationTest.java (new): 9 integration-level tests verifying complete tenant isolation, cross-tenant access prevention, null tenant enforcement, and path traversal blocking.
  • TenantCleanupHandlerTest.java (new): Unit tests for TenantCleanupHandler covering correct prefix usage, exception handling, and interrupt handling.
  • OSSAttachmentsServiceHandlerTest.java: Extended with multitenancy unit tests covering shared-mode key prefixing, non-MT mode backward compatibility, null tenant rejection, and all three attachment operations in shared mode. Added tenant ID validation tests.
  • AWSClientTest.java, AzureClientTest.java, GoogleClientTest.java: Added unit tests for deleteContentByPrefix covering pagination, versioning, empty results, and error cases.
  • RegistrationTest.java: Added tests for shared-mode handler registration, non-MT mode (no cleanup handler), and config propagation.
  • OSClientTest.java (new): Verifies the default deleteContentByPrefix method throws UnsupportedOperationException.
  • OSSAttachmentsServiceHandlerTestUtils.java: Updated constructor call to pass false, null for MT parameters.

  • 🔄 Regenerate and Update Summary
  • ✏️ Insert as PR Description (deletes this comment)
  • 🗑️ Delete comment
PR Bot Information

Version: 1.19.3 | 📖 Documentation | 🚨 Create Incident | 💬 Feedback

  • Event Trigger: pull_request.opened
  • Summary Prompt: Default Prompt
  • Correlation ID: f7afc630-2b61-11f1-9530-36fd128ef1d9
  • Output Template: Default Template
  • LLM: anthropic--claude-4.6-sonnet

💌 Have ideas or want to contribute? Create an issue and share your thoughts with us!
📑 Check out the documentation for more information.
📬 Subscribe to the Hyperspace PR Bot DL to get the latest announcements and pilot features!

Made with ❤️ by Hyperspace.

Copy link
Copy Markdown
Contributor

@hyperspace-insights hyperspace-insights bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR introduces solid multi-tenancy support with good test coverage, but has several correctness issues that need addressing: a null tenant ID in TenantCleanupHandler that silently mutates into a "null/" prefix, a swallowed InterruptedException in the Azure client's parallel delete loop, partial S3 deletion failures that are logged but treated as success, a dead-code/confusing fallback in getTenant, and a leaked ExecutorService with no shutdown lifecycle in Registration.

PR Bot Information

Version: 1.19.3 | 📖 Documentation | 🚨 Create Incident | 💬 Feedback

  • LLM: anthropic--claude-4.6-sonnet
  • Event Trigger: pull_request.opened
  • Correlation ID: f7afc630-2b61-11f1-9530-36fd128ef1d9

@Schmarvinius Schmarvinius changed the title feat: Add shared-bucket multitenancy support for OSS attachments EXPERIMENT: feat: Add shared-bucket multitenancy support for OSS attachments Mar 29, 2026
@Schmarvinius Schmarvinius self-assigned this Mar 30, 2026
@Schmarvinius Schmarvinius requested review from a team and removed request for a team March 30, 2026 07:31
@Schmarvinius Schmarvinius removed their assignment Mar 30, 2026
@Schmarvinius
Copy link
Copy Markdown
Collaborator Author

Tested locally and it looks good

@Schmarvinius
Copy link
Copy Markdown
Collaborator Author

Schmarvinius commented Mar 30, 2026

Next up:

  • ITests
  • Test out deployed

@Schmarvinius Schmarvinius changed the title EXPERIMENT: feat: Add shared-bucket multitenancy support for OSS attachments feat: Add shared-bucket multitenancy support for OSS attachments Mar 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant