Skip to content

[PM-22450] Bump Collection.RevisionDate on edits and access changes#7380

Merged
r-tome merged 23 commits intomainfrom
ac/pm-22450/collection-revision-date-is-not-updated
Apr 10, 2026
Merged

[PM-22450] Bump Collection.RevisionDate on edits and access changes#7380
r-tome merged 23 commits intomainfrom
ac/pm-22450/collection-revision-date-is-not-updated

Conversation

@r-tome
Copy link
Copy Markdown
Contributor

@r-tome r-tome commented Apr 2, 2026

🎟️ Tracking

https://bitwarden.atlassian.net/browse/PM-22450

📔 Objective

Collection.RevisionDate was not updated when a collection was edited or when its access changed. Clients rely on this date to know when to re-sync. This PR bumps it across all code paths: collection edits via UpdateCollectionCommand, user/group assignment changes, and bulk access operations -- in both stored procedures and EF repositories.

…d update corresponding tests. Adjust tests to verify correct RevisionDate assignment during collection updates.
@r-tome r-tome added needs-qa ai-review-vnext Request a Claude code review using the vNext workflow labels Apr 2, 2026
@r-tome r-tome marked this pull request as ready for review April 2, 2026 15:43
@r-tome r-tome requested a review from a team as a code owner April 2, 2026 15:43
@r-tome r-tome requested a review from eliykat April 2, 2026 15:43
@codecov
Copy link
Copy Markdown

codecov bot commented Apr 2, 2026

Codecov Report

❌ Patch coverage is 93.25843% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 62.92%. Comparing base (ebbf6dd) to head (d339457).
⚠️ Report is 13 commits behind head on main.

Files with missing lines Patch % Lines
...Console/Repositories/OrganizationUserRepository.cs 50.00% 2 Missing and 1 partial ⚠️
...Console/Repositories/OrganizationUserRepository.cs 92.10% 2 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #7380      +/-   ##
==========================================
+ Coverage   58.56%   62.92%   +4.36%     
==========================================
  Files        2063     2063              
  Lines       91198    91279      +81     
  Branches     8125     8132       +7     
==========================================
+ Hits        53406    57439    +4033     
+ Misses      35881    31841    -4040     
- Partials     1911     1999      +88     

☔ 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 2, 2026

Logo
Checkmarx One – Scan Summary & Details0979bb56-2b75-49f3-a18d-8c03c5bcd5ae


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 (2) Great job! The following issues were fixed in this Pull Request
Severity Issue Source File / Package
MEDIUM CSRF /src/Api/AdminConsole/Public/Controllers/MembersController.cs: 269
MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 287

eliykat
eliykat previously approved these changes Apr 3, 2026
Copy link
Copy Markdown
Member

@eliykat eliykat left a comment

Choose a reason for hiding this comment

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

The ticket says we need to bump the revision date in these scenarios:

  1. Whenever a collection has its name updated (including when it’s nested)
  2. Whenever a collection has its user/group assignment updated
  3. Whenever a user has their access to a collection updated
  4. Whenever a group has their access to a collection updated

I'm guessing this covers 1 and 2. What about 3 and 4? (That said - this PR is still good to merge.)

r-tome added 6 commits April 3, 2026 15:31
…cess updates. Update ICollectionRepository and its implementations to accept revision date parameter. Modify stored procedure to update collection revision dates accordingly. Add tests to verify correct behavior of access creation and revision date updates.
… affected collections during group creation and updates. Enhance integration tests to verify that collection revision dates are correctly updated when groups are created or modified.
…ionUserRepository and related stored procedures. Add integration tests to ensure revision dates are correctly bumped during organization user creation and updates.
@r-tome r-tome requested a review from a team as a code owner April 3, 2026 15:03
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 3, 2026

🤖 Bitwarden Claude Code Review

Overall Assessment: APPROVE

