Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
4b1dbb3
[PM-45107] feat: Autoscale Privileged Controls seats on sales-initiat…
kdenney Oct 23, 2026
115de3a
[PM-45107] feat: Add a command to give back autoscaled Privileged Con…
kdenney Oct 23, 2026
ecc27f1
[PM-45107] feat: Register Privileged Controls seat autoscaling in eve…
kdenney Oct 23, 2026
543ea24
[PM-45107] feat: Add a command that reserves Privileged Controls seat…
kdenney Oct 23, 2026
00e3476
[PM-45107] refactor: Rename the Privileged Controls seat occupancy he…
kdenney Oct 23, 2026
cd45da8
[PM-45107] feat: Email Owners when a joining member needs a Privilege…
kdenney Oct 23, 2026
1967134
[PM-45107] feat: Autoscale Privileged Controls seats when an admin gi…
kdenney Oct 23, 2026
143e5a1
[PM-45107] feat: Autoscale Privileged Controls seats when bulk activa…
kdenney Oct 23, 2026
fc6ee4e
[PM-45107] feat: Autoscale Privileged Controls seats when restoring m…
kdenney Oct 23, 2026
40f8103
[PM-45107] feat: Autoscale Privileged Controls seats when inviting st…
kdenney Oct 23, 2026
a12f54c
[PM-45107] feat: Let staged members join by invite link without Privi…
kdenney Oct 23, 2026
195f7e7
[PM-45107] feat: Let staged members sign in through SSO without Privi…
kdenney Oct 23, 2026
d0589f5
[PM-45107] fix: Reserve the Privileged Controls seat before creating …
kdenney Oct 23, 2026
e0c6192
[PM-45107] fix: Release Privileged Controls seats when inviting stage…
kdenney Oct 23, 2026
2ef71ac
[PM-45107] fix: Skip Privileged Controls seat reservation when an org…
kdenney Oct 23, 2026
819782f
[PM-45107] refactor: Move the self-hosted Privileged Controls seat er…
kdenney Oct 23, 2026
a6904f0
[PM-45107] fix: Keep rejecting Privileged Controls autoscaling withou…
kdenney Oct 26, 2026
51a81fd
[PM-45107] fix: Email Owners about a missing Privileged Controls seat…
kdenney Oct 26, 2026
29486cc
[PM-45107] fix: Reserve Password Manager seats before Privileged Cont…
kdenney Oct 26, 2026
795d74e
[PM-45107] test: Cover the Privileged Controls seat limit end to end …
kdenney Oct 26, 2026
0ccd547
[PM-45107] fix: Give back Password Manager seats when a restore is bl…
kdenney Oct 27, 2026
03ab2d8
[PM-45107] fix: Reserve Privileged Controls seats when an invite prom…
kdenney Oct 27, 2026
32d904d
[PM-45107] fix: Require a subscription only when Privileged Controls …
kdenney Oct 27, 2026
66cf762
[PM-45107] fix: Give back seats when the Privileged Controls step fai…
kdenney Oct 29, 2026
4b6da19
[PM-45107] refactor: Group Subscriptions.Organization commands into f…
kdenney Oct 29, 2026
d2113ed
[PM-45107] refactor: Return Privileged Controls seat reservation fail…
kdenney Oct 29, 2026
3e6f7bb
[PM-45107] test: Point self-hosted and seat autoscale integration tes…
kdenney Oct 29, 2026
5c9661f
[PM-45107] refactor: Leave the Privileged Controls seat reservation u…
kdenney Oct 29, 2026
3231fe2
[PM-45107] refactor: Give back restore seats from the captured seat c…
kdenney Oct 29, 2026
71a83e8
[PM-45107] refactor: Clarify the Privileged Controls seat count and c…
kdenney Oct 29, 2026
292f7c2
[PM-45107] fix: Word the seat-needed email for restores as well as joins
kdenney Oct 29, 2026
349ef27
[PM-45107] refactor: Point the Privileged Controls purchase handler a…
kdenney Oct 29, 2026
4424d5b
[PM-45107] fix: Give back staged invite Privileged Controls seats bef…
kdenney Oct 29, 2026
f8cd3f9
[PM-45107] refactor: Spell out Privileged Controls in names this bran…
kdenney Oct 29, 2026
9eca4de
[PM-45107] refactor: Reserve a Privileged Controls seat only for join…
kdenney Nov 2, 2026
3ee9862
[PM-45107] refactor: Point the Privileged Controls removal handler at…
kdenney Nov 4, 2026
e8d08e4
[PM-45107] test: Give the invite-link not-staged test an existing inv…
kdenney Nov 4, 2026
3c5882a
Merge branch 'main' into billing/PM-45107/autoscale-pam-seats-on-acce…
kdenney Nov 4, 2026
f09471c
Merge branch 'main' into billing/PM-45107/autoscale-pam-seats-on-acce…
kdenney Nov 5, 2026
4b75d98
[PM-45107] fix: Apply design-approved copy to the Privileged Controls…
kdenney Nov 5, 2026
fe1167f
[PM-45107] fix: Align the Privileged Controls seat email copy and sub…
kdenney Nov 5, 2026
7b3b283
Merge branch 'main' into billing/PM-45107/autoscale-pam-seats-on-acce…
kdenney Nov 5, 2026
f115788
[PM-45107] fix: Let Privileged Controls autoscale proceed without a s…
kdenney Nov 5, 2026
9b4182c
Merge branch 'main' into billing/PM-45107/autoscale-pam-seats-on-acce…
kdenney Nov 5, 2026
30ae970
Merge branch 'main' into billing/PM-45107/autoscale-pam-seats-on-acce…
kdenney Nov 5, 2026
bbe50b4
[PM-45107] refactor: Replace OrganizationService.ReplaceAndUpdateCach…
kdenney Nov 5, 2026
7162305
[PM-45107] feat: Gate Privileged Controls seat autoscaling on the bil…
kdenney Nov 6, 2026
32f30e6
Merge remote-tracking branch 'origin/main' into billing/PM-45107/auto…
kdenney Nov 6, 2026
b9d2de9
Update bitwarden_license/src/Sso/Controllers/AccountController.cs
kdenney Nov 6, 2026
b527eee
Merge branch 'main' into billing/PM-45107/autoscale-pam-seats-on-acce…
kdenney Nov 6, 2026
a9bf862
[PM-45107] test: Enable the billing support flag in Privileged Contro…
kdenney Nov 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Entities.Provider;
using Bit.Core.AdminConsole.Enums.Provider;
using Bit.Core.AdminConsole.OrganizationFeatures.Organizations.Interfaces;
using Bit.Core.AdminConsole.Repositories;
using Bit.Core.Billing;
using Bit.Core.Billing.Constants;
Expand Down Expand Up @@ -31,13 +32,13 @@ public class BusinessUnitConverter(
GlobalSettings globalSettings,
ILogger<BusinessUnitConverter> logger,
IMailService mailService,
IOrganizationService organizationService,
IOrganizationUserRepository organizationUserRepository,
IPricingClient pricingClient,
IProviderOrganizationRepository providerOrganizationRepository,
IProviderPlanRepository providerPlanRepository,
IProviderRepository providerRepository,
IProviderUserRepository providerUserRepository,
IReplaceOrganizationAndUpdateCacheCommand replaceOrganizationAndUpdateCacheCommand,
IStripeAdapter stripeAdapter,
ISubscriberService subscriberService,
IUserRepository userRepository) : IBusinessUnitConverter
Expand Down Expand Up @@ -172,7 +173,7 @@ public async Task<Guid> FinalizeConversion(

// Complete database updates for provider setup.
await Task.WhenAll(
organizationService.ReplaceAndUpdateCacheAsync(organization),
replaceOrganizationAndUpdateCacheCommand.RunAsync(organization),
providerOrganizationRepository.ReplaceAsync(providerOrganization),
providerRepository.ReplaceAsync(provider),
providerUserRepository.ReplaceAsync(providerUser));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Entities.Provider;
using Bit.Core.AdminConsole.Enums.Provider;
using Bit.Core.AdminConsole.OrganizationFeatures.Organizations.Interfaces;
using Bit.Core.AdminConsole.Repositories;
using Bit.Core.Billing;
using Bit.Core.Billing.Constants;
Expand Down Expand Up @@ -42,13 +43,13 @@ public class ProviderBillingService(
IGlobalSettings globalSettings,
ILogger<ProviderBillingService> logger,
IOrganizationRepository organizationRepository,
IOrganizationService organizationService,
IPriceIncreaseScheduler priceIncreaseScheduler,
IPricingClient pricingClient,
IProviderInvoiceItemRepository providerInvoiceItemRepository,
IProviderOrganizationRepository providerOrganizationRepository,
IProviderPlanRepository providerPlanRepository,
IProviderUserRepository providerUserRepository,
IReplaceOrganizationAndUpdateCacheCommand replaceOrganizationAndUpdateCacheCommand,
IStripeAdapter stripeAdapter,
ISubscriberService subscriberService,
ITaxService taxService)
Expand Down Expand Up @@ -149,7 +150,7 @@ await stripeAdapter.FinalizeInvoiceAsync(subscription.LatestInvoiceId,
await ScaleSeats(provider, organization.PlanType, organization.Seats!.Value);

await Task.WhenAll(
organizationService.ReplaceAndUpdateCacheAsync(organization),
replaceOrganizationAndUpdateCacheCommand.RunAsync(organization),
providerOrganizationRepository.CreateAsync(providerOrganization)
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Entities.Provider;
using Bit.Core.AdminConsole.OrganizationFeatures.Organizations.Interfaces;
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers;
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces;
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.RevokeUser.v1;
Expand All @@ -26,7 +27,7 @@ public class RemoveOrganizationFromProviderCommand : IRemoveOrganizationFromProv
private readonly IEventService _eventService;
private readonly IMailService _mailService;
private readonly IOrganizationRepository _organizationRepository;
private readonly IOrganizationService _organizationService;
private readonly IReplaceOrganizationAndUpdateCacheCommand _replaceOrganizationAndUpdateCacheCommand;
private readonly IProviderOrganizationRepository _providerOrganizationRepository;
private readonly IStripeAdapter _stripeAdapter;
private readonly Bitwarden.Server.Sdk.Features.IFeatureService _featureService;
Expand All @@ -39,7 +40,7 @@ public RemoveOrganizationFromProviderCommand(
IEventService eventService,
IMailService mailService,
IOrganizationRepository organizationRepository,
IOrganizationService organizationService,
IReplaceOrganizationAndUpdateCacheCommand replaceOrganizationAndUpdateCacheCommand,
IProviderOrganizationRepository providerOrganizationRepository,
IStripeAdapter stripeAdapter,
Bitwarden.Server.Sdk.Features.IFeatureService featureService,
Expand All @@ -51,7 +52,7 @@ public RemoveOrganizationFromProviderCommand(
_eventService = eventService;
_mailService = mailService;
_organizationRepository = organizationRepository;
_organizationService = organizationService;
_replaceOrganizationAndUpdateCacheCommand = replaceOrganizationAndUpdateCacheCommand;
_providerOrganizationRepository = providerOrganizationRepository;
_stripeAdapter = stripeAdapter;
_featureService = featureService;
Expand Down Expand Up @@ -89,7 +90,7 @@ public async Task RemoveOrganizationFromProvider(

await ResetOrganizationBillingAsync(organization, provider, organizationOwnerEmails);

await _organizationService.ReplaceAndUpdateCacheAsync(organization);
await _replaceOrganizationAndUpdateCacheCommand.RunAsync(organization);

await _providerOrganizationRepository.DeleteAsync(providerOrganization);

Expand Down
1 change: 1 addition & 0 deletions bitwarden_license/src/Scim/Scim.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<PropertyGroup Condition=" '$(RunConfiguration)' == 'Scim' " />
<ItemGroup>
<ProjectReference Include="..\..\..\src\Core\Core.csproj" />
<ProjectReference Include="..\..\..\src\Libraries\Subscriptions.Organization\Subscriptions.Organization.csproj" />
<ProjectReference Include="..\..\..\src\SharedWeb\SharedWeb.csproj" />
</ItemGroup>

Expand Down
2 changes: 2 additions & 0 deletions bitwarden_license/src/Scim/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Bit.Scim.Context;
using Bit.Scim.Utilities;
using Bit.SharedWeb.Utilities;
using Bit.Subscriptions.Organization;
using Duende.IdentityModel;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Stripe;
Expand Down Expand Up @@ -72,6 +73,7 @@ public void ConfigureServices(IServiceCollection services)
services.AddDefaultServices(globalSettings);
services.AddDistributedCache(globalSettings);
services.AddBillingOperations();
services.AddPrivilegedControlsSeatAutoscaling();

services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();

Expand Down
28 changes: 28 additions & 0 deletions bitwarden_license/src/Scim/packages.lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -1212,6 +1212,9 @@
"ZiggyCreatures.FusionCache.Serialization.SystemTextJson": "[2.0.2, 2.0.2]"
}
},
"currentuser": {
"type": "Project"
},
"data": {
"type": "Project"
},
Expand Down Expand Up @@ -1247,6 +1250,15 @@
"linq2db.EntityFrameworkCore": "[8.8.0, 8.8.0]"
}
},
"invoicing": {
"type": "Project",
"dependencies": {
"Bitwarden.Server.Sdk.Environment": "[0.1.0, )",
"Bitwarden.Server.Sdk.Features": "[1.5.0, )",
"Core": "[2026.10.1, )",
"Stripe.net": "[52.1.0, 52.1.0]"
}
},
"maildelivery": {
"type": "Project",
"dependencies": {
Expand All @@ -1255,6 +1267,13 @@
"SendGrid": "[9.29.3, 9.29.3]"
}
},
"organizationauthorization": {
"type": "Project",
"dependencies": {
"Core": "[2026.10.1, )",
"CurrentUser": "[0.0.1, )"
}
},
"pam.domain": {
"type": "Project",
"dependencies": {
Expand Down Expand Up @@ -1284,6 +1303,15 @@
},
"ssrfprotection": {
"type": "Project"
},
"subscriptions.organization": {
"type": "Project",
"dependencies": {
"Core": "[2026.10.1, )",
"ExceptionHandling": "[0.0.1, )",
"Invoicing": "[0.0.1, )",
"OrganizationAuthorization": "[0.0.1, )"
}
}
}
}
Expand Down
48 changes: 46 additions & 2 deletions bitwarden_license/src/Sso/Controllers/AccountController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
using Bit.Core.Auth.Models.Data;
using Bit.Core.Auth.Repositories;
using Bit.Core.Auth.UserFeatures.Registration;
using Bit.Core.Billing.Organizations;
using Bit.Core.Billing.Organizations.Commands;
using Bit.Core.Billing.Organizations.Models;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Models.Api;
Expand Down Expand Up @@ -59,6 +62,8 @@ public class AccountController : Controller
private readonly IOrganizationDomainRepository _organizationDomainRepository;
private readonly IRegisterUserCommand _registerUserCommand;
private readonly ISendOrganizationInvitesCommand _sendOrganizationInvitesCommand;
private readonly IReservePrivilegedControlsSeatsCommand _reservePrivilegedControlsSeatsCommand;
private readonly ISendPrivilegedControlsSeatNeededEmailCommand _sendPrivilegedControlsSeatNeededEmailCommand;

public AccountController(
IAuthenticationSchemeProvider schemeProvider,
Expand All @@ -80,7 +85,9 @@ public AccountController(
IDataProtectorTokenFactory<SsoTokenable> dataProtector,
IOrganizationDomainRepository organizationDomainRepository,
IRegisterUserCommand registerUserCommand,
ISendOrganizationInvitesCommand sendOrganizationInvitesCommand)
ISendOrganizationInvitesCommand sendOrganizationInvitesCommand,
IReservePrivilegedControlsSeatsCommand reservePrivilegedControlsSeatsCommand,
ISendPrivilegedControlsSeatNeededEmailCommand sendPrivilegedControlsSeatNeededEmailCommand)
{
_schemeProvider = schemeProvider;
_clientStore = clientStore;
Expand All @@ -102,6 +109,8 @@ public AccountController(
_organizationDomainRepository = organizationDomainRepository;
_registerUserCommand = registerUserCommand;
_sendOrganizationInvitesCommand = sendOrganizationInvitesCommand;
_reservePrivilegedControlsSeatsCommand = reservePrivilegedControlsSeatsCommand;
_sendPrivilegedControlsSeatNeededEmailCommand = sendPrivilegedControlsSeatNeededEmailCommand;
}

[HttpGet]
Expand Down Expand Up @@ -693,10 +702,20 @@ SsoConfigurationData ssoConfigData
// won't complete. Staged rows aren't seat-counted; a Staged→Invited promotion
// consumes a seat and must gate here alongside the fresh-JIT case.
var willPromoteStagedOrgUser = possibleOrgUser?.Status == OrganizationUserStatusType.Staged;
PrivilegedControlsSeatReservationResult? privilegedControlsSeatReservation = null;

if (possibleOrgUser == null || willPromoteStagedOrgUser)
{
await EnsureSeatAvailableAsync(organization);

if (possibleOrgUser is { Status: OrganizationUserStatusType.Staged, AccessPam: true })
{
privilegedControlsSeatReservation = await _reservePrivilegedControlsSeatsCommand.RunAsync(organization, 1);
if (!privilegedControlsSeatReservation.Success)
{
possibleOrgUser.AccessPam = false;
}
}
}

// If the email domain is verified, we can mark the email as verified
Expand Down Expand Up @@ -772,13 +791,21 @@ SsoConfigurationData ssoConfigData

if (possibleOrgUser.Status == OrganizationUserStatusType.Staged)
{
// Seat availability was verified up-front before user creation so safe to consume this seat.
// The member seat and the Privileged Controls seat were both reserved up-front before user
// creation, so it is safe to consume them here. AccessPam may have been cleared on this instance
// when no Privileged Controls seat was available, which the ReplaceAsync below saves.
possibleOrgUser.Status = OrganizationUserStatusType.Invited;
}

possibleOrgUser.UserId = newUser.Id;
possibleOrgUser.RevisionDate = DateTime.UtcNow;
await _organizationUserRepository.ReplaceAsync(possibleOrgUser);

if (privilegedControlsSeatReservation?.Error is PrivilegedControlsSeatLimitReachedError)
{
await _sendPrivilegedControlsSeatNeededEmailCommand.RunAsync(
organization, possibleOrgUser.Email ?? newUser.Email);
}
Comment on lines +804 to +808

@JaredSnider-Bitwarden JaredSnider-Bitwarden Nov 5, 2026 •

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.

❓ : @ike-kottlowski asked a great question here. Why does the _reservePrivilegedControlsSeatsCommand.RunAsync not own the error handling of calling _sendPrivilegedControlsSeatNeededEmailCommand.RunAsync?

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.

If we do change behavior here, then #8822 will need to be updated as well. Feel free to modify those tests.

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.

If the reserve command sent the email, it would go out before the member is saved, which is handled by the calling code. For some SSO paths, steps after the reservation can still fail and roll the join back. The Owners would then be emailed about a member who never took the seat, and again on every retry. Sending the email from the caller after the save avoids that. It's the same reason the Password Manager autoscale limit email goes out only after the seats are saved.

}

// Create the SsoUser record to link the user to the SSO provider.
Expand Down Expand Up @@ -851,6 +878,17 @@ private async Task PromoteStagedOrgUserAndSendInviteAsync(

var previousStatus = orgUser.Status;
var previousRevisionDate = orgUser.RevisionDate;
var previousAccessPam = orgUser.AccessPam;

PrivilegedControlsSeatReservationResult? privilegedControlsSeatReservation = null;
if (orgUser.AccessPam)
{
privilegedControlsSeatReservation = await _reservePrivilegedControlsSeatsCommand.RunAsync(organization, 1);
if (!privilegedControlsSeatReservation.Success)
{
orgUser.AccessPam = false;
}
}

orgUser.Status = OrganizationUserStatusType.Invited;
orgUser.RevisionDate = DateTime.UtcNow;
Expand All @@ -873,10 +911,16 @@ await _sendOrganizationInvitesCommand.SendInvitesAsync(new SendInvitesRequest(

orgUser.Status = previousStatus;
orgUser.RevisionDate = previousRevisionDate;
orgUser.AccessPam = previousAccessPam;
await _organizationUserRepository.ReplaceAsync(orgUser);

throw;
}

if (privilegedControlsSeatReservation?.Error is PrivilegedControlsSeatLimitReachedError)
{
await _sendPrivilegedControlsSeatNeededEmailCommand.RunAsync(organization, orgUser.Email!);
}
}

/// <summary>
Expand Down
1 change: 1 addition & 0 deletions bitwarden_license/src/Sso/Sso.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

<ItemGroup>
<ProjectReference Include="..\..\..\src\Core\Core.csproj" />
<ProjectReference Include="..\..\..\src\Libraries\Subscriptions.Organization\Subscriptions.Organization.csproj" />
<ProjectReference Include="..\..\..\src\SharedWeb\SharedWeb.csproj" />
</ItemGroup>

Expand Down
2 changes: 2 additions & 0 deletions bitwarden_license/src/Sso/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Bit.Core.Utilities;
using Bit.SharedWeb.Utilities;
using Bit.Sso.Utilities;
using Bit.Subscriptions.Organization;
using Duende.IdentityServer.Services;
using Stripe;

Expand Down Expand Up @@ -83,6 +84,7 @@ public void ConfigureServices(IServiceCollection services)
services.AddDefaultServices(globalSettings);
services.AddCoreLocalizationServices();
services.AddBillingOperations();
services.AddPrivilegedControlsSeatAutoscaling();

// TODO: Remove when OrganizationUser methods are moved out of OrganizationService, this noop dependency should
// TODO: no longer be required - see PM-1880
Expand Down
28 changes: 28 additions & 0 deletions bitwarden_license/src/Sso/packages.lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -1251,6 +1251,9 @@
"ZiggyCreatures.FusionCache.Serialization.SystemTextJson": "[2.0.2, 2.0.2]"
}
},
"currentuser": {
"type": "Project"
},
"data": {
"type": "Project"
},
Expand Down Expand Up @@ -1286,6 +1289,15 @@
"linq2db.EntityFrameworkCore": "[8.8.0, 8.8.0]"
}
},
"invoicing": {
"type": "Project",
"dependencies": {
"Bitwarden.Server.Sdk.Environment": "[0.1.0, )",
"Bitwarden.Server.Sdk.Features": "[1.5.0, )",
"Core": "[2026.10.1, )",
"Stripe.net": "[52.1.0, 52.1.0]"
}
},
"maildelivery": {
"type": "Project",
"dependencies": {
Expand All @@ -1294,6 +1306,13 @@
"SendGrid": "[9.29.3, 9.29.3]"
}
},
"organizationauthorization": {
"type": "Project",
"dependencies": {
"Core": "[2026.10.1, )",
"CurrentUser": "[0.0.1, )"
}
},
"pam.domain": {
"type": "Project",
"dependencies": {
Expand Down Expand Up @@ -1323,6 +1342,15 @@
},
"ssrfprotection": {
"type": "Project"
},
"subscriptions.organization": {
"type": "Project",
"dependencies": {
"Core": "[2026.10.1, )",
"ExceptionHandling": "[0.0.1, )",
"Invoicing": "[0.0.1, )",
"OrganizationAuthorization": "[0.0.1, )"
}
}
}
}
Expand Down
Loading
Loading