@serve.zone/interfaces 27.3.1 → 27.4.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/changelog.md +13 -0
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/runtime.cloudlylegacydeploymentsettlement.offlineexport.d.ts +291 -0
- package/dist_ts/runtime.cloudlylegacydeploymentsettlement.offlineexport.golden.d.ts +30 -0
- package/dist_ts/runtime.cloudlylegacydeploymentsettlement.offlineexport.golden.js +408 -0
- package/dist_ts/runtime.cloudlylegacydeploymentsettlement.offlineexport.js +1126 -0
- package/dist_ts/runtime.corestore.databaseexportpackage.d.ts +118 -0
- package/dist_ts/runtime.corestore.databaseexportpackage.golden.d.ts +22 -0
- package/dist_ts/runtime.corestore.databaseexportpackage.golden.js +242 -0
- package/dist_ts/runtime.corestore.databaseexportpackage.js +428 -0
- package/dist_ts/runtime.d.ts +2 -0
- package/dist_ts/runtime.js +3 -1
- package/package.json +1 -1
- package/readme.md +32 -0
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/runtime.cloudlylegacydeploymentsettlement.offlineexport.golden.ts +510 -0
- package/ts/runtime.cloudlylegacydeploymentsettlement.offlineexport.ts +2470 -0
- package/ts/runtime.corestore.databaseexportpackage.golden.ts +323 -0
- package/ts/runtime.corestore.databaseexportpackage.ts +862 -0
- package/ts/runtime.ts +2 -0
|
@@ -0,0 +1,2470 @@
|
|
|
1
|
+
import * as plugins from './plugins.runtime.js';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
canonicalizeStrictJson,
|
|
5
|
+
deepFreezeValue,
|
|
6
|
+
} from './private/canonicaljson.js';
|
|
7
|
+
import {
|
|
8
|
+
cloudlyLegacyDeploymentSettlementLimits,
|
|
9
|
+
} from './runtime.cloudlylegacydeploymentsettlement.js';
|
|
10
|
+
import type {
|
|
11
|
+
ICorestoreDatabaseAllocationReference,
|
|
12
|
+
} from './runtime.corestore.js';
|
|
13
|
+
import {
|
|
14
|
+
normalizeCorestoreDatabaseAllocationReference,
|
|
15
|
+
} from './runtime.corestore.js';
|
|
16
|
+
|
|
17
|
+
const maximumExactExportBytes = 96 * 1024 * 1024 + 1;
|
|
18
|
+
|
|
19
|
+
export const cloudlyLegacyDeploymentSettlementOfflineExportLimits = Object.freeze({
|
|
20
|
+
maximumIdentifierLength:
|
|
21
|
+
cloudlyLegacyDeploymentSettlementLimits.maximumIdentifierLength,
|
|
22
|
+
maximumSourceDocuments:
|
|
23
|
+
cloudlyLegacyDeploymentSettlementLimits.maximumSourceDocuments,
|
|
24
|
+
maximumOperations: cloudlyLegacyDeploymentSettlementLimits.maximumOperations,
|
|
25
|
+
maximumExactExportBytes,
|
|
26
|
+
maximumJournalGrowthBytes: 64 * 1024,
|
|
27
|
+
maximumJournalCanonicalBytes: 32 * 1024,
|
|
28
|
+
maximumReceiptBytes: 16 * 1024,
|
|
29
|
+
maximumResultBytes: 16 * 1024,
|
|
30
|
+
maximumAuthorityBytes: 16 * 1024,
|
|
31
|
+
maximumPlanBytes: 768 * 1024,
|
|
32
|
+
maximumAuthenticatedArtifactBytes: 768 * 1024,
|
|
33
|
+
maximumAuthorityLifetimeMs:
|
|
34
|
+
cloudlyLegacyDeploymentSettlementLimits.maximumAuthorityLifetimeMs,
|
|
35
|
+
} as const);
|
|
36
|
+
|
|
37
|
+
export const cloudlyLegacyDeploymentSettlementOfflineExportDomains = Object.freeze({
|
|
38
|
+
rehearsalAttestationHmac:
|
|
39
|
+
'serve.zone/cloudly-legacy-deployment-settlement/offline-export/rehearsal-attestation-hmac-v1\0',
|
|
40
|
+
productionTransformAuthorizationHmac:
|
|
41
|
+
'serve.zone/cloudly-legacy-deployment-settlement/offline-export/production-transform-authorization-hmac-v1\0',
|
|
42
|
+
attemptJournalHmac:
|
|
43
|
+
'serve.zone/cloudly-legacy-deployment-settlement/offline-export/attempt-journal-hmac-v1\0',
|
|
44
|
+
completeOutputReceiptHmac:
|
|
45
|
+
'serve.zone/cloudly-legacy-deployment-settlement/offline-export/complete-output-receipt-hmac-v1\0',
|
|
46
|
+
} as const);
|
|
47
|
+
|
|
48
|
+
export const cloudlyLegacyDeploymentSettlementOfflineExportJournalCollectionName =
|
|
49
|
+
'cloudly_legacy_deployment_settlement_export_attempt_v1' as const;
|
|
50
|
+
|
|
51
|
+
export type TCloudlyLegacyDeploymentSettlementOfflineExportCodecErrorCode =
|
|
52
|
+
| 'INVALID_DATA'
|
|
53
|
+
| 'INVALID_SCHEMA'
|
|
54
|
+
| 'INVALID_VALUE'
|
|
55
|
+
| 'LIMIT_EXCEEDED'
|
|
56
|
+
| 'ORDERING_REQUIRED'
|
|
57
|
+
| 'CROSS_FIELD_MISMATCH';
|
|
58
|
+
|
|
59
|
+
export class CloudlyLegacyDeploymentSettlementOfflineExportCodecError extends Error {
|
|
60
|
+
public readonly code: TCloudlyLegacyDeploymentSettlementOfflineExportCodecErrorCode;
|
|
61
|
+
public readonly path: string;
|
|
62
|
+
|
|
63
|
+
public constructor(
|
|
64
|
+
codeArg: TCloudlyLegacyDeploymentSettlementOfflineExportCodecErrorCode,
|
|
65
|
+
pathArg: string,
|
|
66
|
+
) {
|
|
67
|
+
super(`${codeArg}:${pathArg}`);
|
|
68
|
+
this.name = 'CloudlyLegacyDeploymentSettlementOfflineExportCodecError';
|
|
69
|
+
this.code = codeArg;
|
|
70
|
+
this.path = pathArg;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export type TCloudlyLegacyDeploymentSettlementOfflineExportClassification =
|
|
75
|
+
| 'image-recorded-not-current'
|
|
76
|
+
| 'image-recorded-current-failed'
|
|
77
|
+
| 'rolling-out-current-failed'
|
|
78
|
+
| 'rolling-out-superseded';
|
|
79
|
+
|
|
80
|
+
export interface ICloudlyLegacyDeploymentSettlementOfflineExportClassificationCountsV1 {
|
|
81
|
+
'image-recorded-not-current': number;
|
|
82
|
+
'image-recorded-current-failed': number;
|
|
83
|
+
'rolling-out-current-failed': number;
|
|
84
|
+
'rolling-out-superseded': number;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export interface ICloudlyLegacyDeploymentSettlementOfflineExportSourceCensusV1 {
|
|
88
|
+
operations: number;
|
|
89
|
+
services: number;
|
|
90
|
+
images: number;
|
|
91
|
+
releases: number;
|
|
92
|
+
rolloutOperations: number;
|
|
93
|
+
routeClaims: number;
|
|
94
|
+
resourceClaims: number;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export interface ICloudlyLegacyDeploymentSettlementOfflineExportMutationCountsV1 {
|
|
98
|
+
operationCount: number;
|
|
99
|
+
routeClaimsStabilized: number;
|
|
100
|
+
routeClaimsRemoved: number;
|
|
101
|
+
resourceClaimsRemoved: number;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export interface ICloudlyLegacyDeploymentSettlementOfflineExportPlanEntryV1 {
|
|
105
|
+
operationId: string;
|
|
106
|
+
serviceId: string;
|
|
107
|
+
sourceRevision: number;
|
|
108
|
+
sourceState: 'image-recorded' | 'rolling-out';
|
|
109
|
+
classification: TCloudlyLegacyDeploymentSettlementOfflineExportClassification;
|
|
110
|
+
finalRevision: number;
|
|
111
|
+
sourceDocumentHmac: `hmac-sha256:${string}`;
|
|
112
|
+
finalDocumentHmac: `hmac-sha256:${string}`;
|
|
113
|
+
routeClaimsStabilized: number;
|
|
114
|
+
routeClaimsRemoved: number;
|
|
115
|
+
resourceClaimsRemoved: number;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export interface ICloudlyLegacyDeploymentSettlementOfflineExportFileIdentityV1 {
|
|
119
|
+
format: 'smartdb.database.export.v1';
|
|
120
|
+
databaseName: string;
|
|
121
|
+
byteLength: number;
|
|
122
|
+
sha256: string;
|
|
123
|
+
lineFeedTerminator: 'single-lf';
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export interface ICloudlyLegacyDeploymentSettlementOfflineExportApprovedSourceBackupIdentityV1 {
|
|
127
|
+
backupId: string;
|
|
128
|
+
sourceServiceId: string;
|
|
129
|
+
snapshotId: string;
|
|
130
|
+
backupReceiptSha256: string;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export interface ICloudlyLegacyDeploymentSettlementOfflineExportPlanV1 {
|
|
134
|
+
schemaVersion: 1;
|
|
135
|
+
kind: 'cloudly-legacy-deployment-settlement-offline-export-plan';
|
|
136
|
+
operationId: string;
|
|
137
|
+
settlementId: string;
|
|
138
|
+
sourceFile: ICloudlyLegacyDeploymentSettlementOfflineExportFileIdentityV1;
|
|
139
|
+
effectiveAt: number;
|
|
140
|
+
sourceStateHmac: `hmac-sha256:${string}`;
|
|
141
|
+
finalStateHmac: `hmac-sha256:${string}`;
|
|
142
|
+
sourceCensus: ICloudlyLegacyDeploymentSettlementOfflineExportSourceCensusV1;
|
|
143
|
+
entries: ICloudlyLegacyDeploymentSettlementOfflineExportPlanEntryV1[];
|
|
144
|
+
counts: ICloudlyLegacyDeploymentSettlementOfflineExportMutationCountsV1;
|
|
145
|
+
classificationCounts:
|
|
146
|
+
ICloudlyLegacyDeploymentSettlementOfflineExportClassificationCountsV1;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
interface ICloudlyLegacyDeploymentSettlementOfflineExportAuthorityReferenceBaseV1 {
|
|
150
|
+
schemaVersion: 1;
|
|
151
|
+
kind: 'cloudly-legacy-deployment-settlement-offline-export-authority-reference';
|
|
152
|
+
operationId: string;
|
|
153
|
+
settlementId: string;
|
|
154
|
+
authorityId: string;
|
|
155
|
+
keyId: string;
|
|
156
|
+
keyVersion: 1;
|
|
157
|
+
authorityMetadataSha256: string;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export interface ICloudlyLegacyDeploymentSettlementOfflineExportSourceAuthorityReferenceV1
|
|
161
|
+
extends ICloudlyLegacyDeploymentSettlementOfflineExportAuthorityReferenceBaseV1 {
|
|
162
|
+
role: 'source-rehearsal';
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export interface ICloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthorityReferenceV1
|
|
166
|
+
extends ICloudlyLegacyDeploymentSettlementOfflineExportAuthorityReferenceBaseV1 {
|
|
167
|
+
role: 'production-transform';
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export type TCloudlyLegacyDeploymentSettlementOfflineExportAuthorityReferenceV1 =
|
|
171
|
+
| ICloudlyLegacyDeploymentSettlementOfflineExportSourceAuthorityReferenceV1
|
|
172
|
+
| ICloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthorityReferenceV1;
|
|
173
|
+
|
|
174
|
+
export interface ICloudlyLegacyDeploymentSettlementOfflineExportSourceAuthorityV1 {
|
|
175
|
+
schemaVersion: 1;
|
|
176
|
+
kind: 'cloudly-legacy-deployment-settlement-offline-export-source-authority';
|
|
177
|
+
role: 'source-rehearsal';
|
|
178
|
+
operationId: string;
|
|
179
|
+
settlementId: string;
|
|
180
|
+
authorityId: string;
|
|
181
|
+
keyId: string;
|
|
182
|
+
keyVersion: 1;
|
|
183
|
+
issuedAt: number;
|
|
184
|
+
expiresAt: number;
|
|
185
|
+
sourceFile: ICloudlyLegacyDeploymentSettlementOfflineExportFileIdentityV1;
|
|
186
|
+
approvedSourceBackup:
|
|
187
|
+
ICloudlyLegacyDeploymentSettlementOfflineExportApprovedSourceBackupIdentityV1;
|
|
188
|
+
planSha256: string;
|
|
189
|
+
rehearsalRequestSha256: string;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export interface ICloudlyLegacyDeploymentSettlementOfflineExportRehearsalAttestationPayloadV1 {
|
|
193
|
+
schemaVersion: 1;
|
|
194
|
+
kind: 'cloudly-legacy-deployment-settlement-offline-export-rehearsal-attestation';
|
|
195
|
+
sourceAuthority:
|
|
196
|
+
ICloudlyLegacyDeploymentSettlementOfflineExportSourceAuthorityReferenceV1;
|
|
197
|
+
plan: ICloudlyLegacyDeploymentSettlementOfflineExportPlanV1;
|
|
198
|
+
planSha256: string;
|
|
199
|
+
rehearsalRequestSha256: string;
|
|
200
|
+
scratchAllocation: ICorestoreDatabaseAllocationReference;
|
|
201
|
+
outcome: 'transform-required' | 'no-op';
|
|
202
|
+
observedFinalStateHmac: `hmac-sha256:${string}`;
|
|
203
|
+
observedCounts: ICloudlyLegacyDeploymentSettlementOfflineExportMutationCountsV1;
|
|
204
|
+
observedClassificationCounts:
|
|
205
|
+
ICloudlyLegacyDeploymentSettlementOfflineExportClassificationCountsV1;
|
|
206
|
+
completedAt: number;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export interface ICloudlyLegacyDeploymentSettlementOfflineExportRehearsalAttestationV1
|
|
210
|
+
extends ICloudlyLegacyDeploymentSettlementOfflineExportRehearsalAttestationPayloadV1 {
|
|
211
|
+
payloadSha256: string;
|
|
212
|
+
mac: string;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
export type TCloudlyLegacyDeploymentSettlementOfflineExportUnsignedRehearsalAttestationV1 =
|
|
216
|
+
Omit<ICloudlyLegacyDeploymentSettlementOfflineExportRehearsalAttestationV1, 'mac'>;
|
|
217
|
+
|
|
218
|
+
export interface ICloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthorityV1 {
|
|
219
|
+
schemaVersion: 1;
|
|
220
|
+
kind: 'cloudly-legacy-deployment-settlement-offline-export-production-transform-authority';
|
|
221
|
+
role: 'production-transform';
|
|
222
|
+
operationId: string;
|
|
223
|
+
settlementId: string;
|
|
224
|
+
authorityId: string;
|
|
225
|
+
keyId: string;
|
|
226
|
+
keyVersion: 1;
|
|
227
|
+
issuedAt: number;
|
|
228
|
+
expiresAt: number;
|
|
229
|
+
sourceAuthority:
|
|
230
|
+
ICloudlyLegacyDeploymentSettlementOfflineExportSourceAuthorityReferenceV1;
|
|
231
|
+
authenticatedRehearsalAttestationSha256: string;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export interface ICloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthorizationPayloadV1 {
|
|
235
|
+
schemaVersion: 1;
|
|
236
|
+
kind: 'cloudly-legacy-deployment-settlement-offline-export-production-transform-authorization';
|
|
237
|
+
authority:
|
|
238
|
+
ICloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthorityReferenceV1;
|
|
239
|
+
sourceAuthority:
|
|
240
|
+
ICloudlyLegacyDeploymentSettlementOfflineExportSourceAuthorityReferenceV1;
|
|
241
|
+
attemptId: string;
|
|
242
|
+
authenticatedRehearsalAttestationSha256: string;
|
|
243
|
+
planSha256: string;
|
|
244
|
+
requestSha256: string;
|
|
245
|
+
requestedAt: number;
|
|
246
|
+
authorizedAt: number;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
export interface ICloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthorizationV1
|
|
250
|
+
extends ICloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthorizationPayloadV1 {
|
|
251
|
+
payloadSha256: string;
|
|
252
|
+
mac: string;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
export type TCloudlyLegacyDeploymentSettlementOfflineExportUnsignedProductionTransformAuthorizationV1 =
|
|
256
|
+
Omit<
|
|
257
|
+
ICloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthorizationV1,
|
|
258
|
+
'mac'
|
|
259
|
+
>;
|
|
260
|
+
|
|
261
|
+
export interface ICloudlyLegacyDeploymentSettlementOfflineExportAttemptJournalSeedV1 {
|
|
262
|
+
schemaVersion: 1;
|
|
263
|
+
kind: typeof cloudlyLegacyDeploymentSettlementOfflineExportJournalCollectionName;
|
|
264
|
+
purpose: 'production-transform';
|
|
265
|
+
operationId: string;
|
|
266
|
+
settlementId: string;
|
|
267
|
+
attemptId: string;
|
|
268
|
+
sourceAuthority:
|
|
269
|
+
ICloudlyLegacyDeploymentSettlementOfflineExportSourceAuthorityReferenceV1;
|
|
270
|
+
productionTransformAuthority:
|
|
271
|
+
ICloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthorityReferenceV1;
|
|
272
|
+
authenticatedRehearsalAttestationSha256: string;
|
|
273
|
+
transformAuthorizationSha256: string;
|
|
274
|
+
planSha256: string;
|
|
275
|
+
requestSha256: string;
|
|
276
|
+
sourceFile: ICloudlyLegacyDeploymentSettlementOfflineExportFileIdentityV1;
|
|
277
|
+
transformedCoreFile: ICloudlyLegacyDeploymentSettlementOfflineExportFileIdentityV1;
|
|
278
|
+
sourceStateHmac: `hmac-sha256:${string}`;
|
|
279
|
+
finalStateHmac: `hmac-sha256:${string}`;
|
|
280
|
+
outcome: 'transformed' | 'no-op';
|
|
281
|
+
counts: ICloudlyLegacyDeploymentSettlementOfflineExportMutationCountsV1;
|
|
282
|
+
classificationCounts:
|
|
283
|
+
ICloudlyLegacyDeploymentSettlementOfflineExportClassificationCountsV1;
|
|
284
|
+
completedAt: number;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
export interface ICloudlyLegacyDeploymentSettlementOfflineExportAttemptJournalV1
|
|
288
|
+
extends ICloudlyLegacyDeploymentSettlementOfflineExportAttemptJournalSeedV1 {
|
|
289
|
+
_id: string;
|
|
290
|
+
mac: string;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
export type TCloudlyLegacyDeploymentSettlementOfflineExportUnsignedAttemptJournalV1 =
|
|
294
|
+
Omit<ICloudlyLegacyDeploymentSettlementOfflineExportAttemptJournalV1, 'mac'>;
|
|
295
|
+
|
|
296
|
+
export interface ICloudlyLegacyDeploymentSettlementOfflineExportCompleteOutputReceiptPayloadV1 {
|
|
297
|
+
schemaVersion: 1;
|
|
298
|
+
kind: 'cloudly-legacy-deployment-settlement-offline-export-complete-output-receipt';
|
|
299
|
+
authority:
|
|
300
|
+
ICloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthorityReferenceV1;
|
|
301
|
+
sourceAuthority:
|
|
302
|
+
ICloudlyLegacyDeploymentSettlementOfflineExportSourceAuthorityReferenceV1;
|
|
303
|
+
operationId: string;
|
|
304
|
+
settlementId: string;
|
|
305
|
+
attemptId: string;
|
|
306
|
+
journalSha256: string;
|
|
307
|
+
transformedCoreFile: ICloudlyLegacyDeploymentSettlementOfflineExportFileIdentityV1;
|
|
308
|
+
completeOutputFile: ICloudlyLegacyDeploymentSettlementOfflineExportFileIdentityV1;
|
|
309
|
+
journalGrowthBytes: number;
|
|
310
|
+
completedAt: number;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
export interface ICloudlyLegacyDeploymentSettlementOfflineExportCompleteOutputReceiptV1
|
|
314
|
+
extends ICloudlyLegacyDeploymentSettlementOfflineExportCompleteOutputReceiptPayloadV1 {
|
|
315
|
+
payloadSha256: string;
|
|
316
|
+
mac: string;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
export type TCloudlyLegacyDeploymentSettlementOfflineExportUnsignedCompleteOutputReceiptV1 =
|
|
320
|
+
Omit<ICloudlyLegacyDeploymentSettlementOfflineExportCompleteOutputReceiptV1, 'mac'>;
|
|
321
|
+
|
|
322
|
+
export interface ICloudlyLegacyDeploymentSettlementOfflineExportTransformResultV1 {
|
|
323
|
+
schemaVersion: 1;
|
|
324
|
+
kind: 'cloudly-legacy-deployment-settlement-offline-export-transform-result';
|
|
325
|
+
status: 'completed';
|
|
326
|
+
operationId: string;
|
|
327
|
+
settlementId: string;
|
|
328
|
+
attemptId: string;
|
|
329
|
+
sourceAuthority:
|
|
330
|
+
ICloudlyLegacyDeploymentSettlementOfflineExportSourceAuthorityReferenceV1;
|
|
331
|
+
productionTransformAuthority:
|
|
332
|
+
ICloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthorityReferenceV1;
|
|
333
|
+
planSha256: string;
|
|
334
|
+
requestSha256: string;
|
|
335
|
+
completeOutputReceiptSha256: string;
|
|
336
|
+
outcome: 'transformed' | 'no-op';
|
|
337
|
+
counts: ICloudlyLegacyDeploymentSettlementOfflineExportMutationCountsV1;
|
|
338
|
+
classificationCounts:
|
|
339
|
+
ICloudlyLegacyDeploymentSettlementOfflineExportClassificationCountsV1;
|
|
340
|
+
completedAt: number;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
export interface ICloudlyLegacyDeploymentSettlementOfflineExportHmacVerificationInputV1 {
|
|
344
|
+
authority: TCloudlyLegacyDeploymentSettlementOfflineExportAuthorityReferenceV1;
|
|
345
|
+
domain: typeof cloudlyLegacyDeploymentSettlementOfflineExportDomains[keyof
|
|
346
|
+
typeof cloudlyLegacyDeploymentSettlementOfflineExportDomains];
|
|
347
|
+
hmacInput: Uint8Array;
|
|
348
|
+
mac: string;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
export type TCloudlyLegacyDeploymentSettlementOfflineExportHmacVerifier = (
|
|
352
|
+
inputArg: ICloudlyLegacyDeploymentSettlementOfflineExportHmacVerificationInputV1,
|
|
353
|
+
) => boolean | Promise<boolean>;
|
|
354
|
+
|
|
355
|
+
const classificationKeys = [
|
|
356
|
+
'image-recorded-not-current',
|
|
357
|
+
'image-recorded-current-failed',
|
|
358
|
+
'rolling-out-current-failed',
|
|
359
|
+
'rolling-out-superseded',
|
|
360
|
+
] as const;
|
|
361
|
+
const censusKeys = [
|
|
362
|
+
'operations',
|
|
363
|
+
'services',
|
|
364
|
+
'images',
|
|
365
|
+
'releases',
|
|
366
|
+
'rolloutOperations',
|
|
367
|
+
'routeClaims',
|
|
368
|
+
'resourceClaims',
|
|
369
|
+
] as const;
|
|
370
|
+
const mutationCountKeys = [
|
|
371
|
+
'operationCount',
|
|
372
|
+
'routeClaimsStabilized',
|
|
373
|
+
'routeClaimsRemoved',
|
|
374
|
+
'resourceClaimsRemoved',
|
|
375
|
+
] as const;
|
|
376
|
+
const planEntryKeys = [
|
|
377
|
+
'operationId',
|
|
378
|
+
'serviceId',
|
|
379
|
+
'sourceRevision',
|
|
380
|
+
'sourceState',
|
|
381
|
+
'classification',
|
|
382
|
+
'finalRevision',
|
|
383
|
+
'sourceDocumentHmac',
|
|
384
|
+
'finalDocumentHmac',
|
|
385
|
+
'routeClaimsStabilized',
|
|
386
|
+
'routeClaimsRemoved',
|
|
387
|
+
'resourceClaimsRemoved',
|
|
388
|
+
] as const;
|
|
389
|
+
const fileIdentityKeys = [
|
|
390
|
+
'format',
|
|
391
|
+
'databaseName',
|
|
392
|
+
'byteLength',
|
|
393
|
+
'sha256',
|
|
394
|
+
'lineFeedTerminator',
|
|
395
|
+
] as const;
|
|
396
|
+
const approvedSourceBackupKeys = [
|
|
397
|
+
'backupId',
|
|
398
|
+
'sourceServiceId',
|
|
399
|
+
'snapshotId',
|
|
400
|
+
'backupReceiptSha256',
|
|
401
|
+
] as const;
|
|
402
|
+
const authorityReferenceKeys = [
|
|
403
|
+
'schemaVersion',
|
|
404
|
+
'kind',
|
|
405
|
+
'role',
|
|
406
|
+
'operationId',
|
|
407
|
+
'settlementId',
|
|
408
|
+
'authorityId',
|
|
409
|
+
'keyId',
|
|
410
|
+
'keyVersion',
|
|
411
|
+
'authorityMetadataSha256',
|
|
412
|
+
] as const;
|
|
413
|
+
const sourceAuthorityKeys = [
|
|
414
|
+
'schemaVersion',
|
|
415
|
+
'kind',
|
|
416
|
+
'role',
|
|
417
|
+
'operationId',
|
|
418
|
+
'settlementId',
|
|
419
|
+
'authorityId',
|
|
420
|
+
'keyId',
|
|
421
|
+
'keyVersion',
|
|
422
|
+
'issuedAt',
|
|
423
|
+
'expiresAt',
|
|
424
|
+
'sourceFile',
|
|
425
|
+
'approvedSourceBackup',
|
|
426
|
+
'planSha256',
|
|
427
|
+
'rehearsalRequestSha256',
|
|
428
|
+
] as const;
|
|
429
|
+
const productionTransformAuthorityKeys = [
|
|
430
|
+
'schemaVersion',
|
|
431
|
+
'kind',
|
|
432
|
+
'role',
|
|
433
|
+
'operationId',
|
|
434
|
+
'settlementId',
|
|
435
|
+
'authorityId',
|
|
436
|
+
'keyId',
|
|
437
|
+
'keyVersion',
|
|
438
|
+
'issuedAt',
|
|
439
|
+
'expiresAt',
|
|
440
|
+
'sourceAuthority',
|
|
441
|
+
'authenticatedRehearsalAttestationSha256',
|
|
442
|
+
] as const;
|
|
443
|
+
const rehearsalPayloadKeys = [
|
|
444
|
+
'schemaVersion',
|
|
445
|
+
'kind',
|
|
446
|
+
'sourceAuthority',
|
|
447
|
+
'plan',
|
|
448
|
+
'planSha256',
|
|
449
|
+
'rehearsalRequestSha256',
|
|
450
|
+
'scratchAllocation',
|
|
451
|
+
'outcome',
|
|
452
|
+
'observedFinalStateHmac',
|
|
453
|
+
'observedCounts',
|
|
454
|
+
'observedClassificationCounts',
|
|
455
|
+
'completedAt',
|
|
456
|
+
] as const;
|
|
457
|
+
const rehearsalUnsignedKeys = [...rehearsalPayloadKeys, 'payloadSha256'] as const;
|
|
458
|
+
const rehearsalKeys = [...rehearsalUnsignedKeys, 'mac'] as const;
|
|
459
|
+
const authorizationPayloadKeys = [
|
|
460
|
+
'schemaVersion',
|
|
461
|
+
'kind',
|
|
462
|
+
'authority',
|
|
463
|
+
'sourceAuthority',
|
|
464
|
+
'attemptId',
|
|
465
|
+
'authenticatedRehearsalAttestationSha256',
|
|
466
|
+
'planSha256',
|
|
467
|
+
'requestSha256',
|
|
468
|
+
'requestedAt',
|
|
469
|
+
'authorizedAt',
|
|
470
|
+
] as const;
|
|
471
|
+
const authorizationUnsignedKeys = [...authorizationPayloadKeys, 'payloadSha256'] as const;
|
|
472
|
+
const authorizationKeys = [...authorizationUnsignedKeys, 'mac'] as const;
|
|
473
|
+
const journalSeedKeys = [
|
|
474
|
+
'schemaVersion',
|
|
475
|
+
'kind',
|
|
476
|
+
'purpose',
|
|
477
|
+
'operationId',
|
|
478
|
+
'settlementId',
|
|
479
|
+
'attemptId',
|
|
480
|
+
'sourceAuthority',
|
|
481
|
+
'productionTransformAuthority',
|
|
482
|
+
'authenticatedRehearsalAttestationSha256',
|
|
483
|
+
'transformAuthorizationSha256',
|
|
484
|
+
'planSha256',
|
|
485
|
+
'requestSha256',
|
|
486
|
+
'sourceFile',
|
|
487
|
+
'transformedCoreFile',
|
|
488
|
+
'sourceStateHmac',
|
|
489
|
+
'finalStateHmac',
|
|
490
|
+
'outcome',
|
|
491
|
+
'counts',
|
|
492
|
+
'classificationCounts',
|
|
493
|
+
'completedAt',
|
|
494
|
+
] as const;
|
|
495
|
+
const journalUnsignedKeys = ['_id', ...journalSeedKeys] as const;
|
|
496
|
+
const journalKeys = [...journalUnsignedKeys, 'mac'] as const;
|
|
497
|
+
const completeOutputReceiptPayloadKeys = [
|
|
498
|
+
'schemaVersion',
|
|
499
|
+
'kind',
|
|
500
|
+
'authority',
|
|
501
|
+
'sourceAuthority',
|
|
502
|
+
'operationId',
|
|
503
|
+
'settlementId',
|
|
504
|
+
'attemptId',
|
|
505
|
+
'journalSha256',
|
|
506
|
+
'transformedCoreFile',
|
|
507
|
+
'completeOutputFile',
|
|
508
|
+
'journalGrowthBytes',
|
|
509
|
+
'completedAt',
|
|
510
|
+
] as const;
|
|
511
|
+
const completeOutputReceiptUnsignedKeys = [
|
|
512
|
+
...completeOutputReceiptPayloadKeys,
|
|
513
|
+
'payloadSha256',
|
|
514
|
+
] as const;
|
|
515
|
+
const completeOutputReceiptKeys = [...completeOutputReceiptUnsignedKeys, 'mac'] as const;
|
|
516
|
+
|
|
517
|
+
const identifierPattern = /^[A-Za-z0-9][A-Za-z0-9:._@-]{0,199}$/;
|
|
518
|
+
const sha256Pattern = /^[a-f0-9]{64}$/;
|
|
519
|
+
const stateHmacPattern = /^hmac-sha256:[a-f0-9]{64}$/;
|
|
520
|
+
const macPattern = /^[A-Za-z0-9_-]{42}[AEIMQUYcgkosw048]$/;
|
|
521
|
+
|
|
522
|
+
const fail = (
|
|
523
|
+
codeArg: TCloudlyLegacyDeploymentSettlementOfflineExportCodecErrorCode,
|
|
524
|
+
pathArg: string,
|
|
525
|
+
): never => {
|
|
526
|
+
throw new CloudlyLegacyDeploymentSettlementOfflineExportCodecError(codeArg, pathArg);
|
|
527
|
+
};
|
|
528
|
+
|
|
529
|
+
const normalizeScratchAllocation = (
|
|
530
|
+
valueArg: unknown,
|
|
531
|
+
pathArg: string,
|
|
532
|
+
): ICorestoreDatabaseAllocationReference => {
|
|
533
|
+
try {
|
|
534
|
+
return normalizeCorestoreDatabaseAllocationReference(
|
|
535
|
+
valueArg,
|
|
536
|
+
) as ICorestoreDatabaseAllocationReference;
|
|
537
|
+
} catch {
|
|
538
|
+
return fail('INVALID_VALUE', pathArg);
|
|
539
|
+
}
|
|
540
|
+
};
|
|
541
|
+
|
|
542
|
+
const readRecord = (valueArg: unknown, pathArg: string): Record<string, unknown> => {
|
|
543
|
+
if (!valueArg || typeof valueArg !== 'object' || Array.isArray(valueArg)) {
|
|
544
|
+
return fail('INVALID_DATA', pathArg);
|
|
545
|
+
}
|
|
546
|
+
const prototype = Object.getPrototypeOf(valueArg);
|
|
547
|
+
if (prototype !== Object.prototype && prototype !== null) {
|
|
548
|
+
return fail('INVALID_DATA', pathArg);
|
|
549
|
+
}
|
|
550
|
+
const value = valueArg as Record<string, unknown>;
|
|
551
|
+
for (const key of Reflect.ownKeys(value)) {
|
|
552
|
+
if (typeof key !== 'string') return fail('INVALID_DATA', pathArg);
|
|
553
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
554
|
+
if (!descriptor || !descriptor.enumerable || !Object.hasOwn(descriptor, 'value')) {
|
|
555
|
+
return fail('INVALID_DATA', pathArg);
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
return value;
|
|
559
|
+
};
|
|
560
|
+
|
|
561
|
+
const readArray = (
|
|
562
|
+
valueArg: unknown,
|
|
563
|
+
pathArg: string,
|
|
564
|
+
maximumLengthArg: number,
|
|
565
|
+
): unknown[] => {
|
|
566
|
+
if (!Array.isArray(valueArg) || Object.getPrototypeOf(valueArg) !== Array.prototype
|
|
567
|
+
|| valueArg.length > maximumLengthArg) {
|
|
568
|
+
return fail(
|
|
569
|
+
Array.isArray(valueArg) ? 'LIMIT_EXCEEDED' : 'INVALID_DATA',
|
|
570
|
+
pathArg,
|
|
571
|
+
);
|
|
572
|
+
}
|
|
573
|
+
for (let index = 0; index < valueArg.length; index++) {
|
|
574
|
+
if (!Object.hasOwn(valueArg, index)) return fail('INVALID_DATA', `${pathArg}[${index}]`);
|
|
575
|
+
const descriptor = Object.getOwnPropertyDescriptor(valueArg, String(index));
|
|
576
|
+
if (!descriptor || !descriptor.enumerable || !Object.hasOwn(descriptor, 'value')) {
|
|
577
|
+
return fail('INVALID_DATA', `${pathArg}[${index}]`);
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
for (const key of Reflect.ownKeys(valueArg)) {
|
|
581
|
+
if (key === 'length') continue;
|
|
582
|
+
if (typeof key !== 'string'
|
|
583
|
+
|| !/^(?:0|[1-9][0-9]*)$/.test(key)
|
|
584
|
+
|| Number(key) >= valueArg.length) {
|
|
585
|
+
return fail('INVALID_DATA', pathArg);
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
return valueArg;
|
|
589
|
+
};
|
|
590
|
+
|
|
591
|
+
const assertExactKeys = (
|
|
592
|
+
valueArg: Record<string, unknown>,
|
|
593
|
+
keysArg: readonly string[],
|
|
594
|
+
pathArg: string,
|
|
595
|
+
): void => {
|
|
596
|
+
const actual = Object.keys(valueArg).sort();
|
|
597
|
+
const expected = [...keysArg].sort();
|
|
598
|
+
if (actual.length !== expected.length
|
|
599
|
+
|| actual.some((keyArg, indexArg) => keyArg !== expected[indexArg])) {
|
|
600
|
+
fail('INVALID_SCHEMA', pathArg);
|
|
601
|
+
}
|
|
602
|
+
};
|
|
603
|
+
|
|
604
|
+
const readIdentifier = (valueArg: unknown, pathArg: string): string => {
|
|
605
|
+
if (typeof valueArg !== 'string' || !identifierPattern.test(valueArg)) {
|
|
606
|
+
return fail('INVALID_VALUE', pathArg);
|
|
607
|
+
}
|
|
608
|
+
return valueArg;
|
|
609
|
+
};
|
|
610
|
+
|
|
611
|
+
const readSha256 = (valueArg: unknown, pathArg: string): string => {
|
|
612
|
+
if (typeof valueArg !== 'string' || !sha256Pattern.test(valueArg)) {
|
|
613
|
+
return fail('INVALID_VALUE', pathArg);
|
|
614
|
+
}
|
|
615
|
+
return valueArg;
|
|
616
|
+
};
|
|
617
|
+
|
|
618
|
+
const readStateHmac = (
|
|
619
|
+
valueArg: unknown,
|
|
620
|
+
pathArg: string,
|
|
621
|
+
): `hmac-sha256:${string}` => {
|
|
622
|
+
if (typeof valueArg !== 'string' || !stateHmacPattern.test(valueArg)) {
|
|
623
|
+
return fail('INVALID_VALUE', pathArg);
|
|
624
|
+
}
|
|
625
|
+
return valueArg as `hmac-sha256:${string}`;
|
|
626
|
+
};
|
|
627
|
+
|
|
628
|
+
const readMac = (valueArg: unknown, pathArg: string): string => {
|
|
629
|
+
if (typeof valueArg !== 'string' || !macPattern.test(valueArg)) {
|
|
630
|
+
return fail('INVALID_VALUE', pathArg);
|
|
631
|
+
}
|
|
632
|
+
const bytes = Buffer.from(valueArg, 'base64url');
|
|
633
|
+
if (bytes.byteLength !== 32 || bytes.toString('base64url') !== valueArg) {
|
|
634
|
+
return fail('INVALID_VALUE', pathArg);
|
|
635
|
+
}
|
|
636
|
+
return valueArg;
|
|
637
|
+
};
|
|
638
|
+
|
|
639
|
+
const readInteger = (
|
|
640
|
+
valueArg: unknown,
|
|
641
|
+
pathArg: string,
|
|
642
|
+
minimumArg = 0,
|
|
643
|
+
maximumArg = Number.MAX_SAFE_INTEGER,
|
|
644
|
+
): number => {
|
|
645
|
+
if (typeof valueArg !== 'number'
|
|
646
|
+
|| !Number.isSafeInteger(valueArg)
|
|
647
|
+
|| Object.is(valueArg, -0)
|
|
648
|
+
|| valueArg < minimumArg
|
|
649
|
+
|| valueArg > maximumArg) {
|
|
650
|
+
return fail('INVALID_VALUE', pathArg);
|
|
651
|
+
}
|
|
652
|
+
return valueArg;
|
|
653
|
+
};
|
|
654
|
+
|
|
655
|
+
const readLiteral = <TLiteral extends string>(
|
|
656
|
+
valueArg: unknown,
|
|
657
|
+
literalsArg: readonly TLiteral[],
|
|
658
|
+
pathArg: string,
|
|
659
|
+
): TLiteral => {
|
|
660
|
+
if (typeof valueArg !== 'string' || !literalsArg.includes(valueArg as TLiteral)) {
|
|
661
|
+
return fail('INVALID_VALUE', pathArg);
|
|
662
|
+
}
|
|
663
|
+
return valueArg as TLiteral;
|
|
664
|
+
};
|
|
665
|
+
|
|
666
|
+
const canonicalize = (valueArg: unknown, pathArg: string): string => canonicalizeStrictJson(
|
|
667
|
+
valueArg,
|
|
668
|
+
() => fail('INVALID_DATA', pathArg),
|
|
669
|
+
pathArg,
|
|
670
|
+
);
|
|
671
|
+
|
|
672
|
+
const finalize = <T>(
|
|
673
|
+
valueArg: T,
|
|
674
|
+
maximumBytesArg: number,
|
|
675
|
+
pathArg: string,
|
|
676
|
+
): Readonly<T> => {
|
|
677
|
+
const canonical = canonicalize(valueArg, pathArg);
|
|
678
|
+
if (Buffer.byteLength(canonical, 'utf8') > maximumBytesArg) {
|
|
679
|
+
return fail('LIMIT_EXCEEDED', pathArg);
|
|
680
|
+
}
|
|
681
|
+
return deepFreezeValue(valueArg);
|
|
682
|
+
};
|
|
683
|
+
|
|
684
|
+
const encodeNormalized = (valueArg: unknown, pathArg: string): Uint8Array => (
|
|
685
|
+
Buffer.from(canonicalize(valueArg, pathArg), 'utf8')
|
|
686
|
+
);
|
|
687
|
+
|
|
688
|
+
const digestBytes = (valueArg: Uint8Array): string => plugins.crypto
|
|
689
|
+
.createHash('sha256')
|
|
690
|
+
.update(new Uint8Array(valueArg))
|
|
691
|
+
.digest('hex');
|
|
692
|
+
|
|
693
|
+
const frame = (domainArg: string, payloadArg: Uint8Array): Uint8Array => {
|
|
694
|
+
const domain = Buffer.from(domainArg, 'utf8');
|
|
695
|
+
const output = new Uint8Array(domain.byteLength + payloadArg.byteLength);
|
|
696
|
+
output.set(domain, 0);
|
|
697
|
+
output.set(payloadArg, domain.byteLength);
|
|
698
|
+
return output;
|
|
699
|
+
};
|
|
700
|
+
|
|
701
|
+
const canonicalEqual = (leftArg: unknown, rightArg: unknown, pathArg: string): boolean => (
|
|
702
|
+
canonicalize(leftArg, `${pathArg}.left`) === canonicalize(rightArg, `${pathArg}.right`)
|
|
703
|
+
);
|
|
704
|
+
|
|
705
|
+
const normalizeFileIdentityInternal = (
|
|
706
|
+
valueArg: unknown,
|
|
707
|
+
pathArg: string,
|
|
708
|
+
): ICloudlyLegacyDeploymentSettlementOfflineExportFileIdentityV1 => {
|
|
709
|
+
const value = readRecord(valueArg, pathArg);
|
|
710
|
+
assertExactKeys(value, fileIdentityKeys, pathArg);
|
|
711
|
+
if (value.format !== 'smartdb.database.export.v1'
|
|
712
|
+
|| value.lineFeedTerminator !== 'single-lf') {
|
|
713
|
+
fail('INVALID_VALUE', `${pathArg}.format`);
|
|
714
|
+
}
|
|
715
|
+
return {
|
|
716
|
+
format: 'smartdb.database.export.v1',
|
|
717
|
+
databaseName: readIdentifier(value.databaseName, `${pathArg}.databaseName`),
|
|
718
|
+
byteLength: readInteger(
|
|
719
|
+
value.byteLength,
|
|
720
|
+
`${pathArg}.byteLength`,
|
|
721
|
+
1,
|
|
722
|
+
cloudlyLegacyDeploymentSettlementOfflineExportLimits.maximumExactExportBytes,
|
|
723
|
+
),
|
|
724
|
+
sha256: readSha256(value.sha256, `${pathArg}.sha256`),
|
|
725
|
+
lineFeedTerminator: 'single-lf',
|
|
726
|
+
};
|
|
727
|
+
};
|
|
728
|
+
|
|
729
|
+
export const normalizeCloudlyLegacyDeploymentSettlementOfflineExportFileIdentity = (
|
|
730
|
+
valueArg: unknown,
|
|
731
|
+
): Readonly<ICloudlyLegacyDeploymentSettlementOfflineExportFileIdentityV1> => finalize(
|
|
732
|
+
normalizeFileIdentityInternal(valueArg, 'offlineExportFileIdentity'),
|
|
733
|
+
cloudlyLegacyDeploymentSettlementOfflineExportLimits.maximumAuthorityBytes,
|
|
734
|
+
'offlineExportFileIdentity',
|
|
735
|
+
);
|
|
736
|
+
|
|
737
|
+
export const encodeCloudlyLegacyDeploymentSettlementOfflineExportFileIdentity = (
|
|
738
|
+
valueArg: unknown,
|
|
739
|
+
): Uint8Array => encodeNormalized(
|
|
740
|
+
normalizeCloudlyLegacyDeploymentSettlementOfflineExportFileIdentity(valueArg),
|
|
741
|
+
'offlineExportFileIdentity',
|
|
742
|
+
);
|
|
743
|
+
|
|
744
|
+
export const digestCloudlyLegacyDeploymentSettlementOfflineExportFileIdentity = (
|
|
745
|
+
valueArg: unknown,
|
|
746
|
+
): string => digestBytes(
|
|
747
|
+
encodeCloudlyLegacyDeploymentSettlementOfflineExportFileIdentity(valueArg),
|
|
748
|
+
);
|
|
749
|
+
|
|
750
|
+
const normalizeApprovedSourceBackupInternal = (
|
|
751
|
+
valueArg: unknown,
|
|
752
|
+
pathArg: string,
|
|
753
|
+
): ICloudlyLegacyDeploymentSettlementOfflineExportApprovedSourceBackupIdentityV1 => {
|
|
754
|
+
const value = readRecord(valueArg, pathArg);
|
|
755
|
+
assertExactKeys(value, approvedSourceBackupKeys, pathArg);
|
|
756
|
+
return {
|
|
757
|
+
backupId: readIdentifier(value.backupId, `${pathArg}.backupId`),
|
|
758
|
+
sourceServiceId: readIdentifier(value.sourceServiceId, `${pathArg}.sourceServiceId`),
|
|
759
|
+
snapshotId: readIdentifier(value.snapshotId, `${pathArg}.snapshotId`),
|
|
760
|
+
backupReceiptSha256: readSha256(
|
|
761
|
+
value.backupReceiptSha256,
|
|
762
|
+
`${pathArg}.backupReceiptSha256`,
|
|
763
|
+
),
|
|
764
|
+
};
|
|
765
|
+
};
|
|
766
|
+
|
|
767
|
+
export const normalizeCloudlyLegacyDeploymentSettlementOfflineExportApprovedSourceBackupIdentity = (
|
|
768
|
+
valueArg: unknown,
|
|
769
|
+
): Readonly<
|
|
770
|
+
ICloudlyLegacyDeploymentSettlementOfflineExportApprovedSourceBackupIdentityV1
|
|
771
|
+
> => finalize(
|
|
772
|
+
normalizeApprovedSourceBackupInternal(valueArg, 'approvedSourceBackup'),
|
|
773
|
+
cloudlyLegacyDeploymentSettlementOfflineExportLimits.maximumAuthorityBytes,
|
|
774
|
+
'approvedSourceBackup',
|
|
775
|
+
);
|
|
776
|
+
|
|
777
|
+
const normalizeClassificationCounts = (
|
|
778
|
+
valueArg: unknown,
|
|
779
|
+
pathArg: string,
|
|
780
|
+
): ICloudlyLegacyDeploymentSettlementOfflineExportClassificationCountsV1 => {
|
|
781
|
+
const value = readRecord(valueArg, pathArg);
|
|
782
|
+
assertExactKeys(value, classificationKeys, pathArg);
|
|
783
|
+
return {
|
|
784
|
+
'image-recorded-not-current': readInteger(
|
|
785
|
+
value['image-recorded-not-current'],
|
|
786
|
+
`${pathArg}.image-recorded-not-current`,
|
|
787
|
+
0,
|
|
788
|
+
cloudlyLegacyDeploymentSettlementOfflineExportLimits.maximumOperations,
|
|
789
|
+
),
|
|
790
|
+
'image-recorded-current-failed': readInteger(
|
|
791
|
+
value['image-recorded-current-failed'],
|
|
792
|
+
`${pathArg}.image-recorded-current-failed`,
|
|
793
|
+
0,
|
|
794
|
+
cloudlyLegacyDeploymentSettlementOfflineExportLimits.maximumOperations,
|
|
795
|
+
),
|
|
796
|
+
'rolling-out-current-failed': readInteger(
|
|
797
|
+
value['rolling-out-current-failed'],
|
|
798
|
+
`${pathArg}.rolling-out-current-failed`,
|
|
799
|
+
0,
|
|
800
|
+
cloudlyLegacyDeploymentSettlementOfflineExportLimits.maximumOperations,
|
|
801
|
+
),
|
|
802
|
+
'rolling-out-superseded': readInteger(
|
|
803
|
+
value['rolling-out-superseded'],
|
|
804
|
+
`${pathArg}.rolling-out-superseded`,
|
|
805
|
+
0,
|
|
806
|
+
cloudlyLegacyDeploymentSettlementOfflineExportLimits.maximumOperations,
|
|
807
|
+
),
|
|
808
|
+
};
|
|
809
|
+
};
|
|
810
|
+
|
|
811
|
+
const sumClassificationCounts = (
|
|
812
|
+
valueArg: ICloudlyLegacyDeploymentSettlementOfflineExportClassificationCountsV1,
|
|
813
|
+
): number => classificationKeys.reduce((sumArg, keyArg) => sumArg + valueArg[keyArg], 0);
|
|
814
|
+
|
|
815
|
+
const normalizeSourceCensus = (
|
|
816
|
+
valueArg: unknown,
|
|
817
|
+
pathArg: string,
|
|
818
|
+
): ICloudlyLegacyDeploymentSettlementOfflineExportSourceCensusV1 => {
|
|
819
|
+
const value = readRecord(valueArg, pathArg);
|
|
820
|
+
assertExactKeys(value, censusKeys, pathArg);
|
|
821
|
+
const output = Object.fromEntries(censusKeys.map((keyArg) => [
|
|
822
|
+
keyArg,
|
|
823
|
+
readInteger(
|
|
824
|
+
value[keyArg],
|
|
825
|
+
`${pathArg}.${keyArg}`,
|
|
826
|
+
0,
|
|
827
|
+
cloudlyLegacyDeploymentSettlementOfflineExportLimits.maximumSourceDocuments,
|
|
828
|
+
),
|
|
829
|
+
])) as unknown as ICloudlyLegacyDeploymentSettlementOfflineExportSourceCensusV1;
|
|
830
|
+
if (censusKeys.reduce((sumArg, keyArg) => sumArg + output[keyArg], 0)
|
|
831
|
+
> cloudlyLegacyDeploymentSettlementOfflineExportLimits.maximumSourceDocuments) {
|
|
832
|
+
fail('LIMIT_EXCEEDED', pathArg);
|
|
833
|
+
}
|
|
834
|
+
return output;
|
|
835
|
+
};
|
|
836
|
+
|
|
837
|
+
const normalizeMutationCounts = (
|
|
838
|
+
valueArg: unknown,
|
|
839
|
+
pathArg: string,
|
|
840
|
+
): ICloudlyLegacyDeploymentSettlementOfflineExportMutationCountsV1 => {
|
|
841
|
+
const value = readRecord(valueArg, pathArg);
|
|
842
|
+
assertExactKeys(value, mutationCountKeys, pathArg);
|
|
843
|
+
const counts = {
|
|
844
|
+
operationCount: readInteger(
|
|
845
|
+
value.operationCount,
|
|
846
|
+
`${pathArg}.operationCount`,
|
|
847
|
+
0,
|
|
848
|
+
cloudlyLegacyDeploymentSettlementOfflineExportLimits.maximumOperations,
|
|
849
|
+
),
|
|
850
|
+
routeClaimsStabilized: readInteger(
|
|
851
|
+
value.routeClaimsStabilized,
|
|
852
|
+
`${pathArg}.routeClaimsStabilized`,
|
|
853
|
+
),
|
|
854
|
+
routeClaimsRemoved: readInteger(
|
|
855
|
+
value.routeClaimsRemoved,
|
|
856
|
+
`${pathArg}.routeClaimsRemoved`,
|
|
857
|
+
),
|
|
858
|
+
resourceClaimsRemoved: readInteger(
|
|
859
|
+
value.resourceClaimsRemoved,
|
|
860
|
+
`${pathArg}.resourceClaimsRemoved`,
|
|
861
|
+
),
|
|
862
|
+
};
|
|
863
|
+
if (counts.operationCount === 0
|
|
864
|
+
&& mutationCountKeys.some((keyArg) => counts[keyArg] !== 0)) {
|
|
865
|
+
fail('CROSS_FIELD_MISMATCH', pathArg);
|
|
866
|
+
}
|
|
867
|
+
return counts;
|
|
868
|
+
};
|
|
869
|
+
|
|
870
|
+
const hasNoMutations = (
|
|
871
|
+
valueArg: ICloudlyLegacyDeploymentSettlementOfflineExportMutationCountsV1,
|
|
872
|
+
): boolean => mutationCountKeys.every((keyArg) => valueArg[keyArg] === 0);
|
|
873
|
+
|
|
874
|
+
const assertCountsMatchClassifications = (
|
|
875
|
+
countsArg: ICloudlyLegacyDeploymentSettlementOfflineExportMutationCountsV1,
|
|
876
|
+
classificationCountsArg:
|
|
877
|
+
ICloudlyLegacyDeploymentSettlementOfflineExportClassificationCountsV1,
|
|
878
|
+
pathArg: string,
|
|
879
|
+
): void => {
|
|
880
|
+
if (countsArg.operationCount !== sumClassificationCounts(classificationCountsArg)) {
|
|
881
|
+
fail('CROSS_FIELD_MISMATCH', pathArg);
|
|
882
|
+
}
|
|
883
|
+
};
|
|
884
|
+
|
|
885
|
+
const normalizePlanEntry = (
|
|
886
|
+
valueArg: unknown,
|
|
887
|
+
pathArg: string,
|
|
888
|
+
): ICloudlyLegacyDeploymentSettlementOfflineExportPlanEntryV1 => {
|
|
889
|
+
const value = readRecord(valueArg, pathArg);
|
|
890
|
+
assertExactKeys(value, planEntryKeys, pathArg);
|
|
891
|
+
const sourceRevision = readInteger(value.sourceRevision, `${pathArg}.sourceRevision`);
|
|
892
|
+
const finalRevision = readInteger(value.finalRevision, `${pathArg}.finalRevision`);
|
|
893
|
+
if (!Number.isSafeInteger(sourceRevision + 3) || finalRevision !== sourceRevision + 3) {
|
|
894
|
+
fail('CROSS_FIELD_MISMATCH', `${pathArg}.finalRevision`);
|
|
895
|
+
}
|
|
896
|
+
const sourceState = readLiteral(
|
|
897
|
+
value.sourceState,
|
|
898
|
+
['image-recorded', 'rolling-out'],
|
|
899
|
+
`${pathArg}.sourceState`,
|
|
900
|
+
);
|
|
901
|
+
const classification = readLiteral(
|
|
902
|
+
value.classification,
|
|
903
|
+
classificationKeys,
|
|
904
|
+
`${pathArg}.classification`,
|
|
905
|
+
);
|
|
906
|
+
if ((classification.startsWith('image-recorded-') && sourceState !== 'image-recorded')
|
|
907
|
+
|| (classification.startsWith('rolling-out-') && sourceState !== 'rolling-out')) {
|
|
908
|
+
fail('CROSS_FIELD_MISMATCH', `${pathArg}.classification`);
|
|
909
|
+
}
|
|
910
|
+
return {
|
|
911
|
+
operationId: readIdentifier(value.operationId, `${pathArg}.operationId`),
|
|
912
|
+
serviceId: readIdentifier(value.serviceId, `${pathArg}.serviceId`),
|
|
913
|
+
sourceRevision,
|
|
914
|
+
sourceState,
|
|
915
|
+
classification,
|
|
916
|
+
finalRevision,
|
|
917
|
+
sourceDocumentHmac: readStateHmac(
|
|
918
|
+
value.sourceDocumentHmac,
|
|
919
|
+
`${pathArg}.sourceDocumentHmac`,
|
|
920
|
+
),
|
|
921
|
+
finalDocumentHmac: readStateHmac(
|
|
922
|
+
value.finalDocumentHmac,
|
|
923
|
+
`${pathArg}.finalDocumentHmac`,
|
|
924
|
+
),
|
|
925
|
+
routeClaimsStabilized: readInteger(
|
|
926
|
+
value.routeClaimsStabilized,
|
|
927
|
+
`${pathArg}.routeClaimsStabilized`,
|
|
928
|
+
),
|
|
929
|
+
routeClaimsRemoved: readInteger(
|
|
930
|
+
value.routeClaimsRemoved,
|
|
931
|
+
`${pathArg}.routeClaimsRemoved`,
|
|
932
|
+
),
|
|
933
|
+
resourceClaimsRemoved: readInteger(
|
|
934
|
+
value.resourceClaimsRemoved,
|
|
935
|
+
`${pathArg}.resourceClaimsRemoved`,
|
|
936
|
+
),
|
|
937
|
+
};
|
|
938
|
+
};
|
|
939
|
+
|
|
940
|
+
export const normalizeCloudlyLegacyDeploymentSettlementOfflineExportPlan = (
|
|
941
|
+
valueArg: unknown,
|
|
942
|
+
): Readonly<ICloudlyLegacyDeploymentSettlementOfflineExportPlanV1> => {
|
|
943
|
+
const value = readRecord(valueArg, 'offlineExportPlan');
|
|
944
|
+
assertExactKeys(value, [
|
|
945
|
+
'schemaVersion',
|
|
946
|
+
'kind',
|
|
947
|
+
'operationId',
|
|
948
|
+
'settlementId',
|
|
949
|
+
'sourceFile',
|
|
950
|
+
'effectiveAt',
|
|
951
|
+
'sourceStateHmac',
|
|
952
|
+
'finalStateHmac',
|
|
953
|
+
'sourceCensus',
|
|
954
|
+
'entries',
|
|
955
|
+
'counts',
|
|
956
|
+
'classificationCounts',
|
|
957
|
+
], 'offlineExportPlan');
|
|
958
|
+
if (value.schemaVersion !== 1
|
|
959
|
+
|| value.kind !== 'cloudly-legacy-deployment-settlement-offline-export-plan') {
|
|
960
|
+
fail('INVALID_VALUE', 'offlineExportPlan.kind');
|
|
961
|
+
}
|
|
962
|
+
const entries = readArray(
|
|
963
|
+
value.entries,
|
|
964
|
+
'offlineExportPlan.entries',
|
|
965
|
+
cloudlyLegacyDeploymentSettlementOfflineExportLimits.maximumOperations,
|
|
966
|
+
).map((entryArg, indexArg) => normalizePlanEntry(
|
|
967
|
+
entryArg,
|
|
968
|
+
`offlineExportPlan.entries[${indexArg}]`,
|
|
969
|
+
));
|
|
970
|
+
for (let index = 1; index < entries.length; index++) {
|
|
971
|
+
if (entries[index - 1].operationId >= entries[index].operationId) {
|
|
972
|
+
fail('ORDERING_REQUIRED', `offlineExportPlan.entries[${index}].operationId`);
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
const counts = normalizeMutationCounts(value.counts, 'offlineExportPlan.counts');
|
|
976
|
+
const classificationCounts = normalizeClassificationCounts(
|
|
977
|
+
value.classificationCounts,
|
|
978
|
+
'offlineExportPlan.classificationCounts',
|
|
979
|
+
);
|
|
980
|
+
const sourceStateHmac = readStateHmac(
|
|
981
|
+
value.sourceStateHmac,
|
|
982
|
+
'offlineExportPlan.sourceStateHmac',
|
|
983
|
+
);
|
|
984
|
+
const finalStateHmac = readStateHmac(
|
|
985
|
+
value.finalStateHmac,
|
|
986
|
+
'offlineExportPlan.finalStateHmac',
|
|
987
|
+
);
|
|
988
|
+
const expectedCounts = {
|
|
989
|
+
operationCount: entries.length,
|
|
990
|
+
routeClaimsStabilized: entries.reduce(
|
|
991
|
+
(sumArg, entryArg) => sumArg + entryArg.routeClaimsStabilized,
|
|
992
|
+
0,
|
|
993
|
+
),
|
|
994
|
+
routeClaimsRemoved: entries.reduce(
|
|
995
|
+
(sumArg, entryArg) => sumArg + entryArg.routeClaimsRemoved,
|
|
996
|
+
0,
|
|
997
|
+
),
|
|
998
|
+
resourceClaimsRemoved: entries.reduce(
|
|
999
|
+
(sumArg, entryArg) => sumArg + entryArg.resourceClaimsRemoved,
|
|
1000
|
+
0,
|
|
1001
|
+
),
|
|
1002
|
+
};
|
|
1003
|
+
const actualClassifications = Object.fromEntries(classificationKeys.map((keyArg) => [
|
|
1004
|
+
keyArg,
|
|
1005
|
+
entries.filter((entryArg) => entryArg.classification === keyArg).length,
|
|
1006
|
+
]));
|
|
1007
|
+
if (!Object.values(expectedCounts).every((valueArg) => Number.isSafeInteger(valueArg))
|
|
1008
|
+
|| !canonicalEqual(counts, expectedCounts, 'offlineExportPlan.counts')
|
|
1009
|
+
|| classificationKeys.some((keyArg) => (
|
|
1010
|
+
classificationCounts[keyArg] !== actualClassifications[keyArg]
|
|
1011
|
+
))
|
|
1012
|
+
|| (entries.length === 0) !== (sourceStateHmac === finalStateHmac)) {
|
|
1013
|
+
fail('CROSS_FIELD_MISMATCH', 'offlineExportPlan.counts');
|
|
1014
|
+
}
|
|
1015
|
+
assertCountsMatchClassifications(
|
|
1016
|
+
counts,
|
|
1017
|
+
classificationCounts,
|
|
1018
|
+
'offlineExportPlan.classificationCounts',
|
|
1019
|
+
);
|
|
1020
|
+
return finalize({
|
|
1021
|
+
schemaVersion: 1,
|
|
1022
|
+
kind: 'cloudly-legacy-deployment-settlement-offline-export-plan',
|
|
1023
|
+
operationId: readIdentifier(value.operationId, 'offlineExportPlan.operationId'),
|
|
1024
|
+
settlementId: readIdentifier(value.settlementId, 'offlineExportPlan.settlementId'),
|
|
1025
|
+
sourceFile: normalizeFileIdentityInternal(value.sourceFile, 'offlineExportPlan.sourceFile'),
|
|
1026
|
+
effectiveAt: readInteger(value.effectiveAt, 'offlineExportPlan.effectiveAt', 1),
|
|
1027
|
+
sourceStateHmac,
|
|
1028
|
+
finalStateHmac,
|
|
1029
|
+
sourceCensus: normalizeSourceCensus(
|
|
1030
|
+
value.sourceCensus,
|
|
1031
|
+
'offlineExportPlan.sourceCensus',
|
|
1032
|
+
),
|
|
1033
|
+
entries,
|
|
1034
|
+
counts,
|
|
1035
|
+
classificationCounts,
|
|
1036
|
+
} satisfies ICloudlyLegacyDeploymentSettlementOfflineExportPlanV1,
|
|
1037
|
+
cloudlyLegacyDeploymentSettlementOfflineExportLimits.maximumPlanBytes,
|
|
1038
|
+
'offlineExportPlan');
|
|
1039
|
+
};
|
|
1040
|
+
|
|
1041
|
+
export const encodeCloudlyLegacyDeploymentSettlementOfflineExportPlan = (
|
|
1042
|
+
valueArg: unknown,
|
|
1043
|
+
): Uint8Array => encodeNormalized(
|
|
1044
|
+
normalizeCloudlyLegacyDeploymentSettlementOfflineExportPlan(valueArg),
|
|
1045
|
+
'offlineExportPlan',
|
|
1046
|
+
);
|
|
1047
|
+
|
|
1048
|
+
export const digestCloudlyLegacyDeploymentSettlementOfflineExportPlan = (
|
|
1049
|
+
valueArg: unknown,
|
|
1050
|
+
): string => digestBytes(encodeCloudlyLegacyDeploymentSettlementOfflineExportPlan(valueArg));
|
|
1051
|
+
|
|
1052
|
+
const normalizeAuthorityReferenceInternal = <
|
|
1053
|
+
TRole extends TCloudlyLegacyDeploymentSettlementOfflineExportAuthorityReferenceV1['role'],
|
|
1054
|
+
>(
|
|
1055
|
+
valueArg: unknown,
|
|
1056
|
+
pathArg: string,
|
|
1057
|
+
roleArg: TRole,
|
|
1058
|
+
): Extract<
|
|
1059
|
+
TCloudlyLegacyDeploymentSettlementOfflineExportAuthorityReferenceV1,
|
|
1060
|
+
{ role: TRole }
|
|
1061
|
+
> => {
|
|
1062
|
+
const value = readRecord(valueArg, pathArg);
|
|
1063
|
+
assertExactKeys(value, authorityReferenceKeys, pathArg);
|
|
1064
|
+
if (value.schemaVersion !== 1
|
|
1065
|
+
|| value.kind
|
|
1066
|
+
!== 'cloudly-legacy-deployment-settlement-offline-export-authority-reference'
|
|
1067
|
+
|| value.role !== roleArg
|
|
1068
|
+
|| value.keyVersion !== 1) {
|
|
1069
|
+
fail('INVALID_VALUE', `${pathArg}.role`);
|
|
1070
|
+
}
|
|
1071
|
+
return {
|
|
1072
|
+
schemaVersion: 1,
|
|
1073
|
+
kind: 'cloudly-legacy-deployment-settlement-offline-export-authority-reference',
|
|
1074
|
+
role: roleArg,
|
|
1075
|
+
operationId: readIdentifier(value.operationId, `${pathArg}.operationId`),
|
|
1076
|
+
settlementId: readIdentifier(value.settlementId, `${pathArg}.settlementId`),
|
|
1077
|
+
authorityId: readIdentifier(value.authorityId, `${pathArg}.authorityId`),
|
|
1078
|
+
keyId: readIdentifier(value.keyId, `${pathArg}.keyId`),
|
|
1079
|
+
keyVersion: 1,
|
|
1080
|
+
authorityMetadataSha256: readSha256(
|
|
1081
|
+
value.authorityMetadataSha256,
|
|
1082
|
+
`${pathArg}.authorityMetadataSha256`,
|
|
1083
|
+
),
|
|
1084
|
+
} as Extract<
|
|
1085
|
+
TCloudlyLegacyDeploymentSettlementOfflineExportAuthorityReferenceV1,
|
|
1086
|
+
{ role: TRole }
|
|
1087
|
+
>;
|
|
1088
|
+
};
|
|
1089
|
+
|
|
1090
|
+
export const normalizeCloudlyLegacyDeploymentSettlementOfflineExportSourceAuthorityReference = (
|
|
1091
|
+
valueArg: unknown,
|
|
1092
|
+
): Readonly<
|
|
1093
|
+
ICloudlyLegacyDeploymentSettlementOfflineExportSourceAuthorityReferenceV1
|
|
1094
|
+
> => finalize(
|
|
1095
|
+
normalizeAuthorityReferenceInternal(valueArg, 'offlineExportSourceAuthorityReference', 'source-rehearsal'),
|
|
1096
|
+
cloudlyLegacyDeploymentSettlementOfflineExportLimits.maximumAuthorityBytes,
|
|
1097
|
+
'offlineExportSourceAuthorityReference',
|
|
1098
|
+
);
|
|
1099
|
+
|
|
1100
|
+
export const normalizeCloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthorityReference = (
|
|
1101
|
+
valueArg: unknown,
|
|
1102
|
+
): Readonly<
|
|
1103
|
+
ICloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthorityReferenceV1
|
|
1104
|
+
> => finalize(
|
|
1105
|
+
normalizeAuthorityReferenceInternal(
|
|
1106
|
+
valueArg,
|
|
1107
|
+
'offlineExportProductionTransformAuthorityReference',
|
|
1108
|
+
'production-transform',
|
|
1109
|
+
),
|
|
1110
|
+
cloudlyLegacyDeploymentSettlementOfflineExportLimits.maximumAuthorityBytes,
|
|
1111
|
+
'offlineExportProductionTransformAuthorityReference',
|
|
1112
|
+
);
|
|
1113
|
+
|
|
1114
|
+
const normalizeAuthorityWindow = (
|
|
1115
|
+
valueArg: Record<string, unknown>,
|
|
1116
|
+
pathArg: string,
|
|
1117
|
+
): { issuedAt: number; expiresAt: number } => {
|
|
1118
|
+
const issuedAt = readInteger(valueArg.issuedAt, `${pathArg}.issuedAt`, 1);
|
|
1119
|
+
const expiresAt = readInteger(valueArg.expiresAt, `${pathArg}.expiresAt`, 1);
|
|
1120
|
+
if (expiresAt <= issuedAt
|
|
1121
|
+
|| expiresAt - issuedAt
|
|
1122
|
+
> cloudlyLegacyDeploymentSettlementOfflineExportLimits.maximumAuthorityLifetimeMs) {
|
|
1123
|
+
fail('CROSS_FIELD_MISMATCH', `${pathArg}.expiresAt`);
|
|
1124
|
+
}
|
|
1125
|
+
return { issuedAt, expiresAt };
|
|
1126
|
+
};
|
|
1127
|
+
|
|
1128
|
+
const assertTimestampWithinAuthority = (
|
|
1129
|
+
timestampArg: number,
|
|
1130
|
+
authorityArg: { issuedAt: number; expiresAt: number },
|
|
1131
|
+
pathArg: string,
|
|
1132
|
+
): void => {
|
|
1133
|
+
if (timestampArg < authorityArg.issuedAt || timestampArg >= authorityArg.expiresAt) {
|
|
1134
|
+
fail('CROSS_FIELD_MISMATCH', pathArg);
|
|
1135
|
+
}
|
|
1136
|
+
};
|
|
1137
|
+
|
|
1138
|
+
export const normalizeCloudlyLegacyDeploymentSettlementOfflineExportSourceAuthority = (
|
|
1139
|
+
valueArg: unknown,
|
|
1140
|
+
): Readonly<ICloudlyLegacyDeploymentSettlementOfflineExportSourceAuthorityV1> => {
|
|
1141
|
+
const value = readRecord(valueArg, 'offlineExportSourceAuthority');
|
|
1142
|
+
assertExactKeys(value, sourceAuthorityKeys, 'offlineExportSourceAuthority');
|
|
1143
|
+
if (value.schemaVersion !== 1
|
|
1144
|
+
|| value.kind
|
|
1145
|
+
!== 'cloudly-legacy-deployment-settlement-offline-export-source-authority'
|
|
1146
|
+
|| value.role !== 'source-rehearsal'
|
|
1147
|
+
|| value.keyVersion !== 1) {
|
|
1148
|
+
fail('INVALID_VALUE', 'offlineExportSourceAuthority.kind');
|
|
1149
|
+
}
|
|
1150
|
+
const window = normalizeAuthorityWindow(value, 'offlineExportSourceAuthority');
|
|
1151
|
+
return finalize({
|
|
1152
|
+
schemaVersion: 1,
|
|
1153
|
+
kind: 'cloudly-legacy-deployment-settlement-offline-export-source-authority',
|
|
1154
|
+
role: 'source-rehearsal',
|
|
1155
|
+
operationId: readIdentifier(value.operationId, 'offlineExportSourceAuthority.operationId'),
|
|
1156
|
+
settlementId: readIdentifier(value.settlementId, 'offlineExportSourceAuthority.settlementId'),
|
|
1157
|
+
authorityId: readIdentifier(value.authorityId, 'offlineExportSourceAuthority.authorityId'),
|
|
1158
|
+
keyId: readIdentifier(value.keyId, 'offlineExportSourceAuthority.keyId'),
|
|
1159
|
+
keyVersion: 1,
|
|
1160
|
+
...window,
|
|
1161
|
+
sourceFile: normalizeFileIdentityInternal(
|
|
1162
|
+
value.sourceFile,
|
|
1163
|
+
'offlineExportSourceAuthority.sourceFile',
|
|
1164
|
+
),
|
|
1165
|
+
approvedSourceBackup: normalizeApprovedSourceBackupInternal(
|
|
1166
|
+
value.approvedSourceBackup,
|
|
1167
|
+
'offlineExportSourceAuthority.approvedSourceBackup',
|
|
1168
|
+
),
|
|
1169
|
+
planSha256: readSha256(value.planSha256, 'offlineExportSourceAuthority.planSha256'),
|
|
1170
|
+
rehearsalRequestSha256: readSha256(
|
|
1171
|
+
value.rehearsalRequestSha256,
|
|
1172
|
+
'offlineExportSourceAuthority.rehearsalRequestSha256',
|
|
1173
|
+
),
|
|
1174
|
+
} satisfies ICloudlyLegacyDeploymentSettlementOfflineExportSourceAuthorityV1,
|
|
1175
|
+
cloudlyLegacyDeploymentSettlementOfflineExportLimits.maximumAuthorityBytes,
|
|
1176
|
+
'offlineExportSourceAuthority');
|
|
1177
|
+
};
|
|
1178
|
+
|
|
1179
|
+
export const encodeCloudlyLegacyDeploymentSettlementOfflineExportSourceAuthority = (
|
|
1180
|
+
valueArg: unknown,
|
|
1181
|
+
): Uint8Array => encodeNormalized(
|
|
1182
|
+
normalizeCloudlyLegacyDeploymentSettlementOfflineExportSourceAuthority(valueArg),
|
|
1183
|
+
'offlineExportSourceAuthority',
|
|
1184
|
+
);
|
|
1185
|
+
|
|
1186
|
+
export const digestCloudlyLegacyDeploymentSettlementOfflineExportSourceAuthority = (
|
|
1187
|
+
valueArg: unknown,
|
|
1188
|
+
): string => digestBytes(
|
|
1189
|
+
encodeCloudlyLegacyDeploymentSettlementOfflineExportSourceAuthority(valueArg),
|
|
1190
|
+
);
|
|
1191
|
+
|
|
1192
|
+
export const createCloudlyLegacyDeploymentSettlementOfflineExportSourceAuthorityReference = (
|
|
1193
|
+
authorityArg: unknown,
|
|
1194
|
+
): Readonly<
|
|
1195
|
+
ICloudlyLegacyDeploymentSettlementOfflineExportSourceAuthorityReferenceV1
|
|
1196
|
+
> => {
|
|
1197
|
+
const authority = normalizeCloudlyLegacyDeploymentSettlementOfflineExportSourceAuthority(
|
|
1198
|
+
authorityArg,
|
|
1199
|
+
);
|
|
1200
|
+
return finalize({
|
|
1201
|
+
schemaVersion: 1,
|
|
1202
|
+
kind: 'cloudly-legacy-deployment-settlement-offline-export-authority-reference',
|
|
1203
|
+
role: 'source-rehearsal',
|
|
1204
|
+
operationId: authority.operationId,
|
|
1205
|
+
settlementId: authority.settlementId,
|
|
1206
|
+
authorityId: authority.authorityId,
|
|
1207
|
+
keyId: authority.keyId,
|
|
1208
|
+
keyVersion: 1,
|
|
1209
|
+
authorityMetadataSha256:
|
|
1210
|
+
digestCloudlyLegacyDeploymentSettlementOfflineExportSourceAuthority(authority),
|
|
1211
|
+
}, cloudlyLegacyDeploymentSettlementOfflineExportLimits.maximumAuthorityBytes,
|
|
1212
|
+
'offlineExportSourceAuthorityReference');
|
|
1213
|
+
};
|
|
1214
|
+
|
|
1215
|
+
const assertSourceReferenceMatchesAuthority = (
|
|
1216
|
+
referenceArg: unknown,
|
|
1217
|
+
authorityArg: unknown,
|
|
1218
|
+
pathArg: string,
|
|
1219
|
+
): void => {
|
|
1220
|
+
const reference = normalizeCloudlyLegacyDeploymentSettlementOfflineExportSourceAuthorityReference(
|
|
1221
|
+
referenceArg,
|
|
1222
|
+
);
|
|
1223
|
+
const expected = createCloudlyLegacyDeploymentSettlementOfflineExportSourceAuthorityReference(
|
|
1224
|
+
authorityArg,
|
|
1225
|
+
);
|
|
1226
|
+
if (!canonicalEqual(reference, expected, pathArg)) {
|
|
1227
|
+
fail('CROSS_FIELD_MISMATCH', pathArg);
|
|
1228
|
+
}
|
|
1229
|
+
};
|
|
1230
|
+
|
|
1231
|
+
const normalizeRehearsalPayloadInternal = (
|
|
1232
|
+
valueArg: unknown,
|
|
1233
|
+
pathArg: string,
|
|
1234
|
+
): ICloudlyLegacyDeploymentSettlementOfflineExportRehearsalAttestationPayloadV1 => {
|
|
1235
|
+
const value = readRecord(valueArg, pathArg);
|
|
1236
|
+
assertExactKeys(value, rehearsalPayloadKeys, pathArg);
|
|
1237
|
+
if (value.schemaVersion !== 1
|
|
1238
|
+
|| value.kind
|
|
1239
|
+
!== 'cloudly-legacy-deployment-settlement-offline-export-rehearsal-attestation') {
|
|
1240
|
+
fail('INVALID_VALUE', `${pathArg}.kind`);
|
|
1241
|
+
}
|
|
1242
|
+
const sourceAuthority = normalizeAuthorityReferenceInternal(
|
|
1243
|
+
value.sourceAuthority,
|
|
1244
|
+
`${pathArg}.sourceAuthority`,
|
|
1245
|
+
'source-rehearsal',
|
|
1246
|
+
);
|
|
1247
|
+
const plan = normalizeCloudlyLegacyDeploymentSettlementOfflineExportPlan(value.plan);
|
|
1248
|
+
const planSha256 = readSha256(value.planSha256, `${pathArg}.planSha256`);
|
|
1249
|
+
const outcome = readLiteral(
|
|
1250
|
+
value.outcome,
|
|
1251
|
+
['transform-required', 'no-op'],
|
|
1252
|
+
`${pathArg}.outcome`,
|
|
1253
|
+
);
|
|
1254
|
+
const observedCounts = normalizeMutationCounts(
|
|
1255
|
+
value.observedCounts,
|
|
1256
|
+
`${pathArg}.observedCounts`,
|
|
1257
|
+
);
|
|
1258
|
+
const observedClassificationCounts = normalizeClassificationCounts(
|
|
1259
|
+
value.observedClassificationCounts,
|
|
1260
|
+
`${pathArg}.observedClassificationCounts`,
|
|
1261
|
+
);
|
|
1262
|
+
if (sourceAuthority.operationId !== plan.operationId
|
|
1263
|
+
|| sourceAuthority.settlementId !== plan.settlementId
|
|
1264
|
+
|| planSha256 !== digestCloudlyLegacyDeploymentSettlementOfflineExportPlan(plan)
|
|
1265
|
+
|| value.observedFinalStateHmac !== plan.finalStateHmac
|
|
1266
|
+
|| !canonicalEqual(observedCounts, plan.counts, `${pathArg}.observedCounts`)
|
|
1267
|
+
|| !canonicalEqual(
|
|
1268
|
+
observedClassificationCounts,
|
|
1269
|
+
plan.classificationCounts,
|
|
1270
|
+
`${pathArg}.observedClassificationCounts`,
|
|
1271
|
+
)
|
|
1272
|
+
|| (outcome === 'no-op') !== hasNoMutations(plan.counts)) {
|
|
1273
|
+
fail('CROSS_FIELD_MISMATCH', `${pathArg}.plan`);
|
|
1274
|
+
}
|
|
1275
|
+
return {
|
|
1276
|
+
schemaVersion: 1,
|
|
1277
|
+
kind: 'cloudly-legacy-deployment-settlement-offline-export-rehearsal-attestation',
|
|
1278
|
+
sourceAuthority,
|
|
1279
|
+
plan: plan as ICloudlyLegacyDeploymentSettlementOfflineExportPlanV1,
|
|
1280
|
+
planSha256,
|
|
1281
|
+
rehearsalRequestSha256: readSha256(
|
|
1282
|
+
value.rehearsalRequestSha256,
|
|
1283
|
+
`${pathArg}.rehearsalRequestSha256`,
|
|
1284
|
+
),
|
|
1285
|
+
scratchAllocation: normalizeScratchAllocation(
|
|
1286
|
+
value.scratchAllocation,
|
|
1287
|
+
`${pathArg}.scratchAllocation`,
|
|
1288
|
+
),
|
|
1289
|
+
outcome,
|
|
1290
|
+
observedFinalStateHmac: readStateHmac(
|
|
1291
|
+
value.observedFinalStateHmac,
|
|
1292
|
+
`${pathArg}.observedFinalStateHmac`,
|
|
1293
|
+
),
|
|
1294
|
+
observedCounts,
|
|
1295
|
+
observedClassificationCounts,
|
|
1296
|
+
completedAt: readInteger(value.completedAt, `${pathArg}.completedAt`, 1),
|
|
1297
|
+
};
|
|
1298
|
+
};
|
|
1299
|
+
|
|
1300
|
+
const rehearsalPayload = (
|
|
1301
|
+
valueArg: ICloudlyLegacyDeploymentSettlementOfflineExportRehearsalAttestationPayloadV1,
|
|
1302
|
+
): unknown => Object.fromEntries(rehearsalPayloadKeys.map((keyArg) => [
|
|
1303
|
+
keyArg,
|
|
1304
|
+
valueArg[keyArg],
|
|
1305
|
+
]));
|
|
1306
|
+
|
|
1307
|
+
export const digestCloudlyLegacyDeploymentSettlementOfflineExportRehearsalAttestationPayload = (
|
|
1308
|
+
valueArg: unknown,
|
|
1309
|
+
): string => digestBytes(encodeNormalized(
|
|
1310
|
+
rehearsalPayload(normalizeRehearsalPayloadInternal(
|
|
1311
|
+
valueArg,
|
|
1312
|
+
'offlineExportRehearsalAttestationPayload',
|
|
1313
|
+
)),
|
|
1314
|
+
'offlineExportRehearsalAttestationPayload',
|
|
1315
|
+
));
|
|
1316
|
+
|
|
1317
|
+
const normalizeUnsignedRehearsalInternal = (
|
|
1318
|
+
valueArg: unknown,
|
|
1319
|
+
pathArg: string,
|
|
1320
|
+
): TCloudlyLegacyDeploymentSettlementOfflineExportUnsignedRehearsalAttestationV1 => {
|
|
1321
|
+
const value = readRecord(valueArg, pathArg);
|
|
1322
|
+
assertExactKeys(value, rehearsalUnsignedKeys, pathArg);
|
|
1323
|
+
const payload = normalizeRehearsalPayloadInternal(
|
|
1324
|
+
Object.fromEntries(rehearsalPayloadKeys.map((keyArg) => [keyArg, value[keyArg]])),
|
|
1325
|
+
`${pathArg}.payload`,
|
|
1326
|
+
);
|
|
1327
|
+
const payloadSha256 = readSha256(value.payloadSha256, `${pathArg}.payloadSha256`);
|
|
1328
|
+
if (payloadSha256
|
|
1329
|
+
!== digestCloudlyLegacyDeploymentSettlementOfflineExportRehearsalAttestationPayload(
|
|
1330
|
+
payload,
|
|
1331
|
+
)) {
|
|
1332
|
+
fail('CROSS_FIELD_MISMATCH', `${pathArg}.payloadSha256`);
|
|
1333
|
+
}
|
|
1334
|
+
return { ...payload, payloadSha256 };
|
|
1335
|
+
};
|
|
1336
|
+
|
|
1337
|
+
export const normalizeCloudlyLegacyDeploymentSettlementOfflineExportRehearsalAttestation = (
|
|
1338
|
+
valueArg: unknown,
|
|
1339
|
+
): Readonly<
|
|
1340
|
+
ICloudlyLegacyDeploymentSettlementOfflineExportRehearsalAttestationV1
|
|
1341
|
+
> => {
|
|
1342
|
+
const value = readRecord(valueArg, 'offlineExportRehearsalAttestation');
|
|
1343
|
+
assertExactKeys(value, rehearsalKeys, 'offlineExportRehearsalAttestation');
|
|
1344
|
+
return finalize({
|
|
1345
|
+
...normalizeUnsignedRehearsalInternal(
|
|
1346
|
+
Object.fromEntries(rehearsalUnsignedKeys.map((keyArg) => [keyArg, value[keyArg]])),
|
|
1347
|
+
'offlineExportRehearsalAttestation.unsigned',
|
|
1348
|
+
),
|
|
1349
|
+
mac: readMac(value.mac, 'offlineExportRehearsalAttestation.mac'),
|
|
1350
|
+
}, cloudlyLegacyDeploymentSettlementOfflineExportLimits.maximumAuthenticatedArtifactBytes,
|
|
1351
|
+
'offlineExportRehearsalAttestation');
|
|
1352
|
+
};
|
|
1353
|
+
|
|
1354
|
+
export const encodeCloudlyLegacyDeploymentSettlementOfflineExportRehearsalAttestation = (
|
|
1355
|
+
valueArg: unknown,
|
|
1356
|
+
): Uint8Array => encodeNormalized(
|
|
1357
|
+
normalizeCloudlyLegacyDeploymentSettlementOfflineExportRehearsalAttestation(valueArg),
|
|
1358
|
+
'offlineExportRehearsalAttestation',
|
|
1359
|
+
);
|
|
1360
|
+
|
|
1361
|
+
export const digestCloudlyLegacyDeploymentSettlementOfflineExportRehearsalAttestation = (
|
|
1362
|
+
valueArg: unknown,
|
|
1363
|
+
): string => digestBytes(
|
|
1364
|
+
encodeCloudlyLegacyDeploymentSettlementOfflineExportRehearsalAttestation(valueArg),
|
|
1365
|
+
);
|
|
1366
|
+
|
|
1367
|
+
export const encodeCloudlyLegacyDeploymentSettlementOfflineExportRehearsalAttestationHmacInput = (
|
|
1368
|
+
valueArg: unknown,
|
|
1369
|
+
): Uint8Array => frame(
|
|
1370
|
+
cloudlyLegacyDeploymentSettlementOfflineExportDomains.rehearsalAttestationHmac,
|
|
1371
|
+
encodeNormalized(
|
|
1372
|
+
finalize(
|
|
1373
|
+
normalizeUnsignedRehearsalInternal(
|
|
1374
|
+
valueArg,
|
|
1375
|
+
'offlineExportUnsignedRehearsalAttestation',
|
|
1376
|
+
),
|
|
1377
|
+
cloudlyLegacyDeploymentSettlementOfflineExportLimits.maximumAuthenticatedArtifactBytes,
|
|
1378
|
+
'offlineExportUnsignedRehearsalAttestation',
|
|
1379
|
+
),
|
|
1380
|
+
'offlineExportUnsignedRehearsalAttestation',
|
|
1381
|
+
),
|
|
1382
|
+
);
|
|
1383
|
+
|
|
1384
|
+
const requireVerifiedHmac = async (
|
|
1385
|
+
authorityArg: TCloudlyLegacyDeploymentSettlementOfflineExportAuthorityReferenceV1,
|
|
1386
|
+
domainArg: ICloudlyLegacyDeploymentSettlementOfflineExportHmacVerificationInputV1['domain'],
|
|
1387
|
+
hmacInputArg: Uint8Array,
|
|
1388
|
+
macArg: string,
|
|
1389
|
+
verifierArg: TCloudlyLegacyDeploymentSettlementOfflineExportHmacVerifier,
|
|
1390
|
+
pathArg: string,
|
|
1391
|
+
): Promise<void> => {
|
|
1392
|
+
let verified = false;
|
|
1393
|
+
try {
|
|
1394
|
+
verified = await verifierArg({
|
|
1395
|
+
authority: authorityArg,
|
|
1396
|
+
domain: domainArg,
|
|
1397
|
+
hmacInput: new Uint8Array(hmacInputArg),
|
|
1398
|
+
mac: macArg,
|
|
1399
|
+
});
|
|
1400
|
+
} catch {
|
|
1401
|
+
verified = false;
|
|
1402
|
+
}
|
|
1403
|
+
if (!verified) fail('INVALID_VALUE', pathArg);
|
|
1404
|
+
};
|
|
1405
|
+
|
|
1406
|
+
const withoutMac = <TValue extends { mac: string }>(
|
|
1407
|
+
valueArg: TValue,
|
|
1408
|
+
): Omit<TValue, 'mac'> => {
|
|
1409
|
+
const { mac: _mac, ...unsigned } = valueArg;
|
|
1410
|
+
return unsigned;
|
|
1411
|
+
};
|
|
1412
|
+
|
|
1413
|
+
export const normalizeCloudlyLegacyDeploymentSettlementOfflineExportRehearsalAttestationForAuthority = async (
|
|
1414
|
+
attestationArg: unknown,
|
|
1415
|
+
sourceAuthorityArg: unknown,
|
|
1416
|
+
verifierArg: TCloudlyLegacyDeploymentSettlementOfflineExportHmacVerifier,
|
|
1417
|
+
): Promise<Readonly<
|
|
1418
|
+
ICloudlyLegacyDeploymentSettlementOfflineExportRehearsalAttestationV1
|
|
1419
|
+
>> => {
|
|
1420
|
+
const sourceAuthority = normalizeCloudlyLegacyDeploymentSettlementOfflineExportSourceAuthority(
|
|
1421
|
+
sourceAuthorityArg,
|
|
1422
|
+
);
|
|
1423
|
+
const attestation =
|
|
1424
|
+
normalizeCloudlyLegacyDeploymentSettlementOfflineExportRehearsalAttestation(
|
|
1425
|
+
attestationArg,
|
|
1426
|
+
);
|
|
1427
|
+
assertSourceReferenceMatchesAuthority(
|
|
1428
|
+
attestation.sourceAuthority,
|
|
1429
|
+
sourceAuthority,
|
|
1430
|
+
'offlineExportRehearsalAttestation.sourceAuthority',
|
|
1431
|
+
);
|
|
1432
|
+
if (attestation.planSha256 !== sourceAuthority.planSha256
|
|
1433
|
+
|| attestation.rehearsalRequestSha256 !== sourceAuthority.rehearsalRequestSha256
|
|
1434
|
+
|| !canonicalEqual(
|
|
1435
|
+
attestation.plan.sourceFile,
|
|
1436
|
+
sourceAuthority.sourceFile,
|
|
1437
|
+
'offlineExportRehearsalAttestation.plan.sourceFile',
|
|
1438
|
+
)
|
|
1439
|
+
|| attestation.plan.operationId !== sourceAuthority.operationId
|
|
1440
|
+
|| attestation.plan.settlementId !== sourceAuthority.settlementId) {
|
|
1441
|
+
fail('CROSS_FIELD_MISMATCH', 'offlineExportRehearsalAttestation.sourceProof');
|
|
1442
|
+
}
|
|
1443
|
+
assertTimestampWithinAuthority(
|
|
1444
|
+
attestation.plan.effectiveAt,
|
|
1445
|
+
sourceAuthority,
|
|
1446
|
+
'offlineExportRehearsalAttestation.plan.effectiveAt',
|
|
1447
|
+
);
|
|
1448
|
+
assertTimestampWithinAuthority(
|
|
1449
|
+
attestation.completedAt,
|
|
1450
|
+
sourceAuthority,
|
|
1451
|
+
'offlineExportRehearsalAttestation.completedAt',
|
|
1452
|
+
);
|
|
1453
|
+
if (attestation.completedAt < attestation.plan.effectiveAt) {
|
|
1454
|
+
fail('CROSS_FIELD_MISMATCH', 'offlineExportRehearsalAttestation.completedAt');
|
|
1455
|
+
}
|
|
1456
|
+
await requireVerifiedHmac(
|
|
1457
|
+
attestation.sourceAuthority,
|
|
1458
|
+
cloudlyLegacyDeploymentSettlementOfflineExportDomains.rehearsalAttestationHmac,
|
|
1459
|
+
encodeCloudlyLegacyDeploymentSettlementOfflineExportRehearsalAttestationHmacInput(
|
|
1460
|
+
withoutMac(attestation),
|
|
1461
|
+
),
|
|
1462
|
+
attestation.mac,
|
|
1463
|
+
verifierArg,
|
|
1464
|
+
'offlineExportRehearsalAttestation.mac',
|
|
1465
|
+
);
|
|
1466
|
+
return attestation;
|
|
1467
|
+
};
|
|
1468
|
+
|
|
1469
|
+
export const normalizeCloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthority = (
|
|
1470
|
+
valueArg: unknown,
|
|
1471
|
+
): Readonly<
|
|
1472
|
+
ICloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthorityV1
|
|
1473
|
+
> => {
|
|
1474
|
+
const value = readRecord(valueArg, 'offlineExportProductionTransformAuthority');
|
|
1475
|
+
assertExactKeys(
|
|
1476
|
+
value,
|
|
1477
|
+
productionTransformAuthorityKeys,
|
|
1478
|
+
'offlineExportProductionTransformAuthority',
|
|
1479
|
+
);
|
|
1480
|
+
if (value.schemaVersion !== 1
|
|
1481
|
+
|| value.kind
|
|
1482
|
+
!== 'cloudly-legacy-deployment-settlement-offline-export-production-transform-authority'
|
|
1483
|
+
|| value.role !== 'production-transform'
|
|
1484
|
+
|| value.keyVersion !== 1) {
|
|
1485
|
+
fail('INVALID_VALUE', 'offlineExportProductionTransformAuthority.kind');
|
|
1486
|
+
}
|
|
1487
|
+
const sourceAuthority = normalizeAuthorityReferenceInternal(
|
|
1488
|
+
value.sourceAuthority,
|
|
1489
|
+
'offlineExportProductionTransformAuthority.sourceAuthority',
|
|
1490
|
+
'source-rehearsal',
|
|
1491
|
+
);
|
|
1492
|
+
const operationId = readIdentifier(
|
|
1493
|
+
value.operationId,
|
|
1494
|
+
'offlineExportProductionTransformAuthority.operationId',
|
|
1495
|
+
);
|
|
1496
|
+
const settlementId = readIdentifier(
|
|
1497
|
+
value.settlementId,
|
|
1498
|
+
'offlineExportProductionTransformAuthority.settlementId',
|
|
1499
|
+
);
|
|
1500
|
+
const authorityId = readIdentifier(
|
|
1501
|
+
value.authorityId,
|
|
1502
|
+
'offlineExportProductionTransformAuthority.authorityId',
|
|
1503
|
+
);
|
|
1504
|
+
const keyId = readIdentifier(
|
|
1505
|
+
value.keyId,
|
|
1506
|
+
'offlineExportProductionTransformAuthority.keyId',
|
|
1507
|
+
);
|
|
1508
|
+
if (operationId !== sourceAuthority.operationId
|
|
1509
|
+
|| settlementId !== sourceAuthority.settlementId
|
|
1510
|
+
|| authorityId === sourceAuthority.authorityId
|
|
1511
|
+
|| keyId === sourceAuthority.keyId) {
|
|
1512
|
+
fail('CROSS_FIELD_MISMATCH', 'offlineExportProductionTransformAuthority.sourceAuthority');
|
|
1513
|
+
}
|
|
1514
|
+
return finalize({
|
|
1515
|
+
schemaVersion: 1,
|
|
1516
|
+
kind: 'cloudly-legacy-deployment-settlement-offline-export-production-transform-authority',
|
|
1517
|
+
role: 'production-transform',
|
|
1518
|
+
operationId,
|
|
1519
|
+
settlementId,
|
|
1520
|
+
authorityId,
|
|
1521
|
+
keyId,
|
|
1522
|
+
keyVersion: 1,
|
|
1523
|
+
...normalizeAuthorityWindow(value, 'offlineExportProductionTransformAuthority'),
|
|
1524
|
+
sourceAuthority,
|
|
1525
|
+
authenticatedRehearsalAttestationSha256: readSha256(
|
|
1526
|
+
value.authenticatedRehearsalAttestationSha256,
|
|
1527
|
+
'offlineExportProductionTransformAuthority.authenticatedRehearsalAttestationSha256',
|
|
1528
|
+
),
|
|
1529
|
+
} satisfies ICloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthorityV1,
|
|
1530
|
+
cloudlyLegacyDeploymentSettlementOfflineExportLimits.maximumAuthorityBytes,
|
|
1531
|
+
'offlineExportProductionTransformAuthority');
|
|
1532
|
+
};
|
|
1533
|
+
|
|
1534
|
+
export const encodeCloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthority = (
|
|
1535
|
+
valueArg: unknown,
|
|
1536
|
+
): Uint8Array => encodeNormalized(
|
|
1537
|
+
normalizeCloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthority(valueArg),
|
|
1538
|
+
'offlineExportProductionTransformAuthority',
|
|
1539
|
+
);
|
|
1540
|
+
|
|
1541
|
+
export const digestCloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthority = (
|
|
1542
|
+
valueArg: unknown,
|
|
1543
|
+
): string => digestBytes(
|
|
1544
|
+
encodeCloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthority(valueArg),
|
|
1545
|
+
);
|
|
1546
|
+
|
|
1547
|
+
export const createCloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthorityReference = (
|
|
1548
|
+
authorityArg: unknown,
|
|
1549
|
+
): Readonly<
|
|
1550
|
+
ICloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthorityReferenceV1
|
|
1551
|
+
> => {
|
|
1552
|
+
const authority =
|
|
1553
|
+
normalizeCloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthority(
|
|
1554
|
+
authorityArg,
|
|
1555
|
+
);
|
|
1556
|
+
return finalize({
|
|
1557
|
+
schemaVersion: 1,
|
|
1558
|
+
kind: 'cloudly-legacy-deployment-settlement-offline-export-authority-reference',
|
|
1559
|
+
role: 'production-transform',
|
|
1560
|
+
operationId: authority.operationId,
|
|
1561
|
+
settlementId: authority.settlementId,
|
|
1562
|
+
authorityId: authority.authorityId,
|
|
1563
|
+
keyId: authority.keyId,
|
|
1564
|
+
keyVersion: 1,
|
|
1565
|
+
authorityMetadataSha256:
|
|
1566
|
+
digestCloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthority(
|
|
1567
|
+
authority,
|
|
1568
|
+
),
|
|
1569
|
+
}, cloudlyLegacyDeploymentSettlementOfflineExportLimits.maximumAuthorityBytes,
|
|
1570
|
+
'offlineExportProductionTransformAuthorityReference');
|
|
1571
|
+
};
|
|
1572
|
+
|
|
1573
|
+
const assertProductionReferenceMatchesAuthority = (
|
|
1574
|
+
referenceArg: unknown,
|
|
1575
|
+
authorityArg: unknown,
|
|
1576
|
+
pathArg: string,
|
|
1577
|
+
): void => {
|
|
1578
|
+
const reference =
|
|
1579
|
+
normalizeCloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthorityReference(
|
|
1580
|
+
referenceArg,
|
|
1581
|
+
);
|
|
1582
|
+
const expected =
|
|
1583
|
+
createCloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthorityReference(
|
|
1584
|
+
authorityArg,
|
|
1585
|
+
);
|
|
1586
|
+
if (!canonicalEqual(reference, expected, pathArg)) {
|
|
1587
|
+
fail('CROSS_FIELD_MISMATCH', pathArg);
|
|
1588
|
+
}
|
|
1589
|
+
};
|
|
1590
|
+
|
|
1591
|
+
export const normalizeCloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthorityForRehearsal = async (
|
|
1592
|
+
productionAuthorityArg: unknown,
|
|
1593
|
+
sourceAuthorityArg: unknown,
|
|
1594
|
+
rehearsalAttestationArg: unknown,
|
|
1595
|
+
verifierArg: TCloudlyLegacyDeploymentSettlementOfflineExportHmacVerifier,
|
|
1596
|
+
): Promise<Readonly<
|
|
1597
|
+
ICloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthorityV1
|
|
1598
|
+
>> => {
|
|
1599
|
+
const sourceAuthority = normalizeCloudlyLegacyDeploymentSettlementOfflineExportSourceAuthority(
|
|
1600
|
+
sourceAuthorityArg,
|
|
1601
|
+
);
|
|
1602
|
+
const rehearsal =
|
|
1603
|
+
await normalizeCloudlyLegacyDeploymentSettlementOfflineExportRehearsalAttestationForAuthority(
|
|
1604
|
+
rehearsalAttestationArg,
|
|
1605
|
+
sourceAuthority,
|
|
1606
|
+
verifierArg,
|
|
1607
|
+
);
|
|
1608
|
+
const productionAuthority =
|
|
1609
|
+
normalizeCloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthority(
|
|
1610
|
+
productionAuthorityArg,
|
|
1611
|
+
);
|
|
1612
|
+
assertSourceReferenceMatchesAuthority(
|
|
1613
|
+
productionAuthority.sourceAuthority,
|
|
1614
|
+
sourceAuthority,
|
|
1615
|
+
'offlineExportProductionTransformAuthority.sourceAuthority',
|
|
1616
|
+
);
|
|
1617
|
+
if (productionAuthority.authenticatedRehearsalAttestationSha256
|
|
1618
|
+
!== digestCloudlyLegacyDeploymentSettlementOfflineExportRehearsalAttestation(rehearsal)
|
|
1619
|
+
|| productionAuthority.issuedAt <= rehearsal.completedAt) {
|
|
1620
|
+
fail('CROSS_FIELD_MISMATCH', 'offlineExportProductionTransformAuthority.rehearsal');
|
|
1621
|
+
}
|
|
1622
|
+
return productionAuthority;
|
|
1623
|
+
};
|
|
1624
|
+
|
|
1625
|
+
const normalizeAuthorizationPayloadInternal = (
|
|
1626
|
+
valueArg: unknown,
|
|
1627
|
+
pathArg: string,
|
|
1628
|
+
): ICloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthorizationPayloadV1 => {
|
|
1629
|
+
const value = readRecord(valueArg, pathArg);
|
|
1630
|
+
assertExactKeys(value, authorizationPayloadKeys, pathArg);
|
|
1631
|
+
if (value.schemaVersion !== 1
|
|
1632
|
+
|| value.kind
|
|
1633
|
+
!== 'cloudly-legacy-deployment-settlement-offline-export-production-transform-authorization') {
|
|
1634
|
+
fail('INVALID_VALUE', `${pathArg}.kind`);
|
|
1635
|
+
}
|
|
1636
|
+
const authority = normalizeAuthorityReferenceInternal(
|
|
1637
|
+
value.authority,
|
|
1638
|
+
`${pathArg}.authority`,
|
|
1639
|
+
'production-transform',
|
|
1640
|
+
);
|
|
1641
|
+
const sourceAuthority = normalizeAuthorityReferenceInternal(
|
|
1642
|
+
value.sourceAuthority,
|
|
1643
|
+
`${pathArg}.sourceAuthority`,
|
|
1644
|
+
'source-rehearsal',
|
|
1645
|
+
);
|
|
1646
|
+
const requestedAt = readInteger(value.requestedAt, `${pathArg}.requestedAt`, 1);
|
|
1647
|
+
const authorizedAt = readInteger(value.authorizedAt, `${pathArg}.authorizedAt`, requestedAt);
|
|
1648
|
+
if (authority.operationId !== sourceAuthority.operationId
|
|
1649
|
+
|| authority.settlementId !== sourceAuthority.settlementId
|
|
1650
|
+
|| authority.authorityId === sourceAuthority.authorityId
|
|
1651
|
+
|| authority.keyId === sourceAuthority.keyId
|
|
1652
|
+
|| canonicalEqual(authority, sourceAuthority, `${pathArg}.authorities`)) {
|
|
1653
|
+
fail('CROSS_FIELD_MISMATCH', `${pathArg}.authority`);
|
|
1654
|
+
}
|
|
1655
|
+
return {
|
|
1656
|
+
schemaVersion: 1,
|
|
1657
|
+
kind: 'cloudly-legacy-deployment-settlement-offline-export-production-transform-authorization',
|
|
1658
|
+
authority,
|
|
1659
|
+
sourceAuthority,
|
|
1660
|
+
attemptId: readIdentifier(value.attemptId, `${pathArg}.attemptId`),
|
|
1661
|
+
authenticatedRehearsalAttestationSha256: readSha256(
|
|
1662
|
+
value.authenticatedRehearsalAttestationSha256,
|
|
1663
|
+
`${pathArg}.authenticatedRehearsalAttestationSha256`,
|
|
1664
|
+
),
|
|
1665
|
+
planSha256: readSha256(value.planSha256, `${pathArg}.planSha256`),
|
|
1666
|
+
requestSha256: readSha256(value.requestSha256, `${pathArg}.requestSha256`),
|
|
1667
|
+
requestedAt,
|
|
1668
|
+
authorizedAt,
|
|
1669
|
+
};
|
|
1670
|
+
};
|
|
1671
|
+
|
|
1672
|
+
const authorizationPayload = (
|
|
1673
|
+
valueArg:
|
|
1674
|
+
ICloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthorizationPayloadV1,
|
|
1675
|
+
): unknown => Object.fromEntries(authorizationPayloadKeys.map((keyArg) => [
|
|
1676
|
+
keyArg,
|
|
1677
|
+
valueArg[keyArg],
|
|
1678
|
+
]));
|
|
1679
|
+
|
|
1680
|
+
export const digestCloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthorizationPayload = (
|
|
1681
|
+
valueArg: unknown,
|
|
1682
|
+
): string => digestBytes(encodeNormalized(
|
|
1683
|
+
authorizationPayload(normalizeAuthorizationPayloadInternal(
|
|
1684
|
+
valueArg,
|
|
1685
|
+
'offlineExportProductionTransformAuthorizationPayload',
|
|
1686
|
+
)),
|
|
1687
|
+
'offlineExportProductionTransformAuthorizationPayload',
|
|
1688
|
+
));
|
|
1689
|
+
|
|
1690
|
+
const normalizeUnsignedAuthorizationInternal = (
|
|
1691
|
+
valueArg: unknown,
|
|
1692
|
+
pathArg: string,
|
|
1693
|
+
): TCloudlyLegacyDeploymentSettlementOfflineExportUnsignedProductionTransformAuthorizationV1 => {
|
|
1694
|
+
const value = readRecord(valueArg, pathArg);
|
|
1695
|
+
assertExactKeys(value, authorizationUnsignedKeys, pathArg);
|
|
1696
|
+
const payload = normalizeAuthorizationPayloadInternal(
|
|
1697
|
+
Object.fromEntries(authorizationPayloadKeys.map((keyArg) => [keyArg, value[keyArg]])),
|
|
1698
|
+
`${pathArg}.payload`,
|
|
1699
|
+
);
|
|
1700
|
+
const payloadSha256 = readSha256(value.payloadSha256, `${pathArg}.payloadSha256`);
|
|
1701
|
+
if (payloadSha256
|
|
1702
|
+
!== digestCloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthorizationPayload(
|
|
1703
|
+
payload,
|
|
1704
|
+
)) {
|
|
1705
|
+
fail('CROSS_FIELD_MISMATCH', `${pathArg}.payloadSha256`);
|
|
1706
|
+
}
|
|
1707
|
+
return { ...payload, payloadSha256 };
|
|
1708
|
+
};
|
|
1709
|
+
|
|
1710
|
+
export const normalizeCloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthorization = (
|
|
1711
|
+
valueArg: unknown,
|
|
1712
|
+
): Readonly<
|
|
1713
|
+
ICloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthorizationV1
|
|
1714
|
+
> => {
|
|
1715
|
+
const value = readRecord(valueArg, 'offlineExportProductionTransformAuthorization');
|
|
1716
|
+
assertExactKeys(value, authorizationKeys, 'offlineExportProductionTransformAuthorization');
|
|
1717
|
+
return finalize({
|
|
1718
|
+
...normalizeUnsignedAuthorizationInternal(
|
|
1719
|
+
Object.fromEntries(authorizationUnsignedKeys.map((keyArg) => [keyArg, value[keyArg]])),
|
|
1720
|
+
'offlineExportProductionTransformAuthorization.unsigned',
|
|
1721
|
+
),
|
|
1722
|
+
mac: readMac(value.mac, 'offlineExportProductionTransformAuthorization.mac'),
|
|
1723
|
+
}, cloudlyLegacyDeploymentSettlementOfflineExportLimits.maximumAuthenticatedArtifactBytes,
|
|
1724
|
+
'offlineExportProductionTransformAuthorization');
|
|
1725
|
+
};
|
|
1726
|
+
|
|
1727
|
+
export const encodeCloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthorization = (
|
|
1728
|
+
valueArg: unknown,
|
|
1729
|
+
): Uint8Array => encodeNormalized(
|
|
1730
|
+
normalizeCloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthorization(
|
|
1731
|
+
valueArg,
|
|
1732
|
+
),
|
|
1733
|
+
'offlineExportProductionTransformAuthorization',
|
|
1734
|
+
);
|
|
1735
|
+
|
|
1736
|
+
export const digestCloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthorization = (
|
|
1737
|
+
valueArg: unknown,
|
|
1738
|
+
): string => digestBytes(
|
|
1739
|
+
encodeCloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthorization(valueArg),
|
|
1740
|
+
);
|
|
1741
|
+
|
|
1742
|
+
export const encodeCloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthorizationHmacInput = (
|
|
1743
|
+
valueArg: unknown,
|
|
1744
|
+
): Uint8Array => frame(
|
|
1745
|
+
cloudlyLegacyDeploymentSettlementOfflineExportDomains
|
|
1746
|
+
.productionTransformAuthorizationHmac,
|
|
1747
|
+
encodeNormalized(
|
|
1748
|
+
finalize(
|
|
1749
|
+
normalizeUnsignedAuthorizationInternal(
|
|
1750
|
+
valueArg,
|
|
1751
|
+
'offlineExportUnsignedProductionTransformAuthorization',
|
|
1752
|
+
),
|
|
1753
|
+
cloudlyLegacyDeploymentSettlementOfflineExportLimits.maximumAuthenticatedArtifactBytes,
|
|
1754
|
+
'offlineExportUnsignedProductionTransformAuthorization',
|
|
1755
|
+
),
|
|
1756
|
+
'offlineExportUnsignedProductionTransformAuthorization',
|
|
1757
|
+
),
|
|
1758
|
+
);
|
|
1759
|
+
|
|
1760
|
+
export const normalizeCloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthorizationForAuthorities = async (
|
|
1761
|
+
authorizationArg: unknown,
|
|
1762
|
+
productionAuthorityArg: unknown,
|
|
1763
|
+
sourceAuthorityArg: unknown,
|
|
1764
|
+
rehearsalAttestationArg: unknown,
|
|
1765
|
+
verifierArg: TCloudlyLegacyDeploymentSettlementOfflineExportHmacVerifier,
|
|
1766
|
+
): Promise<Readonly<
|
|
1767
|
+
ICloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthorizationV1
|
|
1768
|
+
>> => {
|
|
1769
|
+
const sourceAuthority = normalizeCloudlyLegacyDeploymentSettlementOfflineExportSourceAuthority(
|
|
1770
|
+
sourceAuthorityArg,
|
|
1771
|
+
);
|
|
1772
|
+
const rehearsal =
|
|
1773
|
+
await normalizeCloudlyLegacyDeploymentSettlementOfflineExportRehearsalAttestationForAuthority(
|
|
1774
|
+
rehearsalAttestationArg,
|
|
1775
|
+
sourceAuthority,
|
|
1776
|
+
verifierArg,
|
|
1777
|
+
);
|
|
1778
|
+
const productionAuthority =
|
|
1779
|
+
await normalizeCloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthorityForRehearsal(
|
|
1780
|
+
productionAuthorityArg,
|
|
1781
|
+
sourceAuthority,
|
|
1782
|
+
rehearsal,
|
|
1783
|
+
verifierArg,
|
|
1784
|
+
);
|
|
1785
|
+
const authorization =
|
|
1786
|
+
normalizeCloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthorization(
|
|
1787
|
+
authorizationArg,
|
|
1788
|
+
);
|
|
1789
|
+
assertProductionReferenceMatchesAuthority(
|
|
1790
|
+
authorization.authority,
|
|
1791
|
+
productionAuthority,
|
|
1792
|
+
'offlineExportProductionTransformAuthorization.authority',
|
|
1793
|
+
);
|
|
1794
|
+
assertSourceReferenceMatchesAuthority(
|
|
1795
|
+
authorization.sourceAuthority,
|
|
1796
|
+
sourceAuthority,
|
|
1797
|
+
'offlineExportProductionTransformAuthorization.sourceAuthority',
|
|
1798
|
+
);
|
|
1799
|
+
if (authorization.authenticatedRehearsalAttestationSha256
|
|
1800
|
+
!== productionAuthority.authenticatedRehearsalAttestationSha256
|
|
1801
|
+
|| authorization.planSha256 !== rehearsal.planSha256
|
|
1802
|
+
|| authorization.requestedAt < productionAuthority.issuedAt) {
|
|
1803
|
+
fail('CROSS_FIELD_MISMATCH', 'offlineExportProductionTransformAuthorization.sourceProof');
|
|
1804
|
+
}
|
|
1805
|
+
assertTimestampWithinAuthority(
|
|
1806
|
+
authorization.requestedAt,
|
|
1807
|
+
productionAuthority,
|
|
1808
|
+
'offlineExportProductionTransformAuthorization.requestedAt',
|
|
1809
|
+
);
|
|
1810
|
+
assertTimestampWithinAuthority(
|
|
1811
|
+
authorization.authorizedAt,
|
|
1812
|
+
productionAuthority,
|
|
1813
|
+
'offlineExportProductionTransformAuthorization.authorizedAt',
|
|
1814
|
+
);
|
|
1815
|
+
await requireVerifiedHmac(
|
|
1816
|
+
authorization.authority,
|
|
1817
|
+
cloudlyLegacyDeploymentSettlementOfflineExportDomains
|
|
1818
|
+
.productionTransformAuthorizationHmac,
|
|
1819
|
+
encodeCloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthorizationHmacInput(
|
|
1820
|
+
withoutMac(authorization),
|
|
1821
|
+
),
|
|
1822
|
+
authorization.mac,
|
|
1823
|
+
verifierArg,
|
|
1824
|
+
'offlineExportProductionTransformAuthorization.mac',
|
|
1825
|
+
);
|
|
1826
|
+
return authorization;
|
|
1827
|
+
};
|
|
1828
|
+
|
|
1829
|
+
const normalizeJournalSeedInternal = (
|
|
1830
|
+
valueArg: unknown,
|
|
1831
|
+
pathArg: string,
|
|
1832
|
+
): ICloudlyLegacyDeploymentSettlementOfflineExportAttemptJournalSeedV1 => {
|
|
1833
|
+
const value = readRecord(valueArg, pathArg);
|
|
1834
|
+
assertExactKeys(value, journalSeedKeys, pathArg);
|
|
1835
|
+
if (value.schemaVersion !== 1
|
|
1836
|
+
|| value.kind !== cloudlyLegacyDeploymentSettlementOfflineExportJournalCollectionName
|
|
1837
|
+
|| value.purpose !== 'production-transform') {
|
|
1838
|
+
fail('INVALID_VALUE', `${pathArg}.kind`);
|
|
1839
|
+
}
|
|
1840
|
+
const operationId = readIdentifier(value.operationId, `${pathArg}.operationId`);
|
|
1841
|
+
const settlementId = readIdentifier(value.settlementId, `${pathArg}.settlementId`);
|
|
1842
|
+
const sourceAuthority = normalizeAuthorityReferenceInternal(
|
|
1843
|
+
value.sourceAuthority,
|
|
1844
|
+
`${pathArg}.sourceAuthority`,
|
|
1845
|
+
'source-rehearsal',
|
|
1846
|
+
);
|
|
1847
|
+
const productionTransformAuthority = normalizeAuthorityReferenceInternal(
|
|
1848
|
+
value.productionTransformAuthority,
|
|
1849
|
+
`${pathArg}.productionTransformAuthority`,
|
|
1850
|
+
'production-transform',
|
|
1851
|
+
);
|
|
1852
|
+
const sourceFile = normalizeFileIdentityInternal(value.sourceFile, `${pathArg}.sourceFile`);
|
|
1853
|
+
const transformedCoreFile = normalizeFileIdentityInternal(
|
|
1854
|
+
value.transformedCoreFile,
|
|
1855
|
+
`${pathArg}.transformedCoreFile`,
|
|
1856
|
+
);
|
|
1857
|
+
const sourceStateHmac = readStateHmac(
|
|
1858
|
+
value.sourceStateHmac,
|
|
1859
|
+
`${pathArg}.sourceStateHmac`,
|
|
1860
|
+
);
|
|
1861
|
+
const finalStateHmac = readStateHmac(
|
|
1862
|
+
value.finalStateHmac,
|
|
1863
|
+
`${pathArg}.finalStateHmac`,
|
|
1864
|
+
);
|
|
1865
|
+
const outcome = readLiteral(
|
|
1866
|
+
value.outcome,
|
|
1867
|
+
['transformed', 'no-op'],
|
|
1868
|
+
`${pathArg}.outcome`,
|
|
1869
|
+
);
|
|
1870
|
+
const counts = normalizeMutationCounts(value.counts, `${pathArg}.counts`);
|
|
1871
|
+
const classificationCounts = normalizeClassificationCounts(
|
|
1872
|
+
value.classificationCounts,
|
|
1873
|
+
`${pathArg}.classificationCounts`,
|
|
1874
|
+
);
|
|
1875
|
+
assertCountsMatchClassifications(counts, classificationCounts, `${pathArg}.counts`);
|
|
1876
|
+
if (operationId !== sourceAuthority.operationId
|
|
1877
|
+
|| operationId !== productionTransformAuthority.operationId
|
|
1878
|
+
|| settlementId !== sourceAuthority.settlementId
|
|
1879
|
+
|| settlementId !== productionTransformAuthority.settlementId
|
|
1880
|
+
|| sourceAuthority.authorityId === productionTransformAuthority.authorityId
|
|
1881
|
+
|| sourceAuthority.keyId === productionTransformAuthority.keyId
|
|
1882
|
+
|| sourceFile.databaseName !== transformedCoreFile.databaseName
|
|
1883
|
+
|| (outcome === 'no-op') !== hasNoMutations(counts)
|
|
1884
|
+
|| (outcome === 'no-op') !== (sourceStateHmac === finalStateHmac)
|
|
1885
|
+
|| (outcome === 'no-op') !== canonicalEqual(
|
|
1886
|
+
sourceFile,
|
|
1887
|
+
transformedCoreFile,
|
|
1888
|
+
`${pathArg}.fileIdentity`,
|
|
1889
|
+
)) {
|
|
1890
|
+
fail('CROSS_FIELD_MISMATCH', `${pathArg}.sourceProof`);
|
|
1891
|
+
}
|
|
1892
|
+
return {
|
|
1893
|
+
schemaVersion: 1,
|
|
1894
|
+
kind: cloudlyLegacyDeploymentSettlementOfflineExportJournalCollectionName,
|
|
1895
|
+
purpose: 'production-transform',
|
|
1896
|
+
operationId,
|
|
1897
|
+
settlementId,
|
|
1898
|
+
attemptId: readIdentifier(value.attemptId, `${pathArg}.attemptId`),
|
|
1899
|
+
sourceAuthority,
|
|
1900
|
+
productionTransformAuthority,
|
|
1901
|
+
authenticatedRehearsalAttestationSha256: readSha256(
|
|
1902
|
+
value.authenticatedRehearsalAttestationSha256,
|
|
1903
|
+
`${pathArg}.authenticatedRehearsalAttestationSha256`,
|
|
1904
|
+
),
|
|
1905
|
+
transformAuthorizationSha256: readSha256(
|
|
1906
|
+
value.transformAuthorizationSha256,
|
|
1907
|
+
`${pathArg}.transformAuthorizationSha256`,
|
|
1908
|
+
),
|
|
1909
|
+
planSha256: readSha256(value.planSha256, `${pathArg}.planSha256`),
|
|
1910
|
+
requestSha256: readSha256(value.requestSha256, `${pathArg}.requestSha256`),
|
|
1911
|
+
sourceFile,
|
|
1912
|
+
transformedCoreFile,
|
|
1913
|
+
sourceStateHmac,
|
|
1914
|
+
finalStateHmac,
|
|
1915
|
+
outcome,
|
|
1916
|
+
counts,
|
|
1917
|
+
classificationCounts,
|
|
1918
|
+
completedAt: readInteger(value.completedAt, `${pathArg}.completedAt`, 1),
|
|
1919
|
+
};
|
|
1920
|
+
};
|
|
1921
|
+
|
|
1922
|
+
export const createCloudlyLegacyDeploymentSettlementOfflineExportAttemptJournalId = (
|
|
1923
|
+
seedArg: unknown,
|
|
1924
|
+
): string => {
|
|
1925
|
+
const seed = normalizeJournalSeedInternal(seedArg, 'offlineExportAttemptJournal.seed');
|
|
1926
|
+
return `offline-export-attempt-${digestBytes(encodeNormalized(
|
|
1927
|
+
seed,
|
|
1928
|
+
'offlineExportAttemptJournal.seed',
|
|
1929
|
+
)).slice(0, 40)}`;
|
|
1930
|
+
};
|
|
1931
|
+
|
|
1932
|
+
const normalizeUnsignedJournalInternal = (
|
|
1933
|
+
valueArg: unknown,
|
|
1934
|
+
pathArg: string,
|
|
1935
|
+
): TCloudlyLegacyDeploymentSettlementOfflineExportUnsignedAttemptJournalV1 => {
|
|
1936
|
+
const value = readRecord(valueArg, pathArg);
|
|
1937
|
+
assertExactKeys(value, journalUnsignedKeys, pathArg);
|
|
1938
|
+
const seed = normalizeJournalSeedInternal(
|
|
1939
|
+
Object.fromEntries(journalSeedKeys.map((keyArg) => [keyArg, value[keyArg]])),
|
|
1940
|
+
`${pathArg}.seed`,
|
|
1941
|
+
);
|
|
1942
|
+
const id = readIdentifier(value._id, `${pathArg}._id`);
|
|
1943
|
+
if (id !== createCloudlyLegacyDeploymentSettlementOfflineExportAttemptJournalId(seed)) {
|
|
1944
|
+
fail('CROSS_FIELD_MISMATCH', `${pathArg}._id`);
|
|
1945
|
+
}
|
|
1946
|
+
return { _id: id, ...seed };
|
|
1947
|
+
};
|
|
1948
|
+
|
|
1949
|
+
export const normalizeCloudlyLegacyDeploymentSettlementOfflineExportAttemptJournal = (
|
|
1950
|
+
valueArg: unknown,
|
|
1951
|
+
): Readonly<ICloudlyLegacyDeploymentSettlementOfflineExportAttemptJournalV1> => {
|
|
1952
|
+
const value = readRecord(valueArg, 'offlineExportAttemptJournal');
|
|
1953
|
+
assertExactKeys(value, journalKeys, 'offlineExportAttemptJournal');
|
|
1954
|
+
return finalize({
|
|
1955
|
+
...normalizeUnsignedJournalInternal(
|
|
1956
|
+
Object.fromEntries(journalUnsignedKeys.map((keyArg) => [keyArg, value[keyArg]])),
|
|
1957
|
+
'offlineExportAttemptJournal.unsigned',
|
|
1958
|
+
),
|
|
1959
|
+
mac: readMac(value.mac, 'offlineExportAttemptJournal.mac'),
|
|
1960
|
+
}, cloudlyLegacyDeploymentSettlementOfflineExportLimits.maximumJournalCanonicalBytes,
|
|
1961
|
+
'offlineExportAttemptJournal');
|
|
1962
|
+
};
|
|
1963
|
+
|
|
1964
|
+
export const encodeCloudlyLegacyDeploymentSettlementOfflineExportAttemptJournal = (
|
|
1965
|
+
valueArg: unknown,
|
|
1966
|
+
): Uint8Array => encodeNormalized(
|
|
1967
|
+
normalizeCloudlyLegacyDeploymentSettlementOfflineExportAttemptJournal(valueArg),
|
|
1968
|
+
'offlineExportAttemptJournal',
|
|
1969
|
+
);
|
|
1970
|
+
|
|
1971
|
+
export const digestCloudlyLegacyDeploymentSettlementOfflineExportAttemptJournal = (
|
|
1972
|
+
valueArg: unknown,
|
|
1973
|
+
): string => digestBytes(
|
|
1974
|
+
encodeCloudlyLegacyDeploymentSettlementOfflineExportAttemptJournal(valueArg),
|
|
1975
|
+
);
|
|
1976
|
+
|
|
1977
|
+
export const encodeCloudlyLegacyDeploymentSettlementOfflineExportAttemptJournalHmacInput = (
|
|
1978
|
+
valueArg: unknown,
|
|
1979
|
+
): Uint8Array => frame(
|
|
1980
|
+
cloudlyLegacyDeploymentSettlementOfflineExportDomains.attemptJournalHmac,
|
|
1981
|
+
encodeNormalized(
|
|
1982
|
+
finalize(
|
|
1983
|
+
normalizeUnsignedJournalInternal(valueArg, 'offlineExportUnsignedAttemptJournal'),
|
|
1984
|
+
cloudlyLegacyDeploymentSettlementOfflineExportLimits.maximumJournalCanonicalBytes,
|
|
1985
|
+
'offlineExportUnsignedAttemptJournal',
|
|
1986
|
+
),
|
|
1987
|
+
'offlineExportUnsignedAttemptJournal',
|
|
1988
|
+
),
|
|
1989
|
+
);
|
|
1990
|
+
|
|
1991
|
+
export const normalizeCloudlyLegacyDeploymentSettlementOfflineExportAttemptJournalForAuthorities = async (
|
|
1992
|
+
journalArg: unknown,
|
|
1993
|
+
authorizationArg: unknown,
|
|
1994
|
+
productionAuthorityArg: unknown,
|
|
1995
|
+
sourceAuthorityArg: unknown,
|
|
1996
|
+
rehearsalAttestationArg: unknown,
|
|
1997
|
+
verifierArg: TCloudlyLegacyDeploymentSettlementOfflineExportHmacVerifier,
|
|
1998
|
+
): Promise<Readonly<ICloudlyLegacyDeploymentSettlementOfflineExportAttemptJournalV1>> => {
|
|
1999
|
+
const authorization =
|
|
2000
|
+
await normalizeCloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthorizationForAuthorities(
|
|
2001
|
+
authorizationArg,
|
|
2002
|
+
productionAuthorityArg,
|
|
2003
|
+
sourceAuthorityArg,
|
|
2004
|
+
rehearsalAttestationArg,
|
|
2005
|
+
verifierArg,
|
|
2006
|
+
);
|
|
2007
|
+
const productionAuthority =
|
|
2008
|
+
normalizeCloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthority(
|
|
2009
|
+
productionAuthorityArg,
|
|
2010
|
+
);
|
|
2011
|
+
const rehearsal =
|
|
2012
|
+
normalizeCloudlyLegacyDeploymentSettlementOfflineExportRehearsalAttestation(
|
|
2013
|
+
rehearsalAttestationArg,
|
|
2014
|
+
);
|
|
2015
|
+
const journal = normalizeCloudlyLegacyDeploymentSettlementOfflineExportAttemptJournal(
|
|
2016
|
+
journalArg,
|
|
2017
|
+
);
|
|
2018
|
+
if (!canonicalEqual(
|
|
2019
|
+
journal.sourceAuthority,
|
|
2020
|
+
authorization.sourceAuthority,
|
|
2021
|
+
'offlineExportAttemptJournal.sourceAuthority',
|
|
2022
|
+
)
|
|
2023
|
+
|| !canonicalEqual(
|
|
2024
|
+
journal.productionTransformAuthority,
|
|
2025
|
+
authorization.authority,
|
|
2026
|
+
'offlineExportAttemptJournal.productionTransformAuthority',
|
|
2027
|
+
)
|
|
2028
|
+
|| journal.attemptId !== authorization.attemptId
|
|
2029
|
+
|| journal.authenticatedRehearsalAttestationSha256
|
|
2030
|
+
!== authorization.authenticatedRehearsalAttestationSha256
|
|
2031
|
+
|| journal.transformAuthorizationSha256
|
|
2032
|
+
!== digestCloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthorization(
|
|
2033
|
+
authorization,
|
|
2034
|
+
)
|
|
2035
|
+
|| journal.planSha256 !== authorization.planSha256
|
|
2036
|
+
|| journal.requestSha256 !== authorization.requestSha256
|
|
2037
|
+
|| !canonicalEqual(
|
|
2038
|
+
journal.sourceFile,
|
|
2039
|
+
rehearsal.plan.sourceFile,
|
|
2040
|
+
'offlineExportAttemptJournal.sourceFile',
|
|
2041
|
+
)
|
|
2042
|
+
|| journal.sourceStateHmac !== rehearsal.plan.sourceStateHmac
|
|
2043
|
+
|| journal.finalStateHmac !== rehearsal.plan.finalStateHmac
|
|
2044
|
+
|| !canonicalEqual(journal.counts, rehearsal.plan.counts, 'offlineExportAttemptJournal.counts')
|
|
2045
|
+
|| !canonicalEqual(
|
|
2046
|
+
journal.classificationCounts,
|
|
2047
|
+
rehearsal.plan.classificationCounts,
|
|
2048
|
+
'offlineExportAttemptJournal.classificationCounts',
|
|
2049
|
+
)
|
|
2050
|
+
|| journal.completedAt < authorization.authorizedAt) {
|
|
2051
|
+
fail('CROSS_FIELD_MISMATCH', 'offlineExportAttemptJournal.sourceProof');
|
|
2052
|
+
}
|
|
2053
|
+
assertTimestampWithinAuthority(
|
|
2054
|
+
journal.completedAt,
|
|
2055
|
+
productionAuthority,
|
|
2056
|
+
'offlineExportAttemptJournal.completedAt',
|
|
2057
|
+
);
|
|
2058
|
+
await requireVerifiedHmac(
|
|
2059
|
+
journal.productionTransformAuthority,
|
|
2060
|
+
cloudlyLegacyDeploymentSettlementOfflineExportDomains.attemptJournalHmac,
|
|
2061
|
+
encodeCloudlyLegacyDeploymentSettlementOfflineExportAttemptJournalHmacInput(
|
|
2062
|
+
withoutMac(journal),
|
|
2063
|
+
),
|
|
2064
|
+
journal.mac,
|
|
2065
|
+
verifierArg,
|
|
2066
|
+
'offlineExportAttemptJournal.mac',
|
|
2067
|
+
);
|
|
2068
|
+
return journal;
|
|
2069
|
+
};
|
|
2070
|
+
|
|
2071
|
+
const normalizeCompleteOutputReceiptPayloadInternal = (
|
|
2072
|
+
valueArg: unknown,
|
|
2073
|
+
pathArg: string,
|
|
2074
|
+
): ICloudlyLegacyDeploymentSettlementOfflineExportCompleteOutputReceiptPayloadV1 => {
|
|
2075
|
+
const value = readRecord(valueArg, pathArg);
|
|
2076
|
+
assertExactKeys(value, completeOutputReceiptPayloadKeys, pathArg);
|
|
2077
|
+
if (value.schemaVersion !== 1
|
|
2078
|
+
|| value.kind
|
|
2079
|
+
!== 'cloudly-legacy-deployment-settlement-offline-export-complete-output-receipt') {
|
|
2080
|
+
fail('INVALID_VALUE', `${pathArg}.kind`);
|
|
2081
|
+
}
|
|
2082
|
+
const authority = normalizeAuthorityReferenceInternal(
|
|
2083
|
+
value.authority,
|
|
2084
|
+
`${pathArg}.authority`,
|
|
2085
|
+
'production-transform',
|
|
2086
|
+
);
|
|
2087
|
+
const sourceAuthority = normalizeAuthorityReferenceInternal(
|
|
2088
|
+
value.sourceAuthority,
|
|
2089
|
+
`${pathArg}.sourceAuthority`,
|
|
2090
|
+
'source-rehearsal',
|
|
2091
|
+
);
|
|
2092
|
+
const operationId = readIdentifier(value.operationId, `${pathArg}.operationId`);
|
|
2093
|
+
const settlementId = readIdentifier(value.settlementId, `${pathArg}.settlementId`);
|
|
2094
|
+
const transformedCoreFile = normalizeFileIdentityInternal(
|
|
2095
|
+
value.transformedCoreFile,
|
|
2096
|
+
`${pathArg}.transformedCoreFile`,
|
|
2097
|
+
);
|
|
2098
|
+
const completeOutputFile = normalizeFileIdentityInternal(
|
|
2099
|
+
value.completeOutputFile,
|
|
2100
|
+
`${pathArg}.completeOutputFile`,
|
|
2101
|
+
);
|
|
2102
|
+
const journalGrowthBytes = readInteger(
|
|
2103
|
+
value.journalGrowthBytes,
|
|
2104
|
+
`${pathArg}.journalGrowthBytes`,
|
|
2105
|
+
1,
|
|
2106
|
+
cloudlyLegacyDeploymentSettlementOfflineExportLimits.maximumJournalGrowthBytes,
|
|
2107
|
+
);
|
|
2108
|
+
if (operationId !== authority.operationId
|
|
2109
|
+
|| operationId !== sourceAuthority.operationId
|
|
2110
|
+
|| settlementId !== authority.settlementId
|
|
2111
|
+
|| settlementId !== sourceAuthority.settlementId
|
|
2112
|
+
|| authority.authorityId === sourceAuthority.authorityId
|
|
2113
|
+
|| authority.keyId === sourceAuthority.keyId
|
|
2114
|
+
|| transformedCoreFile.databaseName !== completeOutputFile.databaseName
|
|
2115
|
+
|| completeOutputFile.byteLength - transformedCoreFile.byteLength !== journalGrowthBytes) {
|
|
2116
|
+
fail('CROSS_FIELD_MISMATCH', `${pathArg}.completeOutputFile`);
|
|
2117
|
+
}
|
|
2118
|
+
return {
|
|
2119
|
+
schemaVersion: 1,
|
|
2120
|
+
kind: 'cloudly-legacy-deployment-settlement-offline-export-complete-output-receipt',
|
|
2121
|
+
authority,
|
|
2122
|
+
sourceAuthority,
|
|
2123
|
+
operationId,
|
|
2124
|
+
settlementId,
|
|
2125
|
+
attemptId: readIdentifier(value.attemptId, `${pathArg}.attemptId`),
|
|
2126
|
+
journalSha256: readSha256(value.journalSha256, `${pathArg}.journalSha256`),
|
|
2127
|
+
transformedCoreFile,
|
|
2128
|
+
completeOutputFile,
|
|
2129
|
+
journalGrowthBytes,
|
|
2130
|
+
completedAt: readInteger(value.completedAt, `${pathArg}.completedAt`, 1),
|
|
2131
|
+
};
|
|
2132
|
+
};
|
|
2133
|
+
|
|
2134
|
+
const completeOutputReceiptPayload = (
|
|
2135
|
+
valueArg:
|
|
2136
|
+
ICloudlyLegacyDeploymentSettlementOfflineExportCompleteOutputReceiptPayloadV1,
|
|
2137
|
+
): unknown => Object.fromEntries(completeOutputReceiptPayloadKeys.map((keyArg) => [
|
|
2138
|
+
keyArg,
|
|
2139
|
+
valueArg[keyArg],
|
|
2140
|
+
]));
|
|
2141
|
+
|
|
2142
|
+
export const digestCloudlyLegacyDeploymentSettlementOfflineExportCompleteOutputReceiptPayload = (
|
|
2143
|
+
valueArg: unknown,
|
|
2144
|
+
): string => digestBytes(encodeNormalized(
|
|
2145
|
+
completeOutputReceiptPayload(normalizeCompleteOutputReceiptPayloadInternal(
|
|
2146
|
+
valueArg,
|
|
2147
|
+
'offlineExportCompleteOutputReceiptPayload',
|
|
2148
|
+
)),
|
|
2149
|
+
'offlineExportCompleteOutputReceiptPayload',
|
|
2150
|
+
));
|
|
2151
|
+
|
|
2152
|
+
const normalizeUnsignedCompleteOutputReceiptInternal = (
|
|
2153
|
+
valueArg: unknown,
|
|
2154
|
+
pathArg: string,
|
|
2155
|
+
): TCloudlyLegacyDeploymentSettlementOfflineExportUnsignedCompleteOutputReceiptV1 => {
|
|
2156
|
+
const value = readRecord(valueArg, pathArg);
|
|
2157
|
+
assertExactKeys(value, completeOutputReceiptUnsignedKeys, pathArg);
|
|
2158
|
+
const payload = normalizeCompleteOutputReceiptPayloadInternal(
|
|
2159
|
+
Object.fromEntries(completeOutputReceiptPayloadKeys.map((keyArg) => [keyArg, value[keyArg]])),
|
|
2160
|
+
`${pathArg}.payload`,
|
|
2161
|
+
);
|
|
2162
|
+
const payloadSha256 = readSha256(value.payloadSha256, `${pathArg}.payloadSha256`);
|
|
2163
|
+
if (payloadSha256
|
|
2164
|
+
!== digestCloudlyLegacyDeploymentSettlementOfflineExportCompleteOutputReceiptPayload(
|
|
2165
|
+
payload,
|
|
2166
|
+
)) {
|
|
2167
|
+
fail('CROSS_FIELD_MISMATCH', `${pathArg}.payloadSha256`);
|
|
2168
|
+
}
|
|
2169
|
+
return { ...payload, payloadSha256 };
|
|
2170
|
+
};
|
|
2171
|
+
|
|
2172
|
+
export const normalizeCloudlyLegacyDeploymentSettlementOfflineExportCompleteOutputReceipt = (
|
|
2173
|
+
valueArg: unknown,
|
|
2174
|
+
): Readonly<
|
|
2175
|
+
ICloudlyLegacyDeploymentSettlementOfflineExportCompleteOutputReceiptV1
|
|
2176
|
+
> => {
|
|
2177
|
+
const value = readRecord(valueArg, 'offlineExportCompleteOutputReceipt');
|
|
2178
|
+
assertExactKeys(value, completeOutputReceiptKeys, 'offlineExportCompleteOutputReceipt');
|
|
2179
|
+
return finalize({
|
|
2180
|
+
...normalizeUnsignedCompleteOutputReceiptInternal(
|
|
2181
|
+
Object.fromEntries(completeOutputReceiptUnsignedKeys.map((keyArg) => [
|
|
2182
|
+
keyArg,
|
|
2183
|
+
value[keyArg],
|
|
2184
|
+
])),
|
|
2185
|
+
'offlineExportCompleteOutputReceipt.unsigned',
|
|
2186
|
+
),
|
|
2187
|
+
mac: readMac(value.mac, 'offlineExportCompleteOutputReceipt.mac'),
|
|
2188
|
+
}, cloudlyLegacyDeploymentSettlementOfflineExportLimits.maximumReceiptBytes,
|
|
2189
|
+
'offlineExportCompleteOutputReceipt');
|
|
2190
|
+
};
|
|
2191
|
+
|
|
2192
|
+
export const encodeCloudlyLegacyDeploymentSettlementOfflineExportCompleteOutputReceipt = (
|
|
2193
|
+
valueArg: unknown,
|
|
2194
|
+
): Uint8Array => encodeNormalized(
|
|
2195
|
+
normalizeCloudlyLegacyDeploymentSettlementOfflineExportCompleteOutputReceipt(valueArg),
|
|
2196
|
+
'offlineExportCompleteOutputReceipt',
|
|
2197
|
+
);
|
|
2198
|
+
|
|
2199
|
+
export const digestCloudlyLegacyDeploymentSettlementOfflineExportCompleteOutputReceipt = (
|
|
2200
|
+
valueArg: unknown,
|
|
2201
|
+
): string => digestBytes(
|
|
2202
|
+
encodeCloudlyLegacyDeploymentSettlementOfflineExportCompleteOutputReceipt(valueArg),
|
|
2203
|
+
);
|
|
2204
|
+
|
|
2205
|
+
const assertCompleteOutputReceiptMatchesJournal = (
|
|
2206
|
+
receiptArg: Readonly<
|
|
2207
|
+
ICloudlyLegacyDeploymentSettlementOfflineExportCompleteOutputReceiptV1
|
|
2208
|
+
>,
|
|
2209
|
+
journalArg: Readonly<ICloudlyLegacyDeploymentSettlementOfflineExportAttemptJournalV1>,
|
|
2210
|
+
pathArg: string,
|
|
2211
|
+
): void => {
|
|
2212
|
+
if (!canonicalEqual(receiptArg.authority, journalArg.productionTransformAuthority, pathArg)
|
|
2213
|
+
|| !canonicalEqual(receiptArg.sourceAuthority, journalArg.sourceAuthority, pathArg)
|
|
2214
|
+
|| receiptArg.operationId !== journalArg.operationId
|
|
2215
|
+
|| receiptArg.settlementId !== journalArg.settlementId
|
|
2216
|
+
|| receiptArg.attemptId !== journalArg.attemptId
|
|
2217
|
+
|| receiptArg.journalSha256
|
|
2218
|
+
!== digestCloudlyLegacyDeploymentSettlementOfflineExportAttemptJournal(journalArg)
|
|
2219
|
+
|| !canonicalEqual(receiptArg.transformedCoreFile, journalArg.transformedCoreFile, pathArg)
|
|
2220
|
+
|| receiptArg.journalGrowthBytes
|
|
2221
|
+
< encodeCloudlyLegacyDeploymentSettlementOfflineExportAttemptJournal(journalArg).byteLength
|
|
2222
|
+
|| receiptArg.completedAt < journalArg.completedAt) {
|
|
2223
|
+
fail('CROSS_FIELD_MISMATCH', pathArg);
|
|
2224
|
+
}
|
|
2225
|
+
};
|
|
2226
|
+
|
|
2227
|
+
export const encodeCloudlyLegacyDeploymentSettlementOfflineExportCompleteOutputReceiptHmacInput = (
|
|
2228
|
+
valueArg: unknown,
|
|
2229
|
+
): Uint8Array => frame(
|
|
2230
|
+
cloudlyLegacyDeploymentSettlementOfflineExportDomains.completeOutputReceiptHmac,
|
|
2231
|
+
encodeNormalized(
|
|
2232
|
+
finalize(
|
|
2233
|
+
normalizeUnsignedCompleteOutputReceiptInternal(
|
|
2234
|
+
valueArg,
|
|
2235
|
+
'offlineExportUnsignedCompleteOutputReceipt',
|
|
2236
|
+
),
|
|
2237
|
+
cloudlyLegacyDeploymentSettlementOfflineExportLimits.maximumReceiptBytes,
|
|
2238
|
+
'offlineExportUnsignedCompleteOutputReceipt',
|
|
2239
|
+
),
|
|
2240
|
+
'offlineExportUnsignedCompleteOutputReceipt',
|
|
2241
|
+
),
|
|
2242
|
+
);
|
|
2243
|
+
|
|
2244
|
+
export const normalizeCloudlyLegacyDeploymentSettlementOfflineExportCompleteOutputReceiptForAuthorities = async (
|
|
2245
|
+
receiptArg: unknown,
|
|
2246
|
+
journalArg: unknown,
|
|
2247
|
+
authorizationArg: unknown,
|
|
2248
|
+
productionAuthorityArg: unknown,
|
|
2249
|
+
sourceAuthorityArg: unknown,
|
|
2250
|
+
rehearsalAttestationArg: unknown,
|
|
2251
|
+
verifierArg: TCloudlyLegacyDeploymentSettlementOfflineExportHmacVerifier,
|
|
2252
|
+
): Promise<Readonly<
|
|
2253
|
+
ICloudlyLegacyDeploymentSettlementOfflineExportCompleteOutputReceiptV1
|
|
2254
|
+
>> => {
|
|
2255
|
+
const journal =
|
|
2256
|
+
await normalizeCloudlyLegacyDeploymentSettlementOfflineExportAttemptJournalForAuthorities(
|
|
2257
|
+
journalArg,
|
|
2258
|
+
authorizationArg,
|
|
2259
|
+
productionAuthorityArg,
|
|
2260
|
+
sourceAuthorityArg,
|
|
2261
|
+
rehearsalAttestationArg,
|
|
2262
|
+
verifierArg,
|
|
2263
|
+
);
|
|
2264
|
+
const productionAuthority =
|
|
2265
|
+
normalizeCloudlyLegacyDeploymentSettlementOfflineExportProductionTransformAuthority(
|
|
2266
|
+
productionAuthorityArg,
|
|
2267
|
+
);
|
|
2268
|
+
const receipt =
|
|
2269
|
+
normalizeCloudlyLegacyDeploymentSettlementOfflineExportCompleteOutputReceipt(receiptArg);
|
|
2270
|
+
assertCompleteOutputReceiptMatchesJournal(
|
|
2271
|
+
receipt,
|
|
2272
|
+
journal,
|
|
2273
|
+
'offlineExportCompleteOutputReceipt.sourceProof',
|
|
2274
|
+
);
|
|
2275
|
+
assertTimestampWithinAuthority(
|
|
2276
|
+
receipt.completedAt,
|
|
2277
|
+
productionAuthority,
|
|
2278
|
+
'offlineExportCompleteOutputReceipt.completedAt',
|
|
2279
|
+
);
|
|
2280
|
+
await requireVerifiedHmac(
|
|
2281
|
+
receipt.authority,
|
|
2282
|
+
cloudlyLegacyDeploymentSettlementOfflineExportDomains.completeOutputReceiptHmac,
|
|
2283
|
+
encodeCloudlyLegacyDeploymentSettlementOfflineExportCompleteOutputReceiptHmacInput(
|
|
2284
|
+
withoutMac(receipt),
|
|
2285
|
+
),
|
|
2286
|
+
receipt.mac,
|
|
2287
|
+
verifierArg,
|
|
2288
|
+
'offlineExportCompleteOutputReceipt.mac',
|
|
2289
|
+
);
|
|
2290
|
+
return receipt;
|
|
2291
|
+
};
|
|
2292
|
+
|
|
2293
|
+
export const normalizeCloudlyLegacyDeploymentSettlementOfflineExportTransformResult = (
|
|
2294
|
+
valueArg: unknown,
|
|
2295
|
+
): Readonly<ICloudlyLegacyDeploymentSettlementOfflineExportTransformResultV1> => {
|
|
2296
|
+
const value = readRecord(valueArg, 'offlineExportTransformResult');
|
|
2297
|
+
assertExactKeys(value, [
|
|
2298
|
+
'schemaVersion',
|
|
2299
|
+
'kind',
|
|
2300
|
+
'status',
|
|
2301
|
+
'operationId',
|
|
2302
|
+
'settlementId',
|
|
2303
|
+
'attemptId',
|
|
2304
|
+
'sourceAuthority',
|
|
2305
|
+
'productionTransformAuthority',
|
|
2306
|
+
'planSha256',
|
|
2307
|
+
'requestSha256',
|
|
2308
|
+
'completeOutputReceiptSha256',
|
|
2309
|
+
'outcome',
|
|
2310
|
+
'counts',
|
|
2311
|
+
'classificationCounts',
|
|
2312
|
+
'completedAt',
|
|
2313
|
+
], 'offlineExportTransformResult');
|
|
2314
|
+
if (value.schemaVersion !== 1
|
|
2315
|
+
|| value.kind
|
|
2316
|
+
!== 'cloudly-legacy-deployment-settlement-offline-export-transform-result'
|
|
2317
|
+
|| value.status !== 'completed') {
|
|
2318
|
+
fail('INVALID_VALUE', 'offlineExportTransformResult.kind');
|
|
2319
|
+
}
|
|
2320
|
+
const sourceAuthority = normalizeAuthorityReferenceInternal(
|
|
2321
|
+
value.sourceAuthority,
|
|
2322
|
+
'offlineExportTransformResult.sourceAuthority',
|
|
2323
|
+
'source-rehearsal',
|
|
2324
|
+
);
|
|
2325
|
+
const productionTransformAuthority = normalizeAuthorityReferenceInternal(
|
|
2326
|
+
value.productionTransformAuthority,
|
|
2327
|
+
'offlineExportTransformResult.productionTransformAuthority',
|
|
2328
|
+
'production-transform',
|
|
2329
|
+
);
|
|
2330
|
+
const operationId = readIdentifier(value.operationId, 'offlineExportTransformResult.operationId');
|
|
2331
|
+
const settlementId = readIdentifier(
|
|
2332
|
+
value.settlementId,
|
|
2333
|
+
'offlineExportTransformResult.settlementId',
|
|
2334
|
+
);
|
|
2335
|
+
const counts = normalizeMutationCounts(value.counts, 'offlineExportTransformResult.counts');
|
|
2336
|
+
const classificationCounts = normalizeClassificationCounts(
|
|
2337
|
+
value.classificationCounts,
|
|
2338
|
+
'offlineExportTransformResult.classificationCounts',
|
|
2339
|
+
);
|
|
2340
|
+
const outcome = readLiteral(
|
|
2341
|
+
value.outcome,
|
|
2342
|
+
['transformed', 'no-op'],
|
|
2343
|
+
'offlineExportTransformResult.outcome',
|
|
2344
|
+
);
|
|
2345
|
+
assertCountsMatchClassifications(counts, classificationCounts, 'offlineExportTransformResult.counts');
|
|
2346
|
+
if (operationId !== sourceAuthority.operationId
|
|
2347
|
+
|| operationId !== productionTransformAuthority.operationId
|
|
2348
|
+
|| settlementId !== sourceAuthority.settlementId
|
|
2349
|
+
|| settlementId !== productionTransformAuthority.settlementId
|
|
2350
|
+
|| sourceAuthority.authorityId === productionTransformAuthority.authorityId
|
|
2351
|
+
|| sourceAuthority.keyId === productionTransformAuthority.keyId
|
|
2352
|
+
|| (outcome === 'no-op') !== hasNoMutations(counts)) {
|
|
2353
|
+
fail('CROSS_FIELD_MISMATCH', 'offlineExportTransformResult.authority');
|
|
2354
|
+
}
|
|
2355
|
+
return finalize({
|
|
2356
|
+
schemaVersion: 1,
|
|
2357
|
+
kind: 'cloudly-legacy-deployment-settlement-offline-export-transform-result',
|
|
2358
|
+
status: 'completed',
|
|
2359
|
+
operationId,
|
|
2360
|
+
settlementId,
|
|
2361
|
+
attemptId: readIdentifier(value.attemptId, 'offlineExportTransformResult.attemptId'),
|
|
2362
|
+
sourceAuthority,
|
|
2363
|
+
productionTransformAuthority,
|
|
2364
|
+
planSha256: readSha256(value.planSha256, 'offlineExportTransformResult.planSha256'),
|
|
2365
|
+
requestSha256: readSha256(
|
|
2366
|
+
value.requestSha256,
|
|
2367
|
+
'offlineExportTransformResult.requestSha256',
|
|
2368
|
+
),
|
|
2369
|
+
completeOutputReceiptSha256: readSha256(
|
|
2370
|
+
value.completeOutputReceiptSha256,
|
|
2371
|
+
'offlineExportTransformResult.completeOutputReceiptSha256',
|
|
2372
|
+
),
|
|
2373
|
+
outcome,
|
|
2374
|
+
counts,
|
|
2375
|
+
classificationCounts,
|
|
2376
|
+
completedAt: readInteger(value.completedAt, 'offlineExportTransformResult.completedAt', 1),
|
|
2377
|
+
} satisfies ICloudlyLegacyDeploymentSettlementOfflineExportTransformResultV1,
|
|
2378
|
+
cloudlyLegacyDeploymentSettlementOfflineExportLimits.maximumResultBytes,
|
|
2379
|
+
'offlineExportTransformResult');
|
|
2380
|
+
};
|
|
2381
|
+
|
|
2382
|
+
export const encodeCloudlyLegacyDeploymentSettlementOfflineExportTransformResult = (
|
|
2383
|
+
valueArg: unknown,
|
|
2384
|
+
): Uint8Array => encodeNormalized(
|
|
2385
|
+
normalizeCloudlyLegacyDeploymentSettlementOfflineExportTransformResult(valueArg),
|
|
2386
|
+
'offlineExportTransformResult',
|
|
2387
|
+
);
|
|
2388
|
+
|
|
2389
|
+
export const digestCloudlyLegacyDeploymentSettlementOfflineExportTransformResult = (
|
|
2390
|
+
valueArg: unknown,
|
|
2391
|
+
): string => digestBytes(
|
|
2392
|
+
encodeCloudlyLegacyDeploymentSettlementOfflineExportTransformResult(valueArg),
|
|
2393
|
+
);
|
|
2394
|
+
|
|
2395
|
+
export const normalizeCloudlyLegacyDeploymentSettlementOfflineExportTransformResultForCompleteOutputReceipt = (
|
|
2396
|
+
resultArg: unknown,
|
|
2397
|
+
receiptArg: unknown,
|
|
2398
|
+
journalArg: unknown,
|
|
2399
|
+
): Readonly<ICloudlyLegacyDeploymentSettlementOfflineExportTransformResultV1> => {
|
|
2400
|
+
const result = normalizeCloudlyLegacyDeploymentSettlementOfflineExportTransformResult(resultArg);
|
|
2401
|
+
const receipt =
|
|
2402
|
+
normalizeCloudlyLegacyDeploymentSettlementOfflineExportCompleteOutputReceipt(receiptArg);
|
|
2403
|
+
const journal = normalizeCloudlyLegacyDeploymentSettlementOfflineExportAttemptJournal(journalArg);
|
|
2404
|
+
assertCompleteOutputReceiptMatchesJournal(
|
|
2405
|
+
receipt,
|
|
2406
|
+
journal,
|
|
2407
|
+
'offlineExportTransformResult.completeOutputReceipt',
|
|
2408
|
+
);
|
|
2409
|
+
if (result.completeOutputReceiptSha256
|
|
2410
|
+
!== digestCloudlyLegacyDeploymentSettlementOfflineExportCompleteOutputReceipt(receipt)
|
|
2411
|
+
|| !canonicalEqual(
|
|
2412
|
+
result.sourceAuthority,
|
|
2413
|
+
receipt.sourceAuthority,
|
|
2414
|
+
'offlineExportTransformResult.sourceAuthority',
|
|
2415
|
+
)
|
|
2416
|
+
|| !canonicalEqual(
|
|
2417
|
+
result.productionTransformAuthority,
|
|
2418
|
+
receipt.authority,
|
|
2419
|
+
'offlineExportTransformResult.productionTransformAuthority',
|
|
2420
|
+
)
|
|
2421
|
+
|| result.operationId !== receipt.operationId
|
|
2422
|
+
|| result.settlementId !== receipt.settlementId
|
|
2423
|
+
|| result.attemptId !== receipt.attemptId
|
|
2424
|
+
|| result.planSha256 !== journal.planSha256
|
|
2425
|
+
|| result.requestSha256 !== journal.requestSha256
|
|
2426
|
+
|| result.outcome !== journal.outcome
|
|
2427
|
+
|| !canonicalEqual(result.counts, journal.counts, 'offlineExportTransformResult.counts')
|
|
2428
|
+
|| !canonicalEqual(
|
|
2429
|
+
result.classificationCounts,
|
|
2430
|
+
journal.classificationCounts,
|
|
2431
|
+
'offlineExportTransformResult.classificationCounts',
|
|
2432
|
+
)
|
|
2433
|
+
|| result.completedAt !== receipt.completedAt) {
|
|
2434
|
+
fail('CROSS_FIELD_MISMATCH', 'offlineExportTransformResult.completeOutputReceipt');
|
|
2435
|
+
}
|
|
2436
|
+
return result;
|
|
2437
|
+
};
|
|
2438
|
+
|
|
2439
|
+
export const normalizeCloudlyLegacyDeploymentSettlementOfflineExportTransformResultForAuthorities = async (
|
|
2440
|
+
resultArg: unknown,
|
|
2441
|
+
receiptArg: unknown,
|
|
2442
|
+
journalArg: unknown,
|
|
2443
|
+
authorizationArg: unknown,
|
|
2444
|
+
productionAuthorityArg: unknown,
|
|
2445
|
+
sourceAuthorityArg: unknown,
|
|
2446
|
+
rehearsalAttestationArg: unknown,
|
|
2447
|
+
verifierArg: TCloudlyLegacyDeploymentSettlementOfflineExportHmacVerifier,
|
|
2448
|
+
): Promise<Readonly<
|
|
2449
|
+
ICloudlyLegacyDeploymentSettlementOfflineExportTransformResultV1
|
|
2450
|
+
>> => {
|
|
2451
|
+
const receipt =
|
|
2452
|
+
await normalizeCloudlyLegacyDeploymentSettlementOfflineExportCompleteOutputReceiptForAuthorities(
|
|
2453
|
+
receiptArg,
|
|
2454
|
+
journalArg,
|
|
2455
|
+
authorizationArg,
|
|
2456
|
+
productionAuthorityArg,
|
|
2457
|
+
sourceAuthorityArg,
|
|
2458
|
+
rehearsalAttestationArg,
|
|
2459
|
+
verifierArg,
|
|
2460
|
+
);
|
|
2461
|
+
return normalizeCloudlyLegacyDeploymentSettlementOfflineExportTransformResultForCompleteOutputReceipt(
|
|
2462
|
+
resultArg,
|
|
2463
|
+
receipt,
|
|
2464
|
+
journalArg,
|
|
2465
|
+
);
|
|
2466
|
+
};
|
|
2467
|
+
|
|
2468
|
+
export {
|
|
2469
|
+
cloudlyLegacyDeploymentSettlementOfflineExportGoldenVectors,
|
|
2470
|
+
} from './runtime.cloudlylegacydeploymentsettlement.offlineexport.golden.js';
|