This PR bumps Collection.RevisionDate across all code paths where collection access is modified — collection edits, user/group assignment changes, and bulk access operations. The implementation is consistent between Dapper/SQL stored procedures and EF repositories. Test coverage is thorough with both unit tests (using FakeTimeProvider) and integration tests for create, update, and bulk operations.

Code Review Details
  • 🎨 : internal setset on Group.RevisionDate and OrganizationUser.RevisionDate may be unnecessary — test assemblies already have InternalsVisibleTo and no production code outside Core sets these properties
    • src/Core/AdminConsole/Entities/Group.cs:19, src/Core/AdminConsole/Entities/OrganizationUser.cs:68

@r-tome r-tome changed the title [PM-22450] Fix Collection.RevisionDate not updating when a collection is edited [PM-22450] Bump Collection.RevisionDate on edits and access changes Apr 3, 2026
@r-tome
Copy link
Copy Markdown
Contributor Author

r-tome commented Apr 3, 2026

The ticket says we need to bump the revision date in these scenarios:

  1. Whenever a collection has its name updated (including when it’s nested)
  2. Whenever a collection has its user/group assignment updated
  3. Whenever a user has their access to a collection updated
  4. Whenever a group has their access to a collection updated

I'm guessing this covers 1 and 2. What about 3 and 4? (That said - this PR is still good to merge.)

Great callout! I went even further and also updated when user is invited with collection access.

@r-tome r-tome requested a review from eliykat April 3, 2026 19:39
Copy link
Copy Markdown
Member

@eliykat eliykat left a comment

Choose a reason for hiding this comment

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

Looking good.

@r-tome r-tome marked this pull request as draft April 6, 2026 10:12
r-tome added 6 commits April 6, 2026 11:13
… updating RevisionDate of affected collections. This change improves readability and maintainability by consolidating the logic for identifying affected collections in Group_UpdateWithCollections and OrganizationUser_UpdateWithCollections procedures.
…ocedure to accept RevisionDate parameter for updating affected collections. Update OrganizationUserRepository to utilize the provided RevisionDate when available, ensuring accurate revision date management during organization user operations.
…on script to utilize temporary table for CollectionUser data insertion. This change improves performance and maintains consistency in updating RevisionDate for affected collections.
…from created OrganizationUsers when updating affected collections. This change enhances the accuracy of revision date management across the repository.
…roup and Collection repositories. Update assertions to compare RevisionDate directly, improving accuracy in revision date management during tests.
r-tome added 3 commits April 6, 2026 12:38
…ndling of RevisionDate. Updated collection filtering logic to use HashSet for efficiency and ensured that affected collections are filtered by OrganizationId, enhancing accuracy in revision date management.
The Dapper repositories use a System.Text.Json serialize/deserialize
round-trip to build *WithCollections objects. System.Text.Json silently
skips properties with non-public setters, so RevisionDate was reverting
to DateTime.UtcNow instead of preserving the value set in C#.
…on script to improve the logic for updating RevisionDate. The update now uses INNER JOINs to ensure accurate filtering of collections based on OrganizationId and CollectionUser data, enhancing the precision of revision date management.
[MaxLength(300)]
public string? ExternalId { get; set; }
public DateTime CreationDate { get; internal set; } = DateTime.UtcNow;
public DateTime RevisionDate { get; internal set; } = DateTime.UtcNow;
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The repository serializes/deserializes the entity for the sproc call, and the internal set prevented RevisionDate from being set, causing the value to be lost. Making it public fixes that.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I also saw that only some entities have an internal set. I'm not sure why we have that inconsistency.

@r-tome r-tome marked this pull request as ready for review April 6, 2026 15:05
@r-tome r-tome requested a review from eliykat April 6, 2026 15:05
Copy link
Copy Markdown
Contributor

@mkincaid-bw mkincaid-bw left a comment

Choose a reason for hiding this comment

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

Mainly formatting nit-picks and a comment on joins

IF @RevisionDate IS NOT NULL
BEGIN
-- Bump the revision date on all affected collections
UPDATE C
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.

⛏️ UPDATE statements should be broken out on separate lines per the style guide

