File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -2072,9 +2072,22 @@ const EnvironmentSchema = z
20722072 // Force RBAC to not use the plugin
20732073 RBAC_FORCE_FALLBACK : BoolEnv . default ( false ) ,
20742074
2075+ // Per-process pool sizes for an RBAC plugin that owns its own database
2076+ // client (the fallback queries through Prisma and ignores these). Writes
2077+ // are rare role mutations; reads run on the per-request auth hot path.
2078+ RBAC_DATABASE_WRITER_CONNECTION_LIMIT : z . coerce . number ( ) . int ( ) . default ( 2 ) ,
2079+ RBAC_DATABASE_READER_CONNECTION_LIMIT : z . coerce . number ( ) . int ( ) . default ( 5 ) ,
2080+
20752081 // Force SSO to not use the plugin (contributors without the cloud
20762082 // plugin installed can opt in to a clean OSS-only experience).
20772083 SSO_FORCE_FALLBACK : BoolEnv . default ( false ) ,
2084+
2085+ // Per-process pool sizes for an SSO plugin that owns its own database
2086+ // client (the fallback queries through Prisma and ignores these). Writes
2087+ // are rare config mutations and webhook processing; reads run on the
2088+ // login path.
2089+ SSO_DATABASE_WRITER_CONNECTION_LIMIT : z . coerce . number ( ) . int ( ) . default ( 2 ) ,
2090+ SSO_DATABASE_READER_CONNECTION_LIMIT : z . coerce . number ( ) . int ( ) . default ( 5 ) ,
20782091 // Emit a console.log when the SSO fallback is selected because no
20792092 // plugin is installed. Default off so OSS deployments stay quiet.
20802093 SSO_LOG_FALLBACK : BoolEnv . default ( false ) ,
Original file line number Diff line number Diff line change @@ -27,5 +27,18 @@ export const rbac = plugin.create(
2727 { primary : prisma , replica : $replica as PrismaClient } ,
2828 // SESSION_SECRET signs delegated user-actor tokens; the plugin verifies
2929 // them with it in authenticateUserActor.
30- { forceFallback : env . RBAC_FORCE_FALLBACK , userActorSecret : env . SESSION_SECRET }
30+ {
31+ forceFallback : env . RBAC_FORCE_FALLBACK ,
32+ userActorSecret : env . SESSION_SECRET ,
33+ // A plugin that owns its own database client gets the same
34+ // writer/replica topology the webapp's Prisma clients use (see
35+ // getClient/getReplicaClient in db.server.ts): control-plane URLs win,
36+ // and with no replica configured reads share the writer.
37+ database : {
38+ writerUrl : env . CONTROL_PLANE_DATABASE_URL ?? env . DATABASE_URL ,
39+ readerUrl : env . CONTROL_PLANE_DATABASE_READ_REPLICA_URL ?? env . DATABASE_READ_REPLICA_URL ,
40+ writerConnectionLimit : env . RBAC_DATABASE_WRITER_CONNECTION_LIMIT ,
41+ readerConnectionLimit : env . RBAC_DATABASE_READER_CONNECTION_LIMIT ,
42+ } ,
43+ }
3144) ;
Original file line number Diff line number Diff line change @@ -18,5 +18,17 @@ export const ssoController = sso.create(
1818 // fallback so the entire SSO surface (login, settings, callback,
1919 // re-validation) stays inert. SSO_FORCE_FALLBACK remains an
2020 // independent contributor/debug override.
21- { forceFallback : ! env . SSO_ENABLED || env . SSO_FORCE_FALLBACK }
21+ {
22+ forceFallback : ! env . SSO_ENABLED || env . SSO_FORCE_FALLBACK ,
23+ // A plugin that owns its own database client gets the same
24+ // writer/replica topology the webapp's Prisma clients use (see
25+ // getClient/getReplicaClient in db.server.ts): control-plane URLs win,
26+ // and with no replica configured reads share the writer.
27+ database : {
28+ writerUrl : env . CONTROL_PLANE_DATABASE_URL ?? env . DATABASE_URL ,
29+ readerUrl : env . CONTROL_PLANE_DATABASE_READ_REPLICA_URL ?? env . DATABASE_READ_REPLICA_URL ,
30+ writerConnectionLimit : env . SSO_DATABASE_WRITER_CONNECTION_LIMIT ,
31+ readerConnectionLimit : env . SSO_DATABASE_READER_CONNECTION_LIMIT ,
32+ } ,
33+ }
2234) ;
Original file line number Diff line number Diff line change 11import type {
22 Permission ,
33 RbacAbility ,
4+ RbacDatabaseConfig ,
45 Role ,
56 RbacResource ,
67 RoleAssignmentResult ,
@@ -33,6 +34,11 @@ export type RbacCreateOptions = {
3334 // Platform secret used to verify delegated user-actor tokens (tr_uat_).
3435 // Threaded through to the plugin / fallback's authenticateUserActor.
3536 userActorSecret ?: string ;
37+ // Writer/reader connection URLs + pool sizes for a plugin that owns its
38+ // own database client, resolved by the host from its env so the plugin
39+ // follows the host's writer/replica topology. The fallback ignores this —
40+ // it queries through the Prisma clients passed as `RbacPrismaInput`.
41+ database ?: RbacDatabaseConfig ;
3642} ;
3743
3844// Route actions that historically authorised via the legacy checkAuthorization's
@@ -88,7 +94,10 @@ class LazyController implements RoleBaseAccessController {
8894 const module = await import ( moduleName ) ;
8995 const plugin : RoleBasedAccessControlPlugin = module . default ;
9096 console . log ( "RBAC: using plugin implementation" ) ;
91- return plugin . create ( { userActorSecret : options ?. userActorSecret } ) ;
97+ return plugin . create ( {
98+ userActorSecret : options ?. userActorSecret ,
99+ database : options ?. database ,
100+ } ) ;
92101 } catch ( err ) {
93102 // The dynamic import either succeeded or failed for one of two
94103 // distinct reasons. Distinguishing them is critical for debugging
Original file line number Diff line number Diff line change @@ -2,6 +2,7 @@ import type {
22 DirectorySyncEffect ,
33 DirectorySyncStatus ,
44 OrgSsoStatus ,
5+ PluginDatabaseConfig ,
56 SsoBeginError ,
67 SsoCompleteError ,
78 SsoController ,
@@ -32,6 +33,11 @@ export type SsoCreateOptions = {
3233 // module or a synthetic ERR_MODULE_NOT_FOUND failure without touching
3334 // the real plugin install on disk.
3435 importer ?: ( moduleName : string ) => Promise < { default : SsoPlugin } > ;
36+ // Writer/reader connection URLs + pool sizes for a plugin that owns its
37+ // own database client, resolved by the host from its env so the plugin
38+ // follows the host's writer/replica topology. The fallback ignores this —
39+ // it queries through the Prisma clients passed as `SsoPrismaInput`.
40+ database ?: PluginDatabaseConfig ;
3541} ;
3642
3743// Loads the cloud plugin lazily; falls back to the OSS no-op
@@ -55,7 +61,7 @@ export class LazyController implements SsoController {
5561 const module = await importer ( moduleName ) ;
5662 const plugin : SsoPlugin = module . default ;
5763 console . log ( "SSO: using plugin implementation" ) ;
58- return plugin . create ( ) ;
64+ return plugin . create ( { database : options ?. database } ) ;
5965 } catch ( err ) {
6066 // Distinguish the two failure modes the dynamic import can hit:
6167 //
Original file line number Diff line number Diff line change 1+ // Database connections for a plugin that owns its own client. The host
2+ // resolves the URLs from its env so the plugin follows the same
3+ // writer/replica topology the host uses. Shared by every plugin contract
4+ // that carries a `database` section.
5+ export type PluginDatabaseConfig = {
6+ // Primary (writer) connection URL. Mutations and read-your-writes
7+ // management reads run here.
8+ writerUrl : string ;
9+ // Read-replica URL for the per-request auth reads. Omitted → those reads
10+ // share the writer connection.
11+ readerUrl ?: string ;
12+ // Per-process pool sizes. Omitted → plugin defaults (writer 2, reader 5).
13+ writerConnectionLimit ?: number ;
14+ readerConnectionLimit ?: number ;
15+ } ;
Original file line number Diff line number Diff line change @@ -16,6 +16,7 @@ export type {
1616 UserActorAuthResult ,
1717 UserActorClaims ,
1818 RbacPluginConfig ,
19+ RbacDatabaseConfig ,
1920 SystemRole ,
2021 AuthenticatedEnvironment ,
2122} from "./rbac.js" ;
@@ -28,8 +29,11 @@ export {
2829 USER_ACTOR_TOKEN_PREFIX ,
2930} from "./rbac.js" ;
3031
32+ export type { PluginDatabaseConfig } from "./databaseConfig.js" ;
33+
3134export type {
3235 SsoPlugin ,
36+ SsoPluginConfig ,
3337 SsoController ,
3438 OrgSsoStatus ,
3539 SsoRouteDecision ,
Original file line number Diff line number Diff line change @@ -424,14 +424,21 @@ export type RoleMutationResult = { ok: true; role: Role } | { ok: false; error:
424424// Result for assignment / deletion mutations that don't return a value.
425425export type RoleAssignmentResult = { ok : true } | { ok : false ; error : string } ;
426426
427+ import type { PluginDatabaseConfig } from "./databaseConfig.js" ;
428+
427429// Host-injected configuration the plugin can't read from the environment
428430// itself (the plugin runs in the host's process but owns no env contract).
429431export type RbacPluginConfig = {
430432 // Platform secret the host signs user-actor tokens with; the plugin uses
431433 // it to verify them in `authenticateUserActor`. Omitted → UAT auth 401s.
432434 userActorSecret ?: string ;
435+ // Database connections for a plugin that owns its own client. Omitted →
436+ // the plugin falls back to its own defaults.
437+ database ?: PluginDatabaseConfig ;
433438} ;
434439
440+ export type { PluginDatabaseConfig as RbacDatabaseConfig } from "./databaseConfig.js" ;
441+
435442export interface RoleBasedAccessControlPlugin {
436443 create ( config ?: RbacPluginConfig ) : RoleBaseAccessController | Promise < RoleBaseAccessController > ;
437444}
Original file line number Diff line number Diff line change 11import type { ResultAsync } from "neverthrow" ;
2+ import type { PluginDatabaseConfig } from "./databaseConfig.js" ;
23
34// === Domain types ===
45
@@ -368,6 +369,14 @@ export interface SsoController {
368369 ) : ResultAsync < { effects : DirectorySyncEffect [ ] } , SsoWebhookError > ;
369370}
370371
372+ // Host-injected configuration the plugin can't read from the environment
373+ // itself (the plugin runs in the host's process but owns no env contract).
374+ export type SsoPluginConfig = {
375+ // Database connections for a plugin that owns its own client. Omitted →
376+ // the plugin falls back to its own defaults.
377+ database ?: PluginDatabaseConfig ;
378+ } ;
379+
371380export interface SsoPlugin {
372- create ( ) : SsoController | Promise < SsoController > ;
381+ create ( config ?: SsoPluginConfig ) : SsoController | Promise < SsoController > ;
373382}
You can’t perform that action at this time.
0 commit comments