Skip to content

[PM-25520] - Adding a transaction for mutliple repo calls#7555

Draft
jrmccannon wants to merge 12 commits intomainfrom
jmccannon/ac/poc-transaction
Draft

[PM-25520] - Adding a transaction for mutliple repo calls#7555
jrmccannon wants to merge 12 commits intomainfrom
jmccannon/ac/poc-transaction

Conversation

@jrmccannon
Copy link
Copy Markdown
Contributor

@jrmccannon jrmccannon commented Apr 27, 2026

🎟️ Tracking

PM-25520

📔 Objective

Adding a transaction around subsequent repo calls.

📸 Screenshots

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 27, 2026

Codecov Report

❌ Patch coverage is 52.88754% with 155 lines in your changes missing coverage. Please review.
✅ Project coverage is 14.73%. Comparing base (28bd286) to head (4c4ed74).
⚠️ Report is 9 commits behind head on main.

Files with missing lines Patch % Lines
src/Core/Platform/Data/TransactionState.cs 6.45% 29 Missing ⚠️
...cture.EntityFramework/Data/EfTransactionManager.cs 0.00% 28 Missing ⚠️
src/Core/Platform/Data/RootTransactionScope.cs 0.00% 24 Missing ⚠️
...astructure.Dapper/Data/DapperTransactionManager.cs 0.00% 22 Missing ⚠️
src/Core/Platform/Data/NestedTransactionScope.cs 0.00% 19 Missing ⚠️
...ructure.EntityFramework/Repositories/Repository.cs 38.09% 13 Missing ⚠️
...work/Repositories/BaseEntityFrameworkRepository.cs 76.92% 3 Missing and 3 partials ⚠️
...Console/Repositories/OrganizationUserRepository.cs 88.88% 4 Missing ⚠️
...frastructure.Dapper/Repositories/BaseRepository.cs 89.47% 2 Missing and 2 partials ⚠️
...er/AdminConsole/Repositories/ProviderRepository.cs 0.00% 3 Missing ⚠️
... and 2 more
Additional details and impacted files
@@             Coverage Diff             @@
##             main    #7555       +/-   ##
===========================================
- Coverage   59.50%   14.73%   -44.77%     
===========================================
  Files        2089     1296      -793     
  Lines       92421    56254    -36167     
  Branches     8214     4376     -3838     
===========================================
- Hits        54994     8289    -46705     
- Misses      35484    47819    +12335     
+ Partials     1943      146     -1797     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 28, 2026

Logo
Checkmarx One – Scan Summary & Details6c8e5418-0c83-477c-9bb1-014fe400bb43


New Issues (2) Checkmarx found the following issues in this Pull Request
# Severity Issue Source File / Package Checkmarx Insight
1 MEDIUM CSRF src/Api/Vault/Controllers/CiphersController.cs: 1558
detailsMethod at line 1558 of /src/Api/Vault/Controllers/CiphersController.cs gets a parameter from a user request from id. This parameter value flows ...
Attack Vector
2 MEDIUM CSRF src/Api/Vault/Controllers/CiphersController.cs: 1385
detailsMethod at line 1385 of /src/Api/Vault/Controllers/CiphersController.cs gets a parameter from a user request from id. This parameter value flows ...
Attack Vector

Fixed Issues (27) Great job! The following issues were fixed in this Pull Request
Severity Issue Source File / Package
MEDIUM CSRF src/Api/AdminConsole/Controllers/OrganizationUsersController.cs: 514
MEDIUM CSRF src/Api/Billing/Controllers/VNext/AccountBillingVNextController.cs: 55
MEDIUM CSRF src/Api/KeyManagement/Controllers/AccountsKeyManagementController.cs: 145
MEDIUM CSRF src/Api/KeyManagement/Controllers/AccountsKeyManagementController.cs: 97
MEDIUM CSRF src/Api/KeyManagement/Controllers/AccountsKeyManagementController.cs: 229
MEDIUM CSRF src/Api/Tools/Controllers/SendsController.cs: 73
MEDIUM CSRF src/Api/Billing/Controllers/VNext/AccountBillingVNextController.cs: 145
MEDIUM CSRF src/Identity/Controllers/AccountsController.cs: 138
MEDIUM CSRF src/Api/Auth/Controllers/AccountsController.cs: 217
MEDIUM CSRF src/Api/KeyManagement/Controllers/AccountsKeyManagementController.cs: 173
MEDIUM CSRF src/Api/Billing/Controllers/VNext/AccountBillingVNextController.cs: 104
MEDIUM CSRF src/Api/Billing/Controllers/VNext/OrganizationBillingVNextController.cs: 107
MEDIUM CSRF src/Api/Billing/Controllers/VNext/OrganizationBillingVNextController.cs: 95
MEDIUM CSRF src/Api/Billing/Controllers/VNext/ProviderBillingVNextController.cs: 82
MEDIUM CSRF src/Api/Billing/Controllers/VNext/AccountBillingVNextController.cs: 93
MEDIUM CSRF src/Api/Billing/Controllers/VNext/OrganizationBillingVNextController.cs: 49
MEDIUM CSRF src/Api/Billing/Controllers/VNext/ProviderBillingVNextController.cs: 40
MEDIUM CSRF src/Api/KeyManagement/Controllers/AccountsKeyManagementController.cs: 173
MEDIUM CSRF src/Api/Auth/Controllers/AccountsController.cs: 721
MEDIUM CSRF src/Api/Auth/Controllers/AccountsController.cs: 412
MEDIUM CSRF src/Api/Auth/Controllers/AccountsController.cs: 192
MEDIUM CSRF src/Api/Auth/Controllers/AccountsController.cs: 126
MEDIUM CSRF src/Api/Auth/Controllers/AccountsController.cs: 664
MEDIUM CSRF src/Api/Auth/Controllers/AccountsController.cs: 641
MEDIUM CSRF src/Api/Auth/Controllers/EmergencyAccessController.cs: 173
MEDIUM CSRF src/Api/Auth/Controllers/AccountsController.cs: 385
MEDIUM CSRF src/Api/Auth/Controllers/AccountsController.cs: 558