[Id] IN (SELECT [Id] FROM [AvailableCollectionsCTE])

-- Bump RevisionDate on all affected collections
UPDATE C
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.

⛏️ UPDATE statements should be broken out on separate lines per the style guide


-- Bump RevisionDate on all affected collections
;WITH [AffectedCollectionsCTE] AS (
SELECT [Id] FROM @Collections
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.

⛏️ SELECT statements should be broken out on separate lines per the style guide

-- Bump RevisionDate on all affected collections
IF @RevisionDate IS NOT NULL
BEGIN
UPDATE C
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.

⛏️ UPDATE statements should be broken out on separate lines per the style guide

Also, the join to the OrganizationUser table can cause a performance bottleneck depending on how SQL server decides to execute the query. Since the list of CollectionIds are in the #CollectionUserData table, I think the join is unnecessary, and we can probably just use that.

  UPDATE
      C
  SET
      C.[RevisionDate] = @RevisionDate
  FROM
      [dbo].[Collection] C
  INNER JOIN
      #CollectionUserData CUD ON CUD.[CollectionId] = C.[Id]

[Id] IN (SELECT [Id] FROM [AvailableCollectionsCTE])

-- Bump RevisionDate on all affected collections
UPDATE C
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.

⛏️ UPDATE statements should be broken out on separate lines per the style guide


-- Bump RevisionDate on all affected collections
;WITH [AffectedCollectionsCTE] AS (
SELECT [Id] FROM @Collections
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.

⛏️ SELECT statements should be broken out on separate lines per the style guide

FROM [dbo].[CollectionUser] CU
WHERE CU.[OrganizationUserId] = @Id
)
UPDATE C
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.

⛏️ UPDATE statements should be broken out on separate lines per the style guide

Copy link
Copy Markdown
Member

@eliykat eliykat left a comment

Choose a reason for hiding this comment

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

Very minor things only.

@r-tome r-tome requested review from eliykat and mkincaid-bw April 7, 2026 12:02
@r-tome
Copy link
Copy Markdown
Contributor Author

r-tome commented Apr 7, 2026

@mkincaid-bw Thanks for catching all the style guide violations! All fixed now.

public string? ExternalId { get; set; }
public DateTime CreationDate { get; internal set; } = DateTime.UtcNow;
public DateTime RevisionDate { get; internal set; } = DateTime.UtcNow;
public DateTime RevisionDate { get; set; } = DateTime.UtcNow;
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.

🎨 SUGGESTED: The internal setset change here (and on OrganizationUser.RevisionDate) widens the access modifier. Since Core.csproj already declares InternalsVisibleTo for Core.Test, Infrastructure.IntegrationTest, and Identity.IntegrationTest, the test assemblies can already use internal set. The production callers in this PR (EF/Dapper repos) only read Group.RevisionDate and OrganizationUser.RevisionDate — they don't set them.

Consider keeping internal set to preserve the encapsulation that prevents accidental modification from assemblies outside Core. CreationDate on both entities still uses internal set, so this change also introduces an inconsistency between the two date properties.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

That is wrong, Claude. I had to make the set public because otherwise on

var objWithCollections = JsonSerializer.Deserialize<GroupWithCollections>(JsonSerializer.Serialize(obj))!;
it fails to populate RevisionDate with the given value and defaults to DateTime.UtcNow. I noticed this because the tests would fail.

Copy link
Copy Markdown
Contributor

@mkincaid-bw mkincaid-bw left a comment

Choose a reason for hiding this comment

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

LGTM

@r-tome r-tome removed the ai-review-vnext Request a Claude code review using the vNext workflow label Apr 9, 2026
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud bot commented Apr 9, 2026

@r-tome r-tome removed the needs-qa label Apr 10, 2026
@r-tome r-tome merged commit 3dd72f6 into main Apr 10, 2026
70 of 72 checks passed
@r-tome r-tome deleted the ac/pm-22450/collection-revision-date-is-not-updated branch April 10, 2026 06:27
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