* Add email domain validation to OrganizationInviteLink
- Introduced IsEmailDomainAllowed method to check if an email's domain is permitted based on allowed domains.
- Added necessary using directives for MailAddress and domain sanitization utilities.
* Refactor OrganizationInviteLink by removing email domain validation
- Removed the IsEmailDomainAllowed method and associated using directives for MailAddress.
- Cleaned up the code by eliminating unused methods related to email domain validation.
* Add InviteLinkDomainValidator for email domain validation
- Introduced InviteLinkDomainValidator class with IsEmailDomainAllowed method to validate if an email's domain is in the list of allowed domains.
- Utilized MailAddress for email parsing and added domain sanitization logic.
* Add email domain validation endpoint for organization invite links
- Implemented ValidateEmailDomain method in OrganizationInviteLinksController to check if an email's domain is allowed based on the invite link's permitted domains.
- Created OrganizationInviteLinkValidateEmailDomainRequestModel for request validation and OrganizationInviteLinkValidateEmailDomainResponseModel for response formatting.
- Integrated IOrganizationInviteLinkRepository to retrieve invite link details by code.
* Add unit tests for InviteLinkDomainValidator
- Created InviteLinkDomainValidatorTests class to validate email domain functionality.
- Added tests for various scenarios including invalid emails, empty domain lists, and matching domains.
- Ensured comprehensive coverage of the IsEmailDomainAllowed method's behavior.
* Add integration test for email domain validation in OrganizationInviteLinksController
- Implemented a test to validate that an allowed email domain returns the expected result when checked against an organization invite link.
- Ensured the test verifies the creation of an invite link and the subsequent validation of an email domain against the allowed domains list.
* Add validation query and interface for organization invite link email domain
- Introduced ValidateOrganizationInviteLinkEmailDomainQuery class to validate if an email's domain is allowed based on the invite link's permitted domains.
- Created IValidateOrganizationInviteLinkEmailDomainQuery interface to define the validation method.
- Added unit tests for the validation query to ensure correct behavior for various scenarios, including link not found and domain matching.
* Refactor OrganizationInviteLinksController to use validation query for email domain
- Updated ValidateEmailDomain method to utilize IValidateOrganizationInviteLinkEmailDomainQuery for domain validation instead of directly accessing the repository.
- Removed unnecessary repository dependency and streamlined the response handling for validation results.
- Registered the new validation query in OrganizationServiceCollectionExtensions for dependency injection.
* Refactor InviteLinkDomainValidator and replace MailAddress usage with existing email validation method
* test(org-user-request-model): Add model validation tests.
* feat(request-models): Add Authentication and Unlock Data fields with annotations.
* test(recover-command): Add tests for Authentication and Unlock Data payload signature.
* feat(recover-command): Add overload for Authentication and Unlock Data payload signature.
* test(recover-command): Add tests for behavior with authentication and unlock data.
* feat(recover-command): Add impl for hash and key, authentication and unlock data inputs.
* test(org-users-controller): Add controller tests for dispatch.
* feat(org-users-controller): Add controller impl for dispatch for both request payload variants.
* chore: lint.
* fix(request-model): Validation method drifted in base; rename.
* test(request-model): Update validation tests.
* feat(request-model): Support 2FA-only validation at the boundary.
* test(request-model): Express handling of v1 vs v2 requests.
* PM-35394 - Per reviewer's request, mark AdminRecoverAccountCommand.RecoverAccountAsync that doesn't accept new models obselete
* PM-35394 - Fix using directive after model namespace move
Merge from main moved OrganizationUserResetPasswordRequestModel to the
AdminConsole namespace; update the test's using directive to match,
restoring both the build and dotnet format checks.
---------
Co-authored-by: Jared Snider <jsnider@bitwarden.com>
* docs: follow up to #6682 — cover non-Redis L2 support in ExtendedCache
PR #6682 added support for any IDistributedCache (Cosmos, SQL, EF) as the
L2 store under ExtendedCache, but the docs continued to read as Redis-only.
Update CACHING.md to document the new modes, show wiring for pairing with
Cosmos, and explain the backplane / L1-staleness tradeoff.
* docs: address review feedback on non-Redis L2 documentation
- Drop L1/L2 shorthand from decision tree; define vocabulary once in the
ExtendedCache section.
- Fix Option 5 inline comment about the "persistent" keyed cache —
Cosmos in cloud, aliased to the unnamed IDistributedCache in self-hosted.
- Note that ExtendedCache prefixes every key with cacheName: so aliased
consumers cannot collide with the raw "persistent" namespace.
- Pairing-with-Cosmos: clarify that FusionCache writes per-document ttl
(not container TTL) and call out the RU / eager-refresh tradeoff.
- Add a worked Specific Example for ExtendedCache + Cosmos
(Long-Lived Per-Tenant Computed Aggregates).
- Footnote the Configuration Priority table to point at the opt-in
Cosmos pairing path.
* docs: add sizing, throughput, and cost guidance to caching doc
Volume, write rate, and cache size are first-order constraints that gate which
backend can hold a workload — but the prior decision tree silently assumed the
answer fit. Address that:
- New "Sizing, Throughput, and Cost" section after the overview table, covering
working-set size (L1 bounded by heap, L2 ceilings per backend), read rate
(when L1 absorbs vs. becomes overhead), write rate (backplane saturation,
eager-refresh cost), and per-backend cost shape.
- Callout above the decision tree pointing at the new section.
- Decision-tree branches now include sizing/write-rate gates that can override
the API recommendation.
- SSO grants and Org/Provider Abilities "Why" lists now include the size and
rate profile that makes ExtendedCache appropriate there.
- ExtendedCache Cons and "When NOT to Use" expanded with the two main outs:
working sets too large for L1, and sustained-high write rates that saturate
the Redis backplane.
* docs: call out SRE / infrastructure coordination as a prerequisite
Picking a caching option in code is only half of standing up a new cache.
The runtime — Redis sizing, Cosmos provisioning, RU budgets, eviction
policies, monitoring — is owned by SRE and is not stood up by the
AddExtendedCache / AddDistributedCache registrations.
- New "Coordinating with Infrastructure" section after "Sizing, Throughput,
and Cost", covering: loop SRE in early, defaults are not production
configuration, shared infrastructure has unseen tenants, new backends
need provisioning beyond code, and self-hosted environments differ from
cloud.
- Decision-tree preamble now points at both Sizing and Coordinating
with Infrastructure as prerequisites before using the tree.
* chore(deps): remove Node.js community plugin
* refactor(AppHost): integrate web frontend with Aspire JS hosting
* docs(AppHost): update web frontend and Aspire documentation
* feat(AppHost): configure Azurite emulator with persistent data volume
* docs(AppHost): fix ClientsPath description to reference worktrees section
* fix(Apphost): run dotnet format
* feat(admin-console): Add InjectOrganizationAttribute and OrganizationModelBinder for automatic organization parameter binding
* feat(admin-console): Introduce BindOrganizationAttribute and OrganizationModelBinder for organization parameter binding with unit tests
* feat(admin-console): Update GetResetPasswordDetails to use BindOrganization for organization parameter
* fix(admin-console): Correct organization ID check in GetResetPasswordDetails method to use bound organization
* Refactor OrganizationUsersControllerTests to use bound organization in GetResetPasswordDetails method
- Updated test cases to pass the organization directly instead of relying on repository calls.
- Ensured that the tests correctly assert NotFoundException when the organization user does not match the bound organization.
- Improved clarity in test setup by explicitly binding the organization to the method calls.
* Fix UTF-8 BOM issue in BindOrganizationAttribute.cs
* Add integration tests for OrganizationUsersController's BindOrganization functionality
- Introduced OrganizationUsersControllerBindOrganizationTests to validate the behavior of the GET reset-password-details endpoint.
- Implemented tests for successful retrieval of reset password details, handling of non-existent organization users, and cases where the user belongs to a different organization.
- Ensured comprehensive coverage of scenarios to verify correct status responses and organization binding logic.
* refactor(server): move CloudRegion enum from Setup to Core
Decouples CloudRegion from Bit.Setup.Enums so any project consuming
Core can reference it without a circular dependency back into the
Setup utility. Updates the three downstream Setup references
(Context.cs, Program.cs, Setup.csproj) to point at the new
Bit.Core.Enums namespace. Lands as a standalone PR ahead of
PM-35087 (FedRAMP / bitwarden-gov.com) so SHOT can review the
Setup->Core boundary move in isolation.
Refs: PM-38015
* refactor(server): consolidate cloud region config
Introduces Bit.Core.Settings.CloudRegionConfig -- a sealed class with
a static All array (US + EU entries) and FindByDomain/FindByRegion
helpers -- so per-region URLs live in one place. Refactors three
consumers that previously duplicated hardcoded US/EU strings:
Constants.cs derives BitwardenCloudDomains and
BitwardenMobileSsoCallbackUris from CloudRegionConfig.All;
ServiceCollectionExtensions.cs replaces two hardcoded
AddSwaggerServerWithSecurity calls with a foreach;
HandlebarsMailService.GetCloudVaultSubscriptionUrl is widened to
public and switches from a string switch to FindByRegion(). Adding a
new region is now a single entry in CloudRegionConfig.All. We'll be using
this right away to add the Gov region.
Refs: PM-38015
Decouples CloudRegion from Bit.Setup.Enums so any project consuming
Core can reference it without a circular dependency back into the
Setup utility. Updates the three downstream Setup references
(Context.cs, Program.cs, Setup.csproj) to point at the new
Bit.Core.Enums namespace. Lands as a standalone PR ahead of
PM-35087 (FedRAMP / bitwarden-gov.com) so SHOT can review the
Setup->Core boundary move in isolation.
Refs: PM-38015
* feat(admin-console): Add bulk confirmation and pending auto-confirmation methods for organization users
- Implemented ConfirmManyOrganizationUsersAsync to confirm multiple users in a single operation.
- Added GetManyPendingAutoConfirmAsync to retrieve users pending automatic confirmation.
- Created stored procedures for bulk confirmation and fetching pending users.
- Updated relevant repository interfaces and implementations across Dapper and Entity Framework.
* refactor(admin-console): Change parameter type for ConfirmManyOrganizationUsersAsync to IReadOnlyCollection
- Updated the ConfirmManyOrganizationUsersAsync method signature in the IOrganizationUserRepository and its implementations to use IReadOnlyCollection instead of IEnumerable for better performance and clarity.
- Adjusted related repository methods in both Dapper and Entity Framework implementations to reflect this change.
- Added unit tests to ensure the new implementation behaves as expected, including scenarios for mixed batches and idempotency.
* Remove OrganizationUser_ReadByOrganizationIdStatus stored procedure as part of database cleanup.
* Add integration tests for ConfirmManyOrganizationUsers and GetManyPendingAutoConfirm methods
- Introduced ConfirmManyOrganizationUsersTests to validate the confirmation of multiple organization users, ensuring only accepted users are confirmed and idempotency is maintained.
- Added GetManyPendingAutoConfirmTests to verify retrieval of pending auto-confirm users, ensuring only eligible users are returned based on specific criteria.
- Removed duplicate test implementations from OrganizationUserRepositoryTests to maintain clarity and organization in the test suite.
* Implement OrganizationUser_UpdateStatusKey stored procedure and update related repository method
- Added OrganizationUser_UpdateStatusKey stored procedure to handle updating the status and key of organization users based on a JSON input.
- Updated OrganizationUserRepository to call the new stored procedure instead of the previous confirmation procedure.
- Modified OrganizationUser_ReadByPendingAutoConfirm stored procedure to filter users by a new type value.
- Enhanced integration tests to verify the correct behavior of the updated confirmation logic, ensuring revision dates are accurately tracked.
* Refactor OrganizationUser_UpdateStatusKey to OrganizationUser_UpdateManyStatusKey
- Renamed the stored procedure to OrganizationUser_UpdateManyStatusKey to better reflect its functionality of updating multiple organization users' statuses.
- Updated the OrganizationUserRepository to call the new stored procedure.
- Adjusted the migration script to create or alter the procedure accordingly.
* Update data type for Key column in AddOrganizationUserUpdateStatusKey migration script
- Changed the data type of the Key column from NVARCHAR(MAX) to VARCHAR(MAX) in the UsersToUpdate table and the corresponding JSON parsing logic to improve compatibility and performance.
* Updated spacing
* Add stored procedures for organization user status updates and retrieval
- Created OrganizationUser_UpdateManyStatusKey to update multiple organization users' statuses based on a JSON input, including handling revision dates and tracking updated IDs for idempotency.
- Added OrganizationUser_ReadByPendingAutoConfirm to retrieve organization users pending auto-confirmation based on organization ID and specific status and type filters.
---------
Co-authored-by: mkincaid-bw <mkincaid@bitwarden.com>
feat: add ChangeEmailCommand [PM-35830]
- Add ChangeEmailCommand to encapsulate core email change logic
- Add OrganizationDomainAllowEmailChangeQuery returning OrganizationDomainAllowEmailChangeDenialReason enum so callers can branch on the specific denial reason, if any
- Surface tailored BadRequestException messages per denial reason via a switch expression that fails closed on unknown values
- Push sync-only notification (no logout)
- Add unit tests covering denial reasons, domain case invariance, and the null-customerId-with-gateway path
* fix(billing): guard US customers from missing tax ID warning when automatic tax flag is enabled
US has no customer-facing VAT/Tax ID equivalent, so the warning should never appear for US customers regardless of the PM37597 flag state.
* fix(billing): fix provider warnings test asserting buggy US tax ID warning behavior
* Implement UpdateCollectionManagementSettingsCommand and associated interface for managing organization collection settings
* Add UpdateCollectionManagementSettingsCommand to handle updates to organization collection management settings.
* Create IUpdateCollectionManagementSettingsCommand interface to define the update method.
* Implement unit tests for UpdateCollectionManagementSettingsCommand to verify event logging and exception handling.
* Add IUpdateCollectionManagementSettingsCommand to service collection
* Register IUpdateCollectionManagementSettingsCommand and its implementation, UpdateCollectionManagementSettingsCommand, in the service collection for managing organization collection settings.
* Rename command
* Update OrganizationsController to use IOrganizationUpdateCollectionManagementCommand
* Added IOrganizationUpdateCollectionManagementCommand to the OrganizationsController for managing collection settings updates.
* Updated the constructor to inject the new command and modified the PutCollectionManagement method to utilize it.
* Adjusted unit tests to reflect the changes in the command used for updating collection management settings.
* Refactor IOrganizationService and OrganizationService to remove UpdateCollectionManagementSettingsAsync method
* Removed the UpdateCollectionManagementSettingsAsync method from IOrganizationService and its implementation in OrganizationService.
* Cleaned up unused usings related to collection management settings in both service files.
* Updated unit tests to reflect the removal of the collection management settings update functionality.
* feat(billing): add Organization.ChangePlan extension for structural plan shape
Pure helper that writes plan-derived structural columns (PlanType, Plan,
Use* capability flags, UsersGetPremium, MaxCollections) without touching
customer-purchase columns. Preserves the existing UseKeyConnector carve-out.
Behavior-preserving extraction of the field-copy block at lines 287-310
of UpgradeOrganizationPlanCommand.UpgradePlanAsync.
* refactor(billing): use Organization.ChangePlan in UpgradePlanAsync
Replaces the inline structural field-copy block with a call to the new
ChangePlan helper. Customer-purchase columns (Seats, MaxStorageGb,
Enabled, UseSecretsManager) and the PremiumAccessAddon override on
UsersGetPremium stay inline at the call site. Behavior-preserving.
* feat(billing): register Teams 2020 -> current migration paths
Appends Teams2020AnnualToCurrent (byte 3) and Teams2020MonthlyToCurrent
(byte 4) to MigrationPathId and the MigrationPaths registry. Required for
the business migration handler to resolve cohorts mapped to Teams source
plans; without these entries MigrationPaths.FromId returns null and the
handler no-ops on Teams orgs in Cohort A1. Snapshot tests updated.
* chore(billing): inject migration cohort repositories into SubscriptionUpdatedHandler
Adds IOrganizationPlanMigrationCohortRepository and
IOrganizationPlanMigrationCohortAssignmentRepository as constructor
dependencies in preparation for HandleScheduleTriggeredBusinessMigrationAsync.
No behavior change.
* feat(billing): scaffold business plan Phase-2 migration handler
Adds HandleScheduleTriggeredBusinessMigrationAsync as a sibling call in
HandleAsync's organization branch, gated on PM35215_BusinessPlanPriceMigration.
Initial implementation short-circuits when ScheduleId is null. Locks the
no-op behaviour with NoScheduleId + FeatureFlagOff tests. Full handler body
lands in subsequent commits.
* feat(billing): gate business migration handler on registered source price IDs
Builds the source-price allowlist from MigrationPaths.All, using the
seat-vs-non-seat pattern (HasNonSeatBasedPasswordManagerPlan). All four
Track A 2020 plans register automatically. Skips when the previous
subscription items don't include any registered 2020 source price.
* feat(billing): resolve cohort via assignment row for business migration handler
Reads assignment by organization id (DB is source of truth), then resolves
the cohort and migration path. Stripe subscription.Metadata['migration_cohort_id']
remains stamped by PriceIncreaseScheduler for dashboard attribution but is
not consulted by the handler. Skips with a warning when the assignment is
missing, the cohort is missing, or MigrationPathId references an unregistered
path. Idempotent: skips with info-level log when assignment.MigratedDate is
already set, before any further DB reads.
* feat(billing): defensive target-price sanity check for business migration
After resolving the target plan from cohort.MigrationPath.ToPlan, verifies
the current subscription items contain the target's PM price ID (seat-aware).
Skips with a warning on mismatch to protect against operator data errors or
off-path schedule transitions.
* feat(billing): apply plan shape and mark assignment migrated on Phase 2
Completes HandleScheduleTriggeredBusinessMigrationAsync: loads the org,
calls Organization.ChangePlan(targetPlan), persists via ReplaceAsync, and
sets assignment.MigratedDate + RevisionDate before persisting the
assignment. Happy-path coverage for all four Track A pairs (Teams +
Enterprise, monthly + annual). Teams tests assert the UseScim flip - the
load-bearing capability gain for Teams 2020 -> current.
* Add more unit test
* fix: add UTF-8 BOM to .cs files for editorconfig charset compliance
* Add exception handle
* Code refactoring
* Add more unit testing
* Resolve the pr comment
* feat(billing): introduce unified subscription price increase scheduler API
* feat(billing): implement unified subscription price increase scheduler logic
* refactor(billing): update subscription handlers to use unified scheduler
* feat(billing): extend price migration feature flag checks
* test(billing): add and update tests for unified price increase scheduler
* fix(billing): run dotnet format
* feat(billing): expand customer and customer.discount on subscription fetch
* refactor(ReinstateSubscriptionCommandTests): rename test method for broader scope
* feat(billing): expand customer.discount in update handler
* test(billing): update test name
* feat(billing): add test clock waiting mechanism for upcoming invoices
* feat(billing): introduce cancelling user ID metadata key
* feat(billing): store cancelling user ID on subscription cancellation
* feat(billing): clear cancelling user ID on subscription reinstatement
* test(billing): update subscriber service tests for cancelling user ID
* style(SubscriberService): use 'is not null' pattern matching
* feat(SubscriberService): add PM35215 migration cohort metadata handling
* feat(SubscriberService): extend price migration deferral to PM35215
* test(SubscriberService): add and update tests for PM35215 feature
* feat(billing): Introduce OrganizationPriceIncreaseOptions
* refactor(billing): Centralize price increase eligibility in scheduler
* refactor(billing): Delegate price increase validation from UpcomingInvoiceHandler
* feat(billing): Manage price increase schedules during subscription lifecycle events
* test(billing): Update UpcomingInvoiceHandlerTests for centralized validation
* test(billing): Add PriceIncreaseScheduler tests for SkipIfAlreadyScheduled option
* test(billing): Add SubscriberService tests for price increase schedule management
* fix(billing): run dotnet format
* fix(billing): remove redundant customer expansion
* fix(billing): expand discounts for customer and subscription
* refactor(billing): Rename method to clarify dispatching role for organization scheduling
* fix(billing): Prevent clearing migration cohort metadata on cancellation
* fix(billing): Fallback to standard email when price increase migration fails
* feat(billing): improve observability for missing migration path data
* refactor(billing): simplify business plan type identification
Mirror the existing codecov.io upload to GitHub's new code coverage
feature (public preview, announced 2026-05-26) so coverage shows up
directly on pull requests. Merges per-project Cobertura files with
dotnet-coverage before upload.
* Implementation desktop and browser checkout
* Fixed the failing test
* Add a logger to see gobal settings in qa
* Add log
* fix the lint error
* Removed the log
* added event type and control flow
* add EventType, control flow, and test coverage
* fix failing test and de-dupe enums
* access event log traps on auth and anon endpoints
* prioritize FF check in conditional statements
* Refactor InitPendingOrganizationValidator to remove IPolicyService dependency and replace with IPolicyRequirementQuery for policy checks. Update related tests to reflect changes in policy validation logic.
* Refactor AccountsController and related validators to replace IPolicyService with IPolicyRequirementQuery for policy checks. Update tests accordingly to reflect changes in policy validation logic.
* Remove IPolicyService and related implementations from the codebase, updating PolicyServiceCollectionExtensions and deleting associated tests. This change streamlines policy management by relying on IPolicyRequirementQuery for policy checks.
* Refactor OrganizationUserRepository to remove GetByUserIdWithPolicyDetailsAsync method and associated tests.
* Remove unused stored procedures: OrganizationUser_ReadByUserIdWithPolicyDetails and PolicyDetails_ReadByUserId, as they are no longer called in the codebase.
* Remove OrganizationUserPolicyDetails class and associated test fixtures, as they are no longer needed in the codebase.
* Refactor BaseRequestValidatorTests to replace IPolicyService with IPolicyRequirementQuery for SSO validation checks. Update related test logic to ensure accurate policy validation outcomes. Clean up unused test fixtures in PolicyFixtures.cs to streamline the codebase.
* Refactor BaseRequestValidator and SsoRequestValidator to improve readability by storing policy requirement results in local variables before returning values. This change enhances code clarity while maintaining existing functionality.
* Refactor AccountsController to improve clarity by storing the result of the policy requirement query in a local variable before returning the enforced options. This change enhances code readability while preserving existing functionality.
* Revert "Remove unused stored procedures: OrganizationUser_ReadByUserIdWithPolicyDetails and PolicyDetails_ReadByUserId, as they are no longer called in the codebase."
This reverts commit 0f4fdca6e7.
* [PM-37083] feat: Add per-phase price resolution to UpdateOrganizationSubscriptionCommand
Resolve source vs. target plan pricing per schedule phase so item changes
target the correct phase-specific price ID. Move cohort metadata onto the
schedule phases themselves to avoid Stripe normalization triggered by
direct subscription metadata updates. Filter the schedule-aware update
path to phases where EndDate > now, and drop the feature-flag gate on
PriceIncreaseScheduler.Release so schedule existence is the gate.
* Add defensive guard for source-priced single-phase migration schedules
* Implement GetOrganizationInviteLinkStatusQuery to retrieve invite link status
- Added GetOrganizationInviteLinkStatusQuery class to handle fetching the status of an organization invite link based on its code.
- Introduced OrganizationInviteLinkStatus and OrganizationInviteLinkSsoStatus records to encapsulate the invite link status and SSO information.
- Created IGetOrganizationInviteLinkStatusQuery interface to define the contract for the query implementation.
* Add unit tests for GetOrganizationInviteLinkStatusQuery
- Introduced comprehensive unit tests for GetOrganizationInviteLinkStatusQuery to validate various scenarios including successful retrieval of invite link status, handling of not found errors, and seat availability checks.
- Utilized Xunit and NSubstitute for testing and mocking dependencies, ensuring robust coverage of the query's functionality.
* Add IGetOrganizationInviteLinkStatusQuery to service collection
- Registered IGetOrganizationInviteLinkStatusQuery with the service collection to enable retrieval of organization invite link status.
- This addition supports the recently implemented GetOrganizationInviteLinkStatusQuery functionality.
* Add OrganizationInviteLinksPublicController and response models
- Introduced OrganizationInviteLinksPublicController to handle requests for organization invite link status.
- Implemented GetStatus endpoint to retrieve the status of an invite link using its GUID code.
- Added OrganizationInviteLinkStatusResponseModel and OrganizationInviteLinkSsoResponseModel to structure the response data for the invite link status.
- Ensured the endpoint is accessible to anonymous users while requiring application authorization for other actions.
* Add integration tests for OrganizationInviteLinksPublicController
- Introduced integration tests for OrganizationInviteLinksPublicController to validate the GetStatus endpoint functionality.
- Implemented tests to ensure correct handling of existing invite links and appropriate responses for valid and not found scenarios.
- Utilized Xunit and NSubstitute for testing and mocking dependencies, enhancing test coverage for invite link status retrieval.
* Updated GetOrganizationInviteLinkStatusQuery to return SSO status based on organization settings, including UseSso and UsePolicies
* Move status endpoint into OrganizationInviteLinksController as POST
* Refactor OrganizationInviteLinkStatusResponseModel and OrganizationInviteLinkStatus to remove OrganizationId property
- Removed OrganizationId property from both OrganizationInviteLinkStatusResponseModel and OrganizationInviteLinkStatus records to streamline the data model.
- Updated constructors accordingly to reflect the changes in the response models.
* Refactor GetOrganizationInviteLinkStatusQuery to simplify organization checks
- Updated the logic in GetOrganizationInviteLinkStatusQuery to streamline organization validation by combining null and enabled checks.
- Removed the dependency on IApplicationCacheService and adjusted the seat availability logic to enhance clarity and efficiency.
- Modified the return statement to use organization name directly instead of organization ID.
* Add integration tests for OrganizationInviteLinksController
- Introduced a new test method to validate the GetStatus functionality for existing invite links in OrganizationInviteLinksControllerTests.
- Enhanced existing tests to ensure correct responses for valid and not found scenarios.
- Removed OrganizationInviteLinksPublicControllerTests as its functionality is now covered in the OrganizationInviteLinksControllerTests.
* Refactor OrganizationInviteLinksControllerTests
- Updated test methods in OrganizationInviteLinksControllerTests to utilize GetOrganizationInviteLinkStatusRequestModel instead of individual parameters.
- Added a new test case to handle scenarios where the invite link status is not available, returning a BadRequest response.
- Enhanced existing tests to ensure consistent handling of valid and not found scenarios.
* Update GetOrganizationInviteLinkStatusQueryTests to enable organization for invite link tests
* [PM-36949] Add OrganizationPlanMigrationCohort schema and Core domain types
Add the foundation for cohort-based plan migrations:
- Two tables: OrganizationPlanMigrationCohort and OrganizationPlanMigrationCohortAssignment
- Two views and nine stored procedures (four CRUD on cohort, four CRUD plus
ReadByOrganizationId on assignment)
- Single Migrator script for MSSQL deployment
- Core entities, MigrationPath value object and its registry, and bare repository
interfaces under Bit.Core.Billing.Organizations.PlanMigration
The cohort table holds the human-managed metadata (name, discount coupons,
MigrationPathId byte) and the assignment table records each organization's
position in the migration lifecycle (scheduled, migrated, churn-mitigated).
Both Update SPs follow the accept-but-don't-assign pattern: immutable columns
(OrganizationId, CohortId, CreatedAt) are parameters but not SET clauses.
* [PM-36949] Add Dapper repositories for plan migration cohort tables
OrganizationPlanMigrationCohortRepository inherits the base Repository<T, TId>
CRUD methods unchanged. OrganizationPlanMigrationCohortAssignmentRepository
also relies on the base for CRUD and adds GetByOrganizationIdAsync which
returns at most one row (the UNIQUE constraint on OrganizationId at the
database layer guarantees this).
* [PM-36949] Add EF Core configurations, repositories, and provider migrations for plan migration cohort tables
- EF models wrap the Core entities; the assignment model exposes nav properties
for Organization and Cohort so the FK + cascade-delete is inferred by EF.
- EntityTypeConfiguration classes pin ID generation to application code
(ValueGeneratedNever) and declare the UNIQUE indexes plus the composite
(CohortId, ScheduledAt, MigratedAt) index.
- Repositories follow the OrganizationInstallationRepository template; the
assignment repo adds GetByOrganizationIdAsync to mirror the SP exposed on
the MSSQL side.
- DatabaseContext gets two DbSet properties; auto-discovery picks up the
configuration classes.
- Generated migrations for MySQL, Postgres, and SQLite create matching schemas;
EF truncates FK and index names on providers with 64-char identifier limits,
which is consistent with the rest of the codebase.
* [PM-36949] Wire up DI and add tests for plan migration cohort repositories
Register both Dapper and EF Core repositories in their respective service
collection extensions, following the existing AddSingleton convention in
these files.
Add tests:
- MigrationPathIdsSnapshotTests guards the immortal byte IDs that downstream
code pins on. The class- and method-level comments document why these
values can never be renumbered.
- MigrationPathTests covers the FromId round-trip and the null-on-unknown
behavior the registry promises to callers.
- OrganizationPlanMigrationCohortRepositoryTests exercises CRUD, the UNIQUE
Name constraint, and verifies that ReplaceAsync ignores CreatedAt
mutations (per the accept-but-don't-assign Update SP).
- OrganizationPlanMigrationCohortAssignmentRepositoryTests exercises CRUD,
GetByOrganizationIdAsync, the UNIQUE OrganizationId constraint,
cascade-delete from both Organization and Cohort, and verifies that
ReplaceAsync ignores OrganizationId, CohortId, and CreatedAt mutations.
* [PM-36949] Use PlanType and MigrationPathId enums on MigrationPath
Replace the byte Id with a byte-backed MigrationPathId enum and replace
the string FromPlan/ToPlan fields with PlanType. Persistence is
unchanged -- EF normalises enum-backed properties to their underlying
type in the model snapshot, and Dapper handles enum-to-byte parameter
mapping automatically.
* [PM-36949] Add *.lscache to .gitignore
* [PM-36949] fix: Override ReplaceAsync on EF cohort repositories for immutability parity
The Dapper _Update SPs accept-but-don't-assign certain columns (CreatedAt
on cohort; OrganizationId, CohortId, and CreatedAt on assignment), but
the base EF Repository<T,TEntity,Guid>.ReplaceAsync uses SetValues which
writes every scalar. Override on both repos and mark the immutable
properties as IsModified = false so MySQL/Postgres/Sqlite match MSSQL
behavior. Mirrors the existing DeviceRepository.ReplaceAsync pattern.
* [PM-36949] fix: Bound cohort string columns and widen Name to 255 chars
Add [MaxLength] attributes to the three cohort string properties so the
EF providers (MySQL/Postgres/Sqlite) enforce the same limits as MSSQL,
where the columns were already NVARCHAR-capped. Widen Name from 64 to
255 chars across MSSQL DDL, both _Create/_Update SP signatures, the
Migrator script, the entity, and all three regenerated EF migrations.
Coupon codes stay at 64 (Stripe IDs are short).
* [PM-36949] test: Lock FromPlan and ToPlan per MigrationPath
The snapshot test class doc says "byte N means a specific FromPlan ->
ToPlan transition forever", but only the byte value was being asserted.
A silent refactor of the registry's PlanType references would not have
been caught. Add per-path FromPlan/ToPlan assertions to close the gap.
* [PM-36949] chore: Apply dotnet format
* [PM-36949] test: Use LaxDateTimeComparer for round-tripped DateTimes
Postgres timestamp and MySQL datetime(6) store microsecond precision (6
fractional digits), but .NET DateTime is 100ns ticks (7 digits). Exact
Assert.Equal fails by a single tick on round-trip. Switch the three
DateTime comparisons in ReplaceAsync_UpdatesMutableColumns_AndIgnoresImmutableOnes
to LaxDateTimeComparer.Default -- the same 2ms-tolerance comparer used
by SendRepositoryTests and InstallationRepositoryTests for the same
precision issue.
* Add implementation for dropdown
* Reconcile dropdown work with renamed PM-36949 schema
After merging origin/main, the cohort schema now uses *Date suffixes
(ScheduledDate / MigratedDate / ChurnDiscountAppliedDate / CreationDate).
Rename references in the dropdown work, restore IsLocked() on the merged
entity, and re-add GetManyAsync() to the cohort repository (interface +
Dapper + EF) since the merge took main's pre-dropdown versions.
Also remove the six superseded provider migration files (20260515*) -- the
20260518* renames from origin/main are now the only cohort migrations.
* Fix UTF-8 BOM on cohort assignment unit test file
* Resolve the FF and permission issue
* Extract migration cohort resolution into a helper
Addresses PR feedback to keep the Edit action focused: the cohort
resolution/validation now lives in ResolveMigrationCohortAssignmentChangeAsync
and returns a MigrationCohortAssignmentChange record. The endpoint still
owns the page return.
---------
Co-authored-by: Alex Morask <amorask@bitwarden.com>
Co-authored-by: Alex Morask <144709477+amorask-bitwarden@users.noreply.github.com>
* feat(kdf-settings-validator): Enforce salt cannot be empty string.
* fix(kdf-settings-validator): Prefer IsNullOrWhitespace.
* feat(salt): Make AllowEmptyStrings false for request models.
* Send.Key and Send.Data NOT NULL
* backfill EF providers with empty strings for NULL Data or Key values
* update migration names to match current date