@opengeni/db 3.2.0-canary.0 → 3.4.0-canary.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/canonical-human-identities.js +3 -3
- package/dist/{chunk-SIBYBA2D.js → chunk-6DPJA36C.js} +30 -11
- package/dist/chunk-6DPJA36C.js.map +1 -0
- package/dist/{chunk-KRLPEMLH.js → chunk-C2AFP7SB.js} +184 -6
- package/dist/chunk-C2AFP7SB.js.map +1 -0
- package/dist/{chunk-AZHW7R5V.js → chunk-H7MXYG7R.js} +12 -8
- package/dist/chunk-H7MXYG7R.js.map +1 -0
- package/dist/{chunk-2PRS4J5Q.js → chunk-HY3F5Q4E.js} +3 -3
- package/dist/{chunk-NAB6FKFN.js → chunk-O6FTELKH.js} +3 -3
- package/dist/{chunk-UZNXG44K.js → chunk-PYMY3AJW.js} +324 -8
- package/dist/chunk-PYMY3AJW.js.map +1 -0
- package/dist/{chunk-6HMM2R5T.js → chunk-TRBOWUG3.js} +98 -4
- package/dist/chunk-TRBOWUG3.js.map +1 -0
- package/dist/{chunk-E6CLMKEE.js → chunk-V3TRUXFJ.js} +2 -2
- package/dist/{chunk-2EH4WRHL.js → chunk-ZWRIPCTR.js} +2 -2
- package/dist/editable-artifact-durable-export.js +2 -2
- package/dist/editable-artifacts.js +3 -3
- package/dist/governed-learning-activation.d.ts +16 -0
- package/dist/index.d.ts +108 -7
- package/dist/index.js +3605 -1417
- package/dist/index.js.map +1 -1
- package/dist/insights-model-bundle.d.ts +30 -0
- package/dist/insights-usage-bundle.d.ts +32 -0
- package/dist/insights.d.ts +10 -2
- package/dist/lossless-json.d.ts +1 -1
- package/dist/managed-user-setup.d.ts +82 -0
- package/dist/memory-domain.d.ts +2 -2
- package/dist/migrate.d.ts +3 -1
- package/dist/migrate.js +1 -1
- package/dist/new-session-drafts.d.ts +4 -4
- package/dist/organization-membership-lifecycle.d.ts +60 -1
- package/dist/pr-review.d.ts +44 -3
- package/dist/provision-roles.js +1 -1
- package/dist/runtime-posture.d.ts +12 -7
- package/dist/schema.d.ts +839 -101
- package/dist/schema.js +9 -1
- package/dist/session-background-commands.js +3 -3
- package/dist/session-tenancy.d.ts +12 -1
- package/dist/session-tenancy.js +3 -3
- package/dist/video-generation.js +3 -3
- package/drizzle/0348_named_signup_and_user_setup.sql +838 -0
- package/drizzle/0349_greenfield_session_tenancy_activation.sql +792 -0
- package/drizzle/0350_organization_shared_workspace_administration.sql +889 -0
- package/drizzle/0351_organization_user_setup_delivery.sql +978 -0
- package/drizzle/0352_session_variable_set_attachments.sql +1661 -0
- package/drizzle/0353_automatic_session_title_policy_fence.sql +476 -0
- package/drizzle/0354_automatic_session_title_quarantine_index.sql +9 -0
- package/drizzle/0355_automatic_session_title_quarantine.sql +92 -0
- package/drizzle/0356_set_based_insights_session_visibility.sql +237 -0
- package/drizzle/0357_rig_platform_base_only.sql +44 -0
- package/drizzle/0358_pr_review_managed_github_app.sql +108 -0
- package/drizzle/0359_insights_force_rls_read_capability.sql +936 -0
- package/drizzle/0360_organization_identity_confirmation_prompt.sql +103 -0
- package/drizzle/0361_remember_knowledge_memory_materialization.sql +249 -0
- package/package.json +6 -6
- package/src/database.ts +12 -8
- package/src/governed-learning-activation.ts +74 -2
- package/src/index.ts +879 -92
- package/src/insights-model-bundle.ts +681 -0
- package/src/insights-usage-bundle.ts +240 -0
- package/src/insights.ts +265 -152
- package/src/lossless-json.ts +2 -1
- package/src/managed-user-setup.ts +316 -0
- package/src/memory-domain.ts +3 -3
- package/src/migrate.ts +38 -14
- package/src/new-session-drafts.ts +22 -15
- package/src/organization-membership-lifecycle.ts +253 -1
- package/src/pr-review.ts +449 -6
- package/src/provision-roles.ts +92 -0
- package/src/runtime-posture.ts +247 -4
- package/src/schema.ts +210 -4
- package/src/session-tenancy.ts +120 -2
- package/dist/chunk-6HMM2R5T.js.map +0 -1
- package/dist/chunk-AZHW7R5V.js.map +0 -1
- package/dist/chunk-KRLPEMLH.js.map +0 -1
- package/dist/chunk-SIBYBA2D.js.map +0 -1
- package/dist/chunk-UZNXG44K.js.map +0 -1
- /package/dist/{chunk-2PRS4J5Q.js.map → chunk-HY3F5Q4E.js.map} +0 -0
- /package/dist/{chunk-NAB6FKFN.js.map → chunk-O6FTELKH.js.map} +0 -0
- /package/dist/{chunk-E6CLMKEE.js.map → chunk-V3TRUXFJ.js.map} +0 -0
- /package/dist/{chunk-2EH4WRHL.js.map → chunk-ZWRIPCTR.js.map} +0 -0
package/src/pr-review.ts
CHANGED
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
OPENGENI_PR_REVIEW_PACK_ID,
|
|
4
4
|
OPENGENI_PR_REVIEW_SESSION_ROLE,
|
|
5
5
|
type PrReviewAppRegistration,
|
|
6
|
+
type GitHubRepository,
|
|
6
7
|
type PrReviewProvider,
|
|
7
8
|
type PrReviewRepositoryBinding,
|
|
8
9
|
} from "@opengeni/contracts";
|
|
@@ -32,8 +33,11 @@ export async function createPrReviewAppRegistration(
|
|
|
32
33
|
provider: PrReviewProvider;
|
|
33
34
|
providerBaseUrl: string;
|
|
34
35
|
appId: string | null;
|
|
35
|
-
credentialKind: "github_app" | "provider_token";
|
|
36
|
+
credentialKind: "github_app" | "managed_github_app" | "provider_token";
|
|
36
37
|
credentialEncrypted: string | null;
|
|
38
|
+
installationId?: string | null;
|
|
39
|
+
providerAccountLogin?: string | null;
|
|
40
|
+
providerAccountType?: "User" | "Organization" | null;
|
|
37
41
|
accessTokenExpiresAt: Date | null;
|
|
38
42
|
webhookAuthKind: "hmac_sha256" | "shared_token" | "basic";
|
|
39
43
|
webhookSecretEncrypted: string;
|
|
@@ -83,6 +87,9 @@ export async function createPrReviewAppRegistration(
|
|
|
83
87
|
provider: input.provider,
|
|
84
88
|
providerBaseUrl: input.providerBaseUrl,
|
|
85
89
|
appId: input.appId,
|
|
90
|
+
installationId: input.installationId ?? null,
|
|
91
|
+
providerAccountLogin: input.providerAccountLogin ?? null,
|
|
92
|
+
providerAccountType: input.providerAccountType ?? null,
|
|
86
93
|
credentialKind: input.credentialKind,
|
|
87
94
|
credentialEncrypted: input.credentialEncrypted,
|
|
88
95
|
accessTokenExpiresAt: input.accessTokenExpiresAt,
|
|
@@ -246,6 +253,11 @@ export async function updatePrReviewAppRegistration(
|
|
|
246
253
|
),
|
|
247
254
|
)
|
|
248
255
|
.returning();
|
|
256
|
+
if (input.status === "disabled") {
|
|
257
|
+
await tx
|
|
258
|
+
.delete(schema.prReviewManagedGithubRoutes)
|
|
259
|
+
.where(eq(schema.prReviewManagedGithubRoutes.registrationId, input.registrationId));
|
|
260
|
+
}
|
|
249
261
|
return row ? mapRegistration(row, source.endpointId) : null;
|
|
250
262
|
});
|
|
251
263
|
});
|
|
@@ -268,6 +280,9 @@ export async function deletePrReviewAppRegistration(
|
|
|
268
280
|
)
|
|
269
281
|
.returning({ sourceId: schema.prReviewAppRegistrations.sourceId });
|
|
270
282
|
if (!registration) return false;
|
|
283
|
+
await tx
|
|
284
|
+
.delete(schema.prReviewManagedGithubRoutes)
|
|
285
|
+
.where(eq(schema.prReviewManagedGithubRoutes.registrationId, input.registrationId));
|
|
271
286
|
await tx
|
|
272
287
|
.update(schema.automationSources)
|
|
273
288
|
.set({
|
|
@@ -383,6 +398,425 @@ export async function createPrReviewRepositoryBinding(
|
|
|
383
398
|
});
|
|
384
399
|
}
|
|
385
400
|
|
|
401
|
+
/** Atomically converge one owner-authorized installation of the deployment
|
|
402
|
+
* review App onto the Pack's ordinary source/trigger/binding model. Re-running
|
|
403
|
+
* the browser flow repairs disabled rows, follows GitHub repository selection,
|
|
404
|
+
* and removes shared-webhook routes for repositories no longer selected. */
|
|
405
|
+
export async function syncManagedGitHubPrReviewInstallation(
|
|
406
|
+
db: Database,
|
|
407
|
+
input: {
|
|
408
|
+
accountId: string;
|
|
409
|
+
workspaceId: string;
|
|
410
|
+
installationId: number;
|
|
411
|
+
providerAccountLogin: string | null;
|
|
412
|
+
providerAccountType: "User" | "Organization";
|
|
413
|
+
githubActorId: number;
|
|
414
|
+
authorityKind: "personal_owner" | "organization_owner";
|
|
415
|
+
authorityCheckedAt: Date;
|
|
416
|
+
authorityExpiresAt: Date;
|
|
417
|
+
authorityNonce: string;
|
|
418
|
+
appId: string;
|
|
419
|
+
webhookSecretEncrypted: string;
|
|
420
|
+
repositories: GitHubRepository[];
|
|
421
|
+
createdBySubjectId: string;
|
|
422
|
+
packInstallationId: string;
|
|
423
|
+
packConnectorId: string;
|
|
424
|
+
packTemplateId: string;
|
|
425
|
+
adapterId: string;
|
|
426
|
+
eventTypes: string[];
|
|
427
|
+
configuration: Record<string, unknown>;
|
|
428
|
+
sessionTemplate: AutomationSessionTemplate;
|
|
429
|
+
},
|
|
430
|
+
): Promise<{
|
|
431
|
+
registration: PrReviewAppRegistration;
|
|
432
|
+
repositories: PrReviewRepositoryBinding[];
|
|
433
|
+
}> {
|
|
434
|
+
return await withRlsContext(
|
|
435
|
+
db,
|
|
436
|
+
input,
|
|
437
|
+
async (scopedDb) =>
|
|
438
|
+
await scopedDb.transaction(async (tx) => {
|
|
439
|
+
const [packInstallation] = await tx
|
|
440
|
+
.select({ id: schema.packInstallations.id })
|
|
441
|
+
.from(schema.packInstallations)
|
|
442
|
+
.where(
|
|
443
|
+
and(
|
|
444
|
+
eq(schema.packInstallations.workspaceId, input.workspaceId),
|
|
445
|
+
eq(schema.packInstallations.id, input.packInstallationId),
|
|
446
|
+
eq(schema.packInstallations.packId, OPENGENI_PR_REVIEW_PACK_ID),
|
|
447
|
+
eq(schema.packInstallations.status, "active"),
|
|
448
|
+
),
|
|
449
|
+
)
|
|
450
|
+
.limit(1)
|
|
451
|
+
.for("update");
|
|
452
|
+
if (!packInstallation) {
|
|
453
|
+
throw new PrReviewDispatchAuthorityError("OpenGeni Review Bot Pack is not active");
|
|
454
|
+
}
|
|
455
|
+
const installationId = String(input.installationId);
|
|
456
|
+
const [nonceReceipt] = await tx
|
|
457
|
+
.insert(schema.prReviewManagedGithubAuthorityNonces)
|
|
458
|
+
.values({
|
|
459
|
+
authorityNonce: input.authorityNonce,
|
|
460
|
+
accountId: input.accountId,
|
|
461
|
+
workspaceId: input.workspaceId,
|
|
462
|
+
installationId,
|
|
463
|
+
authorityExpiresAt: input.authorityExpiresAt,
|
|
464
|
+
})
|
|
465
|
+
.onConflictDoNothing()
|
|
466
|
+
.returning({
|
|
467
|
+
authorityNonce: schema.prReviewManagedGithubAuthorityNonces.authorityNonce,
|
|
468
|
+
});
|
|
469
|
+
if (!nonceReceipt) {
|
|
470
|
+
throw new PrReviewDispatchAuthorityError("OpenGeni Lens authorization was already used");
|
|
471
|
+
}
|
|
472
|
+
const [existingRegistration] = await tx
|
|
473
|
+
.select()
|
|
474
|
+
.from(schema.prReviewAppRegistrations)
|
|
475
|
+
.where(
|
|
476
|
+
and(
|
|
477
|
+
eq(schema.prReviewAppRegistrations.workspaceId, input.workspaceId),
|
|
478
|
+
eq(schema.prReviewAppRegistrations.credentialKind, "managed_github_app"),
|
|
479
|
+
eq(schema.prReviewAppRegistrations.installationId, installationId),
|
|
480
|
+
),
|
|
481
|
+
)
|
|
482
|
+
.limit(1)
|
|
483
|
+
.for("update");
|
|
484
|
+
|
|
485
|
+
const registrationId = existingRegistration?.id ?? randomUUID();
|
|
486
|
+
const registrationName = `OpenGeni Lens · ${
|
|
487
|
+
input.providerAccountLogin ?? `installation ${installationId}`
|
|
488
|
+
} (${installationId})`;
|
|
489
|
+
let source: typeof schema.automationSources.$inferSelect;
|
|
490
|
+
let registration: typeof schema.prReviewAppRegistrations.$inferSelect;
|
|
491
|
+
|
|
492
|
+
if (existingRegistration) {
|
|
493
|
+
const nextSourceConfiguration = {
|
|
494
|
+
provider: "github",
|
|
495
|
+
providerBaseUrl: "https://github.com",
|
|
496
|
+
registrationId,
|
|
497
|
+
webhookUsername: null,
|
|
498
|
+
};
|
|
499
|
+
const [updatedSource] = await tx
|
|
500
|
+
.update(schema.automationSources)
|
|
501
|
+
.set({
|
|
502
|
+
name: `${registrationName} webhooks`,
|
|
503
|
+
adapterId: input.adapterId,
|
|
504
|
+
configuration: nextSourceConfiguration,
|
|
505
|
+
webhookSecretEncrypted: input.webhookSecretEncrypted,
|
|
506
|
+
status: "active",
|
|
507
|
+
packInstallationId: input.packInstallationId,
|
|
508
|
+
packConnectorId: input.packConnectorId,
|
|
509
|
+
version: sql`${schema.automationSources.version} + 1`,
|
|
510
|
+
updatedAt: new Date(),
|
|
511
|
+
})
|
|
512
|
+
.where(
|
|
513
|
+
and(
|
|
514
|
+
eq(schema.automationSources.workspaceId, input.workspaceId),
|
|
515
|
+
eq(schema.automationSources.id, existingRegistration.sourceId),
|
|
516
|
+
),
|
|
517
|
+
)
|
|
518
|
+
.returning();
|
|
519
|
+
if (!updatedSource) {
|
|
520
|
+
throw new PrReviewDispatchAuthorityError(
|
|
521
|
+
"OpenGeni Lens automation source is unavailable",
|
|
522
|
+
);
|
|
523
|
+
}
|
|
524
|
+
source = updatedSource;
|
|
525
|
+
const [updatedRegistration] = await tx
|
|
526
|
+
.update(schema.prReviewAppRegistrations)
|
|
527
|
+
.set({
|
|
528
|
+
name: registrationName,
|
|
529
|
+
appId: input.appId,
|
|
530
|
+
providerAccountLogin: input.providerAccountLogin,
|
|
531
|
+
providerAccountType: input.providerAccountType,
|
|
532
|
+
githubActorId: String(input.githubActorId),
|
|
533
|
+
authorityKind: input.authorityKind,
|
|
534
|
+
authorityCheckedAt: input.authorityCheckedAt,
|
|
535
|
+
authorityExpiresAt: input.authorityExpiresAt,
|
|
536
|
+
authorityNonce: input.authorityNonce,
|
|
537
|
+
status: "active",
|
|
538
|
+
updatedAt: new Date(),
|
|
539
|
+
})
|
|
540
|
+
.where(eq(schema.prReviewAppRegistrations.id, existingRegistration.id))
|
|
541
|
+
.returning();
|
|
542
|
+
if (!updatedRegistration) throw new Error("Failed to update OpenGeni Lens registration");
|
|
543
|
+
registration = updatedRegistration;
|
|
544
|
+
} else {
|
|
545
|
+
const [createdSource] = await tx
|
|
546
|
+
.insert(schema.automationSources)
|
|
547
|
+
.values({
|
|
548
|
+
accountId: input.accountId,
|
|
549
|
+
workspaceId: input.workspaceId,
|
|
550
|
+
name: `${registrationName} webhooks`,
|
|
551
|
+
adapterId: input.adapterId,
|
|
552
|
+
configuration: {
|
|
553
|
+
provider: "github",
|
|
554
|
+
providerBaseUrl: "https://github.com",
|
|
555
|
+
registrationId,
|
|
556
|
+
webhookUsername: null,
|
|
557
|
+
},
|
|
558
|
+
webhookSecretEncrypted: input.webhookSecretEncrypted,
|
|
559
|
+
packInstallationId: input.packInstallationId,
|
|
560
|
+
packConnectorId: input.packConnectorId,
|
|
561
|
+
createdBySubjectId: input.createdBySubjectId,
|
|
562
|
+
})
|
|
563
|
+
.returning();
|
|
564
|
+
if (!createdSource) throw new Error("Failed to create OpenGeni Lens automation source");
|
|
565
|
+
source = createdSource;
|
|
566
|
+
const [createdRegistration] = await tx
|
|
567
|
+
.insert(schema.prReviewAppRegistrations)
|
|
568
|
+
.values({
|
|
569
|
+
id: registrationId,
|
|
570
|
+
sourceId: source.id,
|
|
571
|
+
accountId: input.accountId,
|
|
572
|
+
workspaceId: input.workspaceId,
|
|
573
|
+
name: registrationName,
|
|
574
|
+
provider: "github",
|
|
575
|
+
providerBaseUrl: "https://github.com",
|
|
576
|
+
appId: input.appId,
|
|
577
|
+
installationId,
|
|
578
|
+
providerAccountLogin: input.providerAccountLogin,
|
|
579
|
+
providerAccountType: input.providerAccountType,
|
|
580
|
+
githubActorId: String(input.githubActorId),
|
|
581
|
+
authorityKind: input.authorityKind,
|
|
582
|
+
authorityCheckedAt: input.authorityCheckedAt,
|
|
583
|
+
authorityExpiresAt: input.authorityExpiresAt,
|
|
584
|
+
authorityNonce: input.authorityNonce,
|
|
585
|
+
credentialKind: "managed_github_app",
|
|
586
|
+
credentialEncrypted: null,
|
|
587
|
+
accessTokenExpiresAt: null,
|
|
588
|
+
webhookAuthKind: "hmac_sha256",
|
|
589
|
+
webhookUsername: null,
|
|
590
|
+
createdBySubjectId: input.createdBySubjectId,
|
|
591
|
+
})
|
|
592
|
+
.returning();
|
|
593
|
+
if (!createdRegistration) throw new Error("Failed to create OpenGeni Lens registration");
|
|
594
|
+
registration = createdRegistration;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
const existingBindings = await tx
|
|
598
|
+
.select({
|
|
599
|
+
binding: schema.prReviewRepositoryBindings,
|
|
600
|
+
trigger: schema.automationTriggers,
|
|
601
|
+
revision: schema.automationTriggerRevisions,
|
|
602
|
+
})
|
|
603
|
+
.from(schema.prReviewRepositoryBindings)
|
|
604
|
+
.innerJoin(
|
|
605
|
+
schema.automationTriggers,
|
|
606
|
+
and(
|
|
607
|
+
eq(
|
|
608
|
+
schema.automationTriggers.workspaceId,
|
|
609
|
+
schema.prReviewRepositoryBindings.workspaceId,
|
|
610
|
+
),
|
|
611
|
+
eq(schema.automationTriggers.id, schema.prReviewRepositoryBindings.triggerId),
|
|
612
|
+
),
|
|
613
|
+
)
|
|
614
|
+
.innerJoin(
|
|
615
|
+
schema.automationTriggerRevisions,
|
|
616
|
+
and(
|
|
617
|
+
eq(schema.automationTriggerRevisions.triggerId, schema.automationTriggers.id),
|
|
618
|
+
eq(
|
|
619
|
+
schema.automationTriggerRevisions.revision,
|
|
620
|
+
schema.automationTriggers.currentRevision,
|
|
621
|
+
),
|
|
622
|
+
),
|
|
623
|
+
)
|
|
624
|
+
.where(
|
|
625
|
+
and(
|
|
626
|
+
eq(schema.prReviewRepositoryBindings.workspaceId, input.workspaceId),
|
|
627
|
+
eq(schema.prReviewRepositoryBindings.registrationId, registrationId),
|
|
628
|
+
),
|
|
629
|
+
)
|
|
630
|
+
.for("update", { of: schema.automationTriggers });
|
|
631
|
+
const existingByRepositoryId = new Map(
|
|
632
|
+
existingBindings.map((row) => [row.binding.providerRepositoryId, row] as const),
|
|
633
|
+
);
|
|
634
|
+
const selectedIds = new Set(input.repositories.map((repository) => String(repository.id)));
|
|
635
|
+
const synchronized: Array<typeof schema.prReviewRepositoryBindings.$inferSelect> = [];
|
|
636
|
+
|
|
637
|
+
for (const repository of input.repositories) {
|
|
638
|
+
if (repository.installationId !== input.installationId) {
|
|
639
|
+
throw new PrReviewDispatchAuthorityError(
|
|
640
|
+
"OpenGeni Lens repository does not belong to the authorized installation",
|
|
641
|
+
);
|
|
642
|
+
}
|
|
643
|
+
const providerRepositoryId = String(repository.id);
|
|
644
|
+
const current = existingByRepositoryId.get(providerRepositoryId);
|
|
645
|
+
if (!current) {
|
|
646
|
+
const bindingId = randomUUID();
|
|
647
|
+
const [trigger] = await tx
|
|
648
|
+
.insert(schema.automationTriggers)
|
|
649
|
+
.values({
|
|
650
|
+
accountId: input.accountId,
|
|
651
|
+
workspaceId: input.workspaceId,
|
|
652
|
+
sourceId: source.id,
|
|
653
|
+
name: `Review ${repository.fullName}`,
|
|
654
|
+
status: "active",
|
|
655
|
+
packInstallationId: input.packInstallationId,
|
|
656
|
+
packTemplateId: input.packTemplateId,
|
|
657
|
+
createdBySubjectId: input.createdBySubjectId,
|
|
658
|
+
})
|
|
659
|
+
.returning();
|
|
660
|
+
if (!trigger) throw new Error("Failed to create OpenGeni Lens trigger");
|
|
661
|
+
const bindingShape = {
|
|
662
|
+
registrationId,
|
|
663
|
+
provider: "github" as const,
|
|
664
|
+
repositoryUri: repository.cloneUrl,
|
|
665
|
+
repositoryFullName: repository.fullName,
|
|
666
|
+
providerRepositoryId,
|
|
667
|
+
installationId,
|
|
668
|
+
projectId: null,
|
|
669
|
+
model: null,
|
|
670
|
+
additionalInstructions: null,
|
|
671
|
+
};
|
|
672
|
+
await tx.insert(schema.automationTriggerRevisions).values({
|
|
673
|
+
triggerId: trigger.id,
|
|
674
|
+
revision: 1,
|
|
675
|
+
accountId: input.accountId,
|
|
676
|
+
workspaceId: input.workspaceId,
|
|
677
|
+
adapterId: input.adapterId,
|
|
678
|
+
eventTypes: input.eventTypes,
|
|
679
|
+
configuration: input.configuration,
|
|
680
|
+
parameters: prReviewTriggerParameters(bindingShape, bindingId),
|
|
681
|
+
sessionTemplate: input.sessionTemplate,
|
|
682
|
+
createdBySubjectId: input.createdBySubjectId,
|
|
683
|
+
});
|
|
684
|
+
const [binding] = await tx
|
|
685
|
+
.insert(schema.prReviewRepositoryBindings)
|
|
686
|
+
.values({
|
|
687
|
+
id: bindingId,
|
|
688
|
+
triggerId: trigger.id,
|
|
689
|
+
accountId: input.accountId,
|
|
690
|
+
workspaceId: input.workspaceId,
|
|
691
|
+
...bindingShape,
|
|
692
|
+
status: "active",
|
|
693
|
+
createdBySubjectId: input.createdBySubjectId,
|
|
694
|
+
})
|
|
695
|
+
.returning();
|
|
696
|
+
if (!binding) throw new Error("Failed to create OpenGeni Lens repository binding");
|
|
697
|
+
await tx.insert(schema.prReviewManagedGithubRoutes).values({
|
|
698
|
+
bindingId,
|
|
699
|
+
accountId: input.accountId,
|
|
700
|
+
workspaceId: input.workspaceId,
|
|
701
|
+
registrationId,
|
|
702
|
+
sourceId: source.id,
|
|
703
|
+
installationId,
|
|
704
|
+
providerRepositoryId,
|
|
705
|
+
});
|
|
706
|
+
synchronized.push(binding);
|
|
707
|
+
continue;
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
const nextBinding = {
|
|
711
|
+
...current.binding,
|
|
712
|
+
repositoryUri: repository.cloneUrl,
|
|
713
|
+
repositoryFullName: repository.fullName,
|
|
714
|
+
installationId,
|
|
715
|
+
status: "active" as const,
|
|
716
|
+
};
|
|
717
|
+
const nextRevision = current.trigger.currentRevision + 1;
|
|
718
|
+
await tx.insert(schema.automationTriggerRevisions).values({
|
|
719
|
+
triggerId: current.trigger.id,
|
|
720
|
+
revision: nextRevision,
|
|
721
|
+
accountId: input.accountId,
|
|
722
|
+
workspaceId: input.workspaceId,
|
|
723
|
+
adapterId: input.adapterId,
|
|
724
|
+
eventTypes: input.eventTypes,
|
|
725
|
+
configuration: input.configuration,
|
|
726
|
+
parameters: prReviewTriggerParameters(nextBinding, current.binding.id),
|
|
727
|
+
sessionTemplate: input.sessionTemplate,
|
|
728
|
+
createdBySubjectId: input.createdBySubjectId,
|
|
729
|
+
});
|
|
730
|
+
await tx
|
|
731
|
+
.update(schema.automationTriggers)
|
|
732
|
+
.set({
|
|
733
|
+
name: `Review ${repository.fullName}`,
|
|
734
|
+
status: "active",
|
|
735
|
+
currentRevision: nextRevision,
|
|
736
|
+
updatedAt: new Date(),
|
|
737
|
+
})
|
|
738
|
+
.where(eq(schema.automationTriggers.id, current.trigger.id));
|
|
739
|
+
const [binding] = await tx
|
|
740
|
+
.update(schema.prReviewRepositoryBindings)
|
|
741
|
+
.set({
|
|
742
|
+
repositoryUri: repository.cloneUrl,
|
|
743
|
+
repositoryFullName: repository.fullName,
|
|
744
|
+
installationId,
|
|
745
|
+
status: "active",
|
|
746
|
+
updatedAt: new Date(),
|
|
747
|
+
})
|
|
748
|
+
.where(eq(schema.prReviewRepositoryBindings.id, current.binding.id))
|
|
749
|
+
.returning();
|
|
750
|
+
if (!binding) throw new Error("Failed to update OpenGeni Lens repository binding");
|
|
751
|
+
await tx
|
|
752
|
+
.insert(schema.prReviewManagedGithubRoutes)
|
|
753
|
+
.values({
|
|
754
|
+
bindingId: binding.id,
|
|
755
|
+
accountId: input.accountId,
|
|
756
|
+
workspaceId: input.workspaceId,
|
|
757
|
+
registrationId,
|
|
758
|
+
sourceId: source.id,
|
|
759
|
+
installationId,
|
|
760
|
+
providerRepositoryId,
|
|
761
|
+
})
|
|
762
|
+
.onConflictDoUpdate({
|
|
763
|
+
target: schema.prReviewManagedGithubRoutes.bindingId,
|
|
764
|
+
set: {
|
|
765
|
+
accountId: input.accountId,
|
|
766
|
+
workspaceId: input.workspaceId,
|
|
767
|
+
registrationId,
|
|
768
|
+
sourceId: source.id,
|
|
769
|
+
installationId,
|
|
770
|
+
providerRepositoryId,
|
|
771
|
+
},
|
|
772
|
+
});
|
|
773
|
+
synchronized.push(binding);
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
for (const current of existingBindings) {
|
|
777
|
+
if (selectedIds.has(current.binding.providerRepositoryId)) continue;
|
|
778
|
+
await tx
|
|
779
|
+
.update(schema.prReviewRepositoryBindings)
|
|
780
|
+
.set({ status: "disabled", updatedAt: new Date() })
|
|
781
|
+
.where(eq(schema.prReviewRepositoryBindings.id, current.binding.id));
|
|
782
|
+
await tx
|
|
783
|
+
.update(schema.automationTriggers)
|
|
784
|
+
.set({ status: "disabled", updatedAt: new Date() })
|
|
785
|
+
.where(eq(schema.automationTriggers.id, current.trigger.id));
|
|
786
|
+
await tx
|
|
787
|
+
.delete(schema.prReviewManagedGithubRoutes)
|
|
788
|
+
.where(eq(schema.prReviewManagedGithubRoutes.bindingId, current.binding.id));
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
return {
|
|
792
|
+
registration: mapRegistration(registration, source.endpointId),
|
|
793
|
+
repositories: synchronized.map(mapRepositoryBinding),
|
|
794
|
+
};
|
|
795
|
+
}),
|
|
796
|
+
);
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
export async function resolveManagedGitHubPrReviewRoute(
|
|
800
|
+
db: Database,
|
|
801
|
+
input: { installationId: string; providerRepositoryId: string },
|
|
802
|
+
): Promise<{ accountId: string; workspaceId: string; sourceId: string } | null> {
|
|
803
|
+
const [row] = await db
|
|
804
|
+
.select({
|
|
805
|
+
accountId: schema.prReviewManagedGithubRoutes.accountId,
|
|
806
|
+
workspaceId: schema.prReviewManagedGithubRoutes.workspaceId,
|
|
807
|
+
sourceId: schema.prReviewManagedGithubRoutes.sourceId,
|
|
808
|
+
})
|
|
809
|
+
.from(schema.prReviewManagedGithubRoutes)
|
|
810
|
+
.where(
|
|
811
|
+
and(
|
|
812
|
+
eq(schema.prReviewManagedGithubRoutes.installationId, input.installationId),
|
|
813
|
+
eq(schema.prReviewManagedGithubRoutes.providerRepositoryId, input.providerRepositoryId),
|
|
814
|
+
),
|
|
815
|
+
)
|
|
816
|
+
.limit(1);
|
|
817
|
+
return row ?? null;
|
|
818
|
+
}
|
|
819
|
+
|
|
386
820
|
export async function listPrReviewRepositoryBindings(
|
|
387
821
|
db: Database,
|
|
388
822
|
accountId: string,
|
|
@@ -529,7 +963,7 @@ export async function resolvePrReviewGitCredential(
|
|
|
529
963
|
}>;
|
|
530
964
|
},
|
|
531
965
|
): Promise<{
|
|
532
|
-
credentialKind: "github_app" | "provider_token";
|
|
966
|
+
credentialKind: "github_app" | "managed_github_app" | "provider_token";
|
|
533
967
|
appId: string | null;
|
|
534
968
|
credentialEncrypted: string | null;
|
|
535
969
|
expiresAt: string | null;
|
|
@@ -754,7 +1188,10 @@ export async function resolvePrReviewGitCredential(
|
|
|
754
1188
|
if (pack?.status !== "active")
|
|
755
1189
|
throw new PrReviewDispatchAuthorityError("OpenGeni Review Bot Pack is not active");
|
|
756
1190
|
return {
|
|
757
|
-
credentialKind: registration.credentialKind as
|
|
1191
|
+
credentialKind: registration.credentialKind as
|
|
1192
|
+
| "github_app"
|
|
1193
|
+
| "managed_github_app"
|
|
1194
|
+
| "provider_token",
|
|
758
1195
|
appId: registration.appId,
|
|
759
1196
|
credentialEncrypted: registration.credentialEncrypted,
|
|
760
1197
|
expiresAt: registration.accessTokenExpiresAt?.toISOString() ?? null,
|
|
@@ -851,13 +1288,19 @@ function mapRegistration(
|
|
|
851
1288
|
provider: row.provider as PrReviewProvider,
|
|
852
1289
|
providerBaseUrl: row.providerBaseUrl,
|
|
853
1290
|
appId: row.appId,
|
|
854
|
-
credentialKind: row.credentialKind as "github_app" | "provider_token",
|
|
855
|
-
|
|
1291
|
+
credentialKind: row.credentialKind as "github_app" | "managed_github_app" | "provider_token",
|
|
1292
|
+
installationId: row.installationId,
|
|
1293
|
+
providerAccountLogin: row.providerAccountLogin,
|
|
1294
|
+
providerAccountType: row.providerAccountType as "User" | "Organization" | null,
|
|
1295
|
+
hasCredential: row.credentialKind === "managed_github_app" || row.credentialEncrypted !== null,
|
|
856
1296
|
accessTokenExpiresAt: row.accessTokenExpiresAt?.toISOString() ?? null,
|
|
857
1297
|
webhookAuthKind: row.webhookAuthKind as "hmac_sha256" | "shared_token" | "basic",
|
|
858
1298
|
hasWebhookSecret: true,
|
|
859
1299
|
webhookUsername: row.webhookUsername,
|
|
860
|
-
webhookPath:
|
|
1300
|
+
webhookPath:
|
|
1301
|
+
row.credentialKind === "managed_github_app"
|
|
1302
|
+
? "/v1/webhooks/pr-review/github"
|
|
1303
|
+
: `/v1/webhooks/automations/${endpointId}`,
|
|
861
1304
|
status: row.status as "active" | "disabled",
|
|
862
1305
|
createdBySubjectId: row.createdBySubjectId,
|
|
863
1306
|
createdAt: row.createdAt.toISOString(),
|
package/src/provision-roles.ts
CHANGED
|
@@ -488,8 +488,14 @@ async function grantAppRoleIfSchemaExists(
|
|
|
488
488
|
"list_self_organization_invitations(text,uuid,integer)",
|
|
489
489
|
"get_self_organization_invitation(text,uuid)",
|
|
490
490
|
"list_organization_members(uuid,text)",
|
|
491
|
+
"list_organization_administration_members(uuid,text)",
|
|
491
492
|
"list_organization_invitations(uuid,text,uuid,integer)",
|
|
492
493
|
"get_organization_administration_overview(uuid,text)",
|
|
494
|
+
"get_workspace_kind(uuid,uuid)",
|
|
495
|
+
"organization_workspace_command(jsonb)",
|
|
496
|
+
"resolve_organization_workspace_removal_subject(uuid,text,uuid)",
|
|
497
|
+
"prepare_organization_workspace_member_removal(jsonb)",
|
|
498
|
+
"record_organization_workspace_member_removal(jsonb,uuid,uuid)",
|
|
493
499
|
"create_managed_organization(text,text,text,uuid)",
|
|
494
500
|
"assert_organization_shared_workspace_administrator(uuid,uuid,text)",
|
|
495
501
|
"open_organization_shared_workspace_administration_capability(uuid,uuid,text)",
|
|
@@ -501,6 +507,15 @@ async function grantAppRoleIfSchemaExists(
|
|
|
501
507
|
"bind_pending_organization_invitations_for_verified_email(text,text)",
|
|
502
508
|
"has_pending_organization_invitation_for_subject(text)",
|
|
503
509
|
"accept_organization_invitation_v2(jsonb)",
|
|
510
|
+
"complete_self_service_organization_setup(jsonb)",
|
|
511
|
+
"ensure_organization_user_setup_intent(jsonb)",
|
|
512
|
+
"claim_organization_user_setup_delivery(jsonb)",
|
|
513
|
+
"prepare_organization_user_setup_delivery(jsonb)",
|
|
514
|
+
"settle_organization_user_setup_delivery(jsonb)",
|
|
515
|
+
"preview_organization_user_setup(text)",
|
|
516
|
+
"get_organization_invitation_for_administration(uuid,text,uuid)",
|
|
517
|
+
"preflight_organization_user_setup(text)",
|
|
518
|
+
"complete_organization_user_setup(jsonb)",
|
|
504
519
|
"organization_membership_command(jsonb)",
|
|
505
520
|
"prepare_organization_membership_protocol_settlements(jsonb)",
|
|
506
521
|
"assert_active_managed_human_organization_membership(uuid,text)",
|
|
@@ -884,6 +899,19 @@ BEGIN
|
|
|
884
899
|
${literal(role)}
|
|
885
900
|
);
|
|
886
901
|
END IF;
|
|
902
|
+
IF to_regprocedure(
|
|
903
|
+
format('%I.materialize_remember_knowledge_memory(uuid,uuid,uuid)', ${literal(schema)})
|
|
904
|
+
) IS NOT NULL THEN
|
|
905
|
+
EXECUTE format(
|
|
906
|
+
'REVOKE ALL ON FUNCTION %I.materialize_remember_knowledge_memory(uuid, uuid, uuid) FROM PUBLIC',
|
|
907
|
+
${literal(schema)}
|
|
908
|
+
);
|
|
909
|
+
EXECUTE format(
|
|
910
|
+
'GRANT EXECUTE ON FUNCTION %I.materialize_remember_knowledge_memory(uuid, uuid, uuid) TO %I',
|
|
911
|
+
${literal(schema)},
|
|
912
|
+
${literal(role)}
|
|
913
|
+
);
|
|
914
|
+
END IF;
|
|
887
915
|
IF to_regprocedure(
|
|
888
916
|
format('%I.undo_governed_learning_activation(uuid,uuid,uuid,uuid)', ${literal(schema)})
|
|
889
917
|
) IS NOT NULL THEN
|
|
@@ -1298,6 +1326,38 @@ BEGIN
|
|
|
1298
1326
|
${literal(role)}
|
|
1299
1327
|
);
|
|
1300
1328
|
END IF;
|
|
1329
|
+
IF to_regprocedure(
|
|
1330
|
+
format(
|
|
1331
|
+
'%I.fork_session_content_with_runtime(uuid,uuid,uuid,text,uuid,text,boolean,text,text,integer,jsonb,uuid,uuid,text)',
|
|
1332
|
+
${literal(schema)}
|
|
1333
|
+
)
|
|
1334
|
+
) IS NOT NULL THEN
|
|
1335
|
+
EXECUTE format(
|
|
1336
|
+
'REVOKE ALL ON FUNCTION %I.fork_session_content_with_runtime(uuid, uuid, uuid, text, uuid, text, boolean, text, text, integer, jsonb, uuid, uuid, text) FROM PUBLIC',
|
|
1337
|
+
${literal(schema)}
|
|
1338
|
+
);
|
|
1339
|
+
EXECUTE format(
|
|
1340
|
+
'GRANT EXECUTE ON FUNCTION %I.fork_session_content_with_runtime(uuid, uuid, uuid, text, uuid, text, boolean, text, text, integer, jsonb, uuid, uuid, text) TO %I',
|
|
1341
|
+
${literal(schema)},
|
|
1342
|
+
${literal(role)}
|
|
1343
|
+
);
|
|
1344
|
+
END IF;
|
|
1345
|
+
IF to_regprocedure(
|
|
1346
|
+
format(
|
|
1347
|
+
'%I.replay_applied_session_fork_with_runtime(uuid,uuid,uuid,text,uuid,text,boolean,text,text,integer,text)',
|
|
1348
|
+
${literal(schema)}
|
|
1349
|
+
)
|
|
1350
|
+
) IS NOT NULL THEN
|
|
1351
|
+
EXECUTE format(
|
|
1352
|
+
'REVOKE ALL ON FUNCTION %I.replay_applied_session_fork_with_runtime(uuid, uuid, uuid, text, uuid, text, boolean, text, text, integer, text) FROM PUBLIC',
|
|
1353
|
+
${literal(schema)}
|
|
1354
|
+
);
|
|
1355
|
+
EXECUTE format(
|
|
1356
|
+
'GRANT EXECUTE ON FUNCTION %I.replay_applied_session_fork_with_runtime(uuid, uuid, uuid, text, uuid, text, boolean, text, text, integer, text) TO %I',
|
|
1357
|
+
${literal(schema)},
|
|
1358
|
+
${literal(role)}
|
|
1359
|
+
);
|
|
1360
|
+
END IF;
|
|
1301
1361
|
IF to_regprocedure(
|
|
1302
1362
|
format('%I.session_tenancy_product_activated(uuid,integer)', ${literal(schema)})
|
|
1303
1363
|
) IS NOT NULL THEN
|
|
@@ -1921,6 +1981,15 @@ BEGIN
|
|
|
1921
1981
|
${literal(role)}
|
|
1922
1982
|
);
|
|
1923
1983
|
END IF;
|
|
1984
|
+
IF to_regprocedure('opengeni_private.session_variable_set_attachments_protocol_v1_active()') IS NOT NULL THEN
|
|
1985
|
+
REVOKE ALL ON FUNCTION
|
|
1986
|
+
opengeni_private.session_variable_set_attachments_protocol_v1_active()
|
|
1987
|
+
FROM PUBLIC;
|
|
1988
|
+
EXECUTE format(
|
|
1989
|
+
'GRANT EXECUTE ON FUNCTION opengeni_private.session_variable_set_attachments_protocol_v1_active() TO %I',
|
|
1990
|
+
${literal(role)}
|
|
1991
|
+
);
|
|
1992
|
+
END IF;
|
|
1924
1993
|
IF to_regprocedure('opengeni_private.scoped_compute_capability_active(text)') IS NOT NULL THEN
|
|
1925
1994
|
REVOKE ALL ON FUNCTION opengeni_private.scoped_compute_capability_active(text) FROM PUBLIC;
|
|
1926
1995
|
EXECUTE format(
|
|
@@ -1932,6 +2001,29 @@ BEGIN
|
|
|
1932
2001
|
${literal(role)}
|
|
1933
2002
|
);
|
|
1934
2003
|
END IF;
|
|
2004
|
+
-- The automatic-title migration helper and policy trigger deliberately
|
|
2005
|
+
-- retain role-scoped EXECUTE for pre-policy startup/readiness
|
|
2006
|
+
-- compatibility. Both are SECURITY INVOKER and PUBLIC remains revoked; RLS
|
|
2007
|
+
-- and the private-table ACL deny app-role enqueue writes, while PostgreSQL
|
|
2008
|
+
-- refuses direct trigger calls, so neither grant conveys data authority.
|
|
2009
|
+
IF to_regclass('opengeni_private.automatic_session_title_fanout_outbox_v1') IS NOT NULL THEN
|
|
2010
|
+
EXECUTE format(
|
|
2011
|
+
'REVOKE ALL PRIVILEGES ON TABLE opengeni_private.automatic_session_title_fanout_outbox_v1 FROM %I',
|
|
2012
|
+
${literal(role)}
|
|
2013
|
+
);
|
|
2014
|
+
END IF;
|
|
2015
|
+
IF to_regprocedure('opengeni_private.enqueue_automatic_session_title_fanout_v1(uuid,uuid,uuid,uuid)') IS NOT NULL THEN
|
|
2016
|
+
EXECUTE format(
|
|
2017
|
+
'GRANT EXECUTE ON FUNCTION opengeni_private.enqueue_automatic_session_title_fanout_v1(uuid, uuid, uuid, uuid) TO %I',
|
|
2018
|
+
${literal(role)}
|
|
2019
|
+
);
|
|
2020
|
+
END IF;
|
|
2021
|
+
IF to_regprocedure('opengeni_private.enforce_automatic_session_title_policy_v1()') IS NOT NULL THEN
|
|
2022
|
+
EXECUTE format(
|
|
2023
|
+
'GRANT EXECUTE ON FUNCTION opengeni_private.enforce_automatic_session_title_policy_v1() TO %I',
|
|
2024
|
+
${literal(role)}
|
|
2025
|
+
);
|
|
2026
|
+
END IF;
|
|
1935
2027
|
-- Global cross-workspace artifact workers are separate capabilities. Never
|
|
1936
2028
|
-- let the generic tenant-scoped app role inherit them from the historical
|
|
1937
2029
|
-- blanket grant of already-installed helpers.
|