@opengeni/db 0.12.1 → 0.13.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/chunk-ELMUCYZF.js +906 -0
- package/dist/chunk-ELMUCYZF.js.map +1 -0
- package/dist/chunk-N4WTE6SB.js +4033 -0
- package/dist/chunk-N4WTE6SB.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +3594 -2059
- package/dist/index.js.map +1 -1
- package/dist/provision-roles.d.ts +472 -43
- package/dist/provision-roles.js +1 -1
- package/dist/{schema-BejThLcd.d.ts → schema-Bh1Hr7xY.d.ts} +2507 -970
- package/dist/schema.d.ts +1 -1
- package/dist/schema.js +9 -1
- package/drizzle/0122_codex_capacity_same_turn.sql +59 -0
- package/drizzle/0123_session_tool_policy_version.sql +14 -0
- package/drizzle/0124_session_event_duplicate_lookup.sql +4 -0
- package/drizzle/0125_document_drops_visibility.sql +29 -0
- package/drizzle/0126_document_access_constraints.sql +138 -0
- package/drizzle/0127_document_default_base_index.sql +5 -0
- package/drizzle/0128_github_installation_authority.sql +69 -0
- package/drizzle/0129_retained_process_reconciliation.sql +356 -0
- package/drizzle/0130_workspace_instruction_policies.sql +330 -0
- package/drizzle/0131_slack_bot_install_and_post_idempotency.sql +133 -0
- package/package.json +4 -3
- package/src/event-payload-sanitizer.ts +167 -55
- package/src/index.ts +1850 -264
- package/src/new-session-drafts.ts +127 -6
- package/src/provision-roles.ts +184 -2
- package/src/runtime-posture-cli.ts +57 -0
- package/src/runtime-posture.ts +770 -0
- package/src/schema.ts +243 -3
- package/src/session-control.ts +1 -0
- package/src/workspace-instruction-policies-schema.ts +140 -0
- package/src/workspace-instruction-policies.ts +624 -0
- package/dist/chunk-BMFDXFPA.js +0 -155
- package/dist/chunk-BMFDXFPA.js.map +0 -1
- package/dist/chunk-VUKRIBO5.js +0 -3679
- package/dist/chunk-VUKRIBO5.js.map +0 -1
package/src/schema.ts
CHANGED
|
@@ -485,6 +485,12 @@ export const connections = pgTable(
|
|
|
485
485
|
lastUsedAt: timestamp("last_used_at", { withTimezone: true }),
|
|
486
486
|
lastError: text("last_error"),
|
|
487
487
|
version: integer("version").notNull().default(1),
|
|
488
|
+
// Server-owned proof that the dedicated install route verified the exact
|
|
489
|
+
// credential at this connection version. Generic/legacy writers cannot set
|
|
490
|
+
// these columns, and migration 0131 clears them when protected fields change
|
|
491
|
+
// without a fresh verification in the same statement.
|
|
492
|
+
verifiedInstallAt: timestamp("verified_install_at", { withTimezone: true }),
|
|
493
|
+
verifiedInstallVersion: integer("verified_install_version"),
|
|
488
494
|
metadata: jsonb("metadata").$type<Record<string, unknown>>().notNull().default({}),
|
|
489
495
|
createdBySubjectId: text("created_by_subject_id"),
|
|
490
496
|
updatedBySubjectId: text("updated_by_subject_id"),
|
|
@@ -510,6 +516,85 @@ export const connections = pgTable(
|
|
|
510
516
|
}),
|
|
511
517
|
);
|
|
512
518
|
|
|
519
|
+
// Durable provider-operation identity for OpenGeni Slack bot posts. The
|
|
520
|
+
// caller-supplied operation UUID is also Slack's client_msg_id; a bounded claim
|
|
521
|
+
// serializes live attempts while an expired/released claim can safely retry the
|
|
522
|
+
// same provider identity after response loss or process death.
|
|
523
|
+
export const slackBotPostOperations = pgTable(
|
|
524
|
+
"slack_bot_post_operations",
|
|
525
|
+
{
|
|
526
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
527
|
+
accountId: uuid("account_id")
|
|
528
|
+
.notNull()
|
|
529
|
+
.references(() => managedAccounts.id, { onDelete: "cascade" }),
|
|
530
|
+
workspaceId: uuid("workspace_id")
|
|
531
|
+
.notNull()
|
|
532
|
+
.references(() => workspaces.id, { onDelete: "cascade" }),
|
|
533
|
+
connectionId: uuid("connection_id")
|
|
534
|
+
.notNull()
|
|
535
|
+
.references(() => connections.id, { onDelete: "cascade" }),
|
|
536
|
+
operationId: uuid("operation_id").notNull(),
|
|
537
|
+
clientMessageId: uuid("client_message_id").notNull(),
|
|
538
|
+
targetKind: text("target_kind").$type<"channel" | "user">().notNull(),
|
|
539
|
+
targetId: text("target_id").notNull(),
|
|
540
|
+
requestDigest: text("request_digest").notNull(),
|
|
541
|
+
status: text("status").$type<"provider_started" | "completed">().notNull(),
|
|
542
|
+
claimHolderId: uuid("claim_holder_id"),
|
|
543
|
+
claimExpiresAt: timestamp("claim_expires_at", { withTimezone: true }),
|
|
544
|
+
attemptCount: integer("attempt_count").notNull().default(0),
|
|
545
|
+
lastFailureCode: text("last_failure_code"),
|
|
546
|
+
slackChannelId: text("slack_channel_id"),
|
|
547
|
+
slackMessageTimestamp: text("slack_message_timestamp"),
|
|
548
|
+
completedAt: timestamp("completed_at", { withTimezone: true }),
|
|
549
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
550
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
551
|
+
},
|
|
552
|
+
(table) => ({
|
|
553
|
+
workspaceOperation: uniqueIndex("slack_bot_post_operations_workspace_operation_uq").on(
|
|
554
|
+
table.workspaceId,
|
|
555
|
+
table.connectionId,
|
|
556
|
+
table.operationId,
|
|
557
|
+
),
|
|
558
|
+
workspaceStatus: index("slack_bot_post_operations_workspace_status_idx").on(
|
|
559
|
+
table.workspaceId,
|
|
560
|
+
table.status,
|
|
561
|
+
table.updatedAt,
|
|
562
|
+
),
|
|
563
|
+
targetKindValid: check(
|
|
564
|
+
"slack_bot_post_operations_target_kind_check",
|
|
565
|
+
sql`${table.targetKind} in ('channel', 'user')`,
|
|
566
|
+
),
|
|
567
|
+
statusValid: check(
|
|
568
|
+
"slack_bot_post_operations_status_check",
|
|
569
|
+
sql`${table.status} in ('provider_started', 'completed')`,
|
|
570
|
+
),
|
|
571
|
+
identityValid: check(
|
|
572
|
+
"slack_bot_post_operations_identity_check",
|
|
573
|
+
sql`${table.clientMessageId} = ${table.operationId}
|
|
574
|
+
and length(${table.targetId}) between 1 and 64
|
|
575
|
+
and ${table.requestDigest} ~ '^[0-9a-f]{64}$'
|
|
576
|
+
and ${table.attemptCount} > 0
|
|
577
|
+
and ((${table.claimHolderId} is null) = (${table.claimExpiresAt} is null))`,
|
|
578
|
+
),
|
|
579
|
+
completionValid: check(
|
|
580
|
+
"slack_bot_post_operations_completion_check",
|
|
581
|
+
sql`(
|
|
582
|
+
${table.status} = 'provider_started'
|
|
583
|
+
and ${table.slackChannelId} is null
|
|
584
|
+
and ${table.slackMessageTimestamp} is null
|
|
585
|
+
and ${table.completedAt} is null
|
|
586
|
+
) or (
|
|
587
|
+
${table.status} = 'completed'
|
|
588
|
+
and ${table.claimHolderId} is null
|
|
589
|
+
and ${table.claimExpiresAt} is null
|
|
590
|
+
and ${table.slackChannelId} is not null
|
|
591
|
+
and ${table.slackMessageTimestamp} is not null
|
|
592
|
+
and ${table.completedAt} is not null
|
|
593
|
+
)`,
|
|
594
|
+
),
|
|
595
|
+
}),
|
|
596
|
+
);
|
|
597
|
+
|
|
513
598
|
// OAuth client registrations minted through MCP DCR, keyed by authorization
|
|
514
599
|
// server issuer. This is deployment-wide client identity, not a workspace
|
|
515
600
|
// credential; per-user/provider tokens still live only in connections.
|
|
@@ -756,6 +841,8 @@ export const sessions = pgTable(
|
|
|
756
841
|
// mapSession exposes those rows as `legacy` instead of guessing omitted vs
|
|
757
842
|
// explicit [].
|
|
758
843
|
toolPolicy: jsonb("tool_policy").$type<SessionToolPolicy>(),
|
|
844
|
+
// Optimistic-concurrency fence for durable session tool-policy writes.
|
|
845
|
+
toolPolicyVersion: integer("tool_policy_version").notNull().default(1),
|
|
759
846
|
// The manager session that spawned this one via session_create. Set only
|
|
760
847
|
// when the creating grant carried a worker-signed sessionId claim (a session
|
|
761
848
|
// spawning a worker); null for direct API creates and scheduled-task runs.
|
|
@@ -1152,6 +1239,9 @@ export const documentBases = pgTable(
|
|
|
1152
1239
|
table.workspaceId,
|
|
1153
1240
|
table.createdAt,
|
|
1154
1241
|
),
|
|
1242
|
+
defaultName: uniqueIndex("document_bases_workspace_default_name_uq")
|
|
1243
|
+
.on(table.workspaceId)
|
|
1244
|
+
.where(sql`lower(btrim(${table.name})) = 'default'`),
|
|
1155
1245
|
}),
|
|
1156
1246
|
);
|
|
1157
1247
|
|
|
@@ -1185,6 +1275,17 @@ export const documents = pgTable(
|
|
|
1185
1275
|
sourceUpdatedAt: timestamp("source_updated_at", { withTimezone: true }),
|
|
1186
1276
|
sourceVersion: text("source_version"),
|
|
1187
1277
|
aclTags: jsonb("acl_tags").$type<string[]>().notNull().default([]),
|
|
1278
|
+
// Per-document access controls. visibility 'private' restricts human reads to
|
|
1279
|
+
// created_by (a grant subject id, not a uuid); agent_access=false hides the
|
|
1280
|
+
// document from agent retrieval surfaces (docs MCP) while humans keep REST.
|
|
1281
|
+
visibility: text("visibility").notNull().default("workspace"),
|
|
1282
|
+
createdBy: text("created_by"),
|
|
1283
|
+
agentAccess: boolean("agent_access").notNull().default(true),
|
|
1284
|
+
// Auto-curation output (knowledge drops).
|
|
1285
|
+
summary: text("summary"),
|
|
1286
|
+
topics: jsonb("topics").$type<string[]>().notNull().default([]),
|
|
1287
|
+
curationStatus: text("curation_status").notNull().default("none"),
|
|
1288
|
+
curation: jsonb("curation").$type<Record<string, unknown>>(),
|
|
1188
1289
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1189
1290
|
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1190
1291
|
},
|
|
@@ -1207,6 +1308,27 @@ export const documents = pgTable(
|
|
|
1207
1308
|
table.workspaceId,
|
|
1208
1309
|
table.sourceExternalId,
|
|
1209
1310
|
),
|
|
1311
|
+
curationStatus: index("documents_workspace_curation_status_idx").on(
|
|
1312
|
+
table.workspaceId,
|
|
1313
|
+
table.curationStatus,
|
|
1314
|
+
),
|
|
1315
|
+
visibilityState: check(
|
|
1316
|
+
"documents_visibility_chk",
|
|
1317
|
+
sql`${table.visibility} in ('workspace', 'private')`,
|
|
1318
|
+
),
|
|
1319
|
+
curationState: check(
|
|
1320
|
+
"documents_curation_status_chk",
|
|
1321
|
+
sql`${table.curationStatus} in ('none', 'pending', 'suggested', 'auto_filed', 'failed')`,
|
|
1322
|
+
),
|
|
1323
|
+
privateCreator: check(
|
|
1324
|
+
"documents_private_creator_chk",
|
|
1325
|
+
sql`${table.visibility} <> 'private' or nullif(btrim(${table.createdBy}), '') is not null`,
|
|
1326
|
+
),
|
|
1327
|
+
topicsArray: check("documents_topics_array_chk", sql`jsonb_typeof(${table.topics}) = 'array'`),
|
|
1328
|
+
curationObject: check(
|
|
1329
|
+
"documents_curation_object_chk",
|
|
1330
|
+
sql`${table.curation} is null or jsonb_typeof(${table.curation}) = 'object'`,
|
|
1331
|
+
),
|
|
1210
1332
|
}),
|
|
1211
1333
|
);
|
|
1212
1334
|
|
|
@@ -1485,7 +1607,8 @@ export const sessionTurnAttempts = pgTable(
|
|
|
1485
1607
|
"session_turn_attempts_outcome_check",
|
|
1486
1608
|
sql`${table.outcome} is null or ${table.outcome} in (
|
|
1487
1609
|
'completed', 'failed', 'cancelled', 'superseded', 'requires_action',
|
|
1488
|
-
'
|
|
1610
|
+
'waiting_capacity', 'interrupted_recoverable', 'lease_lost_recoverable',
|
|
1611
|
+
'pre_cutover_closed'
|
|
1489
1612
|
)`,
|
|
1490
1613
|
),
|
|
1491
1614
|
closedConsistent: check(
|
|
@@ -2014,12 +2137,13 @@ export const codexCapacityWaiters = pgTable(
|
|
|
2014
2137
|
.notNull()
|
|
2015
2138
|
.references(() => workspaces.id, { onDelete: "cascade" }),
|
|
2016
2139
|
sessionId: uuid("session_id").notNull(),
|
|
2017
|
-
goalId: uuid("goal_id")
|
|
2140
|
+
goalId: uuid("goal_id"),
|
|
2018
2141
|
blockedTurnId: uuid("blocked_turn_id").notNull(),
|
|
2142
|
+
blockedTurnGeneration: integer("blocked_turn_generation").notNull(),
|
|
2019
2143
|
workflowId: text("workflow_id").notNull(),
|
|
2020
2144
|
generation: integer("generation").notNull().default(1),
|
|
2021
2145
|
status: text("status").notNull().default("waiting"), // waiting | resumed | superseded
|
|
2022
|
-
goalVersion: integer("goal_version")
|
|
2146
|
+
goalVersion: integer("goal_version"),
|
|
2023
2147
|
policyHash: text("policy_hash"),
|
|
2024
2148
|
earliestResetAt: timestamp("earliest_reset_at", { withTimezone: true }),
|
|
2025
2149
|
nextCheckAt: timestamp("next_check_at", { withTimezone: true }).notNull(),
|
|
@@ -2118,6 +2242,7 @@ export const sessionEvents = pgTable(
|
|
|
2118
2242
|
.where(
|
|
2119
2243
|
sql`${table.type} not in ('agent.message.delta', 'agent.reasoning.delta', 'sandbox.command.output.delta', 'terminal.pty.output.delta')`,
|
|
2120
2244
|
),
|
|
2245
|
+
duplicateOfEvent: index("session_events_duplicate_of_event_idx").on(table.duplicateOfEventId),
|
|
2121
2246
|
payloadBytes: check(
|
|
2122
2247
|
"session_events_payload_bytes_check",
|
|
2123
2248
|
sql`octet_length(${table.payload}::text) <= 65536`,
|
|
@@ -2499,6 +2624,9 @@ export const sandboxLeases = pgTable(
|
|
|
2499
2624
|
reaperIdx: index("sandbox_leases_reaper_idx")
|
|
2500
2625
|
.on(table.expiresAt)
|
|
2501
2626
|
.where(sql`${table.liveness} in ('warming','warm','draining')`),
|
|
2627
|
+
expiredDrainingInventory: index("sandbox_leases_expired_draining_inventory_idx")
|
|
2628
|
+
.on(table.expiresAt, table.backend)
|
|
2629
|
+
.where(sql`${table.liveness} = 'draining'`),
|
|
2502
2630
|
workspaceGenerationValid: check(
|
|
2503
2631
|
"sandbox_leases_workspace_generation_check",
|
|
2504
2632
|
sql`${table.workspaceGeneration} >= 0`,
|
|
@@ -2736,6 +2864,19 @@ export const sandboxRetainedProcesses = pgTable(
|
|
|
2736
2864
|
settlementReason: text("settlement_reason"),
|
|
2737
2865
|
startedAt: timestamp("started_at", { withTimezone: true }).notNull().defaultNow(),
|
|
2738
2866
|
settledAt: timestamp("settled_at", { withTimezone: true }),
|
|
2867
|
+
// Coordination state for bounded terminal-owner reconciliation. While a
|
|
2868
|
+
// claim is live, reconcileAfter is its expiry; otherwise it is the next
|
|
2869
|
+
// retry time. Becoming due only licenses an exact provider probe and is
|
|
2870
|
+
// never exit/loss proof.
|
|
2871
|
+
reconcileAfter: timestamp("reconcile_after", { withTimezone: true }).notNull().defaultNow(),
|
|
2872
|
+
reconcileClaimId: uuid("reconcile_claim_id"),
|
|
2873
|
+
reconcileClaimedAt: timestamp("reconcile_claimed_at", { withTimezone: true }),
|
|
2874
|
+
reconcileAttempts: integer("reconcile_attempts").notNull().default(0),
|
|
2875
|
+
lastReconcileOutcome: text("last_reconcile_outcome"),
|
|
2876
|
+
reconcileProofOutcome: text("reconcile_proof_outcome", { enum: ["exited", "lost"] }),
|
|
2877
|
+
reconcileProofExitCode: integer("reconcile_proof_exit_code"),
|
|
2878
|
+
reconcileProofReason: text("reconcile_proof_reason"),
|
|
2879
|
+
reconcileProofObservedAt: timestamp("reconcile_proof_observed_at", { withTimezone: true }),
|
|
2739
2880
|
},
|
|
2740
2881
|
(table) => ({
|
|
2741
2882
|
workspaceAccount: foreignKey({
|
|
@@ -2788,6 +2929,12 @@ export const sandboxRetainedProcesses = pgTable(
|
|
|
2788
2929
|
active: index("sandbox_retained_processes_active_idx")
|
|
2789
2930
|
.on(table.workspaceId, table.sessionId, table.startedAt)
|
|
2790
2931
|
.where(sql`${table.state} = 'active'`),
|
|
2932
|
+
reconcileDue: index("sandbox_retained_processes_reconcile_due_idx")
|
|
2933
|
+
.on(table.reconcileAfter, table.startedAt, table.id)
|
|
2934
|
+
.where(sql`${table.state} = 'active'`),
|
|
2935
|
+
activeInventory: index("sandbox_retained_processes_active_inventory_idx")
|
|
2936
|
+
.on(table.ownerActorKind, table.workspaceId, table.ownerTurnId, table.ownerAttemptId)
|
|
2937
|
+
.where(sql`${table.state} = 'active'`),
|
|
2791
2938
|
identityValid: check(
|
|
2792
2939
|
"sandbox_retained_processes_identity_check",
|
|
2793
2940
|
sql`${table.leaseEpoch} >= 0
|
|
@@ -2824,6 +2971,41 @@ export const sandboxRetainedProcesses = pgTable(
|
|
|
2824
2971
|
sql`${table.settlementReason} is null
|
|
2825
2972
|
or octet_length(${table.settlementReason}) between 1 and 512`,
|
|
2826
2973
|
),
|
|
2974
|
+
reconcileClaimValid: check(
|
|
2975
|
+
"sandbox_retained_processes_reconcile_claim_check",
|
|
2976
|
+
sql`(${table.reconcileClaimId} is null and ${table.reconcileClaimedAt} is null)
|
|
2977
|
+
or (${table.reconcileClaimId} is not null and ${table.reconcileClaimedAt} is not null)`,
|
|
2978
|
+
),
|
|
2979
|
+
reconcileAttemptsValid: check(
|
|
2980
|
+
"sandbox_retained_processes_reconcile_attempts_check",
|
|
2981
|
+
sql`${table.reconcileAttempts} >= 0`,
|
|
2982
|
+
),
|
|
2983
|
+
reconcileOutcomeValid: check(
|
|
2984
|
+
"sandbox_retained_processes_reconcile_outcome_check",
|
|
2985
|
+
sql`${table.lastReconcileOutcome} is null
|
|
2986
|
+
or octet_length(${table.lastReconcileOutcome}) between 1 and 64`,
|
|
2987
|
+
),
|
|
2988
|
+
reconcileProofValid: check(
|
|
2989
|
+
"sandbox_retained_processes_reconcile_proof_check",
|
|
2990
|
+
sql`(
|
|
2991
|
+
${table.reconcileProofOutcome} is null
|
|
2992
|
+
and ${table.reconcileProofExitCode} is null
|
|
2993
|
+
and ${table.reconcileProofReason} is null
|
|
2994
|
+
and ${table.reconcileProofObservedAt} is null
|
|
2995
|
+
) or (
|
|
2996
|
+
${table.reconcileProofOutcome} = 'exited'
|
|
2997
|
+
and ${table.reconcileProofExitCode} is not null
|
|
2998
|
+
and ${table.reconcileProofReason} = 'provider_exit_banner'
|
|
2999
|
+
and ${table.reconcileProofObservedAt} is not null
|
|
3000
|
+
) or (
|
|
3001
|
+
${table.reconcileProofOutcome} = 'lost'
|
|
3002
|
+
and ${table.reconcileProofExitCode} is null
|
|
3003
|
+
and ${table.reconcileProofReason} in (
|
|
3004
|
+
'provider_session_lost_banner', 'provider_instance_not_found'
|
|
3005
|
+
)
|
|
3006
|
+
and ${table.reconcileProofObservedAt} is not null
|
|
3007
|
+
)`,
|
|
3008
|
+
),
|
|
2827
3009
|
}),
|
|
2828
3010
|
);
|
|
2829
3011
|
|
|
@@ -3410,10 +3592,17 @@ export const githubInstallations = pgTable(
|
|
|
3410
3592
|
.notNull()
|
|
3411
3593
|
.references(() => workspaces.id, { onDelete: "cascade" }),
|
|
3412
3594
|
installationId: integer("installation_id").notNull(),
|
|
3595
|
+
githubAccountId: bigint("github_account_id", { mode: "number" }),
|
|
3413
3596
|
accountLogin: text("account_login"),
|
|
3414
3597
|
accountType: text("account_type"),
|
|
3415
3598
|
repositoryScope: text("repository_scope").notNull().default("all"),
|
|
3416
3599
|
linkedBySubjectId: text("linked_by_subject_id"),
|
|
3600
|
+
githubActorId: bigint("github_actor_id", { mode: "number" }),
|
|
3601
|
+
githubActorLogin: text("github_actor_login"),
|
|
3602
|
+
authorityKind: text("authority_kind"),
|
|
3603
|
+
authorityCheckedAt: timestamp("authority_checked_at", { withTimezone: true }),
|
|
3604
|
+
authorityExpiresAt: timestamp("authority_expires_at", { withTimezone: true }),
|
|
3605
|
+
authorityNonce: text("authority_nonce"),
|
|
3417
3606
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
3418
3607
|
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
3419
3608
|
},
|
|
@@ -3428,6 +3617,55 @@ export const githubInstallations = pgTable(
|
|
|
3428
3617
|
"github_installations_repository_scope_check",
|
|
3429
3618
|
sql`${table.repositoryScope} in ('all', 'selected')`,
|
|
3430
3619
|
),
|
|
3620
|
+
authorityKindCheck: check(
|
|
3621
|
+
"github_installations_authority_kind_check",
|
|
3622
|
+
sql`
|
|
3623
|
+
(
|
|
3624
|
+
${table.githubAccountId} is null
|
|
3625
|
+
and ${table.githubActorId} is null
|
|
3626
|
+
and ${table.githubActorLogin} is null
|
|
3627
|
+
and ${table.authorityKind} is null
|
|
3628
|
+
and ${table.authorityCheckedAt} is null
|
|
3629
|
+
and ${table.authorityExpiresAt} is null
|
|
3630
|
+
and ${table.authorityNonce} is null
|
|
3631
|
+
)
|
|
3632
|
+
or (
|
|
3633
|
+
${table.githubAccountId} is not null
|
|
3634
|
+
and ${table.githubAccountId} > 0
|
|
3635
|
+
and ${table.githubActorId} is not null
|
|
3636
|
+
and ${table.githubActorId} > 0
|
|
3637
|
+
and ${table.githubActorLogin} is not null
|
|
3638
|
+
and length(${table.githubActorLogin}) > 0
|
|
3639
|
+
and ${table.accountLogin} is not null
|
|
3640
|
+
and length(${table.accountLogin}) > 0
|
|
3641
|
+
and ${table.accountType} is not null
|
|
3642
|
+
and ${table.linkedBySubjectId} is not null
|
|
3643
|
+
and length(${table.linkedBySubjectId}) > 0
|
|
3644
|
+
and ${table.authorityKind} is not null
|
|
3645
|
+
and ${table.authorityCheckedAt} is not null
|
|
3646
|
+
and ${table.authorityExpiresAt} is not null
|
|
3647
|
+
and ${table.authorityCheckedAt} < ${table.authorityExpiresAt}
|
|
3648
|
+
and ${table.authorityExpiresAt} <= ${table.authorityCheckedAt} + interval '10 minutes'
|
|
3649
|
+
and ${table.authorityNonce} is not null
|
|
3650
|
+
and length(${table.authorityNonce}) > 0
|
|
3651
|
+
and ${table.repositoryScope} = 'selected'
|
|
3652
|
+
and (
|
|
3653
|
+
(
|
|
3654
|
+
${table.authorityKind} = 'personal_owner'
|
|
3655
|
+
and ${table.accountType} = 'User'
|
|
3656
|
+
and ${table.githubActorId} = ${table.githubAccountId}
|
|
3657
|
+
)
|
|
3658
|
+
or (
|
|
3659
|
+
${table.authorityKind} = 'organization_owner'
|
|
3660
|
+
and ${table.accountType} = 'Organization'
|
|
3661
|
+
)
|
|
3662
|
+
)
|
|
3663
|
+
)
|
|
3664
|
+
`,
|
|
3665
|
+
),
|
|
3666
|
+
authorityNonce: uniqueIndex("github_installations_authority_nonce_uq")
|
|
3667
|
+
.on(table.authorityNonce)
|
|
3668
|
+
.where(sql`${table.authorityNonce} is not null`),
|
|
3431
3669
|
}),
|
|
3432
3670
|
);
|
|
3433
3671
|
|
|
@@ -4180,3 +4418,5 @@ export const rigChanges = pgTable(
|
|
|
4180
4418
|
workspaceStatus: index("rig_changes_workspace_status_idx").on(table.workspaceId, table.status),
|
|
4181
4419
|
}),
|
|
4182
4420
|
);
|
|
4421
|
+
|
|
4422
|
+
export * from "./workspace-instruction-policies-schema";
|
package/src/session-control.ts
CHANGED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { sql } from "drizzle-orm";
|
|
2
|
+
import {
|
|
3
|
+
bigint,
|
|
4
|
+
check,
|
|
5
|
+
index,
|
|
6
|
+
pgTable,
|
|
7
|
+
text,
|
|
8
|
+
timestamp,
|
|
9
|
+
uniqueIndex,
|
|
10
|
+
uuid,
|
|
11
|
+
} from "drizzle-orm/pg-core";
|
|
12
|
+
|
|
13
|
+
// Foreign keys and the cross-row revision/head integrity triggers live in the
|
|
14
|
+
// SQL migration. Keeping this additive schema leaf independent avoids a cycle
|
|
15
|
+
// back into schema.ts while retaining one canonical Drizzle namespace export.
|
|
16
|
+
|
|
17
|
+
export const workspaceInstructionPolicyRevisions = pgTable(
|
|
18
|
+
"workspace_instruction_policy_revisions",
|
|
19
|
+
{
|
|
20
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
21
|
+
accountId: uuid("account_id").notNull(),
|
|
22
|
+
workspaceId: uuid("workspace_id").notNull(),
|
|
23
|
+
revision: bigint("revision", { mode: "number" })
|
|
24
|
+
.notNull()
|
|
25
|
+
.default(sql`nextval('workspace_instruction_policy_revision_seq')`),
|
|
26
|
+
kind: text("kind").notNull(),
|
|
27
|
+
scope: text("scope").notNull(),
|
|
28
|
+
roleKey: text("role_key"),
|
|
29
|
+
content: text("content").notNull(),
|
|
30
|
+
contentHash: text("content_hash").notNull(),
|
|
31
|
+
provenanceSource: text("provenance_source").notNull(),
|
|
32
|
+
provenanceSourceId: text("provenance_source_id"),
|
|
33
|
+
supersedesRevisionId: uuid("supersedes_revision_id"),
|
|
34
|
+
createdBySubjectId: text("created_by_subject_id").notNull(),
|
|
35
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
36
|
+
},
|
|
37
|
+
(table) => ({
|
|
38
|
+
workspaceRevision: uniqueIndex(
|
|
39
|
+
"workspace_instruction_policy_revisions_workspace_revision_uq",
|
|
40
|
+
).on(table.workspaceId, table.revision),
|
|
41
|
+
workspaceHistory: index("workspace_instruction_policy_revisions_workspace_history_idx").on(
|
|
42
|
+
table.workspaceId,
|
|
43
|
+
table.kind,
|
|
44
|
+
table.scope,
|
|
45
|
+
table.roleKey,
|
|
46
|
+
table.revision,
|
|
47
|
+
),
|
|
48
|
+
target: check(
|
|
49
|
+
"workspace_instruction_policy_revisions_target_chk",
|
|
50
|
+
sql`(
|
|
51
|
+
(${table.kind} = 'charter' and ${table.scope} = 'global' and ${table.roleKey} is null)
|
|
52
|
+
or (${table.kind} = 'policy' and ${table.scope} = 'global' and ${table.roleKey} is null)
|
|
53
|
+
or (${table.kind} = 'policy' and ${table.scope} = 'role' and ${table.roleKey} is not null)
|
|
54
|
+
)`,
|
|
55
|
+
),
|
|
56
|
+
}),
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
export const workspaceInstructionPolicyHeads = pgTable(
|
|
60
|
+
"workspace_instruction_policy_heads",
|
|
61
|
+
{
|
|
62
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
63
|
+
accountId: uuid("account_id").notNull(),
|
|
64
|
+
workspaceId: uuid("workspace_id").notNull(),
|
|
65
|
+
kind: text("kind").notNull(),
|
|
66
|
+
scope: text("scope").notNull(),
|
|
67
|
+
roleKey: text("role_key"),
|
|
68
|
+
revisionId: uuid("revision_id").notNull(),
|
|
69
|
+
revision: bigint("revision", { mode: "number" }).notNull(),
|
|
70
|
+
contentHash: text("content_hash").notNull(),
|
|
71
|
+
activationVersion: bigint("activation_version", { mode: "number" }).notNull(),
|
|
72
|
+
activatedAt: timestamp("activated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
73
|
+
},
|
|
74
|
+
(table) => ({
|
|
75
|
+
charter: uniqueIndex("workspace_instruction_policy_heads_charter_uq")
|
|
76
|
+
.on(table.workspaceId)
|
|
77
|
+
.where(sql`${table.kind} = 'charter'`),
|
|
78
|
+
globalPolicy: uniqueIndex("workspace_instruction_policy_heads_global_policy_uq")
|
|
79
|
+
.on(table.workspaceId)
|
|
80
|
+
.where(sql`${table.kind} = 'policy' and ${table.scope} = 'global'`),
|
|
81
|
+
rolePolicy: uniqueIndex("workspace_instruction_policy_heads_role_policy_uq")
|
|
82
|
+
.on(table.workspaceId, table.roleKey)
|
|
83
|
+
.where(sql`${table.kind} = 'policy' and ${table.scope} = 'role'`),
|
|
84
|
+
target: check(
|
|
85
|
+
"workspace_instruction_policy_heads_target_chk",
|
|
86
|
+
sql`(
|
|
87
|
+
(${table.kind} = 'charter' and ${table.scope} = 'global' and ${table.roleKey} is null)
|
|
88
|
+
or (${table.kind} = 'policy' and ${table.scope} = 'global' and ${table.roleKey} is null)
|
|
89
|
+
or (${table.kind} = 'policy' and ${table.scope} = 'role' and ${table.roleKey} is not null)
|
|
90
|
+
)`,
|
|
91
|
+
),
|
|
92
|
+
}),
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
export const workspaceInstructionPolicyActivationEvents = pgTable(
|
|
96
|
+
"workspace_instruction_policy_activation_events",
|
|
97
|
+
{
|
|
98
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
99
|
+
accountId: uuid("account_id").notNull(),
|
|
100
|
+
workspaceId: uuid("workspace_id").notNull(),
|
|
101
|
+
kind: text("kind").notNull(),
|
|
102
|
+
scope: text("scope").notNull(),
|
|
103
|
+
roleKey: text("role_key"),
|
|
104
|
+
type: text("type").notNull(),
|
|
105
|
+
activationVersion: bigint("activation_version", { mode: "number" }).notNull(),
|
|
106
|
+
oldRevisionId: uuid("old_revision_id"),
|
|
107
|
+
oldRevision: bigint("old_revision", { mode: "number" }),
|
|
108
|
+
oldContentHash: text("old_content_hash"),
|
|
109
|
+
newRevisionId: uuid("new_revision_id").notNull(),
|
|
110
|
+
newRevision: bigint("new_revision", { mode: "number" }).notNull(),
|
|
111
|
+
newContentHash: text("new_content_hash").notNull(),
|
|
112
|
+
actorSubjectId: text("actor_subject_id").notNull(),
|
|
113
|
+
reason: text("reason").notNull(),
|
|
114
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
115
|
+
},
|
|
116
|
+
(table) => ({
|
|
117
|
+
workspaceActivationVersion: uniqueIndex(
|
|
118
|
+
"workspace_instruction_policy_events_target_version_uq",
|
|
119
|
+
).on(
|
|
120
|
+
table.workspaceId,
|
|
121
|
+
table.kind,
|
|
122
|
+
table.scope,
|
|
123
|
+
sql`coalesce(${table.roleKey}, '')`,
|
|
124
|
+
table.activationVersion,
|
|
125
|
+
),
|
|
126
|
+
workspaceTimeline: index("workspace_instruction_policy_events_workspace_time_idx").on(
|
|
127
|
+
table.workspaceId,
|
|
128
|
+
table.createdAt,
|
|
129
|
+
table.id,
|
|
130
|
+
),
|
|
131
|
+
target: check(
|
|
132
|
+
"workspace_instruction_policy_activation_events_target_chk",
|
|
133
|
+
sql`(
|
|
134
|
+
(${table.kind} = 'charter' and ${table.scope} = 'global' and ${table.roleKey} is null)
|
|
135
|
+
or (${table.kind} = 'policy' and ${table.scope} = 'global' and ${table.roleKey} is null)
|
|
136
|
+
or (${table.kind} = 'policy' and ${table.scope} = 'role' and ${table.roleKey} is not null)
|
|
137
|
+
)`,
|
|
138
|
+
),
|
|
139
|
+
}),
|
|
140
|
+
);
|