@jrmccannon
Copy link
Copy Markdown
Contributor Author

Test is failing due to the fact that its creating a SqlServerTestDatabase and it won't be able to pull the connection string to do so. Unsure of how to proceed with this.

Do we want to add a SQL server db for this test or just skip it in CI?

@eliykat @justindbaur

@eliykat
Copy link
Copy Markdown
Member

eliykat commented Apr 30, 2026

Test is failing due to the fact that its creating a SqlServerTestDatabase and it won't be able to pull the connection string to do so. Unsure of how to proceed with this.

Do we want to add a SQL server db for this test or just skip it in CI?

We definitely don't want to skip it in CI, or it'll never be run in practice.

The CI job does set up and connect to SQL server, e.g. https://github.com/bitwarden/server/blob/master/.github/workflows/test-database.yml#L131-L132.

I assume your issue is caused by the DapperTransactionManager getting its connection string from GlobalSettings. Have a look at how DatabaseDataAttribute works - it injects the integration test database strings into the repository implementations during tests, maybe you can do a similar thing here.

@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented May 4, 2026

Copy link
Copy Markdown
Contributor

@mzieniukbw mzieniukbw left a comment

Choose a reason for hiding this comment

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

Nice, i love the direction. There is a bit duplication between EF and Dapper, but generally good direction in my opinion.

Guid organizationId,
ScimProviderType scimProvider)
{
await using var transactionScope = await transactionManager.BeginTransactionAsync(IsolationLevel.Serializable);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Serializable transaction isolation is the strictest you can get, but it have side effects compared to default, like it can throw error if there was a concurrent write (in different transaciton). Is this by choice here ?
On a side note, this changes the business logic, which i wonder, whether this PR should do.

In most cases this transaction isolation is unnecessary, in which case, it is better to begin the transaction just before the first write, not during the get.

One important note, the copy paste code trend is unavoidable and we will see other places using this isolation level for no reason, just because it was used somewhere else. If we would use serializable isolation level by choice here, i think a reasonable comment should be added explaining why it might be needed here.

@bitwarden/dept-dbops Opinions ?

Copy link
Copy Markdown
Contributor Author

@jrmccannon jrmccannon May 5, 2026

Choose a reason for hiding this comment

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

The isolation is needed so that we can get the current seat count and ensure that it won't change before we complete our request.

For this specific command, multiple requests come into SCIM grab the organization at the same time and attempt to add their user. Currently, the orgservice#inviteuser method grabs resources multiple times including calling out to stripe. An optimized command for inviting users was created, but that introduced an issue where multiple requests would race to update the seat count and all set it to the same value instead of incrementing it.

3 requests come in => get Org: { Seats: 2 } and each add a seat to the org.Seat value. Each request would set org.Seat to 3 when in reality they should set it to 5 (assuming both Org.Seats are occupied). There's also the ability for an Org to set a limit (Org.MaxSeats: 4). So two should succeed and one should fail.

The SCIM protocol requires the server tell it whether the user was safely provisioned so we have to succeed or fail and can't just switch it to an asynchronous add.

With serialized, this would ensure that the seat count is updated correctly as the requests come in.

So that was the reason for this approach. I'd be interested in another way as this is very heavy handed.

var existing = TransactionState.Current;
if (existing is not null)
{
existing.ReferenceCount++;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

❓ Since NestedTransactionScope takes care of decreasing the reference count on disposal, shouldn't it also own increasing reference count ?
(Same for dapper)

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.

3 participants