[PM-39210] fix: Block converting a Secrets-Manager-enabled org to a Business Unit Portal#7892
Conversation
…usiness Unit Portal BusinessUnitConverter gated org-to-Business-Unit conversion only on Enterprise tier and never checked UseSecretsManager, so a Secrets-Manager-enabled org could be converted. The Password Manager line was then swapped to the Business Unit price and the org's GatewaySubscriptionId nulled, orphaning the Secrets Manager subscription line. Add a UseSecretsManager guard to both validators, mirroring ProviderService, placed before the Stripe GetSubscription call so a disqualified org short-circuits. ValidateInitiationAsync appends a user-facing problem; ValidateFinalizationAsync fails via the existing log-and-throw convention.
🤖 Bitwarden Claude Code ReviewOverall Assessment: APPROVE Reviewed a defensive billing change that blocks converting a Secrets-Manager-enabled organization to a Business Unit Portal. The change adds a Code Review DetailsNo findings. The logic is correct: |
…manager-enabled-org-to-a-business-unit-portal
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #7892 +/- ##
=======================================
Coverage 61.25% 61.25%
=======================================
Files 2222 2222
Lines 98174 98183 +9
Branches 8867 8869 +2
=======================================
+ Hits 60137 60145 +8
- Misses 35918 35919 +1
Partials 2119 2119 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
amorask-bitwarden
left a comment
There was a problem hiding this comment.
These are both valuable validations, but we should prevent the option from showing in the Admin Portal at all if the organization uses Secrets Manager in order to avoid confusion for the end user.
amorask-bitwarden
left a comment
There was a problem hiding this comment.
Looks good - thanks for making that change.
…manager-enabled-org-to-a-business-unit-portal
|



🎟️ Tracking
https://bitwarden.atlassian.net/browse/PM-39210
📔 Objective
Converting an organization to a Business Unit Portal (BUP) is the only existing-org provider-attach path that is both unguarded against Secrets Manager and billing-destructive.
BusinessUnitConvertergated only on Enterprise tier (the tier that carries SM) and never checkedUseSecretsManager, so an SM-enabled org could be converted — after which the Password Manager line is swapped to the BUP price and the org'sGatewaySubscriptionIdis nulled, orphaning the Secrets Manager subscription line. The org could no longer self-serve its SM seat count.This adds a
UseSecretsManagerguard to both validators inBusinessUnitConverter, mirroring the existing precedent inProviderService(ProviderService.cs:447-451):ValidateInitiationAsync— appends a user-facing problem string ("...Please contact Customer Support to convert this organization to a business unit.") to the returned problems list, so the Admin operator sees an actionable message and no provider is created.ValidateFinalizationAsync— fails via the file's existing log-and-throwFail()convention (BillingException), as defense-in-depth.Both guards are placed before the Stripe
GetSubscriptioncall, so a disqualified org short-circuits without a wasted round-trip and well before any destructive mutation.Tests (
BusinessUnitConverterTests.cs):InitiateConversion_OrganizationUsesSecretsManager_ReturnsError— SM-on Enterprise org is blocked; asserts no provider is created.FinalizeConversion_OrganizationUsesSecretsManager_ThrowsBillingException— asserts the throw and thatGetSubscriptionis never called (proving the short-circuit).InitiateConversion_ValidationFails_ReturnsErrorsto setUseSecretsManager = trueon a non-Enterprise org, proving the SM gate is independent of the tier check (the accumulating path)._Succeeds_tests withUseSecretsManager = falseto avoidBitAutoDataflakiness now that the gate exists.Open question for Billing: the guard keys off the
UseSecretsManagerflag (matching theProviderServiceprecedent), so it blocks any SM-enabled org even if there is no actively-billed SM line on the Stripe subscription. This is the safe default; if conversion should be permitted for orgs that have the flag set without a billable SM line, that is a follow-up scoping decision.