@opengeni/core 3.1.3-canary.38890816741001 → 3.3.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 +13 -0
- package/dist/application/site-session-cancellation.d.ts +14 -0
- package/dist/dependencies.d.ts +3 -0
- package/dist/domain/insights-usage.d.ts +24 -1
- package/dist/domain/vaults/external-provider-connections.d.ts +126 -0
- package/dist/domain/vaults/index.d.ts +2 -1
- package/dist/domain/vaults/mapping.d.ts +18 -2
- package/dist/domain/vaults/provider-registry.d.ts +4 -1
- package/dist/domain/vaults/provider-sync.d.ts +135 -21
- package/dist/domain/vaults/provider-writes.d.ts +102 -12
- package/dist/domain/vaults/remote-provider-runtime.d.ts +7 -0
- package/dist/domain/vaults/secret-resolver.d.ts +29 -1
- package/dist/goal-admission.d.ts +2 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +1578 -394
- package/dist/index.js.map +1 -1
- package/package.json +13 -13
- package/src/access/index.ts +100 -0
- package/src/application/site-session-cancellation.ts +47 -0
- package/src/dependencies.ts +3 -0
- package/src/domain/file-owner.ts +1 -0
- package/src/domain/insights-usage.ts +20 -1
- package/src/domain/realtime-voice-billing.ts +4 -1
- package/src/domain/vaults/external-provider-connections.ts +395 -0
- package/src/domain/vaults/index.ts +8 -0
- package/src/domain/vaults/mapping.ts +95 -1
- package/src/domain/vaults/provider-registry.ts +29 -0
- package/src/domain/vaults/provider-sync.ts +492 -136
- package/src/domain/vaults/provider-writes.ts +415 -71
- package/src/domain/vaults/remote-provider-runtime.ts +129 -0
- package/src/domain/vaults/secret-resolver.ts +203 -33
- package/src/domain/vaults/vault-service.ts +226 -34
- package/src/domain/voice-input-billing.ts +5 -1
- package/src/index.ts +3 -0
- package/src/sandbox/fleet.ts +1 -0
- package/src/session-authorization.ts +21 -0
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
export { buildMissingSecretAskCard } from "@opengeni/contracts";
|
|
3
3
|
export { isVaultError, VaultError, vaultErrorFromDatabase } from "@opengeni/db";
|
|
4
4
|
export {
|
|
5
|
+
intersectProviderOperations,
|
|
6
|
+
providerOperationsForMode,
|
|
7
|
+
storedProviderOperations,
|
|
5
8
|
toVaultItem,
|
|
6
9
|
toVaultItemSummary,
|
|
7
10
|
toVaultSummary,
|
|
@@ -10,6 +13,11 @@ export {
|
|
|
10
13
|
vaultItemReferences,
|
|
11
14
|
type VaultCallerAuthority,
|
|
12
15
|
} from "./mapping";
|
|
16
|
+
export {
|
|
17
|
+
effectiveProviderOperations,
|
|
18
|
+
type ProviderWriteOperation,
|
|
19
|
+
type ProviderWriteOutcome,
|
|
20
|
+
} from "./provider-writes";
|
|
13
21
|
export {
|
|
14
22
|
chooseSecretCandidate,
|
|
15
23
|
createSecretResolver,
|
|
@@ -6,10 +6,12 @@
|
|
|
6
6
|
import {
|
|
7
7
|
formatSecretReference,
|
|
8
8
|
secretNameKey,
|
|
9
|
+
VaultProviderOperations,
|
|
9
10
|
type VaultItem,
|
|
10
11
|
type VaultItemField,
|
|
11
12
|
type VaultItemReferences,
|
|
12
13
|
type VaultItemSummary,
|
|
14
|
+
type VaultMode,
|
|
13
15
|
type VaultSummary,
|
|
14
16
|
} from "@opengeni/contracts";
|
|
15
17
|
import {
|
|
@@ -18,6 +20,7 @@ import {
|
|
|
18
20
|
type VaultItemRow,
|
|
19
21
|
type VaultRow,
|
|
20
22
|
} from "@opengeni/db";
|
|
23
|
+
import { providerVaultFreshness } from "./provider-sync";
|
|
21
24
|
|
|
22
25
|
/** What the caller may do beyond reading; decided by the route's grant. */
|
|
23
26
|
export type VaultCallerAuthority = {
|
|
@@ -27,9 +30,90 @@ export type VaultCallerAuthority = {
|
|
|
27
30
|
accountAdmin: boolean;
|
|
28
31
|
};
|
|
29
32
|
|
|
33
|
+
/** No writes at all: what a read-only link or a read-only provider vault allows. */
|
|
34
|
+
export function withoutProviderWrites(
|
|
35
|
+
operations: VaultProviderOperations,
|
|
36
|
+
): VaultProviderOperations {
|
|
37
|
+
return {
|
|
38
|
+
...operations,
|
|
39
|
+
createItemTypes: [],
|
|
40
|
+
updateItem: false,
|
|
41
|
+
removeField: false,
|
|
42
|
+
archiveItem: false,
|
|
43
|
+
archiveKind: "none",
|
|
44
|
+
deleteItem: false,
|
|
45
|
+
restoreItem: false,
|
|
46
|
+
writeFiles: false,
|
|
47
|
+
createTotp: false,
|
|
48
|
+
updateTotp: false,
|
|
49
|
+
createVault: false,
|
|
50
|
+
restoreFieldHistory: false,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Operations both sides allow (an archive needs both to agree on its kind). */
|
|
55
|
+
export function intersectProviderOperations(
|
|
56
|
+
left: VaultProviderOperations,
|
|
57
|
+
right: VaultProviderOperations,
|
|
58
|
+
): VaultProviderOperations {
|
|
59
|
+
const archiveItem =
|
|
60
|
+
left.archiveItem &&
|
|
61
|
+
right.archiveItem &&
|
|
62
|
+
left.archiveKind === right.archiveKind &&
|
|
63
|
+
left.archiveKind !== "none";
|
|
64
|
+
return {
|
|
65
|
+
createItemTypes: left.createItemTypes.filter(
|
|
66
|
+
(type) => type !== "passkey" && right.createItemTypes.includes(type),
|
|
67
|
+
),
|
|
68
|
+
updateItem: left.updateItem && right.updateItem,
|
|
69
|
+
removeField: left.removeField && right.removeField,
|
|
70
|
+
archiveItem,
|
|
71
|
+
archiveKind: archiveItem ? left.archiveKind : "none",
|
|
72
|
+
deleteItem: false,
|
|
73
|
+
restoreItem: left.restoreItem && right.restoreItem,
|
|
74
|
+
readFiles: left.readFiles && right.readFiles,
|
|
75
|
+
writeFiles: left.writeFiles && right.writeFiles,
|
|
76
|
+
createTotp: left.createTotp && right.createTotp,
|
|
77
|
+
updateTotp: left.updateTotp && right.updateTotp,
|
|
78
|
+
createVault: left.createVault && right.createVault,
|
|
79
|
+
restoreFieldHistory: left.restoreFieldHistory && right.restoreFieldHistory,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* What a linked vault allows: the operations its provider last reported for
|
|
85
|
+
* it, narrowed by the link mode. Null for hosted vaults and for links not yet
|
|
86
|
+
* checked since operations were recorded (callers then ask the provider).
|
|
87
|
+
*/
|
|
88
|
+
export function storedProviderOperations(
|
|
89
|
+
row: Pick<VaultRow, "source" | "mode"> & {
|
|
90
|
+
providerOperations?: VaultProviderOperations | null;
|
|
91
|
+
},
|
|
92
|
+
): VaultProviderOperations | null {
|
|
93
|
+
if (row.source === "opengeni" || !row.providerOperations) return null;
|
|
94
|
+
// Stored JSON is checked against the contract before it grants anything.
|
|
95
|
+
const parsed = VaultProviderOperations.safeParse(row.providerOperations);
|
|
96
|
+
return parsed.success ? providerOperationsForMode(parsed.data, row.mode) : null;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function providerOperationsForMode(
|
|
100
|
+
operations: VaultProviderOperations,
|
|
101
|
+
mode: VaultMode,
|
|
102
|
+
): VaultProviderOperations {
|
|
103
|
+
const normalized = intersectProviderOperations(operations, operations);
|
|
104
|
+
return mode === "read_write" ? normalized : withoutProviderWrites(normalized);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function providerAllowsAnyWrite(operations: VaultProviderOperations | null): boolean {
|
|
108
|
+
if (!operations) return true;
|
|
109
|
+
return operations.createItemTypes.length > 0 || operations.updateItem || operations.archiveItem;
|
|
110
|
+
}
|
|
111
|
+
|
|
30
112
|
export function vaultCanWrite(row: VaultRow, authority: VaultCallerAuthority): boolean {
|
|
31
113
|
// Read-write connected vaults are edited through their provider (W5, OP-3).
|
|
32
114
|
if (row.mode !== "read_write" || !authority.write) return false;
|
|
115
|
+
// A provider that reported no item writes for this vault makes it read-only here too.
|
|
116
|
+
if (!providerAllowsAnyWrite(storedProviderOperations(row))) return false;
|
|
33
117
|
if (row.ownerKind === "user") return row.ownedByCaller;
|
|
34
118
|
return true;
|
|
35
119
|
}
|
|
@@ -47,7 +131,15 @@ export function vaultCanManage(row: VaultRow, authority: VaultCallerAuthority):
|
|
|
47
131
|
}
|
|
48
132
|
}
|
|
49
133
|
|
|
50
|
-
export function toVaultSummary(
|
|
134
|
+
export function toVaultSummary(
|
|
135
|
+
row: VaultRow,
|
|
136
|
+
authority: VaultCallerAuthority,
|
|
137
|
+
options: { now?: Date; refreshing?: boolean } = {},
|
|
138
|
+
): VaultSummary {
|
|
139
|
+
const operations = storedProviderOperations(row);
|
|
140
|
+
const freshness = providerVaultFreshness(row, options.now ?? new Date(), {
|
|
141
|
+
...(options.refreshing ? { refreshing: true } : {}),
|
|
142
|
+
});
|
|
51
143
|
return {
|
|
52
144
|
id: row.id,
|
|
53
145
|
workspaceId: row.workspaceId,
|
|
@@ -64,6 +156,8 @@ export function toVaultSummary(row: VaultRow, authority: VaultCallerAuthority):
|
|
|
64
156
|
lastSyncedAt: row.lastSyncedAt,
|
|
65
157
|
rateLimitedUntil: row.rateLimitedUntil,
|
|
66
158
|
providerConnectionId: row.providerConnectionId,
|
|
159
|
+
...(operations ? { providerOperations: operations } : {}),
|
|
160
|
+
...(freshness ? { freshness } : {}),
|
|
67
161
|
availability: row.availability,
|
|
68
162
|
isDefault: row.isDefault,
|
|
69
163
|
itemCount: Number(row.itemCount),
|
|
@@ -12,7 +12,12 @@ import {
|
|
|
12
12
|
type VaultProvider,
|
|
13
13
|
type VaultProviderErrorCode,
|
|
14
14
|
type VaultProviderRegistry,
|
|
15
|
+
type VaultProviderAuthority,
|
|
15
16
|
} from "@opengeni/vaults";
|
|
17
|
+
import {
|
|
18
|
+
externalVaultProviderForConnection,
|
|
19
|
+
type ExternalVaultProviderFactories,
|
|
20
|
+
} from "./external-provider-connections";
|
|
16
21
|
|
|
17
22
|
/**
|
|
18
23
|
* Provider error codes as vault API error codes (§10B.1.1). `provider_not_found`
|
|
@@ -170,6 +175,8 @@ export function createWorkspaceVaultProviderRegistry(input: {
|
|
|
170
175
|
subjectId: string | null;
|
|
171
176
|
hostVaultProvider?: VaultProvider | null;
|
|
172
177
|
onePasswordVaultProvider?: OnePasswordVaultProviderFactory | null;
|
|
178
|
+
externalVaultProviders?: ExternalVaultProviderFactories | null;
|
|
179
|
+
executionContext?: Pick<VaultProviderAuthority, "sessionId" | "turnId" | "attemptId" | "siteId">;
|
|
173
180
|
}): VaultProviderRegistry {
|
|
174
181
|
const factory = input.onePasswordVaultProvider;
|
|
175
182
|
const host = input.hostVaultProvider;
|
|
@@ -197,5 +204,27 @@ export function createWorkspaceVaultProviderRegistry(input: {
|
|
|
197
204
|
}
|
|
198
205
|
: {}),
|
|
199
206
|
...(host ? { host: async () => host } : {}),
|
|
207
|
+
...Object.fromEntries(
|
|
208
|
+
Object.entries(input.externalVaultProviders ?? {}).map(([provider, providerFactory]) => [
|
|
209
|
+
provider,
|
|
210
|
+
async (connectionId: string | null) => {
|
|
211
|
+
if (!connectionId || !providerFactory)
|
|
212
|
+
throw new VaultProviderError(
|
|
213
|
+
"provider_unavailable",
|
|
214
|
+
"This vault has no available connection.",
|
|
215
|
+
);
|
|
216
|
+
return externalVaultProviderForConnection({
|
|
217
|
+
db: input.db,
|
|
218
|
+
settings: input.settings,
|
|
219
|
+
workspaceId: input.workspaceId,
|
|
220
|
+
subjectId: input.subjectId,
|
|
221
|
+
connectionId,
|
|
222
|
+
provider: provider as keyof ExternalVaultProviderFactories,
|
|
223
|
+
factory: providerFactory,
|
|
224
|
+
...(input.executionContext ? { executionContext: input.executionContext } : {}),
|
|
225
|
+
});
|
|
226
|
+
},
|
|
227
|
+
]),
|
|
228
|
+
),
|
|
200
229
|
});
|
|
201
230
|
}
|