[PM-39557] Replace invite link key columns with an opaque Invite blob#7896
Conversation
…d EncryptedOrgKey with Invite blob and SupportsConfirmation flag. Update stored procedures and migration script accordingly.
…ptedInviteKey with Invite and add SupportsConfirmation flag. Update model snapshot for MySQL, PostgreSQL, and SQLite.
…and EncryptedOrgKey with Invite property and add SupportsConfirmation flag. Update related command and request classes accordingly.
…pportsConfirmation flag, reflecting recent schema changes.
…and EncryptedOrgKey with Invite property in Create and Refresh request models, and update OrganizationInviteLinkResponseModel to include SupportsConfirmation flag. Adjust related command request methods accordingly.
…s various controllers and models, ensuring consistency with recent schema changes. Adjust assertions and request models accordingly to reflect the new structure.
🤖 Bitwarden Claude Code ReviewOverall Assessment: APPROVE Reviewed the replacement of the invite link's No blocking findings. The open reviewer threads (column ordering, |
| name: "EncryptedOrgKey", | ||
| table: "OrganizationInviteLink"); | ||
|
|
||
| migrationBuilder.RenameColumn( |
There was a problem hiding this comment.
EF decided to rename this column instead of dropping and creating a new one. I guess there is no harm because this feature hasn't been rolled out yet.
There was a problem hiding this comment.
Like the SQL migration, this will cause the table to end up with columns out of order from the definition defined in src/Sql/dbo/Tables/OrganizationInviteLink.sql, so I think these should be written so that the existing columns are dropped and then the new ones added at the end.
If you don't want to do that, you could have the SQL Server migration follow the EF pattern and drop EncryptedOrgKey, rename EncryptedInviteKey to Invite, then add SupportsConfirmation. It doesn't really matter except that the end-result of the tables should be consistent across environments.
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #7896 +/- ##
==========================================
+ Coverage 61.35% 65.87% +4.51%
==========================================
Files 2236 2236
Lines 98547 98547
Branches 8911 8911
==========================================
+ Hits 60468 64917 +4449
+ Misses 35943 31397 -4546
- Partials 2136 2233 +97 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
mkincaid-bw
left a comment
There was a problem hiding this comment.
Some minor changes requested.
| CREATE TABLE [dbo].[OrganizationInviteLink] | ||
| ( | ||
| [Id] UNIQUEIDENTIFIER NOT NULL, | ||
| [Code] UNIQUEIDENTIFIER NOT NULL, | ||
| [OrganizationId] UNIQUEIDENTIFIER NOT NULL, | ||
| [AllowedDomains] NVARCHAR(MAX) NOT NULL, | ||
| [EncryptedInviteKey] NVARCHAR(MAX) NOT NULL, | ||
| [EncryptedOrgKey] NVARCHAR(MAX) NULL, | ||
| [CreationDate] DATETIME2(7) NOT NULL, | ||
| [RevisionDate] DATETIME2(7) NOT NULL, | ||
| [Id] UNIQUEIDENTIFIER NOT NULL, | ||
| [Code] UNIQUEIDENTIFIER NOT NULL, | ||
| [OrganizationId] UNIQUEIDENTIFIER NOT NULL, | ||
| [AllowedDomains] NVARCHAR(MAX) NOT NULL, | ||
| [Invite] NVARCHAR(MAX) NOT NULL, | ||
| [SupportsConfirmation] BIT NOT NULL, | ||
| [CreationDate] DATETIME2(7) NOT NULL, | ||
| [RevisionDate] DATETIME2(7) NOT NULL, | ||
| CONSTRAINT [PK_OrganizationInviteLink] PRIMARY KEY CLUSTERED ([Id] ASC), | ||
| CONSTRAINT [FK_OrganizationInviteLink_Organization] FOREIGN KEY ([OrganizationId]) REFERENCES [dbo].[Organization] ([Id]) ON DELETE CASCADE | ||
| ); |
There was a problem hiding this comment.
The net result of the migration script will add these columns at the end, so the table definition will look like this:
CREATE TABLE [dbo].[OrganizationInviteLink]
(
[Id] UNIQUEIDENTIFIER NOT NULL,
[Code] UNIQUEIDENTIFIER NOT NULL,
[OrganizationId] UNIQUEIDENTIFIER NOT NULL,
[AllowedDomains] NVARCHAR(MAX) NOT NULL,
[CreationDate] DATETIME2(7) NOT NULL,
[RevisionDate] DATETIME2(7) NOT NULL,
[Invite] NVARCHAR(MAX) NOT NULL,
[SupportsConfirmation] BIT NOT NULL,
CONSTRAINT [PK_OrganizationInviteLink] PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT [FK_OrganizationInviteLink_Organization] FOREIGN KEY ([OrganizationId]) REFERENCES [dbo].[Organization] ([Id]) ON DELETE CASCADE
);| name: "EncryptedOrgKey", | ||
| table: "OrganizationInviteLink"); | ||
|
|
||
| migrationBuilder.RenameColumn( |
There was a problem hiding this comment.
Like the SQL migration, this will cause the table to end up with columns out of order from the definition defined in src/Sql/dbo/Tables/OrganizationInviteLink.sql, so I think these should be written so that the existing columns are dropped and then the new ones added at the end.
If you don't want to do that, you could have the SQL Server migration follow the EF pattern and drop EncryptedOrgKey, rename EncryptedInviteKey to Invite, then add SupportsConfirmation. It doesn't really matter except that the end-result of the tables should be consistent across environments.
Rewrite the OrganizationInviteLink migration to drop EncryptedOrgKey, rename EncryptedInviteKey to Invite, and add SupportsConfirmation at the end, matching the EF migrations. Reorder the SSDT table definition so SupportsConfirmation sits after RevisionDate, keeping src/Sql/dbo in sync with what a fresh run of all migrations produces across the four supported databases.
Renamed from 2026-06-30 so environments that already applied the previous version pick up the corrected script as a new, distinct migration.
…ngth - Add a required SupportsConfirmation field to the create/refresh API request models and command request records for forward-compatibility. The commands still hardcode the persisted value to false because auto confirmation isn't supported yet; when Milestone 3 ships the flow, the hardcode is removed without changing the request shape. - Cap Invite to 3000 characters via [EncryptedStringLength] on both request models to bound the opaque blob. Intentionally not adding [EncryptedString] — the server treats the blob as opaque so the format can evolve without server changes. - Update unit and integration tests to populate the now-required SupportsConfirmation field and assert the server-side override.
|
@mkincaid-bw thanks for the review and suggestions! I have followed your suggestion to update sql to match EF and rename the existing column and add the new one at the end. |
mkincaid-bw
left a comment
There was a problem hiding this comment.
DB Changes LGTM but I just wanted to leave a note since this could be flagged by others:
This PR technically violates EDD with the column drop/rename. However, the OrganizationInviteLink table in prod is currently empty and from what I understand, the code has never been enabled in prod, so we should be fine. I also checked QA and the table is empty there as well.
… SupportsConfirmation from requests - Modify CreateOrganizationInviteLinkCommand and RefreshOrganizationInviteLinkCommand to use the SupportsConfirmation value from the request instead of hardcoding it to false. - Update related tests to assert the correct SupportsConfirmation value based on the request input, ensuring consistency in behavior across the application.
@mkincaid-bw I agree this violates EDD. Thanks for checking prod and QA and since those tables are empty and this feature hasn't been released no data is at risk. |




🎟️ Tracking
https://bitwarden.atlassian.net/browse/PM-39557
📔 Objective
Store the invite link's cryptographic material as a single opaque
Inviteblob plus aSupportsConfirmationflag instead of the separateEncryptedInviteKey/EncryptedOrgKeycolumns, so the server stays a pure storage/transport layer and the blob's format can evolve without AC changes.