-
Notifications
You must be signed in to change notification settings - Fork 1.4k
[PM-25372] Filter out DefaultUserCollections from CiphersController.GetAssignedOrganizationCiphers #6274
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
- Created a new stored procedure [CollectionCipher_ReadSharedByOrganizationId] that retrieves shared collections based on the provided organization ID.
…sync for retrieving organization collection ciphers
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #6274 +/- ##
==========================================
+ Coverage 49.41% 53.46% +4.05%
==========================================
Files 1784 1782 -2
Lines 78950 79324 +374
Branches 7018 7045 +27
==========================================
+ Hits 39010 42412 +3402
+ Misses 38425 35310 -3115
- Partials 1515 1602 +87 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Fixed Issues (1)Great job! The following issues were fixed in this Pull Request
|
SET NOCOUNT ON | ||
|
||
SELECT | ||
CC.* |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It’s normally wise to only select the columns you need. Even if we need all the columns, we should be explicit about it so that when new columns are added, they don’t automatically get returned.
With that said, I’ve seen companies intentionally use *
as part of a pattern, such as when a stored procedure is meant to be all-purpose. There are trade-offs to this, of course.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right about that! I copied the existing sproc CollectionCipher_ReadByOrganizationId
and didn't even look.
{ | ||
var results = await connection.QueryAsync<CollectionCipher>( | ||
"[dbo].[CollectionCipher_ReadSharedByOrganizationId]", | ||
new { OrganizationId = organizationId }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we add an automated test for this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added an integration test!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some questions
… to select specific columns
- Implemented tests for GetManySharedByOrganizationIdAsync to verify that only shared collections are returned for a given organization ID. - Included setup and cleanup logic for organization, collections, and ciphers to ensure test isolation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couple minor formatting changes.
Also, if the CollectionCipher_ReadSharedByOrganizationId
proc is going to be called very frequently, it could benefit by updating the IX_Collection_OrganizationId_IncludeAll
index to add [Type]
as an included column.
CREATE NONCLUSTERED INDEX [IX_Collection_OrganizationId_IncludeAll]
ON [dbo].[Collection] ([OrganizationId] ASC)
INCLUDE([CreationDate],[Name],[RevisionDate],[TYPE]) WITH (DROP_EXISTING = ON)
GO
SET NOCOUNT ON | ||
|
||
SELECT | ||
CC.CollectionId, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
⛏️ Object identifiers should have square brackets.
SET NOCOUNT ON | ||
|
||
SELECT | ||
CC.CollectionId, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
⛏️ Object identifiers should have square brackets.
…de Type column - Updated [CollectionCipher_ReadSharedByOrganizationId] and migration script to select specific columns with brackets for consistency. - Modified the [IX_Collection_OrganizationId_IncludeAll] index to include the [Type] column for improved query performance.
@mkincaid-bw, Great insight, thanks for pointing that out! For consistency I followed our usual pattern of dropping the index first instead of using |
|
@r-tome Since the net-effect of this change is to add a new column to an existing index, there are a couple issues with the approach of dropping and then re-creating. First, Once the old index is dropped, any queries using that index will no longer be able to, and queries to that table could be impacted while the new index is being built. Second, building the new index will take longer since it has to scan the entire table to build the index. If the existing index was still in place, SQL server can use that index to build the new index, which would be much faster (at least twice as fast in my testing). The query I gave essentially does this behind the scenes:
There are only small schema locks at the beginning and end of the statement so blocking is minimal. The only downside to my If you want to full control over all of that, something like this would give us the best of both worlds, where the new index gets created using the old one (faster), and existing queries won't suffer poor performance during index creation:
Note that re-naming the index isn't technically required (we could just leave the new one named with _V2). The main reason for renaming _V2 back to the old name is on the off-chance that someone, somewhere has put an index hint with that index name on a query. If that were the case, that query would error since the that index name would no longer exist. |
Hey @mkincaid-bw, I’m taking over this PR since Rui is OOO. I was reading through your comments, and I see the concern about the potential for slow queries during index rebuilding. That’s definitely a valid point. I’m wondering, though, given that we release DB changes during maintenance windows and low-traffic periods, do you think it’s still a concern for our system? My preference is to keep things simple if we can, but if this does turn out to be an issue, it would be helpful to add documentation to guide devs on when the more complex approach should be considered. |
🎟️ Tracking
https://bitwarden.atlassian.net/browse/PM-25372
📔 Objective
The
GetAssignedOrganizationCiphers
endpoint is exposing collection IDs for DefaultUserCollection (private collections) that users shouldn’t see.Cause
OrganizationCiphersQuery
which calls_collectionCipherRepository.GetManyByOrganizationIdAsync
, which returns all collections for the org.DefaultUserCollection
(type = 1), which are meant to stay hidden.Fix
GetManySharedByOrganizationIdAsync
SharedCollection
(type = 0) and excludesDefaultUserCollection
.📸 Screenshots
Bug:

With this fix:

⏰ Reminders before review
🦮 Reviewer guidelines
:+1:
) or similar for great changes:memo:
) or ℹ️ (:information_source:
) for notes or general info:question:
) for questions:thinking:
) or 💭 (:thought_balloon:
) for more open inquiry that's not quite a confirmed issue and could potentially benefit from discussion:art:
) for suggestions / improvements:x:
) or:warning:
) for more significant problems or concerns needing attention:seedling:
) or ♻️ (:recycle:
) for future improvements or indications of technical debt:pick:
) for minor or nitpick changes