@opengeni/core 1.0.1 → 2.1.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/access/index.d.ts +37 -0
- package/dist/application/new-session-drafts.d.ts +8 -1
- package/dist/application/session-commands.d.ts +18 -11
- package/dist/application/session-tenancy.d.ts +18 -0
- package/dist/application/user-resource-grants.d.ts +20 -0
- package/dist/{chunk-6WKPWE5S.js → chunk-H7X52RI2.js} +27 -18
- package/dist/chunk-H7X52RI2.js.map +1 -0
- package/dist/{chunk-JJU6I5XD.js → chunk-VCZFFEPB.js} +21 -9
- package/dist/chunk-VCZFFEPB.js.map +1 -0
- package/dist/{chunk-NYPMQ7NO.js → chunk-ZYCNLYGH.js} +29 -27
- package/dist/chunk-ZYCNLYGH.js.map +1 -0
- package/dist/dependencies.d.ts +12 -1
- package/dist/domain/automations.d.ts +51 -0
- package/dist/domain/company-brain-governed-writes.d.ts +70 -0
- package/dist/domain/company-profile-agent-admin.d.ts +24 -0
- package/dist/domain/connection-authority.d.ts +97 -0
- package/dist/domain/connection-authority.js +169 -0
- package/dist/domain/connection-authority.js.map +1 -0
- package/dist/domain/editable-artifacts/service.d.ts +1 -2
- package/dist/domain/environments.d.ts +1 -1
- package/dist/domain/github-repository-bindings.d.ts +117 -0
- package/dist/domain/governed-learning-activation.d.ts +16 -0
- package/dist/domain/governed-learning-evaluator.d.ts +6 -0
- package/dist/domain/governed-learning-slack-publication.d.ts +45 -0
- package/dist/domain/memory-slack-delivery.d.ts +1 -4
- package/dist/domain/organization-membership-lifecycle.d.ts +1 -0
- package/dist/domain/packs.d.ts +5 -1
- package/dist/domain/personal-connection-delegations.d.ts +34 -2
- package/dist/domain/pr-review.d.ts +149 -0
- package/dist/domain/remember.d.ts +69 -0
- package/dist/domain/resources.d.ts +22 -1
- package/dist/domain/scheduled-tasks.d.ts +43 -2
- package/dist/domain/session-tool-policy.d.ts +1 -1
- package/dist/domain/sessions.d.ts +40 -6
- package/dist/editable-artifact-live/application.d.ts +10 -2
- package/dist/editable-artifact-live/ports.d.ts +0 -1
- package/dist/editable-artifact-live/server.d.ts +0 -1
- package/dist/editable-artifact-live/ticket.d.ts +0 -1
- package/dist/editable-artifact-live/types.d.ts +5 -2
- package/dist/editable-artifact-live.js +2 -2
- package/dist/editable-artifacts.js +2 -4
- package/dist/index.d.ts +13 -1
- package/dist/index.js +4827 -1164
- package/dist/index.js.map +1 -1
- package/dist/rigs/index.d.ts +22 -5
- package/dist/sandbox/fleet.d.ts +34 -6
- package/dist/sandbox/routing.d.ts +15 -1
- package/dist/sandbox/runtime-settings.d.ts +39 -0
- package/package.json +16 -11
- package/src/access/index.ts +151 -31
- package/src/application/new-session-drafts.ts +24 -2
- package/src/application/session-commands.ts +305 -71
- package/src/application/session-tenancy.ts +321 -0
- package/src/application/user-resource-grants.ts +140 -0
- package/src/billing/limits.ts +25 -15
- package/src/dependencies.ts +12 -1
- package/src/domain/automations.ts +196 -0
- package/src/domain/capabilities.ts +7 -1
- package/src/domain/company-brain-governed-writes.ts +330 -0
- package/src/domain/company-profile-agent-admin.ts +55 -0
- package/src/domain/connection-authority.ts +329 -0
- package/src/domain/editable-artifacts/agent-application.ts +17 -9
- package/src/domain/editable-artifacts/service.ts +12 -1
- package/src/domain/editable-artifacts/snapshot-compaction.ts +9 -5
- package/src/domain/editable-artifacts/snapshot-verifier-genesis.ts +10 -8
- package/src/domain/editable-artifacts/snapshot-verifier.ts +10 -3
- package/src/domain/environments.ts +16 -3
- package/src/domain/github-repository-bindings.ts +295 -0
- package/src/domain/governed-learning-activation.ts +44 -0
- package/src/domain/governed-learning-evaluator.ts +49 -0
- package/src/domain/governed-learning-slack-publication.ts +157 -0
- package/src/domain/insights.ts +9 -0
- package/src/domain/memory-slack-delivery.ts +0 -30
- package/src/domain/organization-membership-lifecycle.ts +9 -0
- package/src/domain/packs.ts +106 -3
- package/src/domain/personal-connection-delegations.ts +532 -51
- package/src/domain/pr-review.ts +671 -0
- package/src/domain/remember.ts +549 -0
- package/src/domain/resources.ts +131 -4
- package/src/domain/scheduled-tasks.ts +497 -76
- package/src/domain/session-tool-policy.ts +12 -9
- package/src/domain/sessions.ts +613 -166
- package/src/editable-artifact-live/application.ts +21 -3
- package/src/editable-artifact-live/ports.ts +0 -1
- package/src/editable-artifact-live/server.ts +13 -7
- package/src/editable-artifact-live/ticket.ts +1 -5
- package/src/editable-artifact-live/types.ts +6 -2
- package/src/editable-artifact-live/wire.ts +0 -10
- package/src/index.ts +13 -1
- package/src/rigs/index.ts +165 -48
- package/src/sandbox/fleet.ts +376 -30
- package/src/sandbox/routing.ts +91 -29
- package/src/sandbox/runtime-settings.ts +274 -0
- package/src/session-authorization.ts +17 -49
- package/dist/chunk-6WKPWE5S.js.map +0 -1
- package/dist/chunk-JJU6I5XD.js.map +0 -1
- package/dist/chunk-NYPMQ7NO.js.map +0 -1
- package/dist/domain/durable-learning-slack-publication.d.ts +0 -72
- package/src/domain/durable-learning-slack-publication.ts +0 -202
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ConnectionKind,
|
|
3
|
+
ConnectionStatus,
|
|
4
|
+
SessionTenancyVisibility,
|
|
5
|
+
UserResourceDelegation,
|
|
6
|
+
UserResourceGrantMode,
|
|
7
|
+
UserResourceGrantStatus,
|
|
8
|
+
} from "@opengeni/contracts";
|
|
9
|
+
import {
|
|
10
|
+
ConnectionAuthorityEnvelope,
|
|
11
|
+
ConnectionUseAttribution,
|
|
12
|
+
ConnectionUseAuthoritySnapshot,
|
|
13
|
+
type ConnectionUseAuthorizationResult,
|
|
14
|
+
type ConnectionAuthoritySelectionSource,
|
|
15
|
+
type ConnectionUseDenialReason,
|
|
16
|
+
type ConnectionUseSelectionSource,
|
|
17
|
+
} from "@opengeni/contracts/connection-authority";
|
|
18
|
+
|
|
19
|
+
export type ConnectionAuthorityCandidate = {
|
|
20
|
+
id: string;
|
|
21
|
+
organizationId: string;
|
|
22
|
+
workspaceId: string;
|
|
23
|
+
generation: number;
|
|
24
|
+
status: ConnectionStatus;
|
|
25
|
+
providerDomain: string;
|
|
26
|
+
kind: ConnectionKind;
|
|
27
|
+
subjectId: string | null;
|
|
28
|
+
ownerOrganizationMembershipId: string | null;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export type UserConnectionAuthorityCandidate = {
|
|
32
|
+
id: string;
|
|
33
|
+
organizationId: string;
|
|
34
|
+
resourceKind: "connection";
|
|
35
|
+
resourceId: string;
|
|
36
|
+
originWorkspaceId: string;
|
|
37
|
+
ownerSubjectId: string;
|
|
38
|
+
ownerOrganizationMembershipId: string;
|
|
39
|
+
ownerMembershipAuthorizationRevision: number;
|
|
40
|
+
generation: number;
|
|
41
|
+
status: "active" | "retained" | "revoked";
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export class ConnectionAuthorityInvariantError extends Error {
|
|
45
|
+
constructor(readonly code: string) {
|
|
46
|
+
super(`connection authority invariant failed: ${code}`);
|
|
47
|
+
this.name = "ConnectionAuthorityInvariantError";
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function captureConnectionUseAuthority(input: {
|
|
52
|
+
organizationId: string;
|
|
53
|
+
targetWorkspaceId: string;
|
|
54
|
+
targetSessionId: string;
|
|
55
|
+
targetSessionVisibility: SessionTenancyVisibility;
|
|
56
|
+
targetSessionAuthorityEpoch: number;
|
|
57
|
+
acceptedWork:
|
|
58
|
+
| { kind: "turn"; turnId: string }
|
|
59
|
+
| {
|
|
60
|
+
kind: "scheduled_task";
|
|
61
|
+
taskId: string;
|
|
62
|
+
taskAuthorityRevision: number;
|
|
63
|
+
runId: string;
|
|
64
|
+
};
|
|
65
|
+
connection: ConnectionAuthorityCandidate;
|
|
66
|
+
authority?: unknown;
|
|
67
|
+
authorityWasOmitted?: boolean;
|
|
68
|
+
userAuthority?: UserConnectionAuthorityCandidate | null;
|
|
69
|
+
selectionSources: ConnectionUseSelectionSource[];
|
|
70
|
+
}): ConnectionUseAuthoritySnapshot {
|
|
71
|
+
const authority = ConnectionAuthorityEnvelope.parse(input.authority ?? {});
|
|
72
|
+
const connection = input.connection;
|
|
73
|
+
if (connection.organizationId !== input.organizationId) {
|
|
74
|
+
throw new ConnectionAuthorityInvariantError("tenant_mismatch");
|
|
75
|
+
}
|
|
76
|
+
if (connection.status !== "active") {
|
|
77
|
+
throw new ConnectionAuthorityInvariantError("connection_status_inactive");
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
let authoritySource: ConnectionAuthoritySelectionSource;
|
|
81
|
+
let userDelegation: UserResourceDelegation | null = null;
|
|
82
|
+
if (authority.scope === "workspace") {
|
|
83
|
+
if (connection.subjectId !== null || connection.ownerOrganizationMembershipId !== null) {
|
|
84
|
+
throw new ConnectionAuthorityInvariantError("workspace_borrowed_personal_connection");
|
|
85
|
+
}
|
|
86
|
+
if (connection.workspaceId !== input.targetWorkspaceId) {
|
|
87
|
+
throw new ConnectionAuthorityInvariantError("workspace_connection_scope_mismatch");
|
|
88
|
+
}
|
|
89
|
+
authoritySource = input.authorityWasOmitted
|
|
90
|
+
? "legacy_workspace_omission"
|
|
91
|
+
: "explicit_workspace";
|
|
92
|
+
} else {
|
|
93
|
+
const delegation = authority.userDelegation;
|
|
94
|
+
const resourceAuthority = input.userAuthority;
|
|
95
|
+
if (!delegation || !resourceAuthority) {
|
|
96
|
+
throw new ConnectionAuthorityInvariantError("user_authority_missing");
|
|
97
|
+
}
|
|
98
|
+
if (!connection.subjectId || !connection.ownerOrganizationMembershipId) {
|
|
99
|
+
throw new ConnectionAuthorityInvariantError("personal_owner_missing");
|
|
100
|
+
}
|
|
101
|
+
if (
|
|
102
|
+
resourceAuthority.id !== delegation.authorityId ||
|
|
103
|
+
resourceAuthority.organizationId !== input.organizationId ||
|
|
104
|
+
resourceAuthority.resourceKind !== "connection" ||
|
|
105
|
+
resourceAuthority.resourceId !== connection.id ||
|
|
106
|
+
resourceAuthority.originWorkspaceId !== connection.workspaceId ||
|
|
107
|
+
resourceAuthority.ownerSubjectId !== connection.subjectId ||
|
|
108
|
+
resourceAuthority.ownerOrganizationMembershipId !==
|
|
109
|
+
connection.ownerOrganizationMembershipId ||
|
|
110
|
+
resourceAuthority.generation !== delegation.authorityGeneration ||
|
|
111
|
+
resourceAuthority.status !== "active"
|
|
112
|
+
) {
|
|
113
|
+
throw new ConnectionAuthorityInvariantError("user_authority_mismatch");
|
|
114
|
+
}
|
|
115
|
+
userDelegation = delegation;
|
|
116
|
+
authoritySource = "user_delegation";
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return ConnectionUseAuthoritySnapshot.parse({
|
|
120
|
+
organizationId: input.organizationId,
|
|
121
|
+
originWorkspaceId: connection.workspaceId,
|
|
122
|
+
targetWorkspaceId: input.targetWorkspaceId,
|
|
123
|
+
targetSessionId: input.targetSessionId,
|
|
124
|
+
targetSessionVisibility: input.targetSessionVisibility,
|
|
125
|
+
targetSessionAuthorityEpoch: input.targetSessionAuthorityEpoch,
|
|
126
|
+
acceptedWork: input.acceptedWork,
|
|
127
|
+
connectionId: connection.id,
|
|
128
|
+
connectionGeneration: connection.generation,
|
|
129
|
+
connectionStatus: "active",
|
|
130
|
+
providerDomain: connection.providerDomain.toLowerCase(),
|
|
131
|
+
connectionKind: connection.kind,
|
|
132
|
+
scope: authority.scope,
|
|
133
|
+
ownerSubjectId: connection.subjectId,
|
|
134
|
+
ownerOrganizationMembershipId: connection.ownerOrganizationMembershipId,
|
|
135
|
+
ownerMembershipAuthorizationRevision:
|
|
136
|
+
authority.scope === "user" ? input.userAuthority!.ownerMembershipAuthorizationRevision : null,
|
|
137
|
+
authoritySource,
|
|
138
|
+
selectionSources: input.selectionSources,
|
|
139
|
+
userDelegation,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export type LiveConnectionUseState = {
|
|
144
|
+
organizationId: string;
|
|
145
|
+
targetWorkspaceId: string;
|
|
146
|
+
targetWorkspaceAccessActive: boolean;
|
|
147
|
+
session: {
|
|
148
|
+
id: string;
|
|
149
|
+
organizationId: string;
|
|
150
|
+
workspaceId: string;
|
|
151
|
+
visibility: SessionTenancyVisibility;
|
|
152
|
+
authorityEpoch: number;
|
|
153
|
+
active: boolean;
|
|
154
|
+
};
|
|
155
|
+
connection: ConnectionAuthorityCandidate | null;
|
|
156
|
+
ownerMembership: {
|
|
157
|
+
id: string;
|
|
158
|
+
organizationId: string;
|
|
159
|
+
subjectId: string;
|
|
160
|
+
status: "provisioning" | "active" | "suspended" | "revoked";
|
|
161
|
+
authorizationRevision: number;
|
|
162
|
+
} | null;
|
|
163
|
+
userAuthority: UserConnectionAuthorityCandidate | null;
|
|
164
|
+
grant: {
|
|
165
|
+
id: string;
|
|
166
|
+
authorityId: string;
|
|
167
|
+
organizationId: string;
|
|
168
|
+
workspaceId: string;
|
|
169
|
+
sessionId: string | null;
|
|
170
|
+
action: string;
|
|
171
|
+
mode: UserResourceGrantMode;
|
|
172
|
+
context: SessionTenancyVisibility;
|
|
173
|
+
authorityEpoch: number | null;
|
|
174
|
+
generation: number;
|
|
175
|
+
status: UserResourceGrantStatus;
|
|
176
|
+
expiresAt: string | null;
|
|
177
|
+
consumed: boolean;
|
|
178
|
+
} | null;
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
function denied(reason: ConnectionUseDenialReason): ConnectionUseAuthorizationResult {
|
|
182
|
+
return { status: "denied", reason };
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Revalidates every mutable fence immediately before provider use. Callers must
|
|
187
|
+
* resolve the live state in one DB authority boundary; this pure function does
|
|
188
|
+
* not cache, refresh, decrypt, or invoke a provider.
|
|
189
|
+
*/
|
|
190
|
+
export function revalidateConnectionUseAuthority(input: {
|
|
191
|
+
snapshot: ConnectionUseAuthoritySnapshot;
|
|
192
|
+
live: LiveConnectionUseState;
|
|
193
|
+
now?: Date;
|
|
194
|
+
}): ConnectionUseAuthorizationResult {
|
|
195
|
+
const snapshot = ConnectionUseAuthoritySnapshot.parse(input.snapshot);
|
|
196
|
+
const live = input.live;
|
|
197
|
+
const now = input.now ?? new Date();
|
|
198
|
+
if (
|
|
199
|
+
live.organizationId !== snapshot.organizationId ||
|
|
200
|
+
live.targetWorkspaceId !== snapshot.targetWorkspaceId
|
|
201
|
+
) {
|
|
202
|
+
return denied("tenant_mismatch");
|
|
203
|
+
}
|
|
204
|
+
if (!live.targetWorkspaceAccessActive) return denied("workspace_access_inactive");
|
|
205
|
+
if (!live.session.active) return denied("session_inactive");
|
|
206
|
+
if (
|
|
207
|
+
live.session.id !== snapshot.targetSessionId ||
|
|
208
|
+
live.session.organizationId !== snapshot.organizationId ||
|
|
209
|
+
live.session.workspaceId !== snapshot.targetWorkspaceId
|
|
210
|
+
) {
|
|
211
|
+
return denied("session_identity_changed");
|
|
212
|
+
}
|
|
213
|
+
if (live.session.visibility !== snapshot.targetSessionVisibility) {
|
|
214
|
+
return denied("session_visibility_changed");
|
|
215
|
+
}
|
|
216
|
+
if (live.session.authorityEpoch !== snapshot.targetSessionAuthorityEpoch) {
|
|
217
|
+
return denied("session_authority_epoch_changed");
|
|
218
|
+
}
|
|
219
|
+
const connection = live.connection;
|
|
220
|
+
if (!connection) return denied("connection_missing");
|
|
221
|
+
if (
|
|
222
|
+
connection.id !== snapshot.connectionId ||
|
|
223
|
+
connection.organizationId !== snapshot.organizationId ||
|
|
224
|
+
connection.workspaceId !== snapshot.originWorkspaceId ||
|
|
225
|
+
connection.providerDomain.toLowerCase() !== snapshot.providerDomain ||
|
|
226
|
+
connection.kind !== snapshot.connectionKind
|
|
227
|
+
) {
|
|
228
|
+
return denied("connection_identity_changed");
|
|
229
|
+
}
|
|
230
|
+
if (connection.generation !== snapshot.connectionGeneration) {
|
|
231
|
+
return denied("connection_generation_changed");
|
|
232
|
+
}
|
|
233
|
+
if (connection.status !== "active") return denied("connection_status_inactive");
|
|
234
|
+
if (
|
|
235
|
+
connection.subjectId !== snapshot.ownerSubjectId ||
|
|
236
|
+
connection.ownerOrganizationMembershipId !== snapshot.ownerOrganizationMembershipId
|
|
237
|
+
) {
|
|
238
|
+
return denied("connection_owner_changed");
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (snapshot.scope === "workspace") {
|
|
242
|
+
if (connection.subjectId !== null || connection.workspaceId !== snapshot.targetWorkspaceId) {
|
|
243
|
+
return denied("connection_owner_changed");
|
|
244
|
+
}
|
|
245
|
+
return {
|
|
246
|
+
status: "authorized",
|
|
247
|
+
attribution: ConnectionUseAttribution.parse({
|
|
248
|
+
organizationId: snapshot.organizationId,
|
|
249
|
+
workspaceId: snapshot.targetWorkspaceId,
|
|
250
|
+
sessionId: snapshot.targetSessionId,
|
|
251
|
+
connectionId: snapshot.connectionId,
|
|
252
|
+
connectionGeneration: snapshot.connectionGeneration,
|
|
253
|
+
scope: "workspace",
|
|
254
|
+
ownerSubjectId: null,
|
|
255
|
+
authorityId: null,
|
|
256
|
+
grantId: null,
|
|
257
|
+
}),
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
const delegation = snapshot.userDelegation!;
|
|
262
|
+
const membership = live.ownerMembership;
|
|
263
|
+
if (
|
|
264
|
+
!membership ||
|
|
265
|
+
membership.status !== "active" ||
|
|
266
|
+
membership.id !== snapshot.ownerOrganizationMembershipId ||
|
|
267
|
+
membership.organizationId !== snapshot.organizationId ||
|
|
268
|
+
membership.subjectId !== snapshot.ownerSubjectId ||
|
|
269
|
+
membership.authorizationRevision !== snapshot.ownerMembershipAuthorizationRevision
|
|
270
|
+
) {
|
|
271
|
+
return denied("owner_membership_inactive");
|
|
272
|
+
}
|
|
273
|
+
const authority = live.userAuthority;
|
|
274
|
+
if (!authority) return denied("authority_missing");
|
|
275
|
+
if (
|
|
276
|
+
authority.id !== delegation.authorityId ||
|
|
277
|
+
authority.organizationId !== snapshot.organizationId ||
|
|
278
|
+
authority.resourceKind !== "connection" ||
|
|
279
|
+
authority.resourceId !== snapshot.connectionId ||
|
|
280
|
+
authority.originWorkspaceId !== snapshot.originWorkspaceId ||
|
|
281
|
+
authority.ownerSubjectId !== snapshot.ownerSubjectId ||
|
|
282
|
+
authority.ownerOrganizationMembershipId !== snapshot.ownerOrganizationMembershipId
|
|
283
|
+
) {
|
|
284
|
+
return denied("authority_identity_changed");
|
|
285
|
+
}
|
|
286
|
+
if (authority.generation !== delegation.authorityGeneration) {
|
|
287
|
+
return denied("authority_generation_changed");
|
|
288
|
+
}
|
|
289
|
+
if (authority.status !== "active") return denied("authority_status_inactive");
|
|
290
|
+
|
|
291
|
+
const grant = live.grant;
|
|
292
|
+
if (!grant) return denied("grant_missing");
|
|
293
|
+
if (
|
|
294
|
+
grant.id !== delegation.grantId ||
|
|
295
|
+
grant.authorityId !== delegation.authorityId ||
|
|
296
|
+
grant.organizationId !== snapshot.organizationId ||
|
|
297
|
+
grant.workspaceId !== snapshot.targetWorkspaceId ||
|
|
298
|
+
grant.sessionId !== delegation.sessionId ||
|
|
299
|
+
grant.action !== "connection.use" ||
|
|
300
|
+
grant.mode !== delegation.mode ||
|
|
301
|
+
grant.context !== snapshot.targetSessionVisibility ||
|
|
302
|
+
grant.authorityEpoch !== delegation.authorityEpoch
|
|
303
|
+
) {
|
|
304
|
+
return denied("grant_identity_changed");
|
|
305
|
+
}
|
|
306
|
+
if (grant.generation !== delegation.grantGeneration) {
|
|
307
|
+
return denied("grant_generation_changed");
|
|
308
|
+
}
|
|
309
|
+
if (grant.status !== "active") return denied("grant_status_inactive");
|
|
310
|
+
if (grant.expiresAt !== null && Date.parse(grant.expiresAt) <= now.getTime()) {
|
|
311
|
+
return denied("grant_expired");
|
|
312
|
+
}
|
|
313
|
+
if (grant.mode === "once" && grant.consumed) return denied("grant_already_consumed");
|
|
314
|
+
|
|
315
|
+
return {
|
|
316
|
+
status: "authorized",
|
|
317
|
+
attribution: ConnectionUseAttribution.parse({
|
|
318
|
+
organizationId: snapshot.organizationId,
|
|
319
|
+
workspaceId: snapshot.targetWorkspaceId,
|
|
320
|
+
sessionId: snapshot.targetSessionId,
|
|
321
|
+
connectionId: snapshot.connectionId,
|
|
322
|
+
connectionGeneration: snapshot.connectionGeneration,
|
|
323
|
+
scope: "user",
|
|
324
|
+
ownerSubjectId: snapshot.ownerSubjectId,
|
|
325
|
+
authorityId: delegation.authorityId,
|
|
326
|
+
grantId: delegation.grantId,
|
|
327
|
+
}),
|
|
328
|
+
};
|
|
329
|
+
}
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
COMMITTED_TRANSACTION_PROTOCOL_VERSION,
|
|
5
|
-
EDITABLE_ARTIFACT_MODEL_SCHEMA_VERSION,
|
|
6
|
-
} from "@opengeni/contracts/editable-artifact-versions";
|
|
7
3
|
import {
|
|
8
4
|
DOCUMENT_ARTIFACT_COMMAND_VERSION,
|
|
5
|
+
EDITABLE_ARTIFACT_INTENT_PROTOCOL_VERSION,
|
|
9
6
|
EDITABLE_ARTIFACT_INTENT_VERSION,
|
|
10
7
|
PRESENTATION_ARTIFACT_COMMAND_VERSION,
|
|
11
8
|
SPREADSHEET_ARTIFACT_COMMAND_VERSION,
|
|
9
|
+
currentEditableArtifactCompatibility,
|
|
12
10
|
decodeEditableArtifactMutationIntent,
|
|
13
11
|
decodeDocumentArtifactQueryResponse,
|
|
14
12
|
decodePresentationArtifactQueryResponse,
|
|
@@ -364,8 +362,9 @@ export class EditableArtifactAgentApplication {
|
|
|
364
362
|
}
|
|
365
363
|
const authored = hashEditableArtifactMutationIntent({
|
|
366
364
|
envelopeVersion: EDITABLE_ARTIFACT_INTENT_VERSION,
|
|
367
|
-
protocolVersion:
|
|
368
|
-
modelSchemaVersion:
|
|
365
|
+
protocolVersion: EDITABLE_ARTIFACT_INTENT_PROTOCOL_VERSION,
|
|
366
|
+
modelSchemaVersion: currentEditableArtifactCompatibility(input.batch.modality)
|
|
367
|
+
.modelSchemaVersion,
|
|
369
368
|
commandProtocolVersion: commandProtocolVersion(input.batch.modality),
|
|
370
369
|
artifactId,
|
|
371
370
|
clientTransactionId,
|
|
@@ -564,12 +563,21 @@ function agentContext(input: EditableArtifactAgentContext): EditableArtifactAgen
|
|
|
564
563
|
|
|
565
564
|
function encodeCommands(batch: EditableArtifactAgentCommandBatch): Uint8Array {
|
|
566
565
|
if (batch.modality === "spreadsheet") {
|
|
567
|
-
return encodeSpreadsheetArtifactCommandBatch({
|
|
566
|
+
return encodeSpreadsheetArtifactCommandBatch({
|
|
567
|
+
version: SPREADSHEET_ARTIFACT_COMMAND_VERSION,
|
|
568
|
+
commands: batch.commands,
|
|
569
|
+
});
|
|
568
570
|
}
|
|
569
571
|
if (batch.modality === "document") {
|
|
570
|
-
return encodeDocumentArtifactCommandBatch({
|
|
572
|
+
return encodeDocumentArtifactCommandBatch({
|
|
573
|
+
version: DOCUMENT_ARTIFACT_COMMAND_VERSION,
|
|
574
|
+
commands: batch.commands,
|
|
575
|
+
});
|
|
571
576
|
}
|
|
572
|
-
return encodePresentationArtifactCommandBatch({
|
|
577
|
+
return encodePresentationArtifactCommandBatch({
|
|
578
|
+
version: PRESENTATION_ARTIFACT_COMMAND_VERSION,
|
|
579
|
+
commands: batch.commands,
|
|
580
|
+
});
|
|
573
581
|
}
|
|
574
582
|
|
|
575
583
|
function encodeQuery(request: EditableArtifactAgentQuery): Uint8Array {
|
|
@@ -28,9 +28,11 @@ import { hashEditableArtifactCreateRequest, hashEditableArtifactImportRequest }
|
|
|
28
28
|
import {
|
|
29
29
|
EDITABLE_ARTIFACT_COMMAND_MAX_BYTES,
|
|
30
30
|
EDITABLE_ARTIFACT_INTENT_MAX_BYTES,
|
|
31
|
+
EDITABLE_ARTIFACT_INTENT_PROTOCOL_VERSION,
|
|
31
32
|
EDITABLE_ARTIFACT_INTENT_MAX_UNDO_TARGETS,
|
|
32
33
|
EDITABLE_ARTIFACT_INTENT_VERSION,
|
|
33
34
|
EDITABLE_ARTIFACT_KERNEL_VERSION_MAX_BYTES,
|
|
35
|
+
EDITABLE_ARTIFACT_CODEC_REGISTRY,
|
|
34
36
|
} from "@opengeni/contracts/editable-artifacts";
|
|
35
37
|
import {
|
|
36
38
|
COMMITTED_TRANSACTION_PROTOCOL_VERSION,
|
|
@@ -111,7 +113,6 @@ export const EDITABLE_ARTIFACT_MAX_COMMAND_BYTES_PER_TRANSACTION =
|
|
|
111
113
|
EDITABLE_ARTIFACT_COMMAND_MAX_BYTES;
|
|
112
114
|
export const EDITABLE_ARTIFACT_MAX_INTENT_BYTES_PER_TRANSACTION =
|
|
113
115
|
EDITABLE_ARTIFACT_INTENT_MAX_BYTES;
|
|
114
|
-
export const EDITABLE_ARTIFACT_INTENT_PROTOCOL_VERSION = 1;
|
|
115
116
|
export const EDITABLE_ARTIFACT_MAX_OPERATION_BYTES_PER_TRANSACTION =
|
|
116
117
|
MAX_COMMITTED_TRANSACTION_BYTES;
|
|
117
118
|
/** Canonical OGACO envelope bound. Kept as an alias for existing consumers. */
|
|
@@ -2266,6 +2267,10 @@ function validateSnapshotRequest(
|
|
|
2266
2267
|
assertNonnegativeSafeInteger(rawCoveredHeadSequence, "snapshot covered head sequence");
|
|
2267
2268
|
const stateHash = editableArtifactStateHash(rawStateHash);
|
|
2268
2269
|
assertPositiveSafeInteger(rawModelSchemaVersion, "snapshot model schema version");
|
|
2270
|
+
const currentCodec = EDITABLE_ARTIFACT_CODEC_REGISTRY[rawModality];
|
|
2271
|
+
if (rawModelSchemaVersion !== currentCodec.modelSchemaVersion) {
|
|
2272
|
+
throw new TypeError("Snapshot model schema version is unsupported");
|
|
2273
|
+
}
|
|
2269
2274
|
assertBoundedKernelVersion(rawKernelVersion);
|
|
2270
2275
|
assertIsoTimestamp(rawVerifiedAt, "snapshot verified timestamp");
|
|
2271
2276
|
const common = {
|
|
@@ -2294,6 +2299,12 @@ function validateSnapshotRequest(
|
|
|
2294
2299
|
}
|
|
2295
2300
|
assertPositiveSafeInteger(rawOperationProtocolVersion, "snapshot operation protocol version");
|
|
2296
2301
|
assertPositiveSafeInteger(rawCrdtStateVersion, "snapshot CRDT state version");
|
|
2302
|
+
if (
|
|
2303
|
+
rawOperationProtocolVersion !== COMMITTED_TRANSACTION_PROTOCOL_VERSION ||
|
|
2304
|
+
rawCrdtStateVersion !== currentCodec.snapshotVersion
|
|
2305
|
+
) {
|
|
2306
|
+
throw new TypeError("Spreadsheet snapshot version is unsupported");
|
|
2307
|
+
}
|
|
2297
2308
|
return Object.freeze({
|
|
2298
2309
|
...common,
|
|
2299
2310
|
modality: "spreadsheet",
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { type BoundedImmutableObjectWritePort, BoundedObjectWriteError } from "@opengeni/storage";
|
|
2
|
+
import { EDITABLE_ARTIFACT_CODEC_REGISTRY } from "@opengeni/contracts/editable-artifacts";
|
|
3
|
+
import { COMMITTED_TRANSACTION_PROTOCOL_VERSION } from "@opengeni/contracts/editable-artifact-committed-transaction";
|
|
2
4
|
|
|
3
5
|
import type { EditableArtifactCompactionPort, EditableArtifactKernelState } from "./ports";
|
|
4
6
|
import {
|
|
@@ -177,6 +179,7 @@ function validateGenerated(
|
|
|
177
179
|
scope: EditableArtifactScope,
|
|
178
180
|
artifactId: EditableArtifactId,
|
|
179
181
|
): void {
|
|
182
|
+
const currentCodec = EDITABLE_ARTIFACT_CODEC_REGISTRY[value.modality];
|
|
180
183
|
if (
|
|
181
184
|
value.scope.accountId !== scope.accountId ||
|
|
182
185
|
value.scope.workspaceId !== scope.workspaceId ||
|
|
@@ -207,11 +210,12 @@ function validateGenerated(
|
|
|
207
210
|
throw new EditableArtifactSnapshotVerificationError("limit_exceeded");
|
|
208
211
|
}
|
|
209
212
|
editableArtifactContentHash(value.canonicalContentHash);
|
|
210
|
-
|
|
211
|
-
value.
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
213
|
+
if (
|
|
214
|
+
value.modelSchemaVersion !== currentCodec.modelSchemaVersion ||
|
|
215
|
+
(value.modality === "spreadsheet" &&
|
|
216
|
+
(value.operationProtocolVersion !== COMMITTED_TRANSACTION_PROTOCOL_VERSION ||
|
|
217
|
+
value.crdtStateVersion !== currentCodec.snapshotVersion))
|
|
218
|
+
) {
|
|
215
219
|
throw new EditableArtifactSnapshotVerificationError("version_mismatch");
|
|
216
220
|
}
|
|
217
221
|
try {
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { type BoundedImmutableObjectWritePort, BoundedObjectWriteError } from "@opengeni/storage";
|
|
2
|
+
import { EDITABLE_ARTIFACT_CODEC_REGISTRY } from "@opengeni/contracts/editable-artifacts";
|
|
3
|
+
import { COMMITTED_TRANSACTION_PROTOCOL_VERSION } from "@opengeni/contracts/editable-artifact-committed-transaction";
|
|
2
4
|
import type { EditableArtifactGenesisPort } from "./ports";
|
|
3
5
|
import {
|
|
4
6
|
MAX_EDITABLE_ARTIFACT_SNAPSHOT_BYTES,
|
|
@@ -173,6 +175,7 @@ function validateGeneratedGenesis(
|
|
|
173
175
|
artifactId: EditableArtifactId,
|
|
174
176
|
modality: EditableArtifactModality,
|
|
175
177
|
): void {
|
|
178
|
+
const currentCodec = EDITABLE_ARTIFACT_CODEC_REGISTRY[value.modality];
|
|
176
179
|
if (
|
|
177
180
|
value.scope.accountId !== scope.accountId ||
|
|
178
181
|
value.scope.workspaceId !== scope.workspaceId ||
|
|
@@ -198,14 +201,13 @@ function validateGeneratedGenesis(
|
|
|
198
201
|
}
|
|
199
202
|
editableArtifactContentHash(value.canonicalContentHash);
|
|
200
203
|
editableArtifactStateHash(value.stateHash);
|
|
201
|
-
|
|
202
|
-
value.
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
}
|
|
204
|
+
if (
|
|
205
|
+
value.modelSchemaVersion !== currentCodec.modelSchemaVersion ||
|
|
206
|
+
(value.modality === "spreadsheet" &&
|
|
207
|
+
(value.operationProtocolVersion !== COMMITTED_TRANSACTION_PROTOCOL_VERSION ||
|
|
208
|
+
value.crdtStateVersion !== currentCodec.snapshotVersion))
|
|
209
|
+
) {
|
|
210
|
+
throw new EditableArtifactSnapshotVerificationError("version_mismatch");
|
|
209
211
|
}
|
|
210
212
|
try {
|
|
211
213
|
assertBoundedKernelVersion(value.kernelVersion);
|
|
@@ -7,7 +7,11 @@ import {
|
|
|
7
7
|
} from "@opengeni/storage";
|
|
8
8
|
import type { EditableArtifactSnapshotVerifierPort } from "./ports";
|
|
9
9
|
import { decodeEditableArtifactSerializedCommit } from "@opengeni/contracts/editable-artifact-serialized-commit";
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
EDITABLE_ARTIFACT_CODEC_REGISTRY,
|
|
12
|
+
EDITABLE_ARTIFACT_PRODUCT_MAX_SNAPSHOT_BYTES,
|
|
13
|
+
} from "@opengeni/contracts/editable-artifacts";
|
|
14
|
+
import { COMMITTED_TRANSACTION_PROTOCOL_VERSION } from "@opengeni/contracts/editable-artifact-committed-transaction";
|
|
11
15
|
import {
|
|
12
16
|
causalFrontiersEqual,
|
|
13
17
|
editableArtifactCausalFrontier,
|
|
@@ -520,6 +524,7 @@ function validateKernelResult(
|
|
|
520
524
|
>
|
|
521
525
|
| undefined,
|
|
522
526
|
): void {
|
|
527
|
+
const currentCodec = EDITABLE_ARTIFACT_CODEC_REGISTRY[snapshot.modality];
|
|
523
528
|
if (
|
|
524
529
|
result.canonicalReencodeVerified !== true ||
|
|
525
530
|
result.modality !== snapshot.modality ||
|
|
@@ -542,8 +547,8 @@ function validateKernelResult(
|
|
|
542
547
|
throw new EditableArtifactSnapshotVerificationError("state_hash_mismatch");
|
|
543
548
|
}
|
|
544
549
|
if (
|
|
545
|
-
|
|
546
|
-
result.
|
|
550
|
+
snapshot.modelSchemaVersion !== currentCodec.modelSchemaVersion ||
|
|
551
|
+
result.modelSchemaVersion !== snapshot.modelSchemaVersion
|
|
547
552
|
) {
|
|
548
553
|
throw new EditableArtifactSnapshotVerificationError("version_mismatch");
|
|
549
554
|
}
|
|
@@ -559,6 +564,8 @@ function validateKernelResult(
|
|
|
559
564
|
throw new EditableArtifactSnapshotVerificationError("frontier_mismatch");
|
|
560
565
|
}
|
|
561
566
|
if (
|
|
567
|
+
snapshot.operationProtocolVersion !== COMMITTED_TRANSACTION_PROTOCOL_VERSION ||
|
|
568
|
+
snapshot.crdtStateVersion !== currentCodec.snapshotVersion ||
|
|
562
569
|
result.operationProtocolVersion !== snapshot.operationProtocolVersion ||
|
|
563
570
|
result.crdtStateVersion !== snapshot.crdtStateVersion
|
|
564
571
|
) {
|
|
@@ -69,10 +69,18 @@ export const requireEnvironmentEncryption = requireVariableSetEncryption;
|
|
|
69
69
|
|
|
70
70
|
export async function requireVariableSetForApi(
|
|
71
71
|
db: Database,
|
|
72
|
-
|
|
72
|
+
grant: AccessGrant,
|
|
73
73
|
variableSetId: string,
|
|
74
74
|
): Promise<VariableSet> {
|
|
75
|
-
const variableSet = await getVariableSet(
|
|
75
|
+
const variableSet = await getVariableSet(
|
|
76
|
+
db,
|
|
77
|
+
{
|
|
78
|
+
accountId: grant.accountId,
|
|
79
|
+
workspaceId: grant.workspaceId,
|
|
80
|
+
subjectId: grant.subjectId,
|
|
81
|
+
},
|
|
82
|
+
variableSetId,
|
|
83
|
+
);
|
|
76
84
|
if (!variableSet) {
|
|
77
85
|
throw new HTTPException(404, { message: "variableSet not found" });
|
|
78
86
|
}
|
|
@@ -97,9 +105,14 @@ export async function validateVariableSetAttachment(
|
|
|
97
105
|
): Promise<VariableSet> {
|
|
98
106
|
requireVariableSetEncryption(deps.settings);
|
|
99
107
|
if (!options.preauthorized) {
|
|
108
|
+
requirePermission(grant, "variable-sets:attach");
|
|
100
109
|
requirePermission(grant, "variable-sets:use");
|
|
101
110
|
}
|
|
102
|
-
const variableSet = await getVariableSet(
|
|
111
|
+
const variableSet = await getVariableSet(
|
|
112
|
+
deps.db,
|
|
113
|
+
{ accountId: grant.accountId, workspaceId, subjectId: grant.subjectId },
|
|
114
|
+
variableSetId,
|
|
115
|
+
);
|
|
103
116
|
if (!variableSet) {
|
|
104
117
|
throw new HTTPException(422, { message: "unknown variableSetId" });
|
|
105
118
|
}
|