@serve.zone/interfaces 27.2.0 → 27.3.1
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 +18 -0
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/runtime.cloudlylegacydeploymentsettlement.d.ts +513 -5
- package/dist_ts/runtime.cloudlylegacydeploymentsettlement.js +1946 -10
- package/dist_ts/runtime.corestore.d.ts +89 -0
- package/dist_ts/runtime.corestore.js +306 -2
- package/package.json +1 -1
- package/readme.md +78 -1
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/runtime.cloudlylegacydeploymentsettlement.ts +3764 -19
- package/ts/runtime.corestore.ts +608 -0
|
@@ -37,6 +37,12 @@ export const cloudlyLegacyDeploymentSettlementDomains = Object.freeze({
|
|
|
37
37
|
'serve.zone/cloudly-legacy-deployment-settlement/scratch-receipt-hmac-v1\0',
|
|
38
38
|
productionReceiptHmac:
|
|
39
39
|
'serve.zone/cloudly-legacy-deployment-settlement/production-receipt-hmac-v1\0',
|
|
40
|
+
productionExecutionAuthorizationHmac:
|
|
41
|
+
'serve.zone/cloudly-legacy-deployment-settlement/production-execution-authorization-hmac-v1\0',
|
|
42
|
+
productionReceiptV2Hmac:
|
|
43
|
+
'serve.zone/cloudly-legacy-deployment-settlement/production-receipt-hmac-v2\0',
|
|
44
|
+
resolutionHmac:
|
|
45
|
+
'serve.zone/cloudly-legacy-deployment-settlement/resolution-recovery-attestation-hmac-v1\0',
|
|
40
46
|
} as const);
|
|
41
47
|
|
|
42
48
|
export type TCloudlyLegacyDeploymentSettlementCodecErrorCode =
|
|
@@ -84,8 +90,7 @@ export interface ICloudlyLegacyDeploymentSettlementAuthorityReferenceV1 {
|
|
|
84
90
|
authorityMetadataSha256: string;
|
|
85
91
|
}
|
|
86
92
|
|
|
87
|
-
|
|
88
|
-
{
|
|
93
|
+
interface ICloudlyLegacyDeploymentSettlementAuthorityMetadataBaseV1 {
|
|
89
94
|
schemaVersion: 1;
|
|
90
95
|
operationId: string;
|
|
91
96
|
authorityId: string;
|
|
@@ -115,6 +120,47 @@ export interface ICloudlyLegacyDeploymentSettlementAuthorityMetadataV1
|
|
|
115
120
|
digestProofSha256: string;
|
|
116
121
|
}
|
|
117
122
|
|
|
123
|
+
export interface ICloudlyLegacyDeploymentSettlementAuthorityMetadataV1
|
|
124
|
+
extends ICloudlyLegacyDeploymentSettlementAuthorityMetadataBaseV1 {
|
|
125
|
+
executionProtocol?: 'fenced-attempt-v1';
|
|
126
|
+
sourceAuthority?: ICloudlyLegacyDeploymentSettlementAuthorityReferenceV1;
|
|
127
|
+
sourceAuthenticatedPlanSha256?: string;
|
|
128
|
+
sourceRequestBundleSha256?: string;
|
|
129
|
+
scratchReceiptSha256?: string;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export interface ICloudlyLegacyDeploymentSettlementLegacyAuthorityMetadataV1
|
|
133
|
+
extends ICloudlyLegacyDeploymentSettlementAuthorityMetadataBaseV1 {
|
|
134
|
+
executionProtocol?: never;
|
|
135
|
+
sourceAuthority?: never;
|
|
136
|
+
sourceAuthenticatedPlanSha256?: never;
|
|
137
|
+
sourceRequestBundleSha256?: never;
|
|
138
|
+
scratchReceiptSha256?: never;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export interface ICloudlyLegacyDeploymentSettlementFencedSourceAuthorityMetadataV1
|
|
142
|
+
extends ICloudlyLegacyDeploymentSettlementAuthorityMetadataBaseV1 {
|
|
143
|
+
executionProtocol: 'fenced-attempt-v1';
|
|
144
|
+
sourceAuthority?: never;
|
|
145
|
+
sourceAuthenticatedPlanSha256?: never;
|
|
146
|
+
sourceRequestBundleSha256?: never;
|
|
147
|
+
scratchReceiptSha256?: never;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export interface ICloudlyLegacyDeploymentSettlementFencedProductionAuthorityMetadataV1
|
|
151
|
+
extends ICloudlyLegacyDeploymentSettlementAuthorityMetadataBaseV1 {
|
|
152
|
+
executionProtocol: 'fenced-attempt-v1';
|
|
153
|
+
sourceAuthority: ICloudlyLegacyDeploymentSettlementAuthorityReferenceV1;
|
|
154
|
+
sourceAuthenticatedPlanSha256: string;
|
|
155
|
+
sourceRequestBundleSha256: string;
|
|
156
|
+
scratchReceiptSha256: string;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export type TCloudlyLegacyDeploymentSettlementAuthorityMetadataV1 =
|
|
160
|
+
| ICloudlyLegacyDeploymentSettlementLegacyAuthorityMetadataV1
|
|
161
|
+
| ICloudlyLegacyDeploymentSettlementFencedSourceAuthorityMetadataV1
|
|
162
|
+
| ICloudlyLegacyDeploymentSettlementFencedProductionAuthorityMetadataV1;
|
|
163
|
+
|
|
118
164
|
/** Private plaintext HMAC key. Never persist, log, or place in summaries or receipts. */
|
|
119
165
|
export interface ICloudlyLegacyDeploymentSettlementHmacKeyPlaintextV1 {
|
|
120
166
|
format: 'raw-32-byte-base64url';
|
|
@@ -123,9 +169,9 @@ export interface ICloudlyLegacyDeploymentSettlementHmacKeyPlaintextV1 {
|
|
|
123
169
|
|
|
124
170
|
/**
|
|
125
171
|
* Exact private-file handoff parsed by pinned maintenance containers.
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
172
|
+
* Consumers own secure generation, storage, use, and destruction of the key.
|
|
173
|
+
* Interfaces never generates, persists, or logs it; the private stdio verifier
|
|
174
|
+
* transiently decodes it for HMAC verification and wipes the decoded bytes.
|
|
129
175
|
*/
|
|
130
176
|
export interface ICloudlyLegacyDeploymentSettlementAuthorityHandoffPlaintextV1 {
|
|
131
177
|
schemaVersion: 1;
|
|
@@ -444,6 +490,38 @@ const authorityMetadataKeys = [
|
|
|
444
490
|
'restoredDataSha256',
|
|
445
491
|
'digestProofSha256',
|
|
446
492
|
] as const;
|
|
493
|
+
const authorityMetadataOptionalKeys = [
|
|
494
|
+
'executionProtocol',
|
|
495
|
+
'sourceAuthority',
|
|
496
|
+
'sourceAuthenticatedPlanSha256',
|
|
497
|
+
'sourceRequestBundleSha256',
|
|
498
|
+
'scratchReceiptSha256',
|
|
499
|
+
] as const;
|
|
500
|
+
const authorityMetadataCrossAuthorityKeys = [
|
|
501
|
+
'schemaVersion',
|
|
502
|
+
'operationId',
|
|
503
|
+
'keyVersion',
|
|
504
|
+
'settlementId',
|
|
505
|
+
'maintenanceImageDigest',
|
|
506
|
+
'sourceImageDigest',
|
|
507
|
+
'targetImageDigest',
|
|
508
|
+
'targetVersion',
|
|
509
|
+
'targetManifestSha256',
|
|
510
|
+
'targetConfigSha256',
|
|
511
|
+
'backupId',
|
|
512
|
+
'backupSnapshotIdSha256',
|
|
513
|
+
'backupProofSha256',
|
|
514
|
+
'runId',
|
|
515
|
+
'rehearsalId',
|
|
516
|
+
'scratchServiceId',
|
|
517
|
+
'allocationId',
|
|
518
|
+
'allocationGeneration',
|
|
519
|
+
'allocationBindingSha256',
|
|
520
|
+
'allocationReceiptSha256',
|
|
521
|
+
'sourceDataSha256',
|
|
522
|
+
'restoredDataSha256',
|
|
523
|
+
'digestProofSha256',
|
|
524
|
+
] as const;
|
|
447
525
|
const classificationKeys = [
|
|
448
526
|
'image-recorded-not-current',
|
|
449
527
|
'image-recorded-current-failed',
|
|
@@ -662,14 +740,14 @@ const finalize = <T>(
|
|
|
662
740
|
};
|
|
663
741
|
|
|
664
742
|
const encodeNormalized = (valueArg: unknown, pathArg: string): Uint8Array => (
|
|
665
|
-
|
|
743
|
+
Buffer.from(canonicalize(valueArg, pathArg), 'utf8')
|
|
666
744
|
);
|
|
667
745
|
|
|
668
746
|
const frame = (domainArg: string, payloadArg: Uint8Array): Uint8Array => {
|
|
669
747
|
const domain = Buffer.from(domainArg, 'utf8');
|
|
670
748
|
const output = new Uint8Array(domain.byteLength + payloadArg.byteLength);
|
|
671
749
|
output.set(domain, 0);
|
|
672
|
-
output.set(
|
|
750
|
+
output.set(payloadArg, domain.byteLength);
|
|
673
751
|
return output;
|
|
674
752
|
};
|
|
675
753
|
|
|
@@ -707,9 +785,10 @@ export const normalizeCloudlyLegacyDeploymentSettlementAuthorityReference = (
|
|
|
707
785
|
const normalizeAuthorityMetadataInternal = (
|
|
708
786
|
valueArg: unknown,
|
|
709
787
|
pathArg: string,
|
|
710
|
-
):
|
|
788
|
+
): TCloudlyLegacyDeploymentSettlementAuthorityMetadataV1 => {
|
|
711
789
|
const value = readRecord(valueArg, pathArg);
|
|
712
|
-
|
|
790
|
+
const optionalKeys = authorityMetadataOptionalKeys.filter((keyArg) => Object.hasOwn(value, keyArg));
|
|
791
|
+
assertExactKeys(value, [...authorityMetadataKeys, ...optionalKeys], pathArg);
|
|
713
792
|
if (value.schemaVersion !== 1 || value.keyVersion !== 1) {
|
|
714
793
|
fail('INVALID_VALUE', `${pathArg}.schemaVersion`);
|
|
715
794
|
}
|
|
@@ -731,11 +810,37 @@ const normalizeAuthorityMetadataInternal = (
|
|
|
731
810
|
if (sourceDataSha256 !== restoredDataSha256) {
|
|
732
811
|
fail('CROSS_FIELD_MISMATCH', `${pathArg}.restoredDataSha256`);
|
|
733
812
|
}
|
|
734
|
-
|
|
813
|
+
const predecessorKeys = authorityMetadataOptionalKeys.filter((keyArg) => (
|
|
814
|
+
keyArg !== 'executionProtocol'
|
|
815
|
+
));
|
|
816
|
+
const hasExecutionProtocol = Object.hasOwn(value, 'executionProtocol');
|
|
817
|
+
const predecessorKeyCount = predecessorKeys.filter((keyArg) => Object.hasOwn(value, keyArg)).length;
|
|
818
|
+
if (hasExecutionProtocol && value.executionProtocol !== 'fenced-attempt-v1') {
|
|
819
|
+
fail('INVALID_VALUE', `${pathArg}.executionProtocol`);
|
|
820
|
+
}
|
|
821
|
+
if (predecessorKeyCount !== 0 && predecessorKeyCount !== predecessorKeys.length) {
|
|
822
|
+
fail('INVALID_SCHEMA', `${pathArg}.sourceAuthority`);
|
|
823
|
+
}
|
|
824
|
+
if (predecessorKeyCount > 0 && !hasExecutionProtocol) {
|
|
825
|
+
fail('CROSS_FIELD_MISMATCH', `${pathArg}.executionProtocol`);
|
|
826
|
+
}
|
|
827
|
+
const operationId = readIdentifier(value.operationId, `${pathArg}.operationId`);
|
|
828
|
+
const authorityId = readIdentifier(value.authorityId, `${pathArg}.authorityId`);
|
|
829
|
+
const keyId = readIdentifier(value.keyId, `${pathArg}.keyId`);
|
|
830
|
+
const sourceAuthority = predecessorKeyCount === 0
|
|
831
|
+
? undefined
|
|
832
|
+
: normalizeAuthorityReferenceInternal(value.sourceAuthority, `${pathArg}.sourceAuthority`);
|
|
833
|
+
if (sourceAuthority
|
|
834
|
+
&& (sourceAuthority.operationId !== operationId
|
|
835
|
+
|| sourceAuthority.authorityId === authorityId
|
|
836
|
+
|| sourceAuthority.keyId === keyId)) {
|
|
837
|
+
fail('CROSS_FIELD_MISMATCH', `${pathArg}.sourceAuthority`);
|
|
838
|
+
}
|
|
839
|
+
const common: ICloudlyLegacyDeploymentSettlementAuthorityMetadataBaseV1 = {
|
|
735
840
|
schemaVersion: 1,
|
|
736
|
-
operationId
|
|
737
|
-
authorityId
|
|
738
|
-
keyId
|
|
841
|
+
operationId,
|
|
842
|
+
authorityId,
|
|
843
|
+
keyId,
|
|
739
844
|
keyVersion: 1,
|
|
740
845
|
settlementId: readIdentifier(value.settlementId, `${pathArg}.settlementId`),
|
|
741
846
|
issuedAt,
|
|
@@ -779,11 +884,37 @@ const normalizeAuthorityMetadataInternal = (
|
|
|
779
884
|
restoredDataSha256,
|
|
780
885
|
digestProofSha256: readSha256(value.digestProofSha256, `${pathArg}.digestProofSha256`),
|
|
781
886
|
};
|
|
887
|
+
if (!hasExecutionProtocol) {
|
|
888
|
+
return common as ICloudlyLegacyDeploymentSettlementLegacyAuthorityMetadataV1;
|
|
889
|
+
}
|
|
890
|
+
if (!sourceAuthority) {
|
|
891
|
+
return {
|
|
892
|
+
...common,
|
|
893
|
+
executionProtocol: 'fenced-attempt-v1',
|
|
894
|
+
} as ICloudlyLegacyDeploymentSettlementFencedSourceAuthorityMetadataV1;
|
|
895
|
+
}
|
|
896
|
+
return {
|
|
897
|
+
...common,
|
|
898
|
+
executionProtocol: 'fenced-attempt-v1',
|
|
899
|
+
sourceAuthority,
|
|
900
|
+
sourceAuthenticatedPlanSha256: readSha256(
|
|
901
|
+
value.sourceAuthenticatedPlanSha256,
|
|
902
|
+
`${pathArg}.sourceAuthenticatedPlanSha256`,
|
|
903
|
+
),
|
|
904
|
+
sourceRequestBundleSha256: readSha256(
|
|
905
|
+
value.sourceRequestBundleSha256,
|
|
906
|
+
`${pathArg}.sourceRequestBundleSha256`,
|
|
907
|
+
),
|
|
908
|
+
scratchReceiptSha256: readSha256(
|
|
909
|
+
value.scratchReceiptSha256,
|
|
910
|
+
`${pathArg}.scratchReceiptSha256`,
|
|
911
|
+
),
|
|
912
|
+
} as ICloudlyLegacyDeploymentSettlementFencedProductionAuthorityMetadataV1;
|
|
782
913
|
};
|
|
783
914
|
|
|
784
915
|
export const normalizeCloudlyLegacyDeploymentSettlementAuthorityMetadata = (
|
|
785
916
|
valueArg: unknown,
|
|
786
|
-
): Readonly<
|
|
917
|
+
): Readonly<TCloudlyLegacyDeploymentSettlementAuthorityMetadataV1> => finalize(
|
|
787
918
|
normalizeAuthorityMetadataInternal(valueArg, 'authorityMetadata'),
|
|
788
919
|
cloudlyLegacyDeploymentSettlementLimits.maximumAuthorityBytes,
|
|
789
920
|
'authorityMetadata',
|
|
@@ -834,6 +965,81 @@ export const normalizeCloudlyLegacyDeploymentSettlementAuthorityReferenceForMeta
|
|
|
834
965
|
return reference;
|
|
835
966
|
};
|
|
836
967
|
|
|
968
|
+
const normalizeFencedSourceAuthorityMetadata = (
|
|
969
|
+
metadataArg: unknown,
|
|
970
|
+
pathArg: string,
|
|
971
|
+
): Readonly<ICloudlyLegacyDeploymentSettlementFencedSourceAuthorityMetadataV1> => {
|
|
972
|
+
const metadata = normalizeCloudlyLegacyDeploymentSettlementAuthorityMetadata(metadataArg);
|
|
973
|
+
if (metadata.executionProtocol !== 'fenced-attempt-v1'
|
|
974
|
+
|| Object.hasOwn(metadata, 'sourceAuthority')) {
|
|
975
|
+
fail('CROSS_FIELD_MISMATCH', pathArg);
|
|
976
|
+
}
|
|
977
|
+
return metadata as Readonly<
|
|
978
|
+
ICloudlyLegacyDeploymentSettlementFencedSourceAuthorityMetadataV1
|
|
979
|
+
>;
|
|
980
|
+
};
|
|
981
|
+
|
|
982
|
+
const normalizeProductionAuthorityMetadataPair = (
|
|
983
|
+
productionMetadataArg: unknown,
|
|
984
|
+
sourceMetadataArg: unknown,
|
|
985
|
+
): {
|
|
986
|
+
productionMetadata: Readonly<
|
|
987
|
+
ICloudlyLegacyDeploymentSettlementFencedProductionAuthorityMetadataV1
|
|
988
|
+
>;
|
|
989
|
+
sourceMetadata: Readonly<ICloudlyLegacyDeploymentSettlementFencedSourceAuthorityMetadataV1>;
|
|
990
|
+
} => {
|
|
991
|
+
const productionMetadata = normalizeCloudlyLegacyDeploymentSettlementAuthorityMetadata(
|
|
992
|
+
productionMetadataArg,
|
|
993
|
+
);
|
|
994
|
+
const sourceMetadata = normalizeFencedSourceAuthorityMetadata(
|
|
995
|
+
sourceMetadataArg,
|
|
996
|
+
'sourceAuthorityMetadata',
|
|
997
|
+
);
|
|
998
|
+
if (productionMetadata.executionProtocol !== 'fenced-attempt-v1'
|
|
999
|
+
|| !Object.hasOwn(productionMetadata, 'sourceAuthority')) {
|
|
1000
|
+
fail('CROSS_FIELD_MISMATCH', 'productionAuthorityMetadata');
|
|
1001
|
+
}
|
|
1002
|
+
const fencedSourceMetadata = sourceMetadata;
|
|
1003
|
+
const fencedProductionMetadata = productionMetadata as Readonly<
|
|
1004
|
+
ICloudlyLegacyDeploymentSettlementFencedProductionAuthorityMetadataV1
|
|
1005
|
+
>;
|
|
1006
|
+
const sourceAuthority = createCloudlyLegacyDeploymentSettlementAuthorityReference(
|
|
1007
|
+
fencedSourceMetadata,
|
|
1008
|
+
);
|
|
1009
|
+
const productionAuthority = createCloudlyLegacyDeploymentSettlementAuthorityReference(
|
|
1010
|
+
fencedProductionMetadata,
|
|
1011
|
+
);
|
|
1012
|
+
const sourceContext = Object.fromEntries(authorityMetadataCrossAuthorityKeys.map((keyArg) => [
|
|
1013
|
+
keyArg,
|
|
1014
|
+
fencedSourceMetadata[keyArg],
|
|
1015
|
+
]));
|
|
1016
|
+
const productionContext = Object.fromEntries(authorityMetadataCrossAuthorityKeys.map((keyArg) => [
|
|
1017
|
+
keyArg,
|
|
1018
|
+
fencedProductionMetadata[keyArg],
|
|
1019
|
+
]));
|
|
1020
|
+
if (canonicalize(fencedProductionMetadata.sourceAuthority, 'productionMetadata.sourceAuthority')
|
|
1021
|
+
!== canonicalize(sourceAuthority, 'sourceMetadata.authority')
|
|
1022
|
+
|| canonicalize(productionAuthority, 'productionMetadata.authority')
|
|
1023
|
+
=== canonicalize(sourceAuthority, 'sourceMetadata.authority')
|
|
1024
|
+
|| fencedProductionMetadata.authorityId === fencedSourceMetadata.authorityId
|
|
1025
|
+
|| fencedProductionMetadata.keyId === fencedSourceMetadata.keyId
|
|
1026
|
+
|| canonicalize(productionContext, 'productionMetadata.context')
|
|
1027
|
+
!== canonicalize(sourceContext, 'sourceMetadata.context')) {
|
|
1028
|
+
fail('CROSS_FIELD_MISMATCH', 'productionAuthorityMetadata.sourceAuthority');
|
|
1029
|
+
}
|
|
1030
|
+
return {
|
|
1031
|
+
productionMetadata: fencedProductionMetadata,
|
|
1032
|
+
sourceMetadata: fencedSourceMetadata,
|
|
1033
|
+
};
|
|
1034
|
+
};
|
|
1035
|
+
|
|
1036
|
+
export const normalizeCloudlyLegacyDeploymentSettlementProductionAuthorityMetadataForSourceAuthority = (
|
|
1037
|
+
productionMetadataArg: unknown,
|
|
1038
|
+
sourceMetadataArg: unknown,
|
|
1039
|
+
): Readonly<ICloudlyLegacyDeploymentSettlementFencedProductionAuthorityMetadataV1> => (
|
|
1040
|
+
normalizeProductionAuthorityMetadataPair(productionMetadataArg, sourceMetadataArg).productionMetadata
|
|
1041
|
+
);
|
|
1042
|
+
|
|
837
1043
|
export const normalizeCloudlyLegacyDeploymentSettlementAuthorityHandoffPlaintext = (
|
|
838
1044
|
valueArg: unknown,
|
|
839
1045
|
): Readonly<ICloudlyLegacyDeploymentSettlementAuthorityHandoffPlaintextV1> => {
|
|
@@ -875,8 +1081,12 @@ export const normalizeCloudlyLegacyDeploymentSettlementAuthorityHandoffPlaintext
|
|
|
875
1081
|
fail('INVALID_VALUE', 'authorityHandoffPlaintext.hmacKeyPlaintext');
|
|
876
1082
|
}
|
|
877
1083
|
const keyBytes = Buffer.from(keyValue, 'base64url');
|
|
878
|
-
|
|
879
|
-
|
|
1084
|
+
try {
|
|
1085
|
+
if (keyBytes.byteLength !== 32 || keyBytes.toString('base64url') !== keyValue) {
|
|
1086
|
+
fail('INVALID_VALUE', 'authorityHandoffPlaintext.hmacKeyPlaintext.value');
|
|
1087
|
+
}
|
|
1088
|
+
} finally {
|
|
1089
|
+
keyBytes.fill(0);
|
|
880
1090
|
}
|
|
881
1091
|
return finalize({
|
|
882
1092
|
schemaVersion: 1,
|
|
@@ -894,6 +1104,61 @@ export const encodeCloudlyLegacyDeploymentSettlementAuthorityHandoffPlaintext =
|
|
|
894
1104
|
'authorityHandoffPlaintext',
|
|
895
1105
|
);
|
|
896
1106
|
|
|
1107
|
+
/**
|
|
1108
|
+
* Private in-process stdio handoff verification only. Do not persist or log the
|
|
1109
|
+
* handoff or returned verifier; discard both as soon as the stdio exchange ends.
|
|
1110
|
+
*/
|
|
1111
|
+
export const createCloudlyLegacyDeploymentSettlementStdioHandoffHmacVerifier = (
|
|
1112
|
+
handoffArg: unknown,
|
|
1113
|
+
): TCloudlyLegacyDeploymentSettlementHmacVerifier => {
|
|
1114
|
+
const handoff = normalizeCloudlyLegacyDeploymentSettlementAuthorityHandoffPlaintext(
|
|
1115
|
+
handoffArg,
|
|
1116
|
+
);
|
|
1117
|
+
const authorityCanonical = canonicalize(
|
|
1118
|
+
handoff.authorityReference,
|
|
1119
|
+
'stdioHandoffHmacVerifier.authority',
|
|
1120
|
+
);
|
|
1121
|
+
const keyValue = handoff.hmacKeyPlaintext.value;
|
|
1122
|
+
return (inputArg): boolean => {
|
|
1123
|
+
let keyBytes: Buffer | undefined;
|
|
1124
|
+
let suppliedMacBytes: Buffer | undefined;
|
|
1125
|
+
let expectedMacBytes: Buffer | undefined;
|
|
1126
|
+
try {
|
|
1127
|
+
if (!(inputArg.hmacInput instanceof Uint8Array)
|
|
1128
|
+
|| canonicalize(inputArg.authority, 'stdioHandoffHmacVerifier.input.authority')
|
|
1129
|
+
!== authorityCanonical
|
|
1130
|
+
|| !macPattern.test(inputArg.mac)) {
|
|
1131
|
+
return false;
|
|
1132
|
+
}
|
|
1133
|
+
const domainBytes = Buffer.from(inputArg.domain, 'utf8');
|
|
1134
|
+
const hmacInputBytes = Buffer.from(inputArg.hmacInput);
|
|
1135
|
+
if (hmacInputBytes.byteLength < domainBytes.byteLength
|
|
1136
|
+
|| !hmacInputBytes.subarray(0, domainBytes.byteLength).equals(domainBytes)) {
|
|
1137
|
+
return false;
|
|
1138
|
+
}
|
|
1139
|
+
keyBytes = Buffer.from(keyValue, 'base64url');
|
|
1140
|
+
suppliedMacBytes = Buffer.from(inputArg.mac, 'base64url');
|
|
1141
|
+
if (keyBytes.byteLength !== 32
|
|
1142
|
+
|| keyBytes.toString('base64url') !== keyValue
|
|
1143
|
+
|| suppliedMacBytes.byteLength !== 32
|
|
1144
|
+
|| suppliedMacBytes.toString('base64url') !== inputArg.mac) {
|
|
1145
|
+
return false;
|
|
1146
|
+
}
|
|
1147
|
+
expectedMacBytes = plugins.crypto
|
|
1148
|
+
.createHmac('sha256', keyBytes)
|
|
1149
|
+
.update(hmacInputBytes)
|
|
1150
|
+
.digest();
|
|
1151
|
+
return plugins.crypto.timingSafeEqual(expectedMacBytes, suppliedMacBytes);
|
|
1152
|
+
} catch {
|
|
1153
|
+
return false;
|
|
1154
|
+
} finally {
|
|
1155
|
+
keyBytes?.fill(0);
|
|
1156
|
+
suppliedMacBytes?.fill(0);
|
|
1157
|
+
expectedMacBytes?.fill(0);
|
|
1158
|
+
}
|
|
1159
|
+
};
|
|
1160
|
+
};
|
|
1161
|
+
|
|
897
1162
|
const normalizeClassificationCounts = (
|
|
898
1163
|
valueArg: unknown,
|
|
899
1164
|
pathArg: string,
|
|
@@ -2321,7 +2586,7 @@ const requireConsumerVerifiedHmac = async (
|
|
|
2321
2586
|
|
|
2322
2587
|
const assertAuthorityTimestamp = (
|
|
2323
2588
|
timestampArg: number,
|
|
2324
|
-
metadataArg:
|
|
2589
|
+
metadataArg: TCloudlyLegacyDeploymentSettlementAuthorityMetadataV1,
|
|
2325
2590
|
pathArg: string,
|
|
2326
2591
|
): void => {
|
|
2327
2592
|
if (timestampArg < metadataArg.issuedAt || timestampArg >= metadataArg.expiresAt) {
|
|
@@ -2331,7 +2596,7 @@ const assertAuthorityTimestamp = (
|
|
|
2331
2596
|
|
|
2332
2597
|
const assertAuthorityReferenceMatchesMetadata = (
|
|
2333
2598
|
referenceArg: unknown,
|
|
2334
|
-
metadataArg:
|
|
2599
|
+
metadataArg: TCloudlyLegacyDeploymentSettlementAuthorityMetadataV1,
|
|
2335
2600
|
pathArg: string,
|
|
2336
2601
|
): void => {
|
|
2337
2602
|
try {
|
|
@@ -2346,7 +2611,7 @@ const assertAuthorityReferenceMatchesMetadata = (
|
|
|
2346
2611
|
|
|
2347
2612
|
const assertRehearsalBindingMatchesAuthorityMetadata = (
|
|
2348
2613
|
bindingArg: ICloudlyLegacyDeploymentSettlementRehearsalBindingV1,
|
|
2349
|
-
metadataArg:
|
|
2614
|
+
metadataArg: TCloudlyLegacyDeploymentSettlementAuthorityMetadataV1,
|
|
2350
2615
|
pathArg: string,
|
|
2351
2616
|
): void => {
|
|
2352
2617
|
const expected = {
|
|
@@ -2882,4 +3147,3484 @@ export const normalizeCloudlyLegacyDeploymentSettlementProductionReceiptStructur
|
|
|
2882
3147
|
return receipt;
|
|
2883
3148
|
};
|
|
2884
3149
|
|
|
3150
|
+
export interface ICloudlyLegacyDeploymentSettlementRequestBundleV1 {
|
|
3151
|
+
schemaVersion: 1;
|
|
3152
|
+
kind: 'cloudly-legacy-deployment-settlement-request-bundle';
|
|
3153
|
+
authenticatedRehearsalBinding:
|
|
3154
|
+
IAuthenticatedCloudlyLegacyDeploymentSettlementRehearsalBindingV1;
|
|
3155
|
+
authenticatedRequest: IAuthenticatedCloudlyLegacyDeploymentSettlementProductionRequestV1;
|
|
3156
|
+
}
|
|
3157
|
+
|
|
3158
|
+
export type TCloudlyLegacyDeploymentSettlementExecutionPurpose =
|
|
3159
|
+
| 'scratch-rehearsal'
|
|
3160
|
+
| 'production';
|
|
3161
|
+
|
|
3162
|
+
export interface ICloudlyLegacyDeploymentSettlementExecutionAttemptIdentityV1 {
|
|
3163
|
+
schemaVersion: 1;
|
|
3164
|
+
kind: 'cloudly-legacy-deployment-settlement-execution-attempt-identity';
|
|
3165
|
+
attemptId: string;
|
|
3166
|
+
purpose: TCloudlyLegacyDeploymentSettlementExecutionPurpose;
|
|
3167
|
+
operationId: string;
|
|
3168
|
+
settlementId: string;
|
|
3169
|
+
executionAuthority: ICloudlyLegacyDeploymentSettlementAuthorityReferenceV1;
|
|
3170
|
+
sourceAuthority: ICloudlyLegacyDeploymentSettlementAuthorityReferenceV1;
|
|
3171
|
+
authenticatedPlanSha256: string;
|
|
3172
|
+
requestBundleSha256: string;
|
|
3173
|
+
scratchReceiptSha256: string | null;
|
|
3174
|
+
}
|
|
3175
|
+
|
|
3176
|
+
export type TCloudlyLegacyDeploymentSettlementScratchExecutionAttemptIdentityV1 =
|
|
3177
|
+
ICloudlyLegacyDeploymentSettlementExecutionAttemptIdentityV1 & {
|
|
3178
|
+
purpose: 'scratch-rehearsal';
|
|
3179
|
+
scratchReceiptSha256: null;
|
|
3180
|
+
};
|
|
3181
|
+
export type TCloudlyLegacyDeploymentSettlementProductionExecutionAttemptIdentityV1 =
|
|
3182
|
+
ICloudlyLegacyDeploymentSettlementExecutionAttemptIdentityV1 & {
|
|
3183
|
+
purpose: 'production';
|
|
3184
|
+
scratchReceiptSha256: string;
|
|
3185
|
+
};
|
|
3186
|
+
export type TCloudlyLegacyDeploymentSettlementExecutionAttemptIdentityV1 =
|
|
3187
|
+
| TCloudlyLegacyDeploymentSettlementScratchExecutionAttemptIdentityV1
|
|
3188
|
+
| TCloudlyLegacyDeploymentSettlementProductionExecutionAttemptIdentityV1;
|
|
3189
|
+
|
|
3190
|
+
export interface ICloudlyLegacyDeploymentSettlementExecutionAttemptPreparedV1 {
|
|
3191
|
+
schemaVersion: 1;
|
|
3192
|
+
kind: 'cloudly-legacy-deployment-settlement-execution-attempt-observation';
|
|
3193
|
+
identity: TCloudlyLegacyDeploymentSettlementExecutionAttemptIdentityV1;
|
|
3194
|
+
state: 'prepared';
|
|
3195
|
+
preparedAt: number;
|
|
3196
|
+
}
|
|
3197
|
+
|
|
3198
|
+
export interface ICloudlyLegacyDeploymentSettlementExecutionAttemptCommittedV1 {
|
|
3199
|
+
schemaVersion: 1;
|
|
3200
|
+
kind: 'cloudly-legacy-deployment-settlement-execution-attempt-observation';
|
|
3201
|
+
identity: TCloudlyLegacyDeploymentSettlementExecutionAttemptIdentityV1;
|
|
3202
|
+
state: 'committed';
|
|
3203
|
+
preparedAt: number;
|
|
3204
|
+
resolvedAt: number;
|
|
3205
|
+
receiptSchemaVersion: 1 | 2;
|
|
3206
|
+
receiptSha256: string;
|
|
3207
|
+
}
|
|
3208
|
+
|
|
3209
|
+
export interface ICloudlyLegacyDeploymentSettlementExecutionAttemptAbortedV1 {
|
|
3210
|
+
schemaVersion: 1;
|
|
3211
|
+
kind: 'cloudly-legacy-deployment-settlement-execution-attempt-observation';
|
|
3212
|
+
identity: TCloudlyLegacyDeploymentSettlementExecutionAttemptIdentityV1;
|
|
3213
|
+
state: 'aborted';
|
|
3214
|
+
preparedAt: number;
|
|
3215
|
+
resolvedAt: number;
|
|
3216
|
+
}
|
|
3217
|
+
|
|
3218
|
+
export type TCloudlyLegacyDeploymentSettlementExecutionAttemptObservationV1 =
|
|
3219
|
+
| ICloudlyLegacyDeploymentSettlementExecutionAttemptPreparedV1
|
|
3220
|
+
| ICloudlyLegacyDeploymentSettlementExecutionAttemptCommittedV1
|
|
3221
|
+
| ICloudlyLegacyDeploymentSettlementExecutionAttemptAbortedV1;
|
|
3222
|
+
|
|
3223
|
+
const requestBundleKeys = [
|
|
3224
|
+
'schemaVersion',
|
|
3225
|
+
'kind',
|
|
3226
|
+
'authenticatedRehearsalBinding',
|
|
3227
|
+
'authenticatedRequest',
|
|
3228
|
+
] as const;
|
|
3229
|
+
|
|
3230
|
+
export const normalizeCloudlyLegacyDeploymentSettlementRequestBundle = (
|
|
3231
|
+
valueArg: unknown,
|
|
3232
|
+
): Readonly<ICloudlyLegacyDeploymentSettlementRequestBundleV1> => {
|
|
3233
|
+
const value = readRecord(valueArg, 'requestBundle');
|
|
3234
|
+
assertExactKeys(value, requestBundleKeys, 'requestBundle');
|
|
3235
|
+
if (value.schemaVersion !== 1
|
|
3236
|
+
|| value.kind !== 'cloudly-legacy-deployment-settlement-request-bundle') {
|
|
3237
|
+
fail('INVALID_VALUE', 'requestBundle.kind');
|
|
3238
|
+
}
|
|
3239
|
+
const authenticatedRehearsalBinding =
|
|
3240
|
+
normalizeCloudlyLegacyDeploymentSettlementAuthenticatedRehearsalBindingStructure(
|
|
3241
|
+
value.authenticatedRehearsalBinding,
|
|
3242
|
+
);
|
|
3243
|
+
const authenticatedRequest =
|
|
3244
|
+
normalizeCloudlyLegacyDeploymentSettlementAuthenticatedProductionRequestStructure(
|
|
3245
|
+
value.authenticatedRequest,
|
|
3246
|
+
);
|
|
3247
|
+
if (canonicalize(authenticatedRehearsalBinding.authority, 'requestBundle.binding.authority')
|
|
3248
|
+
!== canonicalize(authenticatedRequest.authority, 'requestBundle.request.authority')
|
|
3249
|
+
|| canonicalize(
|
|
3250
|
+
authenticatedRehearsalBinding.payload,
|
|
3251
|
+
'requestBundle.binding.payload',
|
|
3252
|
+
) !== canonicalize(
|
|
3253
|
+
authenticatedRequest.payload.rehearsalBinding,
|
|
3254
|
+
'requestBundle.request.rehearsalBinding',
|
|
3255
|
+
)
|
|
3256
|
+
|| authenticatedRehearsalBinding.payloadSha256
|
|
3257
|
+
!== authenticatedRequest.payload.rehearsalBindingSha256) {
|
|
3258
|
+
fail('CROSS_FIELD_MISMATCH', 'requestBundle.authenticatedRehearsalBinding');
|
|
3259
|
+
}
|
|
3260
|
+
return finalize({
|
|
3261
|
+
schemaVersion: 1,
|
|
3262
|
+
kind: 'cloudly-legacy-deployment-settlement-request-bundle',
|
|
3263
|
+
authenticatedRehearsalBinding,
|
|
3264
|
+
authenticatedRequest,
|
|
3265
|
+
}, cloudlyLegacyDeploymentSettlementLimits.maximumAuthenticatedArtifactBytes * 2, 'requestBundle');
|
|
3266
|
+
};
|
|
3267
|
+
|
|
3268
|
+
export const encodeCloudlyLegacyDeploymentSettlementRequestBundle = (
|
|
3269
|
+
valueArg: unknown,
|
|
3270
|
+
): Uint8Array => encodeNormalized(
|
|
3271
|
+
normalizeCloudlyLegacyDeploymentSettlementRequestBundle(valueArg),
|
|
3272
|
+
'requestBundle',
|
|
3273
|
+
);
|
|
3274
|
+
|
|
3275
|
+
export const digestCloudlyLegacyDeploymentSettlementRequestBundle = (
|
|
3276
|
+
valueArg: unknown,
|
|
3277
|
+
): string => digestBytes(encodeCloudlyLegacyDeploymentSettlementRequestBundle(valueArg));
|
|
3278
|
+
|
|
3279
|
+
const executionAttemptIdentityKeys = [
|
|
3280
|
+
'schemaVersion',
|
|
3281
|
+
'kind',
|
|
3282
|
+
'attemptId',
|
|
3283
|
+
'purpose',
|
|
3284
|
+
'operationId',
|
|
3285
|
+
'settlementId',
|
|
3286
|
+
'executionAuthority',
|
|
3287
|
+
'sourceAuthority',
|
|
3288
|
+
'authenticatedPlanSha256',
|
|
3289
|
+
'requestBundleSha256',
|
|
3290
|
+
'scratchReceiptSha256',
|
|
3291
|
+
] as const;
|
|
3292
|
+
|
|
3293
|
+
const executionAttemptIdentitySeed = (
|
|
3294
|
+
valueArg: Omit<ICloudlyLegacyDeploymentSettlementExecutionAttemptIdentityV1, 'attemptId'>,
|
|
3295
|
+
): unknown => ({
|
|
3296
|
+
schemaVersion: valueArg.schemaVersion,
|
|
3297
|
+
kind: valueArg.kind,
|
|
3298
|
+
purpose: valueArg.purpose,
|
|
3299
|
+
operationId: valueArg.operationId,
|
|
3300
|
+
settlementId: valueArg.settlementId,
|
|
3301
|
+
executionAuthority: valueArg.executionAuthority,
|
|
3302
|
+
sourceAuthority: valueArg.sourceAuthority,
|
|
3303
|
+
authenticatedPlanSha256: valueArg.authenticatedPlanSha256,
|
|
3304
|
+
requestBundleSha256: valueArg.requestBundleSha256,
|
|
3305
|
+
scratchReceiptSha256: valueArg.scratchReceiptSha256,
|
|
3306
|
+
});
|
|
3307
|
+
|
|
3308
|
+
const createExecutionAttemptId = (
|
|
3309
|
+
valueArg: Omit<ICloudlyLegacyDeploymentSettlementExecutionAttemptIdentityV1, 'attemptId'>,
|
|
3310
|
+
): string => `settlement-attempt-${digestBytes(encodeNormalized(
|
|
3311
|
+
executionAttemptIdentitySeed(valueArg),
|
|
3312
|
+
'executionAttemptIdentity.seed',
|
|
3313
|
+
)).slice(0, 40)}`;
|
|
3314
|
+
|
|
3315
|
+
const normalizeExecutionAttemptIdentityInternal = (
|
|
3316
|
+
valueArg: unknown,
|
|
3317
|
+
pathArg: string,
|
|
3318
|
+
): TCloudlyLegacyDeploymentSettlementExecutionAttemptIdentityV1 => {
|
|
3319
|
+
const value = readRecord(valueArg, pathArg);
|
|
3320
|
+
assertExactKeys(value, executionAttemptIdentityKeys, pathArg);
|
|
3321
|
+
if (value.schemaVersion !== 1
|
|
3322
|
+
|| value.kind !== 'cloudly-legacy-deployment-settlement-execution-attempt-identity') {
|
|
3323
|
+
fail('INVALID_VALUE', `${pathArg}.kind`);
|
|
3324
|
+
}
|
|
3325
|
+
const purpose = readLiteral(
|
|
3326
|
+
value.purpose,
|
|
3327
|
+
['scratch-rehearsal', 'production'],
|
|
3328
|
+
`${pathArg}.purpose`,
|
|
3329
|
+
);
|
|
3330
|
+
const operationId = readIdentifier(value.operationId, `${pathArg}.operationId`);
|
|
3331
|
+
const executionAuthority = normalizeAuthorityReferenceInternal(
|
|
3332
|
+
value.executionAuthority,
|
|
3333
|
+
`${pathArg}.executionAuthority`,
|
|
3334
|
+
);
|
|
3335
|
+
const sourceAuthority = normalizeAuthorityReferenceInternal(
|
|
3336
|
+
value.sourceAuthority,
|
|
3337
|
+
`${pathArg}.sourceAuthority`,
|
|
3338
|
+
);
|
|
3339
|
+
const usesSameAuthority = canonicalize(executionAuthority, `${pathArg}.executionAuthority`)
|
|
3340
|
+
=== canonicalize(sourceAuthority, `${pathArg}.sourceAuthority`);
|
|
3341
|
+
if (executionAuthority.operationId !== operationId
|
|
3342
|
+
|| sourceAuthority.operationId !== operationId
|
|
3343
|
+
|| (purpose === 'scratch-rehearsal') !== usesSameAuthority) {
|
|
3344
|
+
fail('CROSS_FIELD_MISMATCH', `${pathArg}.executionAuthority`);
|
|
3345
|
+
}
|
|
3346
|
+
const scratchReceiptSha256 = value.scratchReceiptSha256 === null
|
|
3347
|
+
? null
|
|
3348
|
+
: readSha256(value.scratchReceiptSha256, `${pathArg}.scratchReceiptSha256`);
|
|
3349
|
+
if ((purpose === 'production') !== (scratchReceiptSha256 !== null)) {
|
|
3350
|
+
fail('CROSS_FIELD_MISMATCH', `${pathArg}.scratchReceiptSha256`);
|
|
3351
|
+
}
|
|
3352
|
+
const identityWithoutId = {
|
|
3353
|
+
schemaVersion: 1 as const,
|
|
3354
|
+
kind: 'cloudly-legacy-deployment-settlement-execution-attempt-identity' as const,
|
|
3355
|
+
purpose,
|
|
3356
|
+
operationId,
|
|
3357
|
+
settlementId: readIdentifier(value.settlementId, `${pathArg}.settlementId`),
|
|
3358
|
+
executionAuthority,
|
|
3359
|
+
sourceAuthority,
|
|
3360
|
+
authenticatedPlanSha256: readSha256(
|
|
3361
|
+
value.authenticatedPlanSha256,
|
|
3362
|
+
`${pathArg}.authenticatedPlanSha256`,
|
|
3363
|
+
),
|
|
3364
|
+
requestBundleSha256: readSha256(
|
|
3365
|
+
value.requestBundleSha256,
|
|
3366
|
+
`${pathArg}.requestBundleSha256`,
|
|
3367
|
+
),
|
|
3368
|
+
scratchReceiptSha256,
|
|
3369
|
+
};
|
|
3370
|
+
const attemptId = readIdentifier(value.attemptId, `${pathArg}.attemptId`);
|
|
3371
|
+
if (attemptId !== createExecutionAttemptId(identityWithoutId)) {
|
|
3372
|
+
fail('CROSS_FIELD_MISMATCH', `${pathArg}.attemptId`);
|
|
3373
|
+
}
|
|
3374
|
+
return { ...identityWithoutId, attemptId } as
|
|
3375
|
+
TCloudlyLegacyDeploymentSettlementExecutionAttemptIdentityV1;
|
|
3376
|
+
};
|
|
3377
|
+
|
|
3378
|
+
export function createCloudlyLegacyDeploymentSettlementExecutionAttemptIdentity(
|
|
3379
|
+
valueArg: Omit<
|
|
3380
|
+
TCloudlyLegacyDeploymentSettlementScratchExecutionAttemptIdentityV1,
|
|
3381
|
+
'schemaVersion' | 'kind' | 'attemptId'
|
|
3382
|
+
>,
|
|
3383
|
+
): Readonly<TCloudlyLegacyDeploymentSettlementScratchExecutionAttemptIdentityV1>;
|
|
3384
|
+
export function createCloudlyLegacyDeploymentSettlementExecutionAttemptIdentity(
|
|
3385
|
+
valueArg: Omit<
|
|
3386
|
+
TCloudlyLegacyDeploymentSettlementProductionExecutionAttemptIdentityV1,
|
|
3387
|
+
'schemaVersion' | 'kind' | 'attemptId'
|
|
3388
|
+
>,
|
|
3389
|
+
): Readonly<TCloudlyLegacyDeploymentSettlementProductionExecutionAttemptIdentityV1>;
|
|
3390
|
+
export function createCloudlyLegacyDeploymentSettlementExecutionAttemptIdentity(
|
|
3391
|
+
valueArg: Omit<
|
|
3392
|
+
ICloudlyLegacyDeploymentSettlementExecutionAttemptIdentityV1,
|
|
3393
|
+
'schemaVersion' | 'kind' | 'attemptId'
|
|
3394
|
+
>,
|
|
3395
|
+
): Readonly<TCloudlyLegacyDeploymentSettlementExecutionAttemptIdentityV1>;
|
|
3396
|
+
export function createCloudlyLegacyDeploymentSettlementExecutionAttemptIdentity(
|
|
3397
|
+
valueArg: Omit<
|
|
3398
|
+
ICloudlyLegacyDeploymentSettlementExecutionAttemptIdentityV1,
|
|
3399
|
+
'schemaVersion' | 'kind' | 'attemptId'
|
|
3400
|
+
>,
|
|
3401
|
+
): Readonly<TCloudlyLegacyDeploymentSettlementExecutionAttemptIdentityV1> {
|
|
3402
|
+
const seed = {
|
|
3403
|
+
schemaVersion: 1 as const,
|
|
3404
|
+
kind: 'cloudly-legacy-deployment-settlement-execution-attempt-identity' as const,
|
|
3405
|
+
purpose: valueArg.purpose,
|
|
3406
|
+
operationId: valueArg.operationId,
|
|
3407
|
+
settlementId: valueArg.settlementId,
|
|
3408
|
+
executionAuthority: valueArg.executionAuthority,
|
|
3409
|
+
sourceAuthority: valueArg.sourceAuthority,
|
|
3410
|
+
authenticatedPlanSha256: valueArg.authenticatedPlanSha256,
|
|
3411
|
+
requestBundleSha256: valueArg.requestBundleSha256,
|
|
3412
|
+
scratchReceiptSha256: valueArg.scratchReceiptSha256,
|
|
3413
|
+
};
|
|
3414
|
+
return normalizeCloudlyLegacyDeploymentSettlementExecutionAttemptIdentity({
|
|
3415
|
+
...seed,
|
|
3416
|
+
attemptId: createExecutionAttemptId(seed),
|
|
3417
|
+
});
|
|
3418
|
+
}
|
|
3419
|
+
|
|
3420
|
+
export const normalizeCloudlyLegacyDeploymentSettlementExecutionAttemptIdentity = (
|
|
3421
|
+
valueArg: unknown,
|
|
3422
|
+
): Readonly<TCloudlyLegacyDeploymentSettlementExecutionAttemptIdentityV1> => finalize(
|
|
3423
|
+
normalizeExecutionAttemptIdentityInternal(valueArg, 'executionAttemptIdentity'),
|
|
3424
|
+
cloudlyLegacyDeploymentSettlementLimits.maximumAuthorityBytes,
|
|
3425
|
+
'executionAttemptIdentity',
|
|
3426
|
+
);
|
|
3427
|
+
|
|
3428
|
+
export const encodeCloudlyLegacyDeploymentSettlementExecutionAttemptIdentity = (
|
|
3429
|
+
valueArg: unknown,
|
|
3430
|
+
): Uint8Array => encodeNormalized(
|
|
3431
|
+
normalizeCloudlyLegacyDeploymentSettlementExecutionAttemptIdentity(valueArg),
|
|
3432
|
+
'executionAttemptIdentity',
|
|
3433
|
+
);
|
|
3434
|
+
|
|
3435
|
+
export const digestCloudlyLegacyDeploymentSettlementExecutionAttemptIdentity = (
|
|
3436
|
+
valueArg: unknown,
|
|
3437
|
+
): string => digestBytes(
|
|
3438
|
+
encodeCloudlyLegacyDeploymentSettlementExecutionAttemptIdentity(valueArg),
|
|
3439
|
+
);
|
|
3440
|
+
|
|
3441
|
+
const normalizeExecutionAttemptObservationInternal = (
|
|
3442
|
+
valueArg: unknown,
|
|
3443
|
+
pathArg: string,
|
|
3444
|
+
): TCloudlyLegacyDeploymentSettlementExecutionAttemptObservationV1 => {
|
|
3445
|
+
const value = readRecord(valueArg, pathArg);
|
|
3446
|
+
const state = readLiteral(value.state, ['prepared', 'committed', 'aborted'], `${pathArg}.state`);
|
|
3447
|
+
assertExactKeys(value, [
|
|
3448
|
+
'schemaVersion',
|
|
3449
|
+
'kind',
|
|
3450
|
+
'identity',
|
|
3451
|
+
'state',
|
|
3452
|
+
'preparedAt',
|
|
3453
|
+
...(state === 'committed' ? ['resolvedAt', 'receiptSchemaVersion', 'receiptSha256'] : []),
|
|
3454
|
+
...(state === 'aborted' ? ['resolvedAt'] : []),
|
|
3455
|
+
], pathArg);
|
|
3456
|
+
if (value.schemaVersion !== 1
|
|
3457
|
+
|| value.kind !== 'cloudly-legacy-deployment-settlement-execution-attempt-observation') {
|
|
3458
|
+
fail('INVALID_VALUE', `${pathArg}.kind`);
|
|
3459
|
+
}
|
|
3460
|
+
const identity = normalizeExecutionAttemptIdentityInternal(value.identity, `${pathArg}.identity`);
|
|
3461
|
+
const preparedAt = readInteger(value.preparedAt, `${pathArg}.preparedAt`, 1);
|
|
3462
|
+
if (state === 'prepared') {
|
|
3463
|
+
return {
|
|
3464
|
+
schemaVersion: 1,
|
|
3465
|
+
kind: 'cloudly-legacy-deployment-settlement-execution-attempt-observation',
|
|
3466
|
+
identity,
|
|
3467
|
+
state,
|
|
3468
|
+
preparedAt,
|
|
3469
|
+
};
|
|
3470
|
+
}
|
|
3471
|
+
const resolvedAt = readInteger(value.resolvedAt, `${pathArg}.resolvedAt`, preparedAt);
|
|
3472
|
+
if (state === 'aborted') {
|
|
3473
|
+
return {
|
|
3474
|
+
schemaVersion: 1,
|
|
3475
|
+
kind: 'cloudly-legacy-deployment-settlement-execution-attempt-observation',
|
|
3476
|
+
identity,
|
|
3477
|
+
state,
|
|
3478
|
+
preparedAt,
|
|
3479
|
+
resolvedAt,
|
|
3480
|
+
};
|
|
3481
|
+
}
|
|
3482
|
+
if (value.receiptSchemaVersion !== 1 && value.receiptSchemaVersion !== 2) {
|
|
3483
|
+
fail('INVALID_VALUE', `${pathArg}.receiptSchemaVersion`);
|
|
3484
|
+
}
|
|
3485
|
+
const receiptSchemaVersion = value.receiptSchemaVersion as 1 | 2;
|
|
3486
|
+
return {
|
|
3487
|
+
schemaVersion: 1,
|
|
3488
|
+
kind: 'cloudly-legacy-deployment-settlement-execution-attempt-observation',
|
|
3489
|
+
identity,
|
|
3490
|
+
state,
|
|
3491
|
+
preparedAt,
|
|
3492
|
+
resolvedAt,
|
|
3493
|
+
receiptSchemaVersion,
|
|
3494
|
+
receiptSha256: readSha256(value.receiptSha256, `${pathArg}.receiptSha256`),
|
|
3495
|
+
};
|
|
3496
|
+
};
|
|
3497
|
+
|
|
3498
|
+
export const normalizeCloudlyLegacyDeploymentSettlementExecutionAttemptObservation = (
|
|
3499
|
+
valueArg: unknown,
|
|
3500
|
+
): Readonly<TCloudlyLegacyDeploymentSettlementExecutionAttemptObservationV1> => finalize(
|
|
3501
|
+
normalizeExecutionAttemptObservationInternal(valueArg, 'executionAttemptObservation'),
|
|
3502
|
+
cloudlyLegacyDeploymentSettlementLimits.maximumAuthorityBytes,
|
|
3503
|
+
'executionAttemptObservation',
|
|
3504
|
+
);
|
|
3505
|
+
|
|
3506
|
+
export const encodeCloudlyLegacyDeploymentSettlementExecutionAttemptObservation = (
|
|
3507
|
+
valueArg: unknown,
|
|
3508
|
+
): Uint8Array => encodeNormalized(
|
|
3509
|
+
normalizeCloudlyLegacyDeploymentSettlementExecutionAttemptObservation(valueArg),
|
|
3510
|
+
'executionAttemptObservation',
|
|
3511
|
+
);
|
|
3512
|
+
|
|
3513
|
+
export const digestCloudlyLegacyDeploymentSettlementExecutionAttemptObservation = (
|
|
3514
|
+
valueArg: unknown,
|
|
3515
|
+
): string => digestBytes(
|
|
3516
|
+
encodeCloudlyLegacyDeploymentSettlementExecutionAttemptObservation(valueArg),
|
|
3517
|
+
);
|
|
3518
|
+
|
|
3519
|
+
export interface ICloudlyLegacyDeploymentSettlementProductionExecutionAuthorizationPayloadV1 {
|
|
3520
|
+
schemaVersion: 1;
|
|
3521
|
+
kind: 'cloudly-legacy-deployment-settlement-production-execution-authorization';
|
|
3522
|
+
authority: ICloudlyLegacyDeploymentSettlementAuthorityReferenceV1;
|
|
3523
|
+
sourceAuthority: ICloudlyLegacyDeploymentSettlementAuthorityReferenceV1;
|
|
3524
|
+
executionAttempt: TCloudlyLegacyDeploymentSettlementProductionExecutionAttemptIdentityV1;
|
|
3525
|
+
authenticatedPlanSha256: string;
|
|
3526
|
+
requestBundleSha256: string;
|
|
3527
|
+
scratchReceiptSha256: string;
|
|
3528
|
+
maintenanceImageDigest: `sha256:${string}`;
|
|
3529
|
+
operationId: string;
|
|
3530
|
+
settlementId: string;
|
|
3531
|
+
runId: string;
|
|
3532
|
+
rehearsalId: string;
|
|
3533
|
+
scratchServiceId: string;
|
|
3534
|
+
allocationId: string;
|
|
3535
|
+
allocationGeneration: number;
|
|
3536
|
+
allocationBindingSha256: string;
|
|
3537
|
+
allocationReceiptSha256: string;
|
|
3538
|
+
sourceImageDigest: `sha256:${string}`;
|
|
3539
|
+
targetImageDigest: `sha256:${string}`;
|
|
3540
|
+
requestedAt: number;
|
|
3541
|
+
approvedAt: number;
|
|
3542
|
+
}
|
|
3543
|
+
|
|
3544
|
+
export interface ICloudlyLegacyDeploymentSettlementProductionExecutionAuthorizationV1
|
|
3545
|
+
extends ICloudlyLegacyDeploymentSettlementProductionExecutionAuthorizationPayloadV1 {
|
|
3546
|
+
payloadSha256: string;
|
|
3547
|
+
mac: string;
|
|
3548
|
+
}
|
|
3549
|
+
|
|
3550
|
+
export type TCloudlyLegacyDeploymentSettlementUnsignedProductionExecutionAuthorizationV1 =
|
|
3551
|
+
Omit<ICloudlyLegacyDeploymentSettlementProductionExecutionAuthorizationV1, 'mac'>;
|
|
3552
|
+
|
|
3553
|
+
export interface ICloudlyLegacyDeploymentSettlementProductionReceiptPayloadV2 {
|
|
3554
|
+
schemaVersion: 2;
|
|
3555
|
+
kind: 'cloudly-legacy-deployment-settlement-production-receipt';
|
|
3556
|
+
authority: ICloudlyLegacyDeploymentSettlementAuthorityReferenceV1;
|
|
3557
|
+
sourceAuthority: ICloudlyLegacyDeploymentSettlementAuthorityReferenceV1;
|
|
3558
|
+
executionAttempt: TCloudlyLegacyDeploymentSettlementProductionExecutionAttemptIdentityV1;
|
|
3559
|
+
productionAuthorization:
|
|
3560
|
+
ICloudlyLegacyDeploymentSettlementProductionExecutionAuthorizationV1;
|
|
3561
|
+
productionAuthorizationSha256: string;
|
|
3562
|
+
requestSha256: string;
|
|
3563
|
+
requestBundleSha256: string;
|
|
3564
|
+
scratchReceipt: ICloudlyLegacyDeploymentSettlementScratchReceiptV1;
|
|
3565
|
+
scratchReceiptSha256: string;
|
|
3566
|
+
stableOutcome: ICloudlyLegacyDeploymentSettlementStableOutcomeV1;
|
|
3567
|
+
stableOutcomeSha256: string;
|
|
3568
|
+
transactionCommitted: true;
|
|
3569
|
+
disposition: 'applied' | 'exact-replay' | 'no-op';
|
|
3570
|
+
completedAt: number;
|
|
3571
|
+
}
|
|
3572
|
+
|
|
3573
|
+
export interface ICloudlyLegacyDeploymentSettlementProductionReceiptV2
|
|
3574
|
+
extends ICloudlyLegacyDeploymentSettlementProductionReceiptPayloadV2 {
|
|
3575
|
+
payloadSha256: string;
|
|
3576
|
+
mac: string;
|
|
3577
|
+
}
|
|
3578
|
+
|
|
3579
|
+
export type TCloudlyLegacyDeploymentSettlementUnsignedProductionReceiptV2 =
|
|
3580
|
+
Omit<ICloudlyLegacyDeploymentSettlementProductionReceiptV2, 'mac'>;
|
|
3581
|
+
export type TCloudlyLegacyDeploymentSettlementProductionReceipt =
|
|
3582
|
+
| ICloudlyLegacyDeploymentSettlementProductionReceiptV1
|
|
3583
|
+
| ICloudlyLegacyDeploymentSettlementProductionReceiptV2;
|
|
3584
|
+
|
|
3585
|
+
const productionExecutionAuthorizationPayloadKeys = [
|
|
3586
|
+
'schemaVersion',
|
|
3587
|
+
'kind',
|
|
3588
|
+
'authority',
|
|
3589
|
+
'sourceAuthority',
|
|
3590
|
+
'executionAttempt',
|
|
3591
|
+
'authenticatedPlanSha256',
|
|
3592
|
+
'requestBundleSha256',
|
|
3593
|
+
'scratchReceiptSha256',
|
|
3594
|
+
'maintenanceImageDigest',
|
|
3595
|
+
'operationId',
|
|
3596
|
+
'settlementId',
|
|
3597
|
+
'runId',
|
|
3598
|
+
'rehearsalId',
|
|
3599
|
+
'scratchServiceId',
|
|
3600
|
+
'allocationId',
|
|
3601
|
+
'allocationGeneration',
|
|
3602
|
+
'allocationBindingSha256',
|
|
3603
|
+
'allocationReceiptSha256',
|
|
3604
|
+
'sourceImageDigest',
|
|
3605
|
+
'targetImageDigest',
|
|
3606
|
+
'requestedAt',
|
|
3607
|
+
'approvedAt',
|
|
3608
|
+
] as const;
|
|
3609
|
+
const unsignedProductionExecutionAuthorizationKeys = [
|
|
3610
|
+
...productionExecutionAuthorizationPayloadKeys,
|
|
3611
|
+
'payloadSha256',
|
|
3612
|
+
] as const;
|
|
3613
|
+
const productionExecutionAuthorizationKeys = [
|
|
3614
|
+
...unsignedProductionExecutionAuthorizationKeys,
|
|
3615
|
+
'mac',
|
|
3616
|
+
] as const;
|
|
3617
|
+
|
|
3618
|
+
const productionExecutionAuthorizationPayload = (
|
|
3619
|
+
valueArg: ICloudlyLegacyDeploymentSettlementProductionExecutionAuthorizationPayloadV1,
|
|
3620
|
+
): unknown => Object.fromEntries(productionExecutionAuthorizationPayloadKeys.map((keyArg) => [
|
|
3621
|
+
keyArg,
|
|
3622
|
+
valueArg[keyArg],
|
|
3623
|
+
]));
|
|
3624
|
+
|
|
3625
|
+
const normalizeProductionExecutionAuthorizationPayloadInternal = (
|
|
3626
|
+
valueArg: unknown,
|
|
3627
|
+
pathArg: string,
|
|
3628
|
+
): ICloudlyLegacyDeploymentSettlementProductionExecutionAuthorizationPayloadV1 => {
|
|
3629
|
+
const value = readRecord(valueArg, pathArg);
|
|
3630
|
+
assertExactKeys(value, productionExecutionAuthorizationPayloadKeys, pathArg);
|
|
3631
|
+
if (value.schemaVersion !== 1
|
|
3632
|
+
|| value.kind
|
|
3633
|
+
!== 'cloudly-legacy-deployment-settlement-production-execution-authorization') {
|
|
3634
|
+
fail('INVALID_VALUE', `${pathArg}.kind`);
|
|
3635
|
+
}
|
|
3636
|
+
const authority = normalizeAuthorityReferenceInternal(value.authority, `${pathArg}.authority`);
|
|
3637
|
+
const sourceAuthority = normalizeAuthorityReferenceInternal(
|
|
3638
|
+
value.sourceAuthority,
|
|
3639
|
+
`${pathArg}.sourceAuthority`,
|
|
3640
|
+
);
|
|
3641
|
+
const executionAttempt = normalizeExecutionAttemptIdentityInternal(
|
|
3642
|
+
value.executionAttempt,
|
|
3643
|
+
`${pathArg}.executionAttempt`,
|
|
3644
|
+
);
|
|
3645
|
+
const operationId = readIdentifier(value.operationId, `${pathArg}.operationId`);
|
|
3646
|
+
const settlementId = readIdentifier(value.settlementId, `${pathArg}.settlementId`);
|
|
3647
|
+
const authenticatedPlanSha256 = readSha256(
|
|
3648
|
+
value.authenticatedPlanSha256,
|
|
3649
|
+
`${pathArg}.authenticatedPlanSha256`,
|
|
3650
|
+
);
|
|
3651
|
+
const requestBundleSha256 = readSha256(
|
|
3652
|
+
value.requestBundleSha256,
|
|
3653
|
+
`${pathArg}.requestBundleSha256`,
|
|
3654
|
+
);
|
|
3655
|
+
const scratchReceiptSha256 = readSha256(
|
|
3656
|
+
value.scratchReceiptSha256,
|
|
3657
|
+
`${pathArg}.scratchReceiptSha256`,
|
|
3658
|
+
);
|
|
3659
|
+
if (executionAttempt.purpose !== 'production'
|
|
3660
|
+
|| executionAttempt.operationId !== operationId
|
|
3661
|
+
|| executionAttempt.settlementId !== settlementId
|
|
3662
|
+
|| authority.authorityId === sourceAuthority.authorityId
|
|
3663
|
+
|| authority.keyId === sourceAuthority.keyId
|
|
3664
|
+
|| canonicalize(authority, `${pathArg}.authority`)
|
|
3665
|
+
=== canonicalize(sourceAuthority, `${pathArg}.sourceAuthority`)
|
|
3666
|
+
|| canonicalize(executionAttempt.executionAuthority, `${pathArg}.attempt.executionAuthority`)
|
|
3667
|
+
!== canonicalize(authority, `${pathArg}.authority`)
|
|
3668
|
+
|| canonicalize(executionAttempt.sourceAuthority, `${pathArg}.attempt.sourceAuthority`)
|
|
3669
|
+
!== canonicalize(sourceAuthority, `${pathArg}.sourceAuthority`)
|
|
3670
|
+
|| executionAttempt.authenticatedPlanSha256 !== authenticatedPlanSha256
|
|
3671
|
+
|| executionAttempt.requestBundleSha256 !== requestBundleSha256
|
|
3672
|
+
|| executionAttempt.scratchReceiptSha256 !== scratchReceiptSha256) {
|
|
3673
|
+
fail('CROSS_FIELD_MISMATCH', `${pathArg}.executionAttempt`);
|
|
3674
|
+
}
|
|
3675
|
+
const requestedAt = readInteger(value.requestedAt, `${pathArg}.requestedAt`, 1);
|
|
3676
|
+
const approvedAt = readInteger(value.approvedAt, `${pathArg}.approvedAt`, requestedAt);
|
|
3677
|
+
return {
|
|
3678
|
+
schemaVersion: 1,
|
|
3679
|
+
kind: 'cloudly-legacy-deployment-settlement-production-execution-authorization',
|
|
3680
|
+
authority,
|
|
3681
|
+
sourceAuthority,
|
|
3682
|
+
executionAttempt: executionAttempt as
|
|
3683
|
+
TCloudlyLegacyDeploymentSettlementProductionExecutionAttemptIdentityV1,
|
|
3684
|
+
authenticatedPlanSha256,
|
|
3685
|
+
requestBundleSha256,
|
|
3686
|
+
scratchReceiptSha256,
|
|
3687
|
+
maintenanceImageDigest: readOciDigest(
|
|
3688
|
+
value.maintenanceImageDigest,
|
|
3689
|
+
`${pathArg}.maintenanceImageDigest`,
|
|
3690
|
+
),
|
|
3691
|
+
operationId,
|
|
3692
|
+
settlementId,
|
|
3693
|
+
runId: readIdentifier(value.runId, `${pathArg}.runId`),
|
|
3694
|
+
rehearsalId: readIdentifier(value.rehearsalId, `${pathArg}.rehearsalId`),
|
|
3695
|
+
scratchServiceId: readIdentifier(value.scratchServiceId, `${pathArg}.scratchServiceId`),
|
|
3696
|
+
allocationId: readIdentifier(value.allocationId, `${pathArg}.allocationId`),
|
|
3697
|
+
allocationGeneration: readInteger(
|
|
3698
|
+
value.allocationGeneration,
|
|
3699
|
+
`${pathArg}.allocationGeneration`,
|
|
3700
|
+
1,
|
|
3701
|
+
),
|
|
3702
|
+
allocationBindingSha256: readSha256(
|
|
3703
|
+
value.allocationBindingSha256,
|
|
3704
|
+
`${pathArg}.allocationBindingSha256`,
|
|
3705
|
+
),
|
|
3706
|
+
allocationReceiptSha256: readSha256(
|
|
3707
|
+
value.allocationReceiptSha256,
|
|
3708
|
+
`${pathArg}.allocationReceiptSha256`,
|
|
3709
|
+
),
|
|
3710
|
+
sourceImageDigest: readOciDigest(value.sourceImageDigest, `${pathArg}.sourceImageDigest`),
|
|
3711
|
+
targetImageDigest: readOciDigest(value.targetImageDigest, `${pathArg}.targetImageDigest`),
|
|
3712
|
+
requestedAt,
|
|
3713
|
+
approvedAt,
|
|
3714
|
+
};
|
|
3715
|
+
};
|
|
3716
|
+
|
|
3717
|
+
const normalizeUnsignedProductionExecutionAuthorizationInternal = (
|
|
3718
|
+
valueArg: unknown,
|
|
3719
|
+
pathArg: string,
|
|
3720
|
+
): TCloudlyLegacyDeploymentSettlementUnsignedProductionExecutionAuthorizationV1 => {
|
|
3721
|
+
const value = readRecord(valueArg, pathArg);
|
|
3722
|
+
assertExactKeys(value, unsignedProductionExecutionAuthorizationKeys, pathArg);
|
|
3723
|
+
const payloadInput = Object.fromEntries(productionExecutionAuthorizationPayloadKeys.map(
|
|
3724
|
+
(keyArg) => [keyArg, value[keyArg]],
|
|
3725
|
+
));
|
|
3726
|
+
const payload = normalizeProductionExecutionAuthorizationPayloadInternal(
|
|
3727
|
+
payloadInput,
|
|
3728
|
+
`${pathArg}.payload`,
|
|
3729
|
+
);
|
|
3730
|
+
const payloadSha256 = readSha256(value.payloadSha256, `${pathArg}.payloadSha256`);
|
|
3731
|
+
if (payloadSha256 !== digestBytes(encodeNormalized(
|
|
3732
|
+
productionExecutionAuthorizationPayload(payload),
|
|
3733
|
+
`${pathArg}.payload`,
|
|
3734
|
+
))) {
|
|
3735
|
+
fail('CROSS_FIELD_MISMATCH', `${pathArg}.payloadSha256`);
|
|
3736
|
+
}
|
|
3737
|
+
return { ...payload, payloadSha256 };
|
|
3738
|
+
};
|
|
3739
|
+
|
|
3740
|
+
export const normalizeCloudlyLegacyDeploymentSettlementProductionExecutionAuthorization = (
|
|
3741
|
+
valueArg: unknown,
|
|
3742
|
+
): Readonly<ICloudlyLegacyDeploymentSettlementProductionExecutionAuthorizationV1> => {
|
|
3743
|
+
const value = readRecord(valueArg, 'productionExecutionAuthorization');
|
|
3744
|
+
assertExactKeys(value, productionExecutionAuthorizationKeys, 'productionExecutionAuthorization');
|
|
3745
|
+
const unsignedInput = Object.fromEntries(unsignedProductionExecutionAuthorizationKeys.map(
|
|
3746
|
+
(keyArg) => [keyArg, value[keyArg]],
|
|
3747
|
+
));
|
|
3748
|
+
return finalize({
|
|
3749
|
+
...normalizeUnsignedProductionExecutionAuthorizationInternal(
|
|
3750
|
+
unsignedInput,
|
|
3751
|
+
'productionExecutionAuthorization.unsigned',
|
|
3752
|
+
),
|
|
3753
|
+
mac: readMac(value.mac, 'productionExecutionAuthorization.mac'),
|
|
3754
|
+
}, cloudlyLegacyDeploymentSettlementLimits.maximumReceiptBytes, 'productionExecutionAuthorization');
|
|
3755
|
+
};
|
|
3756
|
+
|
|
3757
|
+
export const digestCloudlyLegacyDeploymentSettlementProductionExecutionAuthorizationPayload = (
|
|
3758
|
+
valueArg: unknown,
|
|
3759
|
+
): string => digestBytes(encodeNormalized(
|
|
3760
|
+
productionExecutionAuthorizationPayload(
|
|
3761
|
+
normalizeProductionExecutionAuthorizationPayloadInternal(
|
|
3762
|
+
valueArg,
|
|
3763
|
+
'productionExecutionAuthorizationPayload',
|
|
3764
|
+
),
|
|
3765
|
+
),
|
|
3766
|
+
'productionExecutionAuthorizationPayload',
|
|
3767
|
+
));
|
|
3768
|
+
|
|
3769
|
+
export const encodeCloudlyLegacyDeploymentSettlementProductionExecutionAuthorization = (
|
|
3770
|
+
valueArg: unknown,
|
|
3771
|
+
): Uint8Array => encodeNormalized(
|
|
3772
|
+
normalizeCloudlyLegacyDeploymentSettlementProductionExecutionAuthorization(valueArg),
|
|
3773
|
+
'productionExecutionAuthorization',
|
|
3774
|
+
);
|
|
3775
|
+
|
|
3776
|
+
export const digestCloudlyLegacyDeploymentSettlementProductionExecutionAuthorization = (
|
|
3777
|
+
valueArg: unknown,
|
|
3778
|
+
): string => digestBytes(
|
|
3779
|
+
encodeCloudlyLegacyDeploymentSettlementProductionExecutionAuthorization(valueArg),
|
|
3780
|
+
);
|
|
3781
|
+
|
|
3782
|
+
export const encodeCloudlyLegacyDeploymentSettlementProductionExecutionAuthorizationHmacInput = (
|
|
3783
|
+
valueArg: unknown,
|
|
3784
|
+
): Uint8Array => frame(
|
|
3785
|
+
cloudlyLegacyDeploymentSettlementDomains.productionExecutionAuthorizationHmac,
|
|
3786
|
+
encodeNormalized(
|
|
3787
|
+
finalize(
|
|
3788
|
+
normalizeUnsignedProductionExecutionAuthorizationInternal(
|
|
3789
|
+
valueArg,
|
|
3790
|
+
'unsignedProductionExecutionAuthorization',
|
|
3791
|
+
),
|
|
3792
|
+
cloudlyLegacyDeploymentSettlementLimits.maximumReceiptBytes,
|
|
3793
|
+
'unsignedProductionExecutionAuthorization',
|
|
3794
|
+
),
|
|
3795
|
+
'productionExecutionAuthorization.authenticated',
|
|
3796
|
+
),
|
|
3797
|
+
);
|
|
3798
|
+
|
|
3799
|
+
export const normalizeCloudlyLegacyDeploymentSettlementRequestBundleForAuthority = async (
|
|
3800
|
+
bundleArg: unknown,
|
|
3801
|
+
authenticatedPlanArg: unknown,
|
|
3802
|
+
metadataArg: unknown,
|
|
3803
|
+
verifierArg: TCloudlyLegacyDeploymentSettlementHmacVerifier,
|
|
3804
|
+
): Promise<Readonly<ICloudlyLegacyDeploymentSettlementRequestBundleV1>> => {
|
|
3805
|
+
const metadata = normalizeCloudlyLegacyDeploymentSettlementAuthorityMetadata(metadataArg);
|
|
3806
|
+
const plan = await normalizeAuthenticatedCloudlyLegacyDeploymentSettlementPlanForAuthority(
|
|
3807
|
+
authenticatedPlanArg,
|
|
3808
|
+
metadata,
|
|
3809
|
+
verifierArg,
|
|
3810
|
+
);
|
|
3811
|
+
const bundle = normalizeCloudlyLegacyDeploymentSettlementRequestBundle(bundleArg);
|
|
3812
|
+
await normalizeAuthenticatedCloudlyLegacyDeploymentSettlementRehearsalBindingForAuthority(
|
|
3813
|
+
bundle.authenticatedRehearsalBinding,
|
|
3814
|
+
metadata,
|
|
3815
|
+
verifierArg,
|
|
3816
|
+
);
|
|
3817
|
+
await normalizeAuthenticatedCloudlyLegacyDeploymentSettlementProductionRequestForAuthority(
|
|
3818
|
+
bundle.authenticatedRequest,
|
|
3819
|
+
metadata,
|
|
3820
|
+
verifierArg,
|
|
3821
|
+
);
|
|
3822
|
+
if (canonicalize(plan.payload, 'requestBundle.plan')
|
|
3823
|
+
!== canonicalize(bundle.authenticatedRequest.payload.plan, 'requestBundle.request.plan')
|
|
3824
|
+
|| plan.payloadSha256 !== bundle.authenticatedRequest.payload.planSha256) {
|
|
3825
|
+
fail('CROSS_FIELD_MISMATCH', 'requestBundle.authenticatedRequest.plan');
|
|
3826
|
+
}
|
|
3827
|
+
return bundle;
|
|
3828
|
+
};
|
|
3829
|
+
|
|
3830
|
+
const assertProductionAuthorizationMetadata = (
|
|
3831
|
+
authorizationArg: ICloudlyLegacyDeploymentSettlementProductionExecutionAuthorizationV1,
|
|
3832
|
+
productionMetadataArg:
|
|
3833
|
+
ICloudlyLegacyDeploymentSettlementFencedProductionAuthorityMetadataV1,
|
|
3834
|
+
sourceMetadataArg: ICloudlyLegacyDeploymentSettlementFencedSourceAuthorityMetadataV1,
|
|
3835
|
+
): void => {
|
|
3836
|
+
assertAuthorityReferenceMatchesMetadata(
|
|
3837
|
+
authorizationArg.authority,
|
|
3838
|
+
productionMetadataArg,
|
|
3839
|
+
'productionExecutionAuthorization.authority',
|
|
3840
|
+
);
|
|
3841
|
+
assertAuthorityReferenceMatchesMetadata(
|
|
3842
|
+
authorizationArg.sourceAuthority,
|
|
3843
|
+
sourceMetadataArg,
|
|
3844
|
+
'productionExecutionAuthorization.sourceAuthority',
|
|
3845
|
+
);
|
|
3846
|
+
if (canonicalize(productionMetadataArg.sourceAuthority, 'productionMetadata.sourceAuthority')
|
|
3847
|
+
!== canonicalize(authorizationArg.sourceAuthority, 'authorization.sourceAuthority')
|
|
3848
|
+
|| productionMetadataArg.sourceAuthenticatedPlanSha256
|
|
3849
|
+
!== authorizationArg.authenticatedPlanSha256
|
|
3850
|
+
|| productionMetadataArg.sourceRequestBundleSha256 !== authorizationArg.requestBundleSha256
|
|
3851
|
+
|| productionMetadataArg.scratchReceiptSha256 !== authorizationArg.scratchReceiptSha256
|
|
3852
|
+
|| authorizationArg.operationId !== productionMetadataArg.operationId
|
|
3853
|
+
|| authorizationArg.operationId !== sourceMetadataArg.operationId
|
|
3854
|
+
|| authorizationArg.settlementId !== productionMetadataArg.settlementId
|
|
3855
|
+
|| authorizationArg.settlementId !== sourceMetadataArg.settlementId
|
|
3856
|
+
|| authorizationArg.runId !== productionMetadataArg.runId
|
|
3857
|
+
|| authorizationArg.runId !== sourceMetadataArg.runId
|
|
3858
|
+
|| authorizationArg.rehearsalId !== productionMetadataArg.rehearsalId
|
|
3859
|
+
|| authorizationArg.rehearsalId !== sourceMetadataArg.rehearsalId
|
|
3860
|
+
|| authorizationArg.scratchServiceId !== productionMetadataArg.scratchServiceId
|
|
3861
|
+
|| authorizationArg.scratchServiceId !== sourceMetadataArg.scratchServiceId
|
|
3862
|
+
|| authorizationArg.allocationId !== productionMetadataArg.allocationId
|
|
3863
|
+
|| authorizationArg.allocationId !== sourceMetadataArg.allocationId
|
|
3864
|
+
|| authorizationArg.allocationGeneration !== productionMetadataArg.allocationGeneration
|
|
3865
|
+
|| authorizationArg.allocationGeneration !== sourceMetadataArg.allocationGeneration
|
|
3866
|
+
|| authorizationArg.allocationBindingSha256 !== productionMetadataArg.allocationBindingSha256
|
|
3867
|
+
|| authorizationArg.allocationBindingSha256 !== sourceMetadataArg.allocationBindingSha256
|
|
3868
|
+
|| authorizationArg.allocationReceiptSha256 !== productionMetadataArg.allocationReceiptSha256
|
|
3869
|
+
|| authorizationArg.allocationReceiptSha256 !== sourceMetadataArg.allocationReceiptSha256
|
|
3870
|
+
|| authorizationArg.maintenanceImageDigest !== productionMetadataArg.maintenanceImageDigest
|
|
3871
|
+
|| authorizationArg.sourceImageDigest !== productionMetadataArg.sourceImageDigest
|
|
3872
|
+
|| authorizationArg.sourceImageDigest !== sourceMetadataArg.sourceImageDigest
|
|
3873
|
+
|| authorizationArg.targetImageDigest !== productionMetadataArg.targetImageDigest
|
|
3874
|
+
|| authorizationArg.targetImageDigest !== sourceMetadataArg.targetImageDigest) {
|
|
3875
|
+
fail('CROSS_FIELD_MISMATCH', 'productionExecutionAuthorization.authorityMetadata');
|
|
3876
|
+
}
|
|
3877
|
+
assertAuthorityTimestamp(
|
|
3878
|
+
authorizationArg.requestedAt,
|
|
3879
|
+
productionMetadataArg,
|
|
3880
|
+
'productionExecutionAuthorization.requestedAt',
|
|
3881
|
+
);
|
|
3882
|
+
assertAuthorityTimestamp(
|
|
3883
|
+
authorizationArg.approvedAt,
|
|
3884
|
+
productionMetadataArg,
|
|
3885
|
+
'productionExecutionAuthorization.approvedAt',
|
|
3886
|
+
);
|
|
3887
|
+
};
|
|
3888
|
+
|
|
3889
|
+
const assertProductionAuthorizationArtifacts = (
|
|
3890
|
+
authorizationArg: ICloudlyLegacyDeploymentSettlementProductionExecutionAuthorizationV1,
|
|
3891
|
+
productionMetadataArg:
|
|
3892
|
+
ICloudlyLegacyDeploymentSettlementFencedProductionAuthorityMetadataV1,
|
|
3893
|
+
sourceMetadataArg: ICloudlyLegacyDeploymentSettlementFencedSourceAuthorityMetadataV1,
|
|
3894
|
+
authenticatedPlanArg: IAuthenticatedCloudlyLegacyDeploymentSettlementPlanV1,
|
|
3895
|
+
requestBundleArg: ICloudlyLegacyDeploymentSettlementRequestBundleV1,
|
|
3896
|
+
scratchReceiptArg: ICloudlyLegacyDeploymentSettlementScratchReceiptV1,
|
|
3897
|
+
): void => {
|
|
3898
|
+
if (authorizationArg.authenticatedPlanSha256
|
|
3899
|
+
!== digestAuthenticatedCloudlyLegacyDeploymentSettlementPlan(authenticatedPlanArg)
|
|
3900
|
+
|| authorizationArg.requestBundleSha256
|
|
3901
|
+
!== digestCloudlyLegacyDeploymentSettlementRequestBundle(requestBundleArg)
|
|
3902
|
+
|| authorizationArg.scratchReceiptSha256
|
|
3903
|
+
!== digestCloudlyLegacyDeploymentSettlementScratchReceipt(scratchReceiptArg)
|
|
3904
|
+
|| productionMetadataArg.issuedAt <= scratchReceiptArg.completedAt
|
|
3905
|
+
|| authorizationArg.requestedAt <= scratchReceiptArg.completedAt
|
|
3906
|
+
|| authorizationArg.requestedAt < productionMetadataArg.issuedAt
|
|
3907
|
+
|| authorizationArg.approvedAt < authorizationArg.requestedAt) {
|
|
3908
|
+
fail('CROSS_FIELD_MISMATCH', 'productionExecutionAuthorization.sourceProof');
|
|
3909
|
+
}
|
|
3910
|
+
assertProductionAuthorizationMetadata(
|
|
3911
|
+
authorizationArg,
|
|
3912
|
+
productionMetadataArg,
|
|
3913
|
+
sourceMetadataArg,
|
|
3914
|
+
);
|
|
3915
|
+
};
|
|
3916
|
+
|
|
3917
|
+
export const normalizeCloudlyLegacyDeploymentSettlementProductionExecutionAuthorizationForAuthorities = async (
|
|
3918
|
+
authorizationArg: unknown,
|
|
3919
|
+
productionMetadataArg: unknown,
|
|
3920
|
+
sourceMetadataArg: unknown,
|
|
3921
|
+
authenticatedPlanArg: unknown,
|
|
3922
|
+
requestBundleArg: unknown,
|
|
3923
|
+
scratchReceiptArg: unknown,
|
|
3924
|
+
verifierArg: TCloudlyLegacyDeploymentSettlementHmacVerifier,
|
|
3925
|
+
): Promise<Readonly<ICloudlyLegacyDeploymentSettlementProductionExecutionAuthorizationV1>> => {
|
|
3926
|
+
const {
|
|
3927
|
+
productionMetadata,
|
|
3928
|
+
sourceMetadata,
|
|
3929
|
+
} = normalizeProductionAuthorityMetadataPair(
|
|
3930
|
+
productionMetadataArg,
|
|
3931
|
+
sourceMetadataArg,
|
|
3932
|
+
);
|
|
3933
|
+
const plan = await normalizeAuthenticatedCloudlyLegacyDeploymentSettlementPlanForAuthority(
|
|
3934
|
+
authenticatedPlanArg,
|
|
3935
|
+
sourceMetadata,
|
|
3936
|
+
verifierArg,
|
|
3937
|
+
);
|
|
3938
|
+
const requestBundle = await normalizeCloudlyLegacyDeploymentSettlementRequestBundleForAuthority(
|
|
3939
|
+
requestBundleArg,
|
|
3940
|
+
plan,
|
|
3941
|
+
sourceMetadata,
|
|
3942
|
+
verifierArg,
|
|
3943
|
+
);
|
|
3944
|
+
const scratchReceipt = await normalizeCloudlyLegacyDeploymentSettlementScratchReceiptForAuthority(
|
|
3945
|
+
scratchReceiptArg,
|
|
3946
|
+
sourceMetadata,
|
|
3947
|
+
requestBundle.authenticatedRequest,
|
|
3948
|
+
verifierArg,
|
|
3949
|
+
);
|
|
3950
|
+
const authorization =
|
|
3951
|
+
normalizeCloudlyLegacyDeploymentSettlementProductionExecutionAuthorization(authorizationArg);
|
|
3952
|
+
assertProductionAuthorizationArtifacts(
|
|
3953
|
+
authorization,
|
|
3954
|
+
productionMetadata,
|
|
3955
|
+
sourceMetadata,
|
|
3956
|
+
plan,
|
|
3957
|
+
requestBundle,
|
|
3958
|
+
scratchReceipt,
|
|
3959
|
+
);
|
|
3960
|
+
await requireConsumerVerifiedHmac(
|
|
3961
|
+
authorization.authority,
|
|
3962
|
+
cloudlyLegacyDeploymentSettlementDomains.productionExecutionAuthorizationHmac,
|
|
3963
|
+
encodeCloudlyLegacyDeploymentSettlementProductionExecutionAuthorizationHmacInput(
|
|
3964
|
+
withoutArtifactMac(authorization),
|
|
3965
|
+
),
|
|
3966
|
+
authorization.mac,
|
|
3967
|
+
verifierArg,
|
|
3968
|
+
'productionExecutionAuthorization.mac',
|
|
3969
|
+
);
|
|
3970
|
+
return authorization;
|
|
3971
|
+
};
|
|
3972
|
+
|
|
3973
|
+
const productionReceiptV2PayloadKeys = [
|
|
3974
|
+
'schemaVersion',
|
|
3975
|
+
'kind',
|
|
3976
|
+
'authority',
|
|
3977
|
+
'sourceAuthority',
|
|
3978
|
+
'executionAttempt',
|
|
3979
|
+
'productionAuthorization',
|
|
3980
|
+
'productionAuthorizationSha256',
|
|
3981
|
+
'requestSha256',
|
|
3982
|
+
'requestBundleSha256',
|
|
3983
|
+
'scratchReceipt',
|
|
3984
|
+
'scratchReceiptSha256',
|
|
3985
|
+
'stableOutcome',
|
|
3986
|
+
'stableOutcomeSha256',
|
|
3987
|
+
'transactionCommitted',
|
|
3988
|
+
'disposition',
|
|
3989
|
+
'completedAt',
|
|
3990
|
+
] as const;
|
|
3991
|
+
const unsignedProductionReceiptV2Keys = [...productionReceiptV2PayloadKeys, 'payloadSha256'] as const;
|
|
3992
|
+
const productionReceiptV2Keys = [...unsignedProductionReceiptV2Keys, 'mac'] as const;
|
|
3993
|
+
|
|
3994
|
+
const productionReceiptV2Payload = (
|
|
3995
|
+
valueArg: ICloudlyLegacyDeploymentSettlementProductionReceiptPayloadV2,
|
|
3996
|
+
): unknown => Object.fromEntries(productionReceiptV2PayloadKeys.map((keyArg) => [
|
|
3997
|
+
keyArg,
|
|
3998
|
+
valueArg[keyArg],
|
|
3999
|
+
]));
|
|
4000
|
+
|
|
4001
|
+
const normalizeProductionReceiptV2PayloadInternal = (
|
|
4002
|
+
valueArg: unknown,
|
|
4003
|
+
pathArg: string,
|
|
4004
|
+
): ICloudlyLegacyDeploymentSettlementProductionReceiptPayloadV2 => {
|
|
4005
|
+
const value = readRecord(valueArg, pathArg);
|
|
4006
|
+
assertExactKeys(value, productionReceiptV2PayloadKeys, pathArg);
|
|
4007
|
+
if (value.schemaVersion !== 2
|
|
4008
|
+
|| value.kind !== 'cloudly-legacy-deployment-settlement-production-receipt'
|
|
4009
|
+
|| value.transactionCommitted !== true) {
|
|
4010
|
+
fail('INVALID_VALUE', `${pathArg}.kind`);
|
|
4011
|
+
}
|
|
4012
|
+
const authority = normalizeAuthorityReferenceInternal(value.authority, `${pathArg}.authority`);
|
|
4013
|
+
const sourceAuthority = normalizeAuthorityReferenceInternal(
|
|
4014
|
+
value.sourceAuthority,
|
|
4015
|
+
`${pathArg}.sourceAuthority`,
|
|
4016
|
+
);
|
|
4017
|
+
const executionAttempt = normalizeExecutionAttemptIdentityInternal(
|
|
4018
|
+
value.executionAttempt,
|
|
4019
|
+
`${pathArg}.executionAttempt`,
|
|
4020
|
+
);
|
|
4021
|
+
const productionAuthorization =
|
|
4022
|
+
normalizeCloudlyLegacyDeploymentSettlementProductionExecutionAuthorization(
|
|
4023
|
+
value.productionAuthorization,
|
|
4024
|
+
);
|
|
4025
|
+
const productionAuthorizationSha256 = readSha256(
|
|
4026
|
+
value.productionAuthorizationSha256,
|
|
4027
|
+
`${pathArg}.productionAuthorizationSha256`,
|
|
4028
|
+
);
|
|
4029
|
+
const requestBundleSha256 = readSha256(
|
|
4030
|
+
value.requestBundleSha256,
|
|
4031
|
+
`${pathArg}.requestBundleSha256`,
|
|
4032
|
+
);
|
|
4033
|
+
const scratchReceipt = normalizeScratchReceiptInternal(
|
|
4034
|
+
value.scratchReceipt,
|
|
4035
|
+
`${pathArg}.scratchReceipt`,
|
|
4036
|
+
);
|
|
4037
|
+
const scratchReceiptSha256 = readSha256(
|
|
4038
|
+
value.scratchReceiptSha256,
|
|
4039
|
+
`${pathArg}.scratchReceiptSha256`,
|
|
4040
|
+
);
|
|
4041
|
+
const stableOutcome = normalizeStableOutcomeInternal(
|
|
4042
|
+
value.stableOutcome,
|
|
4043
|
+
`${pathArg}.stableOutcome`,
|
|
4044
|
+
);
|
|
4045
|
+
const stableOutcomeSha256 = readSha256(
|
|
4046
|
+
value.stableOutcomeSha256,
|
|
4047
|
+
`${pathArg}.stableOutcomeSha256`,
|
|
4048
|
+
);
|
|
4049
|
+
const requestSha256 = readSha256(value.requestSha256, `${pathArg}.requestSha256`);
|
|
4050
|
+
const disposition = readLiteral(
|
|
4051
|
+
value.disposition,
|
|
4052
|
+
['applied', 'exact-replay', 'no-op'],
|
|
4053
|
+
`${pathArg}.disposition`,
|
|
4054
|
+
);
|
|
4055
|
+
const dispositionMatchesScratch = disposition === scratchReceipt.disposition
|
|
4056
|
+
|| (scratchReceipt.disposition === 'applied' && disposition === 'exact-replay');
|
|
4057
|
+
if (canonicalize(authority, `${pathArg}.authority`)
|
|
4058
|
+
!== canonicalize(productionAuthorization.authority, `${pathArg}.authorization.authority`)
|
|
4059
|
+
|| canonicalize(sourceAuthority, `${pathArg}.sourceAuthority`)
|
|
4060
|
+
!== canonicalize(productionAuthorization.sourceAuthority, `${pathArg}.authorization.sourceAuthority`)
|
|
4061
|
+
|| canonicalize(executionAttempt, `${pathArg}.executionAttempt`)
|
|
4062
|
+
!== canonicalize(productionAuthorization.executionAttempt, `${pathArg}.authorization.attempt`)
|
|
4063
|
+
|| productionAuthorizationSha256
|
|
4064
|
+
!== digestCloudlyLegacyDeploymentSettlementProductionExecutionAuthorization(
|
|
4065
|
+
productionAuthorization,
|
|
4066
|
+
)
|
|
4067
|
+
|| requestBundleSha256 !== productionAuthorization.requestBundleSha256
|
|
4068
|
+
|| scratchReceiptSha256 !== productionAuthorization.scratchReceiptSha256
|
|
4069
|
+
|| scratchReceiptSha256
|
|
4070
|
+
!== digestCloudlyLegacyDeploymentSettlementScratchReceipt(scratchReceipt)
|
|
4071
|
+
|| canonicalize(sourceAuthority, `${pathArg}.sourceAuthority`)
|
|
4072
|
+
!== canonicalize(scratchReceipt.authority, `${pathArg}.scratchReceipt.authority`)
|
|
4073
|
+
|| requestSha256 !== scratchReceipt.requestSha256
|
|
4074
|
+
|| !dispositionMatchesScratch
|
|
4075
|
+
|| canonicalize(stableOutcome, `${pathArg}.stableOutcome`)
|
|
4076
|
+
!== canonicalize(scratchReceipt.stableOutcome, `${pathArg}.scratchReceipt.stableOutcome`)
|
|
4077
|
+
|| stableOutcomeSha256 !== scratchReceipt.stableOutcomeSha256
|
|
4078
|
+
|| stableOutcomeSha256
|
|
4079
|
+
!== digestCloudlyLegacyDeploymentSettlementStableOutcome(stableOutcome)) {
|
|
4080
|
+
fail('CROSS_FIELD_MISMATCH', `${pathArg}.productionAuthorization`);
|
|
4081
|
+
}
|
|
4082
|
+
return {
|
|
4083
|
+
schemaVersion: 2,
|
|
4084
|
+
kind: 'cloudly-legacy-deployment-settlement-production-receipt',
|
|
4085
|
+
authority,
|
|
4086
|
+
sourceAuthority,
|
|
4087
|
+
executionAttempt: executionAttempt as
|
|
4088
|
+
TCloudlyLegacyDeploymentSettlementProductionExecutionAttemptIdentityV1,
|
|
4089
|
+
productionAuthorization,
|
|
4090
|
+
productionAuthorizationSha256,
|
|
4091
|
+
requestSha256,
|
|
4092
|
+
requestBundleSha256,
|
|
4093
|
+
scratchReceipt,
|
|
4094
|
+
scratchReceiptSha256,
|
|
4095
|
+
stableOutcome,
|
|
4096
|
+
stableOutcomeSha256,
|
|
4097
|
+
transactionCommitted: true,
|
|
4098
|
+
disposition,
|
|
4099
|
+
completedAt: readInteger(
|
|
4100
|
+
value.completedAt,
|
|
4101
|
+
`${pathArg}.completedAt`,
|
|
4102
|
+
productionAuthorization.approvedAt,
|
|
4103
|
+
),
|
|
4104
|
+
};
|
|
4105
|
+
};
|
|
4106
|
+
|
|
4107
|
+
const normalizeUnsignedProductionReceiptV2Internal = (
|
|
4108
|
+
valueArg: unknown,
|
|
4109
|
+
pathArg: string,
|
|
4110
|
+
): TCloudlyLegacyDeploymentSettlementUnsignedProductionReceiptV2 => {
|
|
4111
|
+
const value = readRecord(valueArg, pathArg);
|
|
4112
|
+
assertExactKeys(value, unsignedProductionReceiptV2Keys, pathArg);
|
|
4113
|
+
const payloadInput = Object.fromEntries(productionReceiptV2PayloadKeys.map(
|
|
4114
|
+
(keyArg) => [keyArg, value[keyArg]],
|
|
4115
|
+
));
|
|
4116
|
+
const payload = normalizeProductionReceiptV2PayloadInternal(payloadInput, `${pathArg}.payload`);
|
|
4117
|
+
const payloadSha256 = readSha256(value.payloadSha256, `${pathArg}.payloadSha256`);
|
|
4118
|
+
if (payloadSha256 !== digestBytes(encodeNormalized(
|
|
4119
|
+
productionReceiptV2Payload(payload),
|
|
4120
|
+
`${pathArg}.payload`,
|
|
4121
|
+
))) {
|
|
4122
|
+
fail('CROSS_FIELD_MISMATCH', `${pathArg}.payloadSha256`);
|
|
4123
|
+
}
|
|
4124
|
+
return { ...payload, payloadSha256 };
|
|
4125
|
+
};
|
|
4126
|
+
|
|
4127
|
+
export const digestCloudlyLegacyDeploymentSettlementProductionReceiptPayloadV2 = (
|
|
4128
|
+
valueArg: unknown,
|
|
4129
|
+
): string => digestBytes(encodeNormalized(
|
|
4130
|
+
productionReceiptV2Payload(
|
|
4131
|
+
normalizeProductionReceiptV2PayloadInternal(valueArg, 'productionReceiptPayloadV2'),
|
|
4132
|
+
),
|
|
4133
|
+
'productionReceiptPayloadV2',
|
|
4134
|
+
));
|
|
4135
|
+
|
|
4136
|
+
export const normalizeCloudlyLegacyDeploymentSettlementProductionReceiptV2 = (
|
|
4137
|
+
valueArg: unknown,
|
|
4138
|
+
): Readonly<ICloudlyLegacyDeploymentSettlementProductionReceiptV2> => {
|
|
4139
|
+
const value = readRecord(valueArg, 'productionReceiptV2');
|
|
4140
|
+
assertExactKeys(value, productionReceiptV2Keys, 'productionReceiptV2');
|
|
4141
|
+
const unsignedInput = Object.fromEntries(unsignedProductionReceiptV2Keys.map(
|
|
4142
|
+
(keyArg) => [keyArg, value[keyArg]],
|
|
4143
|
+
));
|
|
4144
|
+
return finalize({
|
|
4145
|
+
...normalizeUnsignedProductionReceiptV2Internal(unsignedInput, 'productionReceiptV2.unsigned'),
|
|
4146
|
+
mac: readMac(value.mac, 'productionReceiptV2.mac'),
|
|
4147
|
+
}, cloudlyLegacyDeploymentSettlementLimits.maximumReceiptBytes * 3, 'productionReceiptV2');
|
|
4148
|
+
};
|
|
4149
|
+
|
|
4150
|
+
export const normalizeCloudlyLegacyDeploymentSettlementProductionReceiptAnyVersion = (
|
|
4151
|
+
valueArg: unknown,
|
|
4152
|
+
): Readonly<TCloudlyLegacyDeploymentSettlementProductionReceipt> => {
|
|
4153
|
+
const value = readRecord(valueArg, 'productionReceipt');
|
|
4154
|
+
return value.schemaVersion === 2
|
|
4155
|
+
? normalizeCloudlyLegacyDeploymentSettlementProductionReceiptV2(value)
|
|
4156
|
+
: normalizeCloudlyLegacyDeploymentSettlementProductionReceipt(value);
|
|
4157
|
+
};
|
|
4158
|
+
|
|
4159
|
+
export const encodeCloudlyLegacyDeploymentSettlementProductionReceiptV2 = (
|
|
4160
|
+
valueArg: unknown,
|
|
4161
|
+
): Uint8Array => encodeNormalized(
|
|
4162
|
+
normalizeCloudlyLegacyDeploymentSettlementProductionReceiptV2(valueArg),
|
|
4163
|
+
'productionReceiptV2',
|
|
4164
|
+
);
|
|
4165
|
+
|
|
4166
|
+
export const digestCloudlyLegacyDeploymentSettlementProductionReceiptV2 = (
|
|
4167
|
+
valueArg: unknown,
|
|
4168
|
+
): string => digestBytes(encodeCloudlyLegacyDeploymentSettlementProductionReceiptV2(valueArg));
|
|
4169
|
+
|
|
4170
|
+
export const encodeCloudlyLegacyDeploymentSettlementProductionReceiptV2HmacInput = (
|
|
4171
|
+
valueArg: unknown,
|
|
4172
|
+
): Uint8Array => frame(
|
|
4173
|
+
cloudlyLegacyDeploymentSettlementDomains.productionReceiptV2Hmac,
|
|
4174
|
+
encodeNormalized(
|
|
4175
|
+
finalize(
|
|
4176
|
+
normalizeUnsignedProductionReceiptV2Internal(valueArg, 'unsignedProductionReceiptV2'),
|
|
4177
|
+
cloudlyLegacyDeploymentSettlementLimits.maximumReceiptBytes * 3,
|
|
4178
|
+
'unsignedProductionReceiptV2',
|
|
4179
|
+
),
|
|
4180
|
+
'productionReceiptV2.authenticated',
|
|
4181
|
+
),
|
|
4182
|
+
);
|
|
4183
|
+
|
|
4184
|
+
export const normalizeCloudlyLegacyDeploymentSettlementProductionReceiptV2ForAuthorities = async (
|
|
4185
|
+
receiptArg: unknown,
|
|
4186
|
+
productionMetadataArg: unknown,
|
|
4187
|
+
sourceMetadataArg: unknown,
|
|
4188
|
+
authenticatedPlanArg: unknown,
|
|
4189
|
+
requestBundleArg: unknown,
|
|
4190
|
+
verifierArg: TCloudlyLegacyDeploymentSettlementHmacVerifier,
|
|
4191
|
+
): Promise<Readonly<ICloudlyLegacyDeploymentSettlementProductionReceiptV2>> => {
|
|
4192
|
+
const {
|
|
4193
|
+
productionMetadata,
|
|
4194
|
+
sourceMetadata,
|
|
4195
|
+
} = normalizeProductionAuthorityMetadataPair(
|
|
4196
|
+
productionMetadataArg,
|
|
4197
|
+
sourceMetadataArg,
|
|
4198
|
+
);
|
|
4199
|
+
const receipt = normalizeCloudlyLegacyDeploymentSettlementProductionReceiptV2(receiptArg);
|
|
4200
|
+
const requestBundle = normalizeCloudlyLegacyDeploymentSettlementRequestBundle(requestBundleArg);
|
|
4201
|
+
await normalizeCloudlyLegacyDeploymentSettlementProductionExecutionAuthorizationForAuthorities(
|
|
4202
|
+
receipt.productionAuthorization,
|
|
4203
|
+
productionMetadata,
|
|
4204
|
+
sourceMetadata,
|
|
4205
|
+
authenticatedPlanArg,
|
|
4206
|
+
requestBundle,
|
|
4207
|
+
receipt.scratchReceipt,
|
|
4208
|
+
verifierArg,
|
|
4209
|
+
);
|
|
4210
|
+
await normalizeCloudlyLegacyDeploymentSettlementScratchReceiptForAuthority(
|
|
4211
|
+
receipt.scratchReceipt,
|
|
4212
|
+
sourceMetadata,
|
|
4213
|
+
requestBundle.authenticatedRequest,
|
|
4214
|
+
verifierArg,
|
|
4215
|
+
);
|
|
4216
|
+
assertAuthorityReferenceMatchesMetadata(
|
|
4217
|
+
receipt.authority,
|
|
4218
|
+
productionMetadata,
|
|
4219
|
+
'productionReceiptV2.authority',
|
|
4220
|
+
);
|
|
4221
|
+
assertAuthorityTimestamp(receipt.completedAt, productionMetadata, 'productionReceiptV2.completedAt');
|
|
4222
|
+
await requireConsumerVerifiedHmac(
|
|
4223
|
+
receipt.authority,
|
|
4224
|
+
cloudlyLegacyDeploymentSettlementDomains.productionReceiptV2Hmac,
|
|
4225
|
+
encodeCloudlyLegacyDeploymentSettlementProductionReceiptV2HmacInput(
|
|
4226
|
+
withoutArtifactMac(receipt),
|
|
4227
|
+
),
|
|
4228
|
+
receipt.mac,
|
|
4229
|
+
verifierArg,
|
|
4230
|
+
'productionReceiptV2.mac',
|
|
4231
|
+
);
|
|
4232
|
+
return receipt;
|
|
4233
|
+
};
|
|
4234
|
+
|
|
4235
|
+
export type TCloudlyLegacyDeploymentSettlementAuthorityStatus = 'active' | 'expired';
|
|
4236
|
+
export type TCloudlyLegacyDeploymentSettlementResolutionMode =
|
|
4237
|
+
| 'committed-schema1'
|
|
4238
|
+
| 'committed-schema2'
|
|
4239
|
+
| 'aborted-prepared'
|
|
4240
|
+
| 'observed-aborted'
|
|
4241
|
+
| 'absent-tombstone'
|
|
4242
|
+
| 'legacy-no-op';
|
|
4243
|
+
|
|
4244
|
+
export type TCloudlyLegacyDeploymentSettlementCommittedReceipt =
|
|
4245
|
+
| ICloudlyLegacyDeploymentSettlementScratchReceiptV1
|
|
4246
|
+
| ICloudlyLegacyDeploymentSettlementProductionReceiptV2;
|
|
4247
|
+
type TCloudlyLegacyDeploymentSettlementCommittedObservationV1<
|
|
4248
|
+
TAttempt extends TCloudlyLegacyDeploymentSettlementExecutionAttemptIdentityV1,
|
|
4249
|
+
TReceiptSchemaVersion extends 1 | 2,
|
|
4250
|
+
> = Omit<
|
|
4251
|
+
ICloudlyLegacyDeploymentSettlementExecutionAttemptCommittedV1,
|
|
4252
|
+
'identity' | 'receiptSchemaVersion'
|
|
4253
|
+
> & {
|
|
4254
|
+
identity: TAttempt;
|
|
4255
|
+
receiptSchemaVersion: TReceiptSchemaVersion;
|
|
4256
|
+
};
|
|
4257
|
+
|
|
4258
|
+
interface ICloudlyLegacyDeploymentSettlementResolutionBundleBaseV1 {
|
|
4259
|
+
schemaVersion: 1;
|
|
4260
|
+
kind: 'cloudly-legacy-deployment-settlement-resolution-bundle';
|
|
4261
|
+
executionAttempt: TCloudlyLegacyDeploymentSettlementExecutionAttemptIdentityV1;
|
|
4262
|
+
observedAt: number;
|
|
4263
|
+
sourceAuthorityStatus: TCloudlyLegacyDeploymentSettlementAuthorityStatus;
|
|
4264
|
+
executionAuthorityStatus: TCloudlyLegacyDeploymentSettlementAuthorityStatus;
|
|
4265
|
+
}
|
|
4266
|
+
|
|
4267
|
+
export interface ICloudlyLegacyDeploymentSettlementCommittedScratchSchema1ResolutionBundleV1
|
|
4268
|
+
extends ICloudlyLegacyDeploymentSettlementResolutionBundleBaseV1 {
|
|
4269
|
+
outcome: 'committed';
|
|
4270
|
+
mode: 'committed-schema1';
|
|
4271
|
+
executionAttempt: TCloudlyLegacyDeploymentSettlementScratchExecutionAttemptIdentityV1;
|
|
4272
|
+
attemptObservation: TCloudlyLegacyDeploymentSettlementCommittedObservationV1<
|
|
4273
|
+
TCloudlyLegacyDeploymentSettlementScratchExecutionAttemptIdentityV1,
|
|
4274
|
+
1
|
|
4275
|
+
>;
|
|
4276
|
+
originalReceipt: ICloudlyLegacyDeploymentSettlementScratchReceiptV1;
|
|
4277
|
+
originalReceiptSha256: string;
|
|
4278
|
+
}
|
|
4279
|
+
|
|
4280
|
+
export interface ICloudlyLegacyDeploymentSettlementCommittedSchema2ResolutionBundleV1
|
|
4281
|
+
extends ICloudlyLegacyDeploymentSettlementResolutionBundleBaseV1 {
|
|
4282
|
+
outcome: 'committed';
|
|
4283
|
+
mode: 'committed-schema2';
|
|
4284
|
+
executionAttempt: TCloudlyLegacyDeploymentSettlementProductionExecutionAttemptIdentityV1;
|
|
4285
|
+
attemptObservation: TCloudlyLegacyDeploymentSettlementCommittedObservationV1<
|
|
4286
|
+
TCloudlyLegacyDeploymentSettlementProductionExecutionAttemptIdentityV1,
|
|
4287
|
+
2
|
|
4288
|
+
>;
|
|
4289
|
+
originalReceipt: ICloudlyLegacyDeploymentSettlementProductionReceiptV2;
|
|
4290
|
+
originalReceiptSha256: string;
|
|
4291
|
+
}
|
|
4292
|
+
|
|
4293
|
+
export type TCloudlyLegacyDeploymentSettlementCommittedResolutionBundleV1 =
|
|
4294
|
+
| ICloudlyLegacyDeploymentSettlementCommittedScratchSchema1ResolutionBundleV1
|
|
4295
|
+
| ICloudlyLegacyDeploymentSettlementCommittedSchema2ResolutionBundleV1;
|
|
4296
|
+
|
|
4297
|
+
export interface ICloudlyLegacyDeploymentSettlementAbortedPreparedResolutionBundleV1
|
|
4298
|
+
extends ICloudlyLegacyDeploymentSettlementResolutionBundleBaseV1 {
|
|
4299
|
+
outcome: 'unapplied';
|
|
4300
|
+
mode: 'aborted-prepared';
|
|
4301
|
+
attemptObservation: ICloudlyLegacyDeploymentSettlementExecutionAttemptAbortedV1;
|
|
4302
|
+
}
|
|
4303
|
+
|
|
4304
|
+
export interface ICloudlyLegacyDeploymentSettlementObservedAbortedResolutionBundleV1
|
|
4305
|
+
extends ICloudlyLegacyDeploymentSettlementResolutionBundleBaseV1 {
|
|
4306
|
+
outcome: 'unapplied';
|
|
4307
|
+
mode: 'observed-aborted';
|
|
4308
|
+
attemptObservation: ICloudlyLegacyDeploymentSettlementExecutionAttemptAbortedV1;
|
|
4309
|
+
}
|
|
4310
|
+
|
|
4311
|
+
export type TCloudlyLegacyDeploymentSettlementAbortedResolutionBundleV1 =
|
|
4312
|
+
| ICloudlyLegacyDeploymentSettlementAbortedPreparedResolutionBundleV1
|
|
4313
|
+
| ICloudlyLegacyDeploymentSettlementObservedAbortedResolutionBundleV1;
|
|
4314
|
+
|
|
4315
|
+
export interface ICloudlyLegacyDeploymentSettlementAbsentTombstoneResolutionBundleV1
|
|
4316
|
+
extends ICloudlyLegacyDeploymentSettlementResolutionBundleBaseV1 {
|
|
4317
|
+
outcome: 'unapplied';
|
|
4318
|
+
mode: 'absent-tombstone';
|
|
4319
|
+
attemptObservation: ICloudlyLegacyDeploymentSettlementExecutionAttemptAbortedV1;
|
|
4320
|
+
}
|
|
4321
|
+
|
|
4322
|
+
export interface ICloudlyLegacyDeploymentSettlementLegacyNoOpResolutionBundleV1
|
|
4323
|
+
extends ICloudlyLegacyDeploymentSettlementResolutionBundleBaseV1 {
|
|
4324
|
+
outcome: 'unapplied';
|
|
4325
|
+
mode: 'legacy-no-op';
|
|
4326
|
+
executionAttempt: TCloudlyLegacyDeploymentSettlementScratchExecutionAttemptIdentityV1;
|
|
4327
|
+
attemptObservation: null;
|
|
4328
|
+
}
|
|
4329
|
+
|
|
4330
|
+
export type TCloudlyLegacyDeploymentSettlementResolutionBundleV1 =
|
|
4331
|
+
| ICloudlyLegacyDeploymentSettlementCommittedScratchSchema1ResolutionBundleV1
|
|
4332
|
+
| ICloudlyLegacyDeploymentSettlementCommittedSchema2ResolutionBundleV1
|
|
4333
|
+
| ICloudlyLegacyDeploymentSettlementAbortedPreparedResolutionBundleV1
|
|
4334
|
+
| ICloudlyLegacyDeploymentSettlementObservedAbortedResolutionBundleV1
|
|
4335
|
+
| ICloudlyLegacyDeploymentSettlementAbsentTombstoneResolutionBundleV1
|
|
4336
|
+
| ICloudlyLegacyDeploymentSettlementLegacyNoOpResolutionBundleV1;
|
|
4337
|
+
|
|
4338
|
+
const normalizeCommittedResolutionReceipt = (
|
|
4339
|
+
valueArg: unknown,
|
|
4340
|
+
pathArg: string,
|
|
4341
|
+
): Readonly<TCloudlyLegacyDeploymentSettlementCommittedReceipt> => {
|
|
4342
|
+
const value = readRecord(valueArg, pathArg);
|
|
4343
|
+
if (value.kind === 'cloudly-legacy-deployment-settlement-scratch-receipt') {
|
|
4344
|
+
return normalizeCloudlyLegacyDeploymentSettlementScratchReceipt(value);
|
|
4345
|
+
}
|
|
4346
|
+
if (value.kind !== 'cloudly-legacy-deployment-settlement-production-receipt') {
|
|
4347
|
+
fail('INVALID_VALUE', `${pathArg}.kind`);
|
|
4348
|
+
}
|
|
4349
|
+
if (value.schemaVersion !== 2) {
|
|
4350
|
+
fail('INVALID_VALUE', `${pathArg}.schemaVersion`);
|
|
4351
|
+
}
|
|
4352
|
+
return normalizeCloudlyLegacyDeploymentSettlementProductionReceiptV2(value);
|
|
4353
|
+
};
|
|
4354
|
+
|
|
4355
|
+
/** Structural only; this function does not authenticate receipt MACs. */
|
|
4356
|
+
export const normalizeCloudlyLegacyDeploymentSettlementResolutionBundle = (
|
|
4357
|
+
valueArg: unknown,
|
|
4358
|
+
): Readonly<TCloudlyLegacyDeploymentSettlementResolutionBundleV1> => {
|
|
4359
|
+
const value = readRecord(valueArg, 'resolutionBundle');
|
|
4360
|
+
const outcome = readLiteral(value.outcome, ['committed', 'unapplied'], 'resolutionBundle.outcome');
|
|
4361
|
+
const mode = readLiteral(value.mode, [
|
|
4362
|
+
'committed-schema1',
|
|
4363
|
+
'committed-schema2',
|
|
4364
|
+
'aborted-prepared',
|
|
4365
|
+
'observed-aborted',
|
|
4366
|
+
'absent-tombstone',
|
|
4367
|
+
'legacy-no-op',
|
|
4368
|
+
], 'resolutionBundle.mode');
|
|
4369
|
+
const committed = outcome === 'committed';
|
|
4370
|
+
assertExactKeys(value, [
|
|
4371
|
+
'schemaVersion',
|
|
4372
|
+
'kind',
|
|
4373
|
+
'executionAttempt',
|
|
4374
|
+
'observedAt',
|
|
4375
|
+
'sourceAuthorityStatus',
|
|
4376
|
+
'executionAuthorityStatus',
|
|
4377
|
+
'outcome',
|
|
4378
|
+
'mode',
|
|
4379
|
+
'attemptObservation',
|
|
4380
|
+
...(committed ? ['originalReceipt', 'originalReceiptSha256'] : []),
|
|
4381
|
+
], 'resolutionBundle');
|
|
4382
|
+
if (value.schemaVersion !== 1
|
|
4383
|
+
|| value.kind !== 'cloudly-legacy-deployment-settlement-resolution-bundle') {
|
|
4384
|
+
fail('INVALID_VALUE', 'resolutionBundle.kind');
|
|
4385
|
+
}
|
|
4386
|
+
const executionAttempt = normalizeExecutionAttemptIdentityInternal(
|
|
4387
|
+
value.executionAttempt,
|
|
4388
|
+
'resolutionBundle.executionAttempt',
|
|
4389
|
+
);
|
|
4390
|
+
const observedAt = readInteger(value.observedAt, 'resolutionBundle.observedAt', 1);
|
|
4391
|
+
const sourceAuthorityStatus = readLiteral(
|
|
4392
|
+
value.sourceAuthorityStatus,
|
|
4393
|
+
['active', 'expired'],
|
|
4394
|
+
'resolutionBundle.sourceAuthorityStatus',
|
|
4395
|
+
);
|
|
4396
|
+
const executionAuthorityStatus = readLiteral(
|
|
4397
|
+
value.executionAuthorityStatus,
|
|
4398
|
+
['active', 'expired'],
|
|
4399
|
+
'resolutionBundle.executionAuthorityStatus',
|
|
4400
|
+
);
|
|
4401
|
+
if (canonicalize(executionAttempt.sourceAuthority, 'resolutionBundle.sourceAuthority')
|
|
4402
|
+
=== canonicalize(executionAttempt.executionAuthority, 'resolutionBundle.executionAuthority')
|
|
4403
|
+
&& sourceAuthorityStatus !== executionAuthorityStatus) {
|
|
4404
|
+
fail('CROSS_FIELD_MISMATCH', 'resolutionBundle.executionAuthorityStatus');
|
|
4405
|
+
}
|
|
4406
|
+
if (committed) {
|
|
4407
|
+
if (mode !== 'committed-schema1' && mode !== 'committed-schema2') {
|
|
4408
|
+
fail('CROSS_FIELD_MISMATCH', 'resolutionBundle.mode');
|
|
4409
|
+
}
|
|
4410
|
+
const attemptObservation = normalizeExecutionAttemptObservationInternal(
|
|
4411
|
+
value.attemptObservation,
|
|
4412
|
+
'resolutionBundle.attemptObservation',
|
|
4413
|
+
);
|
|
4414
|
+
if (attemptObservation.state !== 'committed') {
|
|
4415
|
+
fail('CROSS_FIELD_MISMATCH', 'resolutionBundle.attemptObservation');
|
|
4416
|
+
}
|
|
4417
|
+
const committedObservation = attemptObservation as
|
|
4418
|
+
ICloudlyLegacyDeploymentSettlementExecutionAttemptCommittedV1;
|
|
4419
|
+
if (canonicalize(committedObservation.identity, 'resolutionBundle.observation.identity')
|
|
4420
|
+
!== canonicalize(executionAttempt, 'resolutionBundle.executionAttempt')) {
|
|
4421
|
+
fail('CROSS_FIELD_MISMATCH', 'resolutionBundle.attemptObservation');
|
|
4422
|
+
}
|
|
4423
|
+
const originalReceipt = normalizeCommittedResolutionReceipt(
|
|
4424
|
+
value.originalReceipt,
|
|
4425
|
+
'resolutionBundle.originalReceipt',
|
|
4426
|
+
);
|
|
4427
|
+
const receiptSchemaVersion = originalReceipt.schemaVersion;
|
|
4428
|
+
const originalReceiptSha256 = readSha256(
|
|
4429
|
+
value.originalReceiptSha256,
|
|
4430
|
+
'resolutionBundle.originalReceiptSha256',
|
|
4431
|
+
);
|
|
4432
|
+
const expectedReceiptSha256 = originalReceipt.kind
|
|
4433
|
+
=== 'cloudly-legacy-deployment-settlement-scratch-receipt'
|
|
4434
|
+
? digestCloudlyLegacyDeploymentSettlementScratchReceipt(originalReceipt)
|
|
4435
|
+
: originalReceipt.schemaVersion === 2
|
|
4436
|
+
? digestCloudlyLegacyDeploymentSettlementProductionReceiptV2(originalReceipt)
|
|
4437
|
+
: digestCloudlyLegacyDeploymentSettlementProductionReceipt(originalReceipt);
|
|
4438
|
+
const receiptExecutionAuthority = originalReceipt.authority;
|
|
4439
|
+
const receiptSourceAuthority = originalReceipt.schemaVersion === 2
|
|
4440
|
+
? originalReceipt.sourceAuthority
|
|
4441
|
+
: originalReceipt.authority;
|
|
4442
|
+
if ((mode === 'committed-schema1') !== (receiptSchemaVersion === 1)
|
|
4443
|
+
|| committedObservation.receiptSchemaVersion !== receiptSchemaVersion
|
|
4444
|
+
|| committedObservation.receiptSha256 !== originalReceiptSha256
|
|
4445
|
+
|| originalReceiptSha256 !== expectedReceiptSha256
|
|
4446
|
+
|| committedObservation.resolvedAt !== originalReceipt.completedAt
|
|
4447
|
+
|| observedAt < committedObservation.resolvedAt
|
|
4448
|
+
|| canonicalize(receiptExecutionAuthority, 'resolutionBundle.receipt.executionAuthority')
|
|
4449
|
+
!== canonicalize(executionAttempt.executionAuthority, 'resolutionBundle.executionAuthority')
|
|
4450
|
+
|| canonicalize(receiptSourceAuthority, 'resolutionBundle.receipt.sourceAuthority')
|
|
4451
|
+
!== canonicalize(executionAttempt.sourceAuthority, 'resolutionBundle.sourceAuthority')
|
|
4452
|
+
|| (originalReceipt.schemaVersion === 2
|
|
4453
|
+
&& canonicalize(originalReceipt.executionAttempt, 'resolutionBundle.receipt.executionAttempt')
|
|
4454
|
+
!== canonicalize(executionAttempt, 'resolutionBundle.executionAttempt'))
|
|
4455
|
+
|| (executionAttempt.purpose === 'scratch-rehearsal')
|
|
4456
|
+
!== (originalReceipt.kind
|
|
4457
|
+
=== 'cloudly-legacy-deployment-settlement-scratch-receipt')) {
|
|
4458
|
+
fail('CROSS_FIELD_MISMATCH', 'resolutionBundle.originalReceipt');
|
|
4459
|
+
}
|
|
4460
|
+
let result: TCloudlyLegacyDeploymentSettlementCommittedResolutionBundleV1;
|
|
4461
|
+
if (mode === 'committed-schema1'
|
|
4462
|
+
&& originalReceipt.kind === 'cloudly-legacy-deployment-settlement-scratch-receipt') {
|
|
4463
|
+
const scratchAttempt = executionAttempt as
|
|
4464
|
+
TCloudlyLegacyDeploymentSettlementScratchExecutionAttemptIdentityV1;
|
|
4465
|
+
result = {
|
|
4466
|
+
schemaVersion: 1,
|
|
4467
|
+
kind: 'cloudly-legacy-deployment-settlement-resolution-bundle',
|
|
4468
|
+
executionAttempt: scratchAttempt,
|
|
4469
|
+
observedAt,
|
|
4470
|
+
sourceAuthorityStatus,
|
|
4471
|
+
executionAuthorityStatus,
|
|
4472
|
+
outcome,
|
|
4473
|
+
mode,
|
|
4474
|
+
attemptObservation: {
|
|
4475
|
+
...committedObservation,
|
|
4476
|
+
identity: scratchAttempt,
|
|
4477
|
+
receiptSchemaVersion: 1,
|
|
4478
|
+
},
|
|
4479
|
+
originalReceipt,
|
|
4480
|
+
originalReceiptSha256,
|
|
4481
|
+
};
|
|
4482
|
+
} else {
|
|
4483
|
+
const productionAttempt = executionAttempt as
|
|
4484
|
+
TCloudlyLegacyDeploymentSettlementProductionExecutionAttemptIdentityV1;
|
|
4485
|
+
result = {
|
|
4486
|
+
schemaVersion: 1,
|
|
4487
|
+
kind: 'cloudly-legacy-deployment-settlement-resolution-bundle',
|
|
4488
|
+
executionAttempt: productionAttempt,
|
|
4489
|
+
observedAt,
|
|
4490
|
+
sourceAuthorityStatus,
|
|
4491
|
+
executionAuthorityStatus,
|
|
4492
|
+
outcome,
|
|
4493
|
+
mode: 'committed-schema2',
|
|
4494
|
+
attemptObservation: {
|
|
4495
|
+
...committedObservation,
|
|
4496
|
+
identity: productionAttempt,
|
|
4497
|
+
receiptSchemaVersion: 2,
|
|
4498
|
+
},
|
|
4499
|
+
originalReceipt: originalReceipt as
|
|
4500
|
+
ICloudlyLegacyDeploymentSettlementProductionReceiptV2,
|
|
4501
|
+
originalReceiptSha256,
|
|
4502
|
+
};
|
|
4503
|
+
}
|
|
4504
|
+
return finalize(
|
|
4505
|
+
result,
|
|
4506
|
+
cloudlyLegacyDeploymentSettlementLimits.maximumReceiptBytes * 4,
|
|
4507
|
+
'resolutionBundle',
|
|
4508
|
+
);
|
|
4509
|
+
}
|
|
4510
|
+
if (mode === 'committed-schema1' || mode === 'committed-schema2') {
|
|
4511
|
+
fail('CROSS_FIELD_MISMATCH', 'resolutionBundle.mode');
|
|
4512
|
+
}
|
|
4513
|
+
if (mode === 'aborted-prepared'
|
|
4514
|
+
|| mode === 'observed-aborted'
|
|
4515
|
+
|| mode === 'absent-tombstone') {
|
|
4516
|
+
const attemptObservation = normalizeExecutionAttemptObservationInternal(
|
|
4517
|
+
value.attemptObservation,
|
|
4518
|
+
'resolutionBundle.attemptObservation',
|
|
4519
|
+
);
|
|
4520
|
+
if (attemptObservation.state !== 'aborted') {
|
|
4521
|
+
fail('CROSS_FIELD_MISMATCH', 'resolutionBundle.attemptObservation');
|
|
4522
|
+
}
|
|
4523
|
+
const abortedObservation = attemptObservation as
|
|
4524
|
+
ICloudlyLegacyDeploymentSettlementExecutionAttemptAbortedV1;
|
|
4525
|
+
if (canonicalize(abortedObservation.identity, 'resolutionBundle.observation.identity')
|
|
4526
|
+
!== canonicalize(executionAttempt, 'resolutionBundle.executionAttempt')
|
|
4527
|
+
|| observedAt < abortedObservation.resolvedAt) {
|
|
4528
|
+
fail('CROSS_FIELD_MISMATCH', 'resolutionBundle.attemptObservation');
|
|
4529
|
+
}
|
|
4530
|
+
if (mode === 'absent-tombstone') {
|
|
4531
|
+
const result: ICloudlyLegacyDeploymentSettlementAbsentTombstoneResolutionBundleV1 = {
|
|
4532
|
+
schemaVersion: 1,
|
|
4533
|
+
kind: 'cloudly-legacy-deployment-settlement-resolution-bundle',
|
|
4534
|
+
executionAttempt,
|
|
4535
|
+
observedAt,
|
|
4536
|
+
sourceAuthorityStatus,
|
|
4537
|
+
executionAuthorityStatus,
|
|
4538
|
+
outcome,
|
|
4539
|
+
mode,
|
|
4540
|
+
attemptObservation: abortedObservation,
|
|
4541
|
+
};
|
|
4542
|
+
return finalize(
|
|
4543
|
+
result,
|
|
4544
|
+
cloudlyLegacyDeploymentSettlementLimits.maximumReceiptBytes,
|
|
4545
|
+
'resolutionBundle',
|
|
4546
|
+
);
|
|
4547
|
+
}
|
|
4548
|
+
const result = mode === 'aborted-prepared'
|
|
4549
|
+
? {
|
|
4550
|
+
schemaVersion: 1 as const,
|
|
4551
|
+
kind: 'cloudly-legacy-deployment-settlement-resolution-bundle' as const,
|
|
4552
|
+
executionAttempt,
|
|
4553
|
+
observedAt,
|
|
4554
|
+
sourceAuthorityStatus,
|
|
4555
|
+
executionAuthorityStatus,
|
|
4556
|
+
outcome,
|
|
4557
|
+
mode,
|
|
4558
|
+
attemptObservation: abortedObservation,
|
|
4559
|
+
} satisfies ICloudlyLegacyDeploymentSettlementAbortedPreparedResolutionBundleV1
|
|
4560
|
+
: {
|
|
4561
|
+
schemaVersion: 1 as const,
|
|
4562
|
+
kind: 'cloudly-legacy-deployment-settlement-resolution-bundle' as const,
|
|
4563
|
+
executionAttempt,
|
|
4564
|
+
observedAt,
|
|
4565
|
+
sourceAuthorityStatus,
|
|
4566
|
+
executionAuthorityStatus,
|
|
4567
|
+
outcome,
|
|
4568
|
+
mode,
|
|
4569
|
+
attemptObservation: abortedObservation,
|
|
4570
|
+
} satisfies ICloudlyLegacyDeploymentSettlementObservedAbortedResolutionBundleV1;
|
|
4571
|
+
return finalize(
|
|
4572
|
+
result,
|
|
4573
|
+
cloudlyLegacyDeploymentSettlementLimits.maximumReceiptBytes,
|
|
4574
|
+
'resolutionBundle',
|
|
4575
|
+
);
|
|
4576
|
+
}
|
|
4577
|
+
if (value.attemptObservation !== null) {
|
|
4578
|
+
fail('CROSS_FIELD_MISMATCH', 'resolutionBundle.attemptObservation');
|
|
4579
|
+
}
|
|
4580
|
+
if (executionAttempt.purpose !== 'scratch-rehearsal') {
|
|
4581
|
+
fail('CROSS_FIELD_MISMATCH', 'resolutionBundle.executionAttempt');
|
|
4582
|
+
}
|
|
4583
|
+
const scratchExecutionAttempt = executionAttempt as
|
|
4584
|
+
TCloudlyLegacyDeploymentSettlementScratchExecutionAttemptIdentityV1;
|
|
4585
|
+
const result: ICloudlyLegacyDeploymentSettlementLegacyNoOpResolutionBundleV1 = {
|
|
4586
|
+
schemaVersion: 1,
|
|
4587
|
+
kind: 'cloudly-legacy-deployment-settlement-resolution-bundle',
|
|
4588
|
+
executionAttempt: scratchExecutionAttempt,
|
|
4589
|
+
observedAt,
|
|
4590
|
+
sourceAuthorityStatus,
|
|
4591
|
+
executionAuthorityStatus,
|
|
4592
|
+
outcome,
|
|
4593
|
+
mode: 'legacy-no-op',
|
|
4594
|
+
attemptObservation: null,
|
|
4595
|
+
};
|
|
4596
|
+
return finalize(
|
|
4597
|
+
result,
|
|
4598
|
+
cloudlyLegacyDeploymentSettlementLimits.maximumReceiptBytes,
|
|
4599
|
+
'resolutionBundle',
|
|
4600
|
+
);
|
|
4601
|
+
};
|
|
4602
|
+
|
|
4603
|
+
export const encodeCloudlyLegacyDeploymentSettlementResolutionBundle = (
|
|
4604
|
+
valueArg: unknown,
|
|
4605
|
+
): Uint8Array => encodeNormalized(
|
|
4606
|
+
normalizeCloudlyLegacyDeploymentSettlementResolutionBundle(valueArg),
|
|
4607
|
+
'resolutionBundle',
|
|
4608
|
+
);
|
|
4609
|
+
|
|
4610
|
+
export const digestCloudlyLegacyDeploymentSettlementResolutionBundle = (
|
|
4611
|
+
valueArg: unknown,
|
|
4612
|
+
): string => digestBytes(encodeCloudlyLegacyDeploymentSettlementResolutionBundle(valueArg));
|
|
4613
|
+
|
|
4614
|
+
/** Recovery attestation only; this is neither a receipt nor an execution authorization. */
|
|
4615
|
+
export interface IAuthenticatedCloudlyLegacyDeploymentSettlementResolutionV1 {
|
|
4616
|
+
schemaVersion: 1;
|
|
4617
|
+
kind: 'authenticated-cloudly-legacy-deployment-settlement-resolution';
|
|
4618
|
+
authority: ICloudlyLegacyDeploymentSettlementAuthorityReferenceV1;
|
|
4619
|
+
payload: TCloudlyLegacyDeploymentSettlementResolutionBundleV1;
|
|
4620
|
+
payloadSha256: string;
|
|
4621
|
+
mac: string;
|
|
4622
|
+
}
|
|
4623
|
+
|
|
4624
|
+
export type TUnsignedAuthenticatedCloudlyLegacyDeploymentSettlementResolutionV1 = Omit<
|
|
4625
|
+
IAuthenticatedCloudlyLegacyDeploymentSettlementResolutionV1,
|
|
4626
|
+
'mac'
|
|
4627
|
+
>;
|
|
4628
|
+
|
|
4629
|
+
const unsignedAuthenticatedResolutionKeys = [
|
|
4630
|
+
'schemaVersion',
|
|
4631
|
+
'kind',
|
|
4632
|
+
'authority',
|
|
4633
|
+
'payload',
|
|
4634
|
+
'payloadSha256',
|
|
4635
|
+
] as const;
|
|
4636
|
+
const authenticatedResolutionKeys = [...unsignedAuthenticatedResolutionKeys, 'mac'] as const;
|
|
4637
|
+
|
|
4638
|
+
const normalizeUnsignedAuthenticatedResolutionInternal = (
|
|
4639
|
+
valueArg: unknown,
|
|
4640
|
+
pathArg: string,
|
|
4641
|
+
): TUnsignedAuthenticatedCloudlyLegacyDeploymentSettlementResolutionV1 => {
|
|
4642
|
+
const value = readRecord(valueArg, pathArg);
|
|
4643
|
+
assertExactKeys(value, unsignedAuthenticatedResolutionKeys, pathArg);
|
|
4644
|
+
if (value.schemaVersion !== 1
|
|
4645
|
+
|| value.kind !== 'authenticated-cloudly-legacy-deployment-settlement-resolution') {
|
|
4646
|
+
fail('INVALID_VALUE', `${pathArg}.kind`);
|
|
4647
|
+
}
|
|
4648
|
+
const authority = normalizeAuthorityReferenceInternal(value.authority, `${pathArg}.authority`);
|
|
4649
|
+
const payload = normalizeCloudlyLegacyDeploymentSettlementResolutionBundle(value.payload);
|
|
4650
|
+
const payloadSha256 = readSha256(value.payloadSha256, `${pathArg}.payloadSha256`);
|
|
4651
|
+
if (canonicalize(authority, `${pathArg}.authority`)
|
|
4652
|
+
!== canonicalize(payload.executionAttempt.executionAuthority, `${pathArg}.payload.authority`)
|
|
4653
|
+
|| payloadSha256 !== digestCloudlyLegacyDeploymentSettlementResolutionBundle(payload)) {
|
|
4654
|
+
fail('CROSS_FIELD_MISMATCH', `${pathArg}.payload`);
|
|
4655
|
+
}
|
|
4656
|
+
return {
|
|
4657
|
+
schemaVersion: 1,
|
|
4658
|
+
kind: 'authenticated-cloudly-legacy-deployment-settlement-resolution',
|
|
4659
|
+
authority,
|
|
4660
|
+
payload,
|
|
4661
|
+
payloadSha256,
|
|
4662
|
+
};
|
|
4663
|
+
};
|
|
4664
|
+
|
|
4665
|
+
/** Structural only; this function does not authenticate the recovery-attestation MAC. */
|
|
4666
|
+
export const normalizeCloudlyLegacyDeploymentSettlementAuthenticatedResolutionStructure = (
|
|
4667
|
+
valueArg: unknown,
|
|
4668
|
+
): Readonly<IAuthenticatedCloudlyLegacyDeploymentSettlementResolutionV1> => {
|
|
4669
|
+
const value = readRecord(valueArg, 'authenticatedResolution');
|
|
4670
|
+
assertExactKeys(value, authenticatedResolutionKeys, 'authenticatedResolution');
|
|
4671
|
+
return finalize({
|
|
4672
|
+
...normalizeUnsignedAuthenticatedResolutionInternal(
|
|
4673
|
+
Object.fromEntries(unsignedAuthenticatedResolutionKeys.map((keyArg) => [
|
|
4674
|
+
keyArg,
|
|
4675
|
+
value[keyArg],
|
|
4676
|
+
])),
|
|
4677
|
+
'authenticatedResolution.unsigned',
|
|
4678
|
+
),
|
|
4679
|
+
mac: readMac(value.mac, 'authenticatedResolution.mac'),
|
|
4680
|
+
}, cloudlyLegacyDeploymentSettlementLimits.maximumReceiptBytes * 5, 'authenticatedResolution');
|
|
4681
|
+
};
|
|
4682
|
+
|
|
4683
|
+
export const encodeAuthenticatedCloudlyLegacyDeploymentSettlementResolution = (
|
|
4684
|
+
valueArg: unknown,
|
|
4685
|
+
): Uint8Array => encodeNormalized(
|
|
4686
|
+
normalizeCloudlyLegacyDeploymentSettlementAuthenticatedResolutionStructure(valueArg),
|
|
4687
|
+
'authenticatedResolution',
|
|
4688
|
+
);
|
|
4689
|
+
|
|
4690
|
+
export const digestAuthenticatedCloudlyLegacyDeploymentSettlementResolution = (
|
|
4691
|
+
valueArg: unknown,
|
|
4692
|
+
): string => digestBytes(encodeAuthenticatedCloudlyLegacyDeploymentSettlementResolution(valueArg));
|
|
4693
|
+
|
|
4694
|
+
export const encodeCloudlyLegacyDeploymentSettlementResolutionHmacInput = (
|
|
4695
|
+
valueArg: unknown,
|
|
4696
|
+
): Uint8Array => frame(
|
|
4697
|
+
cloudlyLegacyDeploymentSettlementDomains.resolutionHmac,
|
|
4698
|
+
encodeNormalized(
|
|
4699
|
+
finalize(
|
|
4700
|
+
normalizeUnsignedAuthenticatedResolutionInternal(
|
|
4701
|
+
valueArg,
|
|
4702
|
+
'unsignedAuthenticatedResolution',
|
|
4703
|
+
),
|
|
4704
|
+
cloudlyLegacyDeploymentSettlementLimits.maximumReceiptBytes * 5,
|
|
4705
|
+
'unsignedAuthenticatedResolution',
|
|
4706
|
+
),
|
|
4707
|
+
'authenticatedResolution.authenticated',
|
|
4708
|
+
),
|
|
4709
|
+
);
|
|
4710
|
+
|
|
4711
|
+
const normalizeExecutionAttemptAuthorityMetadata = (
|
|
4712
|
+
attemptArg: ICloudlyLegacyDeploymentSettlementExecutionAttemptIdentityV1,
|
|
4713
|
+
sourceMetadataArg: unknown,
|
|
4714
|
+
executionMetadataArg: unknown,
|
|
4715
|
+
): {
|
|
4716
|
+
sourceMetadata: Readonly<ICloudlyLegacyDeploymentSettlementFencedSourceAuthorityMetadataV1>;
|
|
4717
|
+
executionMetadata: Readonly<TCloudlyLegacyDeploymentSettlementAuthorityMetadataV1>;
|
|
4718
|
+
splitProductionAuthority: boolean;
|
|
4719
|
+
} => {
|
|
4720
|
+
const sourceMetadata = normalizeFencedSourceAuthorityMetadata(
|
|
4721
|
+
sourceMetadataArg,
|
|
4722
|
+
'executionAttempt.sourceAuthorityMetadata',
|
|
4723
|
+
);
|
|
4724
|
+
const executionMetadata = normalizeCloudlyLegacyDeploymentSettlementAuthorityMetadata(
|
|
4725
|
+
executionMetadataArg,
|
|
4726
|
+
);
|
|
4727
|
+
assertAuthorityReferenceMatchesMetadata(
|
|
4728
|
+
attemptArg.sourceAuthority,
|
|
4729
|
+
sourceMetadata,
|
|
4730
|
+
'executionAttempt.sourceAuthority',
|
|
4731
|
+
);
|
|
4732
|
+
assertAuthorityReferenceMatchesMetadata(
|
|
4733
|
+
attemptArg.executionAuthority,
|
|
4734
|
+
executionMetadata,
|
|
4735
|
+
'executionAttempt.executionAuthority',
|
|
4736
|
+
);
|
|
4737
|
+
const splitProductionAuthority = canonicalize(
|
|
4738
|
+
attemptArg.sourceAuthority,
|
|
4739
|
+
'executionAttempt.sourceAuthority',
|
|
4740
|
+
) !== canonicalize(attemptArg.executionAuthority, 'executionAttempt.executionAuthority');
|
|
4741
|
+
if (attemptArg.purpose === 'scratch-rehearsal') {
|
|
4742
|
+
if (splitProductionAuthority) {
|
|
4743
|
+
fail('CROSS_FIELD_MISMATCH', 'executionAttempt.executionAuthority');
|
|
4744
|
+
}
|
|
4745
|
+
normalizeFencedSourceAuthorityMetadata(
|
|
4746
|
+
executionMetadata,
|
|
4747
|
+
'executionAttempt.executionAuthorityMetadata',
|
|
4748
|
+
);
|
|
4749
|
+
} else {
|
|
4750
|
+
if (!splitProductionAuthority) {
|
|
4751
|
+
fail('CROSS_FIELD_MISMATCH', 'executionAttempt.executionAuthority');
|
|
4752
|
+
}
|
|
4753
|
+
const productionMetadata = normalizeProductionAuthorityMetadataPair(
|
|
4754
|
+
executionMetadata,
|
|
4755
|
+
sourceMetadata,
|
|
4756
|
+
).productionMetadata;
|
|
4757
|
+
if (productionMetadata.sourceAuthenticatedPlanSha256
|
|
4758
|
+
!== attemptArg.authenticatedPlanSha256
|
|
4759
|
+
|| productionMetadata.sourceRequestBundleSha256 !== attemptArg.requestBundleSha256
|
|
4760
|
+
|| productionMetadata.scratchReceiptSha256 !== attemptArg.scratchReceiptSha256) {
|
|
4761
|
+
fail('CROSS_FIELD_MISMATCH', 'executionAttempt.productionAuthorityMetadata');
|
|
4762
|
+
}
|
|
4763
|
+
}
|
|
4764
|
+
return { sourceMetadata, executionMetadata, splitProductionAuthority };
|
|
4765
|
+
};
|
|
4766
|
+
|
|
4767
|
+
const authorityStatusAt = (
|
|
4768
|
+
observedAtArg: number,
|
|
4769
|
+
metadataArg: TCloudlyLegacyDeploymentSettlementAuthorityMetadataV1,
|
|
4770
|
+
pathArg: string,
|
|
4771
|
+
): TCloudlyLegacyDeploymentSettlementAuthorityStatus => {
|
|
4772
|
+
if (observedAtArg < metadataArg.issuedAt) {
|
|
4773
|
+
fail('CROSS_FIELD_MISMATCH', pathArg);
|
|
4774
|
+
}
|
|
4775
|
+
return observedAtArg < metadataArg.expiresAt ? 'active' : 'expired';
|
|
4776
|
+
};
|
|
4777
|
+
|
|
4778
|
+
const normalizeExecutionAttemptProofArtifacts = async (argsArg: {
|
|
4779
|
+
executionAttempt: ICloudlyLegacyDeploymentSettlementExecutionAttemptIdentityV1;
|
|
4780
|
+
sourceMetadata: unknown;
|
|
4781
|
+
executionMetadata: unknown;
|
|
4782
|
+
authenticatedPlan: unknown;
|
|
4783
|
+
requestBundle: unknown;
|
|
4784
|
+
scratchReceipt: unknown | null;
|
|
4785
|
+
productionAuthorization: unknown | null;
|
|
4786
|
+
requireProductionAuthorization: boolean;
|
|
4787
|
+
verifier: TCloudlyLegacyDeploymentSettlementHmacVerifier;
|
|
4788
|
+
}): Promise<{
|
|
4789
|
+
sourceMetadata: Readonly<ICloudlyLegacyDeploymentSettlementFencedSourceAuthorityMetadataV1>;
|
|
4790
|
+
executionMetadata: Readonly<TCloudlyLegacyDeploymentSettlementAuthorityMetadataV1>;
|
|
4791
|
+
authenticatedPlan: Readonly<IAuthenticatedCloudlyLegacyDeploymentSettlementPlanV1>;
|
|
4792
|
+
requestBundle: Readonly<ICloudlyLegacyDeploymentSettlementRequestBundleV1>;
|
|
4793
|
+
scratchReceipt: Readonly<ICloudlyLegacyDeploymentSettlementScratchReceiptV1> | null;
|
|
4794
|
+
productionAuthorization:
|
|
4795
|
+
Readonly<ICloudlyLegacyDeploymentSettlementProductionExecutionAuthorizationV1> | null;
|
|
4796
|
+
splitProductionAuthority: boolean;
|
|
4797
|
+
}> => {
|
|
4798
|
+
const metadata = normalizeExecutionAttemptAuthorityMetadata(
|
|
4799
|
+
argsArg.executionAttempt,
|
|
4800
|
+
argsArg.sourceMetadata,
|
|
4801
|
+
argsArg.executionMetadata,
|
|
4802
|
+
);
|
|
4803
|
+
const authenticatedPlan =
|
|
4804
|
+
await normalizeAuthenticatedCloudlyLegacyDeploymentSettlementPlanForAuthority(
|
|
4805
|
+
argsArg.authenticatedPlan,
|
|
4806
|
+
metadata.sourceMetadata,
|
|
4807
|
+
argsArg.verifier,
|
|
4808
|
+
);
|
|
4809
|
+
const requestBundle = await normalizeCloudlyLegacyDeploymentSettlementRequestBundleForAuthority(
|
|
4810
|
+
argsArg.requestBundle,
|
|
4811
|
+
authenticatedPlan,
|
|
4812
|
+
metadata.sourceMetadata,
|
|
4813
|
+
argsArg.verifier,
|
|
4814
|
+
);
|
|
4815
|
+
let scratchReceipt: Readonly<ICloudlyLegacyDeploymentSettlementScratchReceiptV1> | null = null;
|
|
4816
|
+
let productionAuthorization:
|
|
4817
|
+
Readonly<ICloudlyLegacyDeploymentSettlementProductionExecutionAuthorizationV1> | null = null;
|
|
4818
|
+
if (argsArg.executionAttempt.purpose === 'production') {
|
|
4819
|
+
if (argsArg.scratchReceipt === null) {
|
|
4820
|
+
fail('INVALID_SCHEMA', 'executionAttempt.scratchReceipt');
|
|
4821
|
+
}
|
|
4822
|
+
scratchReceipt = await normalizeCloudlyLegacyDeploymentSettlementScratchReceiptForAuthority(
|
|
4823
|
+
argsArg.scratchReceipt,
|
|
4824
|
+
metadata.sourceMetadata,
|
|
4825
|
+
requestBundle.authenticatedRequest,
|
|
4826
|
+
argsArg.verifier,
|
|
4827
|
+
);
|
|
4828
|
+
if (metadata.splitProductionAuthority) {
|
|
4829
|
+
if (argsArg.productionAuthorization === null) {
|
|
4830
|
+
if (argsArg.requireProductionAuthorization) {
|
|
4831
|
+
fail('INVALID_SCHEMA', 'executionAttempt.productionAuthorization');
|
|
4832
|
+
}
|
|
4833
|
+
} else {
|
|
4834
|
+
productionAuthorization =
|
|
4835
|
+
await normalizeCloudlyLegacyDeploymentSettlementProductionExecutionAuthorizationForAuthorities(
|
|
4836
|
+
argsArg.productionAuthorization,
|
|
4837
|
+
metadata.executionMetadata,
|
|
4838
|
+
metadata.sourceMetadata,
|
|
4839
|
+
authenticatedPlan,
|
|
4840
|
+
requestBundle,
|
|
4841
|
+
scratchReceipt,
|
|
4842
|
+
argsArg.verifier,
|
|
4843
|
+
);
|
|
4844
|
+
}
|
|
4845
|
+
} else if (argsArg.productionAuthorization !== null) {
|
|
4846
|
+
fail('INVALID_SCHEMA', 'executionAttempt.productionAuthorization');
|
|
4847
|
+
}
|
|
4848
|
+
} else if (argsArg.scratchReceipt !== null || argsArg.productionAuthorization !== null) {
|
|
4849
|
+
fail('INVALID_SCHEMA', 'executionAttempt.sourceProof');
|
|
4850
|
+
}
|
|
4851
|
+
const expectedScratchReceiptSha256 = scratchReceipt
|
|
4852
|
+
? digestCloudlyLegacyDeploymentSettlementScratchReceipt(scratchReceipt)
|
|
4853
|
+
: null;
|
|
4854
|
+
if (argsArg.executionAttempt.authenticatedPlanSha256
|
|
4855
|
+
!== digestAuthenticatedCloudlyLegacyDeploymentSettlementPlan(authenticatedPlan)
|
|
4856
|
+
|| argsArg.executionAttempt.requestBundleSha256
|
|
4857
|
+
!== digestCloudlyLegacyDeploymentSettlementRequestBundle(requestBundle)
|
|
4858
|
+
|| argsArg.executionAttempt.scratchReceiptSha256 !== expectedScratchReceiptSha256) {
|
|
4859
|
+
fail('CROSS_FIELD_MISMATCH', 'executionAttempt.sourceProof');
|
|
4860
|
+
}
|
|
4861
|
+
return {
|
|
4862
|
+
...metadata,
|
|
4863
|
+
authenticatedPlan,
|
|
4864
|
+
requestBundle,
|
|
4865
|
+
scratchReceipt,
|
|
4866
|
+
productionAuthorization,
|
|
4867
|
+
};
|
|
4868
|
+
};
|
|
4869
|
+
|
|
4870
|
+
const normalizeAuthenticatedApplyResultForExecutionAuthority = async (
|
|
4871
|
+
resultArg: unknown,
|
|
4872
|
+
executionMetadataArg: unknown,
|
|
4873
|
+
requestArg: unknown,
|
|
4874
|
+
productionAuthorizationArg:
|
|
4875
|
+
ICloudlyLegacyDeploymentSettlementProductionExecutionAuthorizationV1,
|
|
4876
|
+
verifierArg: TCloudlyLegacyDeploymentSettlementHmacVerifier,
|
|
4877
|
+
): Promise<Readonly<IAuthenticatedCloudlyLegacyDeploymentSettlementApplyResultV1>> => {
|
|
4878
|
+
const executionMetadata = normalizeCloudlyLegacyDeploymentSettlementAuthorityMetadata(
|
|
4879
|
+
executionMetadataArg,
|
|
4880
|
+
);
|
|
4881
|
+
const request = normalizeCloudlyLegacyDeploymentSettlementAuthenticatedProductionRequestStructure(
|
|
4882
|
+
requestArg,
|
|
4883
|
+
);
|
|
4884
|
+
const result = normalizeCloudlyLegacyDeploymentSettlementAuthenticatedApplyResultStructure(resultArg);
|
|
4885
|
+
assertAuthorityReferenceMatchesMetadata(result.authority, executionMetadata, 'applyResult.authority');
|
|
4886
|
+
assertSummaryMatchesProductionRequest(result.payload, request.payload, 'applyResult.payload');
|
|
4887
|
+
const resultAt = result.payload.status === 'completed'
|
|
4888
|
+
? result.payload.completedAt
|
|
4889
|
+
: result.payload.rejectedAt;
|
|
4890
|
+
const resultAtPath = result.payload.status === 'completed'
|
|
4891
|
+
? 'applyResult.payload.completedAt'
|
|
4892
|
+
: 'applyResult.payload.rejectedAt';
|
|
4893
|
+
if (canonicalize(result.authority, 'applyResult.authority')
|
|
4894
|
+
!== canonicalize(productionAuthorizationArg.authority, 'productionAuthorization.authority')
|
|
4895
|
+
|| resultAt < request.payload.requestedAt
|
|
4896
|
+
|| resultAt < productionAuthorizationArg.approvedAt) {
|
|
4897
|
+
fail('CROSS_FIELD_MISMATCH', resultAtPath);
|
|
4898
|
+
}
|
|
4899
|
+
assertAuthorityTimestamp(resultAt, executionMetadata, resultAtPath);
|
|
4900
|
+
await requireConsumerVerifiedHmac(
|
|
4901
|
+
result.authority,
|
|
4902
|
+
cloudlyLegacyDeploymentSettlementDomains.applyResultHmac,
|
|
4903
|
+
encodeCloudlyLegacyDeploymentSettlementApplyResultHmacInput(withoutArtifactMac(result)),
|
|
4904
|
+
result.mac,
|
|
4905
|
+
verifierArg,
|
|
4906
|
+
'applyResult.mac',
|
|
4907
|
+
);
|
|
4908
|
+
return result;
|
|
4909
|
+
};
|
|
4910
|
+
|
|
4911
|
+
const normalizeAuthenticatedCheckResultForExecutionAuthority = async (
|
|
4912
|
+
resultArg: unknown,
|
|
4913
|
+
executionMetadataArg: unknown,
|
|
4914
|
+
requestArg: unknown,
|
|
4915
|
+
productionAuthorizationArg:
|
|
4916
|
+
ICloudlyLegacyDeploymentSettlementProductionExecutionAuthorizationV1,
|
|
4917
|
+
verifierArg: TCloudlyLegacyDeploymentSettlementHmacVerifier,
|
|
4918
|
+
): Promise<Readonly<IAuthenticatedCloudlyLegacyDeploymentSettlementCheckResultV1>> => {
|
|
4919
|
+
const executionMetadata = normalizeCloudlyLegacyDeploymentSettlementAuthorityMetadata(
|
|
4920
|
+
executionMetadataArg,
|
|
4921
|
+
);
|
|
4922
|
+
const request = normalizeCloudlyLegacyDeploymentSettlementAuthenticatedProductionRequestStructure(
|
|
4923
|
+
requestArg,
|
|
4924
|
+
);
|
|
4925
|
+
const result = normalizeCloudlyLegacyDeploymentSettlementAuthenticatedCheckResultStructure(resultArg);
|
|
4926
|
+
assertAuthorityReferenceMatchesMetadata(result.authority, executionMetadata, 'checkResult.authority');
|
|
4927
|
+
assertSummaryMatchesProductionRequest(result.payload, request.payload, 'checkResult.payload');
|
|
4928
|
+
if (canonicalize(result.authority, 'checkResult.authority')
|
|
4929
|
+
!== canonicalize(productionAuthorizationArg.authority, 'productionAuthorization.authority')
|
|
4930
|
+
|| result.payload.checkedAt < request.payload.requestedAt
|
|
4931
|
+
|| result.payload.checkedAt < productionAuthorizationArg.approvedAt) {
|
|
4932
|
+
fail('CROSS_FIELD_MISMATCH', 'checkResult.payload.checkedAt');
|
|
4933
|
+
}
|
|
4934
|
+
assertAuthorityTimestamp(result.payload.checkedAt, executionMetadata, 'checkResult.checkedAt');
|
|
4935
|
+
await requireConsumerVerifiedHmac(
|
|
4936
|
+
result.authority,
|
|
4937
|
+
cloudlyLegacyDeploymentSettlementDomains.checkResultHmac,
|
|
4938
|
+
encodeCloudlyLegacyDeploymentSettlementCheckResultHmacInput(withoutArtifactMac(result)),
|
|
4939
|
+
result.mac,
|
|
4940
|
+
verifierArg,
|
|
4941
|
+
'checkResult.mac',
|
|
4942
|
+
);
|
|
4943
|
+
return result;
|
|
4944
|
+
};
|
|
4945
|
+
|
|
4946
|
+
/** Artifact/status binding only; trust the authenticated recovery attestation instead. */
|
|
4947
|
+
export const normalizeCloudlyLegacyDeploymentSettlementResolutionBundleForAuthorities = async (
|
|
4948
|
+
bundleArg: unknown,
|
|
4949
|
+
sourceMetadataArg: unknown,
|
|
4950
|
+
executionMetadataArg: unknown,
|
|
4951
|
+
authenticatedPlanArg: unknown,
|
|
4952
|
+
requestBundleArg: unknown,
|
|
4953
|
+
scratchReceiptArg: unknown | null,
|
|
4954
|
+
productionAuthorizationArg: unknown | null,
|
|
4955
|
+
verifierArg: TCloudlyLegacyDeploymentSettlementHmacVerifier,
|
|
4956
|
+
): Promise<Readonly<TCloudlyLegacyDeploymentSettlementResolutionBundleV1>> => {
|
|
4957
|
+
const bundle = normalizeCloudlyLegacyDeploymentSettlementResolutionBundle(bundleArg);
|
|
4958
|
+
const artifacts = await normalizeExecutionAttemptProofArtifacts({
|
|
4959
|
+
executionAttempt: bundle.executionAttempt,
|
|
4960
|
+
sourceMetadata: sourceMetadataArg,
|
|
4961
|
+
executionMetadata: executionMetadataArg,
|
|
4962
|
+
authenticatedPlan: authenticatedPlanArg,
|
|
4963
|
+
requestBundle: requestBundleArg,
|
|
4964
|
+
scratchReceipt: scratchReceiptArg,
|
|
4965
|
+
productionAuthorization: productionAuthorizationArg,
|
|
4966
|
+
requireProductionAuthorization: true,
|
|
4967
|
+
verifier: verifierArg,
|
|
4968
|
+
});
|
|
4969
|
+
if (bundle.sourceAuthorityStatus !== authorityStatusAt(
|
|
4970
|
+
bundle.observedAt,
|
|
4971
|
+
artifacts.sourceMetadata,
|
|
4972
|
+
'resolutionBundle.sourceAuthorityStatus',
|
|
4973
|
+
)) {
|
|
4974
|
+
fail('CROSS_FIELD_MISMATCH', 'resolutionBundle.sourceAuthorityStatus');
|
|
4975
|
+
}
|
|
4976
|
+
if (bundle.executionAuthorityStatus !== authorityStatusAt(
|
|
4977
|
+
bundle.observedAt,
|
|
4978
|
+
artifacts.executionMetadata,
|
|
4979
|
+
'resolutionBundle.executionAuthorityStatus',
|
|
4980
|
+
)) {
|
|
4981
|
+
fail('CROSS_FIELD_MISMATCH', 'resolutionBundle.executionAuthorityStatus');
|
|
4982
|
+
}
|
|
4983
|
+
if (bundle.executionAttempt.purpose === 'production') {
|
|
4984
|
+
const productionAuthorization = artifacts.productionAuthorization
|
|
4985
|
+
?? fail('CROSS_FIELD_MISMATCH', 'resolutionBundle.productionAuthorization');
|
|
4986
|
+
const attemptObservation = bundle.attemptObservation
|
|
4987
|
+
?? fail('CROSS_FIELD_MISMATCH', 'resolutionBundle.attemptObservation');
|
|
4988
|
+
if (attemptObservation.preparedAt < productionAuthorization.approvedAt
|
|
4989
|
+
|| attemptObservation.resolvedAt < productionAuthorization.approvedAt
|
|
4990
|
+
|| bundle.observedAt < productionAuthorization.approvedAt) {
|
|
4991
|
+
fail('CROSS_FIELD_MISMATCH', 'resolutionBundle.attemptObservation.preparedAt');
|
|
4992
|
+
}
|
|
4993
|
+
}
|
|
4994
|
+
if (bundle.outcome === 'committed') {
|
|
4995
|
+
const receipt = bundle.originalReceipt;
|
|
4996
|
+
if (receipt.kind === 'cloudly-legacy-deployment-settlement-scratch-receipt') {
|
|
4997
|
+
await normalizeCloudlyLegacyDeploymentSettlementScratchReceiptForAuthority(
|
|
4998
|
+
receipt,
|
|
4999
|
+
artifacts.sourceMetadata,
|
|
5000
|
+
artifacts.requestBundle.authenticatedRequest,
|
|
5001
|
+
verifierArg,
|
|
5002
|
+
);
|
|
5003
|
+
} else if (receipt.schemaVersion === 2) {
|
|
5004
|
+
if (!artifacts.splitProductionAuthority || !artifacts.productionAuthorization) {
|
|
5005
|
+
fail('CROSS_FIELD_MISMATCH', 'resolutionBundle.originalReceipt.authority');
|
|
5006
|
+
}
|
|
5007
|
+
await normalizeCloudlyLegacyDeploymentSettlementProductionReceiptV2ForAuthorities(
|
|
5008
|
+
receipt,
|
|
5009
|
+
artifacts.executionMetadata,
|
|
5010
|
+
artifacts.sourceMetadata,
|
|
5011
|
+
artifacts.authenticatedPlan,
|
|
5012
|
+
artifacts.requestBundle,
|
|
5013
|
+
verifierArg,
|
|
5014
|
+
);
|
|
5015
|
+
if (canonicalize(
|
|
5016
|
+
receipt.productionAuthorization,
|
|
5017
|
+
'resolutionBundle.originalReceipt.productionAuthorization',
|
|
5018
|
+
) !== canonicalize(
|
|
5019
|
+
artifacts.productionAuthorization,
|
|
5020
|
+
'resolutionBundle.productionAuthorization',
|
|
5021
|
+
)) {
|
|
5022
|
+
fail('CROSS_FIELD_MISMATCH', 'resolutionBundle.originalReceipt.productionAuthorization');
|
|
5023
|
+
}
|
|
5024
|
+
} else {
|
|
5025
|
+
if (artifacts.splitProductionAuthority) {
|
|
5026
|
+
fail('CROSS_FIELD_MISMATCH', 'resolutionBundle.originalReceipt.authority');
|
|
5027
|
+
}
|
|
5028
|
+
await normalizeCloudlyLegacyDeploymentSettlementProductionReceiptForAuthority(
|
|
5029
|
+
receipt,
|
|
5030
|
+
artifacts.sourceMetadata,
|
|
5031
|
+
artifacts.requestBundle.authenticatedRequest,
|
|
5032
|
+
verifierArg,
|
|
5033
|
+
);
|
|
5034
|
+
}
|
|
5035
|
+
if (receipt.kind === 'cloudly-legacy-deployment-settlement-production-receipt'
|
|
5036
|
+
&& artifacts.scratchReceipt
|
|
5037
|
+
&& digestCloudlyLegacyDeploymentSettlementScratchReceipt(receipt.scratchReceipt)
|
|
5038
|
+
!== digestCloudlyLegacyDeploymentSettlementScratchReceipt(artifacts.scratchReceipt)) {
|
|
5039
|
+
fail('CROSS_FIELD_MISMATCH', 'resolutionBundle.originalReceipt.scratchReceipt');
|
|
5040
|
+
}
|
|
5041
|
+
}
|
|
5042
|
+
return bundle;
|
|
5043
|
+
};
|
|
5044
|
+
|
|
5045
|
+
export const normalizeAuthenticatedCloudlyLegacyDeploymentSettlementResolutionForAuthorities = async (
|
|
5046
|
+
attestationArg: unknown,
|
|
5047
|
+
sourceMetadataArg: unknown,
|
|
5048
|
+
executionMetadataArg: unknown,
|
|
5049
|
+
authenticatedPlanArg: unknown,
|
|
5050
|
+
requestBundleArg: unknown,
|
|
5051
|
+
scratchReceiptArg: unknown | null,
|
|
5052
|
+
productionAuthorizationArg: unknown | null,
|
|
5053
|
+
verifierArg: TCloudlyLegacyDeploymentSettlementHmacVerifier,
|
|
5054
|
+
): Promise<Readonly<IAuthenticatedCloudlyLegacyDeploymentSettlementResolutionV1>> => {
|
|
5055
|
+
const attestation =
|
|
5056
|
+
normalizeCloudlyLegacyDeploymentSettlementAuthenticatedResolutionStructure(attestationArg);
|
|
5057
|
+
const executionMetadata = normalizeCloudlyLegacyDeploymentSettlementAuthorityMetadata(
|
|
5058
|
+
executionMetadataArg,
|
|
5059
|
+
);
|
|
5060
|
+
assertAuthorityReferenceMatchesMetadata(
|
|
5061
|
+
attestation.authority,
|
|
5062
|
+
executionMetadata,
|
|
5063
|
+
'authenticatedResolution.authority',
|
|
5064
|
+
);
|
|
5065
|
+
await requireConsumerVerifiedHmac(
|
|
5066
|
+
attestation.authority,
|
|
5067
|
+
cloudlyLegacyDeploymentSettlementDomains.resolutionHmac,
|
|
5068
|
+
encodeCloudlyLegacyDeploymentSettlementResolutionHmacInput(
|
|
5069
|
+
withoutArtifactMac(attestation),
|
|
5070
|
+
),
|
|
5071
|
+
attestation.mac,
|
|
5072
|
+
verifierArg,
|
|
5073
|
+
'authenticatedResolution.mac',
|
|
5074
|
+
);
|
|
5075
|
+
const payload = await normalizeCloudlyLegacyDeploymentSettlementResolutionBundleForAuthorities(
|
|
5076
|
+
attestation.payload,
|
|
5077
|
+
sourceMetadataArg,
|
|
5078
|
+
executionMetadata,
|
|
5079
|
+
authenticatedPlanArg,
|
|
5080
|
+
requestBundleArg,
|
|
5081
|
+
scratchReceiptArg,
|
|
5082
|
+
productionAuthorizationArg,
|
|
5083
|
+
verifierArg,
|
|
5084
|
+
);
|
|
5085
|
+
if (canonicalize(attestation.payload, 'authenticatedResolution.payload')
|
|
5086
|
+
!== canonicalize(payload, 'authenticatedResolution.verifiedPayload')) {
|
|
5087
|
+
fail('CROSS_FIELD_MISMATCH', 'authenticatedResolution.payload');
|
|
5088
|
+
}
|
|
5089
|
+
return attestation;
|
|
5090
|
+
};
|
|
5091
|
+
|
|
5092
|
+
export type TCloudlyLegacyDeploymentSettlementCompletedApplyResultV1 = Extract<
|
|
5093
|
+
TCloudlyLegacyDeploymentSettlementApplyResultV1,
|
|
5094
|
+
{ status: 'completed' }
|
|
5095
|
+
>;
|
|
5096
|
+
export type TCloudlyLegacyDeploymentSettlementRejectedApplyResultV1 = Extract<
|
|
5097
|
+
TCloudlyLegacyDeploymentSettlementApplyResultV1,
|
|
5098
|
+
{ status: 'rejected' }
|
|
5099
|
+
>;
|
|
5100
|
+
export type TAuthenticatedCloudlyLegacyDeploymentSettlementCompletedApplyResultV1 = Omit<
|
|
5101
|
+
IAuthenticatedCloudlyLegacyDeploymentSettlementApplyResultV1,
|
|
5102
|
+
'payload'
|
|
5103
|
+
> & {
|
|
5104
|
+
payload: TCloudlyLegacyDeploymentSettlementCompletedApplyResultV1;
|
|
5105
|
+
};
|
|
5106
|
+
export type TAuthenticatedCloudlyLegacyDeploymentSettlementRejectedApplyResultV1 = Omit<
|
|
5107
|
+
IAuthenticatedCloudlyLegacyDeploymentSettlementApplyResultV1,
|
|
5108
|
+
'payload'
|
|
5109
|
+
> & {
|
|
5110
|
+
payload: TCloudlyLegacyDeploymentSettlementRejectedApplyResultV1;
|
|
5111
|
+
};
|
|
5112
|
+
|
|
5113
|
+
interface ICloudlyLegacyDeploymentSettlementScratchExecutionBundleBaseV1 {
|
|
5114
|
+
schemaVersion: 1;
|
|
5115
|
+
kind: 'cloudly-legacy-deployment-settlement-execution-bundle';
|
|
5116
|
+
purpose: 'scratch-rehearsal';
|
|
5117
|
+
executionAttempt: TCloudlyLegacyDeploymentSettlementScratchExecutionAttemptIdentityV1;
|
|
5118
|
+
}
|
|
5119
|
+
|
|
5120
|
+
export interface ICloudlyLegacyDeploymentSettlementCompletedScratchExecutionBundleV1
|
|
5121
|
+
extends ICloudlyLegacyDeploymentSettlementScratchExecutionBundleBaseV1 {
|
|
5122
|
+
authenticatedResult:
|
|
5123
|
+
TAuthenticatedCloudlyLegacyDeploymentSettlementCompletedApplyResultV1;
|
|
5124
|
+
receipt: ICloudlyLegacyDeploymentSettlementScratchReceiptV1;
|
|
5125
|
+
}
|
|
5126
|
+
|
|
5127
|
+
export interface ICloudlyLegacyDeploymentSettlementRejectedScratchExecutionBundleV1
|
|
5128
|
+
extends ICloudlyLegacyDeploymentSettlementScratchExecutionBundleBaseV1 {
|
|
5129
|
+
authenticatedResult:
|
|
5130
|
+
TAuthenticatedCloudlyLegacyDeploymentSettlementRejectedApplyResultV1;
|
|
5131
|
+
receipt?: never;
|
|
5132
|
+
}
|
|
5133
|
+
|
|
5134
|
+
export type TCloudlyLegacyDeploymentSettlementScratchExecutionBundleV1 =
|
|
5135
|
+
| ICloudlyLegacyDeploymentSettlementCompletedScratchExecutionBundleV1
|
|
5136
|
+
| ICloudlyLegacyDeploymentSettlementRejectedScratchExecutionBundleV1;
|
|
5137
|
+
|
|
5138
|
+
interface ICloudlyLegacyDeploymentSettlementProductionExecutionBundleBaseV2 {
|
|
5139
|
+
schemaVersion: 2;
|
|
5140
|
+
kind: 'cloudly-legacy-deployment-settlement-execution-bundle';
|
|
5141
|
+
purpose: 'production';
|
|
5142
|
+
executionAttempt: TCloudlyLegacyDeploymentSettlementProductionExecutionAttemptIdentityV1;
|
|
5143
|
+
}
|
|
5144
|
+
|
|
5145
|
+
export interface ICloudlyLegacyDeploymentSettlementCompletedProductionExecutionBundleV2
|
|
5146
|
+
extends ICloudlyLegacyDeploymentSettlementProductionExecutionBundleBaseV2 {
|
|
5147
|
+
authenticatedResult:
|
|
5148
|
+
TAuthenticatedCloudlyLegacyDeploymentSettlementCompletedApplyResultV1;
|
|
5149
|
+
receipt: ICloudlyLegacyDeploymentSettlementProductionReceiptV2;
|
|
5150
|
+
}
|
|
5151
|
+
|
|
5152
|
+
export interface ICloudlyLegacyDeploymentSettlementRejectedProductionExecutionBundleV2
|
|
5153
|
+
extends ICloudlyLegacyDeploymentSettlementProductionExecutionBundleBaseV2 {
|
|
5154
|
+
authenticatedResult:
|
|
5155
|
+
TAuthenticatedCloudlyLegacyDeploymentSettlementRejectedApplyResultV1;
|
|
5156
|
+
receipt?: never;
|
|
5157
|
+
}
|
|
5158
|
+
|
|
5159
|
+
export type TCloudlyLegacyDeploymentSettlementProductionExecutionBundleV2 =
|
|
5160
|
+
| ICloudlyLegacyDeploymentSettlementCompletedProductionExecutionBundleV2
|
|
5161
|
+
| ICloudlyLegacyDeploymentSettlementRejectedProductionExecutionBundleV2;
|
|
5162
|
+
|
|
5163
|
+
const normalizeSettlementExecutionBundleCommon = (
|
|
5164
|
+
valueArg: unknown,
|
|
5165
|
+
pathArg: string,
|
|
5166
|
+
purposeArg: TCloudlyLegacyDeploymentSettlementExecutionPurpose,
|
|
5167
|
+
): {
|
|
5168
|
+
value: Record<string, unknown>;
|
|
5169
|
+
executionAttempt: ICloudlyLegacyDeploymentSettlementExecutionAttemptIdentityV1;
|
|
5170
|
+
authenticatedResult: IAuthenticatedCloudlyLegacyDeploymentSettlementApplyResultV1;
|
|
5171
|
+
hasReceipt: boolean;
|
|
5172
|
+
} => {
|
|
5173
|
+
const value = readRecord(valueArg, pathArg);
|
|
5174
|
+
const hasReceipt = Object.hasOwn(value, 'receipt');
|
|
5175
|
+
assertExactKeys(value, [
|
|
5176
|
+
'schemaVersion',
|
|
5177
|
+
'kind',
|
|
5178
|
+
'purpose',
|
|
5179
|
+
'executionAttempt',
|
|
5180
|
+
'authenticatedResult',
|
|
5181
|
+
...(hasReceipt ? ['receipt'] : []),
|
|
5182
|
+
], pathArg);
|
|
5183
|
+
if (value.kind !== 'cloudly-legacy-deployment-settlement-execution-bundle'
|
|
5184
|
+
|| value.purpose !== purposeArg) {
|
|
5185
|
+
fail('INVALID_VALUE', `${pathArg}.kind`);
|
|
5186
|
+
}
|
|
5187
|
+
const executionAttempt = normalizeExecutionAttemptIdentityInternal(
|
|
5188
|
+
value.executionAttempt,
|
|
5189
|
+
`${pathArg}.executionAttempt`,
|
|
5190
|
+
);
|
|
5191
|
+
const authenticatedResult =
|
|
5192
|
+
normalizeCloudlyLegacyDeploymentSettlementAuthenticatedApplyResultStructure(
|
|
5193
|
+
value.authenticatedResult,
|
|
5194
|
+
);
|
|
5195
|
+
if (executionAttempt.purpose !== purposeArg
|
|
5196
|
+
|| canonicalize(authenticatedResult.authority, `${pathArg}.result.authority`)
|
|
5197
|
+
!== canonicalize(executionAttempt.executionAuthority, `${pathArg}.attempt.authority`)
|
|
5198
|
+
|| (authenticatedResult.payload.status === 'completed') !== hasReceipt) {
|
|
5199
|
+
fail('CROSS_FIELD_MISMATCH', `${pathArg}.authenticatedResult`);
|
|
5200
|
+
}
|
|
5201
|
+
return { value, executionAttempt, authenticatedResult, hasReceipt };
|
|
5202
|
+
};
|
|
5203
|
+
|
|
5204
|
+
/** Structural only; this function does not authenticate result or receipt MACs. */
|
|
5205
|
+
export const normalizeCloudlyLegacyDeploymentSettlementScratchExecutionBundle = (
|
|
5206
|
+
valueArg: unknown,
|
|
5207
|
+
): Readonly<TCloudlyLegacyDeploymentSettlementScratchExecutionBundleV1> => {
|
|
5208
|
+
const normalized = normalizeSettlementExecutionBundleCommon(
|
|
5209
|
+
valueArg,
|
|
5210
|
+
'scratchExecutionBundle',
|
|
5211
|
+
'scratch-rehearsal',
|
|
5212
|
+
);
|
|
5213
|
+
if (normalized.value.schemaVersion !== 1) {
|
|
5214
|
+
fail('INVALID_VALUE', 'scratchExecutionBundle.schemaVersion');
|
|
5215
|
+
}
|
|
5216
|
+
const receipt = normalized.hasReceipt
|
|
5217
|
+
? normalizeCloudlyLegacyDeploymentSettlementScratchReceipt(normalized.value.receipt)
|
|
5218
|
+
: undefined;
|
|
5219
|
+
if (receipt
|
|
5220
|
+
&& (canonicalize(receipt.authority, 'scratchExecutionBundle.receipt.authority')
|
|
5221
|
+
!== canonicalize(
|
|
5222
|
+
normalized.executionAttempt.executionAuthority,
|
|
5223
|
+
'scratchExecutionBundle.attempt.authority',
|
|
5224
|
+
)
|
|
5225
|
+
|| normalized.authenticatedResult.payload.status !== 'completed'
|
|
5226
|
+
|| normalized.authenticatedResult.payload.requestSha256 !== receipt.requestSha256
|
|
5227
|
+
|| (normalized.authenticatedResult.payload.disposition !== receipt.disposition
|
|
5228
|
+
&& !(receipt.disposition === 'applied'
|
|
5229
|
+
&& normalized.authenticatedResult.payload.disposition === 'exact-replay')))) {
|
|
5230
|
+
fail('CROSS_FIELD_MISMATCH', 'scratchExecutionBundle.receipt');
|
|
5231
|
+
}
|
|
5232
|
+
const executionAttempt = normalized.executionAttempt as
|
|
5233
|
+
TCloudlyLegacyDeploymentSettlementScratchExecutionAttemptIdentityV1;
|
|
5234
|
+
const result: TCloudlyLegacyDeploymentSettlementScratchExecutionBundleV1 = receipt
|
|
5235
|
+
? {
|
|
5236
|
+
schemaVersion: 1,
|
|
5237
|
+
kind: 'cloudly-legacy-deployment-settlement-execution-bundle',
|
|
5238
|
+
purpose: 'scratch-rehearsal',
|
|
5239
|
+
executionAttempt,
|
|
5240
|
+
authenticatedResult: normalized.authenticatedResult as
|
|
5241
|
+
TAuthenticatedCloudlyLegacyDeploymentSettlementCompletedApplyResultV1,
|
|
5242
|
+
receipt,
|
|
5243
|
+
}
|
|
5244
|
+
: {
|
|
5245
|
+
schemaVersion: 1,
|
|
5246
|
+
kind: 'cloudly-legacy-deployment-settlement-execution-bundle',
|
|
5247
|
+
purpose: 'scratch-rehearsal',
|
|
5248
|
+
executionAttempt,
|
|
5249
|
+
authenticatedResult: normalized.authenticatedResult as
|
|
5250
|
+
TAuthenticatedCloudlyLegacyDeploymentSettlementRejectedApplyResultV1,
|
|
5251
|
+
};
|
|
5252
|
+
return finalize(
|
|
5253
|
+
result,
|
|
5254
|
+
cloudlyLegacyDeploymentSettlementLimits.maximumReceiptBytes * 2,
|
|
5255
|
+
'scratchExecutionBundle',
|
|
5256
|
+
);
|
|
5257
|
+
};
|
|
5258
|
+
|
|
5259
|
+
/** Structural only; this function does not authenticate result or receipt MACs. */
|
|
5260
|
+
export const normalizeCloudlyLegacyDeploymentSettlementProductionExecutionBundleV2 = (
|
|
5261
|
+
valueArg: unknown,
|
|
5262
|
+
): Readonly<TCloudlyLegacyDeploymentSettlementProductionExecutionBundleV2> => {
|
|
5263
|
+
const normalized = normalizeSettlementExecutionBundleCommon(
|
|
5264
|
+
valueArg,
|
|
5265
|
+
'productionExecutionBundleV2',
|
|
5266
|
+
'production',
|
|
5267
|
+
);
|
|
5268
|
+
if (normalized.value.schemaVersion !== 2) {
|
|
5269
|
+
fail('INVALID_VALUE', 'productionExecutionBundleV2.schemaVersion');
|
|
5270
|
+
}
|
|
5271
|
+
const receipt = normalized.hasReceipt
|
|
5272
|
+
? normalizeCloudlyLegacyDeploymentSettlementProductionReceiptV2(normalized.value.receipt)
|
|
5273
|
+
: undefined;
|
|
5274
|
+
if (receipt
|
|
5275
|
+
&& (canonicalize(receipt.executionAttempt, 'productionExecutionBundleV2.receipt.attempt')
|
|
5276
|
+
!== canonicalize(
|
|
5277
|
+
normalized.executionAttempt,
|
|
5278
|
+
'productionExecutionBundleV2.executionAttempt',
|
|
5279
|
+
)
|
|
5280
|
+
|| normalized.authenticatedResult.payload.status !== 'completed'
|
|
5281
|
+
|| normalized.authenticatedResult.payload.requestSha256 !== receipt.requestSha256
|
|
5282
|
+
|| (normalized.authenticatedResult.payload.disposition !== receipt.disposition
|
|
5283
|
+
&& !(receipt.disposition === 'applied'
|
|
5284
|
+
&& normalized.authenticatedResult.payload.disposition === 'exact-replay')))) {
|
|
5285
|
+
fail('CROSS_FIELD_MISMATCH', 'productionExecutionBundleV2.receipt');
|
|
5286
|
+
}
|
|
5287
|
+
const executionAttempt = normalized.executionAttempt as
|
|
5288
|
+
TCloudlyLegacyDeploymentSettlementProductionExecutionAttemptIdentityV1;
|
|
5289
|
+
const result: TCloudlyLegacyDeploymentSettlementProductionExecutionBundleV2 = receipt
|
|
5290
|
+
? {
|
|
5291
|
+
schemaVersion: 2,
|
|
5292
|
+
kind: 'cloudly-legacy-deployment-settlement-execution-bundle',
|
|
5293
|
+
purpose: 'production',
|
|
5294
|
+
executionAttempt,
|
|
5295
|
+
authenticatedResult: normalized.authenticatedResult as
|
|
5296
|
+
TAuthenticatedCloudlyLegacyDeploymentSettlementCompletedApplyResultV1,
|
|
5297
|
+
receipt,
|
|
5298
|
+
}
|
|
5299
|
+
: {
|
|
5300
|
+
schemaVersion: 2,
|
|
5301
|
+
kind: 'cloudly-legacy-deployment-settlement-execution-bundle',
|
|
5302
|
+
purpose: 'production',
|
|
5303
|
+
executionAttempt,
|
|
5304
|
+
authenticatedResult: normalized.authenticatedResult as
|
|
5305
|
+
TAuthenticatedCloudlyLegacyDeploymentSettlementRejectedApplyResultV1,
|
|
5306
|
+
};
|
|
5307
|
+
return finalize(
|
|
5308
|
+
result,
|
|
5309
|
+
cloudlyLegacyDeploymentSettlementLimits.maximumReceiptBytes * 4,
|
|
5310
|
+
'productionExecutionBundleV2',
|
|
5311
|
+
);
|
|
5312
|
+
};
|
|
5313
|
+
|
|
5314
|
+
export const encodeCloudlyLegacyDeploymentSettlementScratchExecutionBundle = (
|
|
5315
|
+
valueArg: unknown,
|
|
5316
|
+
): Uint8Array => encodeNormalized(
|
|
5317
|
+
normalizeCloudlyLegacyDeploymentSettlementScratchExecutionBundle(valueArg),
|
|
5318
|
+
'scratchExecutionBundle',
|
|
5319
|
+
);
|
|
5320
|
+
|
|
5321
|
+
export const encodeCloudlyLegacyDeploymentSettlementProductionExecutionBundleV2 = (
|
|
5322
|
+
valueArg: unknown,
|
|
5323
|
+
): Uint8Array => encodeNormalized(
|
|
5324
|
+
normalizeCloudlyLegacyDeploymentSettlementProductionExecutionBundleV2(valueArg),
|
|
5325
|
+
'productionExecutionBundleV2',
|
|
5326
|
+
);
|
|
5327
|
+
|
|
5328
|
+
export const normalizeCloudlyLegacyDeploymentSettlementScratchExecutionBundleForAuthority = async (
|
|
5329
|
+
bundleArg: unknown,
|
|
5330
|
+
sourceMetadataArg: unknown,
|
|
5331
|
+
authenticatedPlanArg: unknown,
|
|
5332
|
+
requestBundleArg: unknown,
|
|
5333
|
+
verifierArg: TCloudlyLegacyDeploymentSettlementHmacVerifier,
|
|
5334
|
+
): Promise<Readonly<TCloudlyLegacyDeploymentSettlementScratchExecutionBundleV1>> => {
|
|
5335
|
+
const bundle = normalizeCloudlyLegacyDeploymentSettlementScratchExecutionBundle(bundleArg);
|
|
5336
|
+
const artifacts = await normalizeExecutionAttemptProofArtifacts({
|
|
5337
|
+
executionAttempt: bundle.executionAttempt,
|
|
5338
|
+
sourceMetadata: sourceMetadataArg,
|
|
5339
|
+
executionMetadata: sourceMetadataArg,
|
|
5340
|
+
authenticatedPlan: authenticatedPlanArg,
|
|
5341
|
+
requestBundle: requestBundleArg,
|
|
5342
|
+
scratchReceipt: null,
|
|
5343
|
+
productionAuthorization: null,
|
|
5344
|
+
requireProductionAuthorization: false,
|
|
5345
|
+
verifier: verifierArg,
|
|
5346
|
+
});
|
|
5347
|
+
await normalizeAuthenticatedCloudlyLegacyDeploymentSettlementApplyResultForAuthority(
|
|
5348
|
+
bundle.authenticatedResult,
|
|
5349
|
+
artifacts.sourceMetadata,
|
|
5350
|
+
artifacts.requestBundle.authenticatedRequest,
|
|
5351
|
+
verifierArg,
|
|
5352
|
+
);
|
|
5353
|
+
if (bundle.receipt) {
|
|
5354
|
+
await normalizeCloudlyLegacyDeploymentSettlementScratchReceiptForAuthority(
|
|
5355
|
+
bundle.receipt,
|
|
5356
|
+
artifacts.sourceMetadata,
|
|
5357
|
+
artifacts.requestBundle.authenticatedRequest,
|
|
5358
|
+
verifierArg,
|
|
5359
|
+
);
|
|
5360
|
+
}
|
|
5361
|
+
return bundle;
|
|
5362
|
+
};
|
|
5363
|
+
|
|
5364
|
+
export const normalizeCloudlyLegacyDeploymentSettlementProductionExecutionBundleV2ForAuthorities = async (
|
|
5365
|
+
bundleArg: unknown,
|
|
5366
|
+
productionAuthorizationArg: unknown,
|
|
5367
|
+
productionMetadataArg: unknown,
|
|
5368
|
+
sourceMetadataArg: unknown,
|
|
5369
|
+
authenticatedPlanArg: unknown,
|
|
5370
|
+
requestBundleArg: unknown,
|
|
5371
|
+
scratchReceiptArg: unknown,
|
|
5372
|
+
verifierArg: TCloudlyLegacyDeploymentSettlementHmacVerifier,
|
|
5373
|
+
): Promise<Readonly<TCloudlyLegacyDeploymentSettlementProductionExecutionBundleV2>> => {
|
|
5374
|
+
const bundle = normalizeCloudlyLegacyDeploymentSettlementProductionExecutionBundleV2(bundleArg);
|
|
5375
|
+
const artifacts = await normalizeExecutionAttemptProofArtifacts({
|
|
5376
|
+
executionAttempt: bundle.executionAttempt,
|
|
5377
|
+
sourceMetadata: sourceMetadataArg,
|
|
5378
|
+
executionMetadata: productionMetadataArg,
|
|
5379
|
+
authenticatedPlan: authenticatedPlanArg,
|
|
5380
|
+
requestBundle: requestBundleArg,
|
|
5381
|
+
scratchReceipt: scratchReceiptArg,
|
|
5382
|
+
productionAuthorization: productionAuthorizationArg,
|
|
5383
|
+
requireProductionAuthorization: true,
|
|
5384
|
+
verifier: verifierArg,
|
|
5385
|
+
});
|
|
5386
|
+
const productionAuthorization = artifacts.productionAuthorization
|
|
5387
|
+
?? fail('CROSS_FIELD_MISMATCH', 'productionExecutionBundleV2.executionAuthority');
|
|
5388
|
+
if (!artifacts.splitProductionAuthority) {
|
|
5389
|
+
fail('CROSS_FIELD_MISMATCH', 'productionExecutionBundleV2.executionAuthority');
|
|
5390
|
+
}
|
|
5391
|
+
await normalizeAuthenticatedApplyResultForExecutionAuthority(
|
|
5392
|
+
bundle.authenticatedResult,
|
|
5393
|
+
artifacts.executionMetadata,
|
|
5394
|
+
artifacts.requestBundle.authenticatedRequest,
|
|
5395
|
+
productionAuthorization,
|
|
5396
|
+
verifierArg,
|
|
5397
|
+
);
|
|
5398
|
+
if (bundle.receipt) {
|
|
5399
|
+
await normalizeCloudlyLegacyDeploymentSettlementProductionReceiptV2ForAuthorities(
|
|
5400
|
+
bundle.receipt,
|
|
5401
|
+
artifacts.executionMetadata,
|
|
5402
|
+
artifacts.sourceMetadata,
|
|
5403
|
+
artifacts.authenticatedPlan,
|
|
5404
|
+
artifacts.requestBundle,
|
|
5405
|
+
verifierArg,
|
|
5406
|
+
);
|
|
5407
|
+
if (canonicalize(
|
|
5408
|
+
bundle.receipt.productionAuthorization,
|
|
5409
|
+
'productionExecutionBundleV2.receipt.productionAuthorization',
|
|
5410
|
+
) !== canonicalize(
|
|
5411
|
+
artifacts.productionAuthorization,
|
|
5412
|
+
'productionExecutionBundleV2.productionAuthorization',
|
|
5413
|
+
)) {
|
|
5414
|
+
fail('CROSS_FIELD_MISMATCH', 'productionExecutionBundleV2.productionAuthorization');
|
|
5415
|
+
}
|
|
5416
|
+
}
|
|
5417
|
+
return bundle;
|
|
5418
|
+
};
|
|
5419
|
+
|
|
5420
|
+
export const cloudlyLegacyDeploymentSettlementStdioLimits = Object.freeze({
|
|
5421
|
+
maximumMongoDescriptorBytes: 16 * 1024,
|
|
5422
|
+
maximumPrivateArtifactAggregateBytes: 4 * 1024 * 1024,
|
|
5423
|
+
maximumRequestFrameBytes: 5 * 1024 * 1024,
|
|
5424
|
+
maximumResponseFrameBytes: 4 * 1024 * 1024,
|
|
5425
|
+
});
|
|
5426
|
+
|
|
5427
|
+
export const cloudlyLegacyDeploymentSettlementStdioCommands = Object.freeze([
|
|
5428
|
+
'settlement-plan',
|
|
5429
|
+
'settlement-request',
|
|
5430
|
+
'settlement-scratch-check',
|
|
5431
|
+
'settlement-scratch-apply',
|
|
5432
|
+
'settlement-scratch-resolve',
|
|
5433
|
+
'settlement-production-authorize',
|
|
5434
|
+
'settlement-production-check',
|
|
5435
|
+
'settlement-production-apply',
|
|
5436
|
+
'settlement-production-resolve',
|
|
5437
|
+
] as const);
|
|
5438
|
+
|
|
5439
|
+
export type TCloudlyLegacyDeploymentSettlementStdioCommand =
|
|
5440
|
+
typeof cloudlyLegacyDeploymentSettlementStdioCommands[number];
|
|
5441
|
+
|
|
5442
|
+
export interface ICloudlyLegacyDeploymentSettlementMongoDescriptorV1 {
|
|
5443
|
+
mongoDbUrl: string;
|
|
5444
|
+
mongoDbName: string;
|
|
5445
|
+
mongoDbUser: string;
|
|
5446
|
+
mongoDbPass: string;
|
|
5447
|
+
}
|
|
5448
|
+
|
|
5449
|
+
interface ICloudlyLegacyDeploymentSettlementStdioRequestBaseV1 {
|
|
5450
|
+
schemaVersion: 1;
|
|
5451
|
+
kind: 'cloudly-legacy-deployment-settlement-stdio-request';
|
|
5452
|
+
requestId: string;
|
|
5453
|
+
command: TCloudlyLegacyDeploymentSettlementStdioCommand;
|
|
5454
|
+
}
|
|
5455
|
+
|
|
5456
|
+
export interface ICloudlyLegacyDeploymentSettlementPlanStdioRequestV1
|
|
5457
|
+
extends ICloudlyLegacyDeploymentSettlementStdioRequestBaseV1 {
|
|
5458
|
+
command: 'settlement-plan';
|
|
5459
|
+
payload: {
|
|
5460
|
+
mongoDescriptor: ICloudlyLegacyDeploymentSettlementMongoDescriptorV1;
|
|
5461
|
+
authorityHandoff: ICloudlyLegacyDeploymentSettlementAuthorityHandoffPlaintextV1;
|
|
5462
|
+
effectiveAt: number;
|
|
5463
|
+
};
|
|
5464
|
+
}
|
|
5465
|
+
|
|
5466
|
+
export interface ICloudlyLegacyDeploymentSettlementRequestStdioRequestV1
|
|
5467
|
+
extends ICloudlyLegacyDeploymentSettlementStdioRequestBaseV1 {
|
|
5468
|
+
command: 'settlement-request';
|
|
5469
|
+
payload: {
|
|
5470
|
+
authorityHandoff: ICloudlyLegacyDeploymentSettlementAuthorityHandoffPlaintextV1;
|
|
5471
|
+
authenticatedPlan: IAuthenticatedCloudlyLegacyDeploymentSettlementPlanV1;
|
|
5472
|
+
requestedAt: number;
|
|
5473
|
+
};
|
|
5474
|
+
}
|
|
5475
|
+
|
|
5476
|
+
interface ICloudlyLegacyDeploymentSettlementScratchStdioPayloadV1 {
|
|
5477
|
+
mongoDescriptor: ICloudlyLegacyDeploymentSettlementMongoDescriptorV1;
|
|
5478
|
+
authorityHandoff: ICloudlyLegacyDeploymentSettlementAuthorityHandoffPlaintextV1;
|
|
5479
|
+
authenticatedPlan: IAuthenticatedCloudlyLegacyDeploymentSettlementPlanV1;
|
|
5480
|
+
requestBundle: ICloudlyLegacyDeploymentSettlementRequestBundleV1;
|
|
5481
|
+
executionAttempt: TCloudlyLegacyDeploymentSettlementScratchExecutionAttemptIdentityV1;
|
|
5482
|
+
}
|
|
5483
|
+
|
|
5484
|
+
export interface ICloudlyLegacyDeploymentSettlementScratchCheckStdioRequestV1
|
|
5485
|
+
extends ICloudlyLegacyDeploymentSettlementStdioRequestBaseV1 {
|
|
5486
|
+
command: 'settlement-scratch-check';
|
|
5487
|
+
payload: ICloudlyLegacyDeploymentSettlementScratchStdioPayloadV1;
|
|
5488
|
+
}
|
|
5489
|
+
|
|
5490
|
+
export interface ICloudlyLegacyDeploymentSettlementScratchApplyStdioRequestV1
|
|
5491
|
+
extends ICloudlyLegacyDeploymentSettlementStdioRequestBaseV1 {
|
|
5492
|
+
command: 'settlement-scratch-apply';
|
|
5493
|
+
payload: ICloudlyLegacyDeploymentSettlementScratchStdioPayloadV1;
|
|
5494
|
+
}
|
|
5495
|
+
|
|
5496
|
+
export interface ICloudlyLegacyDeploymentSettlementScratchResolveStdioRequestV1
|
|
5497
|
+
extends ICloudlyLegacyDeploymentSettlementStdioRequestBaseV1 {
|
|
5498
|
+
command: 'settlement-scratch-resolve';
|
|
5499
|
+
payload: ICloudlyLegacyDeploymentSettlementScratchStdioPayloadV1 & {
|
|
5500
|
+
observedAt: number;
|
|
5501
|
+
};
|
|
5502
|
+
}
|
|
5503
|
+
|
|
5504
|
+
export interface ICloudlyLegacyDeploymentSettlementProductionAuthorizeStdioRequestV1
|
|
5505
|
+
extends ICloudlyLegacyDeploymentSettlementStdioRequestBaseV1 {
|
|
5506
|
+
command: 'settlement-production-authorize';
|
|
5507
|
+
payload: {
|
|
5508
|
+
sourceAuthorityHandoff: ICloudlyLegacyDeploymentSettlementAuthorityHandoffPlaintextV1;
|
|
5509
|
+
productionAuthorityHandoff: ICloudlyLegacyDeploymentSettlementAuthorityHandoffPlaintextV1;
|
|
5510
|
+
authenticatedPlan: IAuthenticatedCloudlyLegacyDeploymentSettlementPlanV1;
|
|
5511
|
+
requestBundle: ICloudlyLegacyDeploymentSettlementRequestBundleV1;
|
|
5512
|
+
scratchReceipt: ICloudlyLegacyDeploymentSettlementScratchReceiptV1;
|
|
5513
|
+
executionAttempt: TCloudlyLegacyDeploymentSettlementProductionExecutionAttemptIdentityV1;
|
|
5514
|
+
requestedAt: number;
|
|
5515
|
+
approvedAt: number;
|
|
5516
|
+
};
|
|
5517
|
+
}
|
|
5518
|
+
|
|
5519
|
+
interface ICloudlyLegacyDeploymentSettlementProductionStdioPayloadV1 {
|
|
5520
|
+
mongoDescriptor: ICloudlyLegacyDeploymentSettlementMongoDescriptorV1;
|
|
5521
|
+
sourceAuthorityHandoff: ICloudlyLegacyDeploymentSettlementAuthorityHandoffPlaintextV1;
|
|
5522
|
+
productionAuthorityHandoff: ICloudlyLegacyDeploymentSettlementAuthorityHandoffPlaintextV1;
|
|
5523
|
+
authenticatedPlan: IAuthenticatedCloudlyLegacyDeploymentSettlementPlanV1;
|
|
5524
|
+
requestBundle: ICloudlyLegacyDeploymentSettlementRequestBundleV1;
|
|
5525
|
+
scratchReceipt: ICloudlyLegacyDeploymentSettlementScratchReceiptV1;
|
|
5526
|
+
productionAuthorization:
|
|
5527
|
+
ICloudlyLegacyDeploymentSettlementProductionExecutionAuthorizationV1;
|
|
5528
|
+
executionAttempt: TCloudlyLegacyDeploymentSettlementProductionExecutionAttemptIdentityV1;
|
|
5529
|
+
}
|
|
5530
|
+
|
|
5531
|
+
export interface ICloudlyLegacyDeploymentSettlementProductionCheckStdioRequestV1
|
|
5532
|
+
extends ICloudlyLegacyDeploymentSettlementStdioRequestBaseV1 {
|
|
5533
|
+
command: 'settlement-production-check';
|
|
5534
|
+
payload: ICloudlyLegacyDeploymentSettlementProductionStdioPayloadV1;
|
|
5535
|
+
}
|
|
5536
|
+
|
|
5537
|
+
export interface ICloudlyLegacyDeploymentSettlementProductionApplyStdioRequestV1
|
|
5538
|
+
extends ICloudlyLegacyDeploymentSettlementStdioRequestBaseV1 {
|
|
5539
|
+
command: 'settlement-production-apply';
|
|
5540
|
+
payload: ICloudlyLegacyDeploymentSettlementProductionStdioPayloadV1;
|
|
5541
|
+
}
|
|
5542
|
+
|
|
5543
|
+
export interface ICloudlyLegacyDeploymentSettlementProductionResolveStdioRequestV1
|
|
5544
|
+
extends ICloudlyLegacyDeploymentSettlementStdioRequestBaseV1 {
|
|
5545
|
+
command: 'settlement-production-resolve';
|
|
5546
|
+
payload: ICloudlyLegacyDeploymentSettlementProductionStdioPayloadV1 & {
|
|
5547
|
+
observedAt: number;
|
|
5548
|
+
};
|
|
5549
|
+
}
|
|
5550
|
+
|
|
5551
|
+
export type TCloudlyLegacyDeploymentSettlementStdioRequestV1 =
|
|
5552
|
+
| ICloudlyLegacyDeploymentSettlementPlanStdioRequestV1
|
|
5553
|
+
| ICloudlyLegacyDeploymentSettlementRequestStdioRequestV1
|
|
5554
|
+
| ICloudlyLegacyDeploymentSettlementScratchCheckStdioRequestV1
|
|
5555
|
+
| ICloudlyLegacyDeploymentSettlementScratchApplyStdioRequestV1
|
|
5556
|
+
| ICloudlyLegacyDeploymentSettlementScratchResolveStdioRequestV1
|
|
5557
|
+
| ICloudlyLegacyDeploymentSettlementProductionAuthorizeStdioRequestV1
|
|
5558
|
+
| ICloudlyLegacyDeploymentSettlementProductionCheckStdioRequestV1
|
|
5559
|
+
| ICloudlyLegacyDeploymentSettlementProductionApplyStdioRequestV1
|
|
5560
|
+
| ICloudlyLegacyDeploymentSettlementProductionResolveStdioRequestV1;
|
|
5561
|
+
|
|
5562
|
+
export const cloudlyLegacyDeploymentSettlementStdioErrorMetadata = Object.freeze({
|
|
5563
|
+
INVALID_FRAME: Object.freeze({ retryable: false }),
|
|
5564
|
+
INVALID_REQUEST: Object.freeze({ retryable: false }),
|
|
5565
|
+
AUTHORITY_INVALID: Object.freeze({ retryable: false }),
|
|
5566
|
+
AUTHORITY_EXPIRED: Object.freeze({ retryable: true }),
|
|
5567
|
+
REQUEST_MISMATCH: Object.freeze({ retryable: false }),
|
|
5568
|
+
PLAN_MISMATCH: Object.freeze({ retryable: false }),
|
|
5569
|
+
SOURCE_STATE_MISMATCH: Object.freeze({ retryable: false }),
|
|
5570
|
+
FINAL_STATE_MISMATCH: Object.freeze({ retryable: true }),
|
|
5571
|
+
TRANSACTIONS_UNSUPPORTED: Object.freeze({ retryable: false }),
|
|
5572
|
+
OPERATION_DRIFT: Object.freeze({ retryable: false }),
|
|
5573
|
+
CLAIM_DRIFT: Object.freeze({ retryable: false }),
|
|
5574
|
+
CLASSIFICATION_MISMATCH: Object.freeze({ retryable: false }),
|
|
5575
|
+
ATTEMPT_CONFLICT: Object.freeze({ retryable: false }),
|
|
5576
|
+
ATTEMPT_NOT_FOUND: Object.freeze({ retryable: false }),
|
|
5577
|
+
INTERNAL_ERROR: Object.freeze({ retryable: true }),
|
|
5578
|
+
} as const);
|
|
5579
|
+
|
|
5580
|
+
export type TCloudlyLegacyDeploymentSettlementStdioErrorCode =
|
|
5581
|
+
keyof typeof cloudlyLegacyDeploymentSettlementStdioErrorMetadata;
|
|
5582
|
+
|
|
5583
|
+
export type TCloudlyLegacyDeploymentSettlementStdioSafeErrorV1 = {
|
|
5584
|
+
[TCode in TCloudlyLegacyDeploymentSettlementStdioErrorCode]: {
|
|
5585
|
+
code: TCode;
|
|
5586
|
+
retryable: typeof cloudlyLegacyDeploymentSettlementStdioErrorMetadata[TCode]['retryable'];
|
|
5587
|
+
};
|
|
5588
|
+
}[TCloudlyLegacyDeploymentSettlementStdioErrorCode];
|
|
5589
|
+
|
|
5590
|
+
interface ICloudlyLegacyDeploymentSettlementStdioResponseBaseV1<
|
|
5591
|
+
TCommand extends TCloudlyLegacyDeploymentSettlementStdioCommand,
|
|
5592
|
+
> {
|
|
5593
|
+
schemaVersion: 1;
|
|
5594
|
+
kind: 'cloudly-legacy-deployment-settlement-stdio-response';
|
|
5595
|
+
requestId: string;
|
|
5596
|
+
command: TCommand;
|
|
5597
|
+
}
|
|
5598
|
+
|
|
5599
|
+
export interface ICloudlyLegacyDeploymentSettlementStdioSuccessPayloadByCommandV1 {
|
|
5600
|
+
'settlement-plan': {
|
|
5601
|
+
authenticatedPlan: IAuthenticatedCloudlyLegacyDeploymentSettlementPlanV1;
|
|
5602
|
+
};
|
|
5603
|
+
'settlement-request': {
|
|
5604
|
+
requestBundle: ICloudlyLegacyDeploymentSettlementRequestBundleV1;
|
|
5605
|
+
};
|
|
5606
|
+
'settlement-scratch-check': {
|
|
5607
|
+
authenticatedResult: IAuthenticatedCloudlyLegacyDeploymentSettlementCheckResultV1;
|
|
5608
|
+
};
|
|
5609
|
+
'settlement-scratch-apply': {
|
|
5610
|
+
executionBundle: TCloudlyLegacyDeploymentSettlementScratchExecutionBundleV1;
|
|
5611
|
+
};
|
|
5612
|
+
'settlement-scratch-resolve': {
|
|
5613
|
+
authenticatedResolution: IAuthenticatedCloudlyLegacyDeploymentSettlementResolutionV1;
|
|
5614
|
+
};
|
|
5615
|
+
'settlement-production-authorize': {
|
|
5616
|
+
productionAuthorization:
|
|
5617
|
+
ICloudlyLegacyDeploymentSettlementProductionExecutionAuthorizationV1;
|
|
5618
|
+
};
|
|
5619
|
+
'settlement-production-check': {
|
|
5620
|
+
authenticatedResult: IAuthenticatedCloudlyLegacyDeploymentSettlementCheckResultV1;
|
|
5621
|
+
};
|
|
5622
|
+
'settlement-production-apply': {
|
|
5623
|
+
executionBundle: TCloudlyLegacyDeploymentSettlementProductionExecutionBundleV2;
|
|
5624
|
+
};
|
|
5625
|
+
'settlement-production-resolve': {
|
|
5626
|
+
authenticatedResolution: IAuthenticatedCloudlyLegacyDeploymentSettlementResolutionV1;
|
|
5627
|
+
};
|
|
5628
|
+
}
|
|
5629
|
+
|
|
5630
|
+
export type TCloudlyLegacyDeploymentSettlementStdioSuccessPayloadV1 =
|
|
5631
|
+
ICloudlyLegacyDeploymentSettlementStdioSuccessPayloadByCommandV1[
|
|
5632
|
+
TCloudlyLegacyDeploymentSettlementStdioCommand
|
|
5633
|
+
];
|
|
5634
|
+
|
|
5635
|
+
export type TCloudlyLegacyDeploymentSettlementStdioSuccessResponseV1 = {
|
|
5636
|
+
[TCommand in TCloudlyLegacyDeploymentSettlementStdioCommand]:
|
|
5637
|
+
ICloudlyLegacyDeploymentSettlementStdioResponseBaseV1<TCommand> & {
|
|
5638
|
+
ok: true;
|
|
5639
|
+
payload: ICloudlyLegacyDeploymentSettlementStdioSuccessPayloadByCommandV1[TCommand];
|
|
5640
|
+
};
|
|
5641
|
+
}[TCloudlyLegacyDeploymentSettlementStdioCommand];
|
|
5642
|
+
|
|
5643
|
+
export type TCloudlyLegacyDeploymentSettlementStdioErrorResponseV1 = {
|
|
5644
|
+
[TCommand in TCloudlyLegacyDeploymentSettlementStdioCommand]:
|
|
5645
|
+
ICloudlyLegacyDeploymentSettlementStdioResponseBaseV1<TCommand> & {
|
|
5646
|
+
ok: false;
|
|
5647
|
+
error: TCloudlyLegacyDeploymentSettlementStdioSafeErrorV1;
|
|
5648
|
+
};
|
|
5649
|
+
}[TCloudlyLegacyDeploymentSettlementStdioCommand];
|
|
5650
|
+
|
|
5651
|
+
export type TCloudlyLegacyDeploymentSettlementStdioResponseV1 =
|
|
5652
|
+
| TCloudlyLegacyDeploymentSettlementStdioSuccessResponseV1
|
|
5653
|
+
| TCloudlyLegacyDeploymentSettlementStdioErrorResponseV1;
|
|
5654
|
+
|
|
5655
|
+
const stdioRequestKeys = ['schemaVersion', 'kind', 'requestId', 'command', 'payload'] as const;
|
|
5656
|
+
const stdioResponseSuccessKeys = [
|
|
5657
|
+
'schemaVersion',
|
|
5658
|
+
'kind',
|
|
5659
|
+
'requestId',
|
|
5660
|
+
'command',
|
|
5661
|
+
'ok',
|
|
5662
|
+
'payload',
|
|
5663
|
+
] as const;
|
|
5664
|
+
const stdioResponseErrorKeys = [
|
|
5665
|
+
'schemaVersion',
|
|
5666
|
+
'kind',
|
|
5667
|
+
'requestId',
|
|
5668
|
+
'command',
|
|
5669
|
+
'ok',
|
|
5670
|
+
'error',
|
|
5671
|
+
] as const;
|
|
5672
|
+
|
|
5673
|
+
const normalizeSettlementMongoDescriptor = (
|
|
5674
|
+
valueArg: unknown,
|
|
5675
|
+
pathArg: string,
|
|
5676
|
+
): ICloudlyLegacyDeploymentSettlementMongoDescriptorV1 => {
|
|
5677
|
+
const value = readRecord(valueArg, pathArg);
|
|
5678
|
+
assertExactKeys(value, ['mongoDbUrl', 'mongoDbName', 'mongoDbUser', 'mongoDbPass'], pathArg);
|
|
5679
|
+
for (const key of ['mongoDbUrl', 'mongoDbName', 'mongoDbUser', 'mongoDbPass'] as const) {
|
|
5680
|
+
if (typeof value[key] !== 'string'
|
|
5681
|
+
|| value[key].length === 0
|
|
5682
|
+
|| Buffer.byteLength(value[key], 'utf8')
|
|
5683
|
+
> cloudlyLegacyDeploymentSettlementStdioLimits.maximumMongoDescriptorBytes
|
|
5684
|
+
|| /[\u0000-\u0020\u007f]/u.test(value[key])) {
|
|
5685
|
+
fail('INVALID_VALUE', `${pathArg}.${key}`);
|
|
5686
|
+
}
|
|
5687
|
+
}
|
|
5688
|
+
const descriptor = value as unknown as ICloudlyLegacyDeploymentSettlementMongoDescriptorV1;
|
|
5689
|
+
let url: URL;
|
|
5690
|
+
let mongoDbName: string;
|
|
5691
|
+
let mongoDbUser: string;
|
|
5692
|
+
let mongoDbPass: string;
|
|
5693
|
+
try {
|
|
5694
|
+
url = new URL(descriptor.mongoDbUrl);
|
|
5695
|
+
mongoDbName = decodeURIComponent(url.pathname.slice(1));
|
|
5696
|
+
mongoDbUser = decodeURIComponent(url.username);
|
|
5697
|
+
mongoDbPass = decodeURIComponent(url.password);
|
|
5698
|
+
} catch {
|
|
5699
|
+
return fail('INVALID_VALUE', `${pathArg}.mongoDbUrl`);
|
|
5700
|
+
}
|
|
5701
|
+
const queryKeys = [...new Set(url.searchParams.keys())].sort();
|
|
5702
|
+
if (url.protocol !== 'mongodb:'
|
|
5703
|
+
|| !url.hostname
|
|
5704
|
+
|| !url.port
|
|
5705
|
+
|| url.hash !== ''
|
|
5706
|
+
|| mongoDbName !== descriptor.mongoDbName
|
|
5707
|
+
|| mongoDbUser !== descriptor.mongoDbUser
|
|
5708
|
+
|| mongoDbPass !== descriptor.mongoDbPass
|
|
5709
|
+
|| JSON.stringify(queryKeys) !== JSON.stringify(['authSource', 'directConnection'])
|
|
5710
|
+
|| url.searchParams.getAll('authSource').length !== 1
|
|
5711
|
+
|| url.searchParams.get('authSource') !== descriptor.mongoDbName
|
|
5712
|
+
|| url.searchParams.getAll('directConnection').length !== 1
|
|
5713
|
+
|| url.searchParams.get('directConnection') !== 'true') {
|
|
5714
|
+
fail('CROSS_FIELD_MISMATCH', pathArg);
|
|
5715
|
+
}
|
|
5716
|
+
const output = {
|
|
5717
|
+
mongoDbUrl: descriptor.mongoDbUrl,
|
|
5718
|
+
mongoDbName: descriptor.mongoDbName,
|
|
5719
|
+
mongoDbUser: descriptor.mongoDbUser,
|
|
5720
|
+
mongoDbPass: descriptor.mongoDbPass,
|
|
5721
|
+
};
|
|
5722
|
+
if (Buffer.byteLength(canonicalize(output, pathArg), 'utf8')
|
|
5723
|
+
> cloudlyLegacyDeploymentSettlementStdioLimits.maximumMongoDescriptorBytes) {
|
|
5724
|
+
fail('LIMIT_EXCEEDED', pathArg);
|
|
5725
|
+
}
|
|
5726
|
+
return output;
|
|
5727
|
+
};
|
|
5728
|
+
|
|
5729
|
+
export const normalizeCloudlyLegacyDeploymentSettlementMongoDescriptor = (
|
|
5730
|
+
valueArg: unknown,
|
|
5731
|
+
): Readonly<ICloudlyLegacyDeploymentSettlementMongoDescriptorV1> => finalize(
|
|
5732
|
+
normalizeSettlementMongoDescriptor(valueArg, 'mongoDescriptor'),
|
|
5733
|
+
cloudlyLegacyDeploymentSettlementStdioLimits.maximumMongoDescriptorBytes,
|
|
5734
|
+
'mongoDescriptor',
|
|
5735
|
+
);
|
|
5736
|
+
|
|
5737
|
+
const assertStdioArtifactAggregate = (valueArg: unknown, pathArg: string): void => {
|
|
5738
|
+
if (Buffer.byteLength(canonicalize(valueArg, pathArg), 'utf8')
|
|
5739
|
+
> cloudlyLegacyDeploymentSettlementStdioLimits.maximumPrivateArtifactAggregateBytes) {
|
|
5740
|
+
fail('LIMIT_EXCEEDED', pathArg);
|
|
5741
|
+
}
|
|
5742
|
+
};
|
|
5743
|
+
|
|
5744
|
+
const assertDistinctStdioHandoffKeyMaterial = (
|
|
5745
|
+
sourceHandoffArg: ICloudlyLegacyDeploymentSettlementAuthorityHandoffPlaintextV1,
|
|
5746
|
+
executionHandoffArg: ICloudlyLegacyDeploymentSettlementAuthorityHandoffPlaintextV1,
|
|
5747
|
+
pathArg: string,
|
|
5748
|
+
): void => {
|
|
5749
|
+
const sourceKey = Buffer.from(sourceHandoffArg.hmacKeyPlaintext.value, 'base64url');
|
|
5750
|
+
const executionKey = Buffer.from(executionHandoffArg.hmacKeyPlaintext.value, 'base64url');
|
|
5751
|
+
let equal = false;
|
|
5752
|
+
try {
|
|
5753
|
+
equal = plugins.crypto.timingSafeEqual(sourceKey, executionKey);
|
|
5754
|
+
} finally {
|
|
5755
|
+
sourceKey.fill(0);
|
|
5756
|
+
executionKey.fill(0);
|
|
5757
|
+
}
|
|
5758
|
+
if (equal) {
|
|
5759
|
+
fail('CROSS_FIELD_MISMATCH', pathArg);
|
|
5760
|
+
}
|
|
5761
|
+
};
|
|
5762
|
+
|
|
5763
|
+
const assertExecutionAttemptMatchesStdioArtifacts = (argsArg: {
|
|
5764
|
+
attempt: ICloudlyLegacyDeploymentSettlementExecutionAttemptIdentityV1;
|
|
5765
|
+
purpose: TCloudlyLegacyDeploymentSettlementExecutionPurpose;
|
|
5766
|
+
sourceHandoff: ICloudlyLegacyDeploymentSettlementAuthorityHandoffPlaintextV1;
|
|
5767
|
+
executionHandoff: ICloudlyLegacyDeploymentSettlementAuthorityHandoffPlaintextV1;
|
|
5768
|
+
authenticatedPlan: IAuthenticatedCloudlyLegacyDeploymentSettlementPlanV1;
|
|
5769
|
+
requestBundle: ICloudlyLegacyDeploymentSettlementRequestBundleV1;
|
|
5770
|
+
scratchReceipt?: ICloudlyLegacyDeploymentSettlementScratchReceiptV1;
|
|
5771
|
+
path: string;
|
|
5772
|
+
}): void => {
|
|
5773
|
+
const sourceReference = argsArg.sourceHandoff.authorityReference;
|
|
5774
|
+
const executionReference = argsArg.executionHandoff.authorityReference;
|
|
5775
|
+
const sourceMetadata = normalizeFencedSourceAuthorityMetadata(
|
|
5776
|
+
argsArg.sourceHandoff.authorityMetadata,
|
|
5777
|
+
`${argsArg.path}.sourceAuthorityMetadata`,
|
|
5778
|
+
);
|
|
5779
|
+
if (argsArg.purpose === 'production') {
|
|
5780
|
+
assertDistinctStdioHandoffKeyMaterial(
|
|
5781
|
+
argsArg.sourceHandoff,
|
|
5782
|
+
argsArg.executionHandoff,
|
|
5783
|
+
`${argsArg.path}.authorityKeySeparation`,
|
|
5784
|
+
);
|
|
5785
|
+
normalizeProductionAuthorityMetadataPair(
|
|
5786
|
+
argsArg.executionHandoff.authorityMetadata,
|
|
5787
|
+
sourceMetadata,
|
|
5788
|
+
);
|
|
5789
|
+
} else {
|
|
5790
|
+
normalizeFencedSourceAuthorityMetadata(
|
|
5791
|
+
argsArg.executionHandoff.authorityMetadata,
|
|
5792
|
+
`${argsArg.path}.executionAuthorityMetadata`,
|
|
5793
|
+
);
|
|
5794
|
+
}
|
|
5795
|
+
normalizeCloudlyLegacyDeploymentSettlementPlanForAuthority(
|
|
5796
|
+
argsArg.authenticatedPlan.payload,
|
|
5797
|
+
sourceMetadata,
|
|
5798
|
+
);
|
|
5799
|
+
normalizeCloudlyLegacyDeploymentSettlementProductionRequestForAuthority(
|
|
5800
|
+
argsArg.requestBundle.authenticatedRequest.payload,
|
|
5801
|
+
sourceMetadata,
|
|
5802
|
+
);
|
|
5803
|
+
if (argsArg.scratchReceipt) {
|
|
5804
|
+
normalizeCloudlyLegacyDeploymentSettlementScratchReceiptStructureForRequest(
|
|
5805
|
+
argsArg.scratchReceipt,
|
|
5806
|
+
argsArg.requestBundle.authenticatedRequest,
|
|
5807
|
+
);
|
|
5808
|
+
}
|
|
5809
|
+
if (canonicalize(argsArg.authenticatedPlan.authority, `${argsArg.path}.plan.authority`)
|
|
5810
|
+
!== canonicalize(sourceReference, `${argsArg.path}.sourceAuthority`)
|
|
5811
|
+
|| canonicalize(
|
|
5812
|
+
argsArg.requestBundle.authenticatedRequest.authority,
|
|
5813
|
+
`${argsArg.path}.request.authority`,
|
|
5814
|
+
) !== canonicalize(sourceReference, `${argsArg.path}.sourceAuthority`)
|
|
5815
|
+
|| canonicalize(
|
|
5816
|
+
argsArg.requestBundle.authenticatedRehearsalBinding.authority,
|
|
5817
|
+
`${argsArg.path}.binding.authority`,
|
|
5818
|
+
) !== canonicalize(sourceReference, `${argsArg.path}.sourceAuthority`)
|
|
5819
|
+
|| canonicalize(argsArg.authenticatedPlan.payload, `${argsArg.path}.plan.payload`)
|
|
5820
|
+
!== canonicalize(
|
|
5821
|
+
argsArg.requestBundle.authenticatedRequest.payload.plan,
|
|
5822
|
+
`${argsArg.path}.request.plan`,
|
|
5823
|
+
)
|
|
5824
|
+
|| argsArg.authenticatedPlan.payloadSha256
|
|
5825
|
+
!== argsArg.requestBundle.authenticatedRequest.payload.planSha256
|
|
5826
|
+
|| (argsArg.scratchReceipt !== undefined
|
|
5827
|
+
&& (canonicalize(argsArg.scratchReceipt.authority, `${argsArg.path}.scratch.authority`)
|
|
5828
|
+
!== canonicalize(sourceReference, `${argsArg.path}.sourceAuthority`)
|
|
5829
|
+
|| argsArg.scratchReceipt.requestSha256
|
|
5830
|
+
!== argsArg.requestBundle.authenticatedRequest.payloadSha256))) {
|
|
5831
|
+
fail('CROSS_FIELD_MISMATCH', `${argsArg.path}.sourceArtifacts`);
|
|
5832
|
+
}
|
|
5833
|
+
const scratchReceiptSha256 = argsArg.scratchReceipt
|
|
5834
|
+
? digestCloudlyLegacyDeploymentSettlementScratchReceipt(argsArg.scratchReceipt)
|
|
5835
|
+
: null;
|
|
5836
|
+
if (argsArg.attempt.purpose !== argsArg.purpose
|
|
5837
|
+
|| argsArg.attempt.operationId !== argsArg.executionHandoff.authorityMetadata.operationId
|
|
5838
|
+
|| argsArg.attempt.settlementId !== argsArg.executionHandoff.authorityMetadata.settlementId
|
|
5839
|
+
|| canonicalize(argsArg.attempt.sourceAuthority, `${argsArg.path}.attempt.sourceAuthority`)
|
|
5840
|
+
!== canonicalize(sourceReference, `${argsArg.path}.sourceAuthority`)
|
|
5841
|
+
|| canonicalize(argsArg.attempt.executionAuthority, `${argsArg.path}.attempt.executionAuthority`)
|
|
5842
|
+
!== canonicalize(executionReference, `${argsArg.path}.executionAuthority`)
|
|
5843
|
+
|| argsArg.attempt.authenticatedPlanSha256
|
|
5844
|
+
!== digestAuthenticatedCloudlyLegacyDeploymentSettlementPlan(argsArg.authenticatedPlan)
|
|
5845
|
+
|| argsArg.attempt.requestBundleSha256
|
|
5846
|
+
!== digestCloudlyLegacyDeploymentSettlementRequestBundle(argsArg.requestBundle)
|
|
5847
|
+
|| argsArg.attempt.scratchReceiptSha256 !== scratchReceiptSha256) {
|
|
5848
|
+
fail('CROSS_FIELD_MISMATCH', `${argsArg.path}.executionAttempt`);
|
|
5849
|
+
}
|
|
5850
|
+
if (argsArg.purpose === 'production') {
|
|
5851
|
+
const productionMetadata = argsArg.executionHandoff.authorityMetadata;
|
|
5852
|
+
if (!productionMetadata.sourceAuthority
|
|
5853
|
+
|| canonicalize(productionMetadata.sourceAuthority, `${argsArg.path}.metadata.sourceAuthority`)
|
|
5854
|
+
!== canonicalize(sourceReference, `${argsArg.path}.sourceAuthority`)
|
|
5855
|
+
|| productionMetadata.sourceAuthenticatedPlanSha256
|
|
5856
|
+
!== argsArg.attempt.authenticatedPlanSha256
|
|
5857
|
+
|| productionMetadata.sourceRequestBundleSha256 !== argsArg.attempt.requestBundleSha256
|
|
5858
|
+
|| productionMetadata.scratchReceiptSha256 !== scratchReceiptSha256) {
|
|
5859
|
+
fail('CROSS_FIELD_MISMATCH', `${argsArg.path}.productionAuthorityHandoff`);
|
|
5860
|
+
}
|
|
5861
|
+
}
|
|
5862
|
+
};
|
|
5863
|
+
|
|
5864
|
+
const normalizeScratchStdioPayload = (
|
|
5865
|
+
valueArg: unknown,
|
|
5866
|
+
pathArg: string,
|
|
5867
|
+
resolveArg: boolean,
|
|
5868
|
+
): ICloudlyLegacyDeploymentSettlementScratchStdioPayloadV1 & { observedAt?: number } => {
|
|
5869
|
+
const value = readRecord(valueArg, pathArg);
|
|
5870
|
+
assertExactKeys(value, [
|
|
5871
|
+
'mongoDescriptor',
|
|
5872
|
+
'authorityHandoff',
|
|
5873
|
+
'authenticatedPlan',
|
|
5874
|
+
'requestBundle',
|
|
5875
|
+
'executionAttempt',
|
|
5876
|
+
...(resolveArg ? ['observedAt'] : []),
|
|
5877
|
+
], pathArg);
|
|
5878
|
+
const authorityHandoff = normalizeCloudlyLegacyDeploymentSettlementAuthorityHandoffPlaintext(
|
|
5879
|
+
value.authorityHandoff,
|
|
5880
|
+
);
|
|
5881
|
+
const authenticatedPlan =
|
|
5882
|
+
normalizeCloudlyLegacyDeploymentSettlementAuthenticatedPlanStructure(value.authenticatedPlan);
|
|
5883
|
+
const requestBundle = normalizeCloudlyLegacyDeploymentSettlementRequestBundle(value.requestBundle);
|
|
5884
|
+
const executionAttempt = normalizeExecutionAttemptIdentityInternal(
|
|
5885
|
+
value.executionAttempt,
|
|
5886
|
+
`${pathArg}.executionAttempt`,
|
|
5887
|
+
);
|
|
5888
|
+
assertExecutionAttemptMatchesStdioArtifacts({
|
|
5889
|
+
attempt: executionAttempt,
|
|
5890
|
+
purpose: 'scratch-rehearsal',
|
|
5891
|
+
sourceHandoff: authorityHandoff,
|
|
5892
|
+
executionHandoff: authorityHandoff,
|
|
5893
|
+
authenticatedPlan,
|
|
5894
|
+
requestBundle,
|
|
5895
|
+
path: pathArg,
|
|
5896
|
+
});
|
|
5897
|
+
const output = {
|
|
5898
|
+
mongoDescriptor: normalizeSettlementMongoDescriptor(
|
|
5899
|
+
value.mongoDescriptor,
|
|
5900
|
+
`${pathArg}.mongoDescriptor`,
|
|
5901
|
+
),
|
|
5902
|
+
authorityHandoff,
|
|
5903
|
+
authenticatedPlan,
|
|
5904
|
+
requestBundle,
|
|
5905
|
+
executionAttempt: executionAttempt as
|
|
5906
|
+
TCloudlyLegacyDeploymentSettlementScratchExecutionAttemptIdentityV1,
|
|
5907
|
+
...(resolveArg
|
|
5908
|
+
? { observedAt: readInteger(value.observedAt, `${pathArg}.observedAt`, 1) }
|
|
5909
|
+
: {}),
|
|
5910
|
+
};
|
|
5911
|
+
assertStdioArtifactAggregate(output, pathArg);
|
|
5912
|
+
return output;
|
|
5913
|
+
};
|
|
5914
|
+
|
|
5915
|
+
const normalizeProductionStdioPayload = (
|
|
5916
|
+
valueArg: unknown,
|
|
5917
|
+
pathArg: string,
|
|
5918
|
+
resolveArg: boolean,
|
|
5919
|
+
): ICloudlyLegacyDeploymentSettlementProductionStdioPayloadV1 & { observedAt?: number } => {
|
|
5920
|
+
const value = readRecord(valueArg, pathArg);
|
|
5921
|
+
assertExactKeys(value, [
|
|
5922
|
+
'mongoDescriptor',
|
|
5923
|
+
'sourceAuthorityHandoff',
|
|
5924
|
+
'productionAuthorityHandoff',
|
|
5925
|
+
'authenticatedPlan',
|
|
5926
|
+
'requestBundle',
|
|
5927
|
+
'scratchReceipt',
|
|
5928
|
+
'productionAuthorization',
|
|
5929
|
+
'executionAttempt',
|
|
5930
|
+
...(resolveArg ? ['observedAt'] : []),
|
|
5931
|
+
], pathArg);
|
|
5932
|
+
const sourceAuthorityHandoff =
|
|
5933
|
+
normalizeCloudlyLegacyDeploymentSettlementAuthorityHandoffPlaintext(
|
|
5934
|
+
value.sourceAuthorityHandoff,
|
|
5935
|
+
);
|
|
5936
|
+
const productionAuthorityHandoff =
|
|
5937
|
+
normalizeCloudlyLegacyDeploymentSettlementAuthorityHandoffPlaintext(
|
|
5938
|
+
value.productionAuthorityHandoff,
|
|
5939
|
+
);
|
|
5940
|
+
const authenticatedPlan =
|
|
5941
|
+
normalizeCloudlyLegacyDeploymentSettlementAuthenticatedPlanStructure(value.authenticatedPlan);
|
|
5942
|
+
const requestBundle = normalizeCloudlyLegacyDeploymentSettlementRequestBundle(value.requestBundle);
|
|
5943
|
+
const scratchReceipt = normalizeCloudlyLegacyDeploymentSettlementScratchReceipt(
|
|
5944
|
+
value.scratchReceipt,
|
|
5945
|
+
);
|
|
5946
|
+
const productionAuthorization =
|
|
5947
|
+
normalizeCloudlyLegacyDeploymentSettlementProductionExecutionAuthorization(
|
|
5948
|
+
value.productionAuthorization,
|
|
5949
|
+
);
|
|
5950
|
+
const executionAttempt = normalizeExecutionAttemptIdentityInternal(
|
|
5951
|
+
value.executionAttempt,
|
|
5952
|
+
`${pathArg}.executionAttempt`,
|
|
5953
|
+
);
|
|
5954
|
+
assertExecutionAttemptMatchesStdioArtifacts({
|
|
5955
|
+
attempt: executionAttempt,
|
|
5956
|
+
purpose: 'production',
|
|
5957
|
+
sourceHandoff: sourceAuthorityHandoff,
|
|
5958
|
+
executionHandoff: productionAuthorityHandoff,
|
|
5959
|
+
authenticatedPlan,
|
|
5960
|
+
requestBundle,
|
|
5961
|
+
scratchReceipt,
|
|
5962
|
+
path: pathArg,
|
|
5963
|
+
});
|
|
5964
|
+
if (canonicalize(productionAuthorization.executionAttempt, `${pathArg}.authorization.attempt`)
|
|
5965
|
+
!== canonicalize(executionAttempt, `${pathArg}.executionAttempt`)) {
|
|
5966
|
+
fail('CROSS_FIELD_MISMATCH', `${pathArg}.productionAuthorization`);
|
|
5967
|
+
}
|
|
5968
|
+
const metadata = normalizeProductionAuthorityMetadataPair(
|
|
5969
|
+
productionAuthorityHandoff.authorityMetadata,
|
|
5970
|
+
sourceAuthorityHandoff.authorityMetadata,
|
|
5971
|
+
);
|
|
5972
|
+
assertProductionAuthorizationArtifacts(
|
|
5973
|
+
productionAuthorization,
|
|
5974
|
+
metadata.productionMetadata,
|
|
5975
|
+
metadata.sourceMetadata,
|
|
5976
|
+
authenticatedPlan,
|
|
5977
|
+
requestBundle,
|
|
5978
|
+
scratchReceipt,
|
|
5979
|
+
);
|
|
5980
|
+
const output = {
|
|
5981
|
+
mongoDescriptor: normalizeSettlementMongoDescriptor(
|
|
5982
|
+
value.mongoDescriptor,
|
|
5983
|
+
`${pathArg}.mongoDescriptor`,
|
|
5984
|
+
),
|
|
5985
|
+
sourceAuthorityHandoff,
|
|
5986
|
+
productionAuthorityHandoff,
|
|
5987
|
+
authenticatedPlan,
|
|
5988
|
+
requestBundle,
|
|
5989
|
+
scratchReceipt,
|
|
5990
|
+
productionAuthorization,
|
|
5991
|
+
executionAttempt: executionAttempt as
|
|
5992
|
+
TCloudlyLegacyDeploymentSettlementProductionExecutionAttemptIdentityV1,
|
|
5993
|
+
...(resolveArg
|
|
5994
|
+
? { observedAt: readInteger(value.observedAt, `${pathArg}.observedAt`, 1) }
|
|
5995
|
+
: {}),
|
|
5996
|
+
};
|
|
5997
|
+
assertStdioArtifactAggregate(output, pathArg);
|
|
5998
|
+
return output;
|
|
5999
|
+
};
|
|
6000
|
+
|
|
6001
|
+
/** Structural only; use the authority-aware variant before trusting artifacts. */
|
|
6002
|
+
export const normalizeCloudlyLegacyDeploymentSettlementStdioRequest = (
|
|
6003
|
+
valueArg: unknown,
|
|
6004
|
+
): Readonly<TCloudlyLegacyDeploymentSettlementStdioRequestV1> => {
|
|
6005
|
+
const value = readRecord(valueArg, 'stdioRequest');
|
|
6006
|
+
assertExactKeys(value, stdioRequestKeys, 'stdioRequest');
|
|
6007
|
+
assertStdioArtifactAggregate(value.payload, 'stdioRequest.payload');
|
|
6008
|
+
if (value.schemaVersion !== 1
|
|
6009
|
+
|| value.kind !== 'cloudly-legacy-deployment-settlement-stdio-request') {
|
|
6010
|
+
fail('INVALID_VALUE', 'stdioRequest.kind');
|
|
6011
|
+
}
|
|
6012
|
+
const requestId = readIdentifier(value.requestId, 'stdioRequest.requestId');
|
|
6013
|
+
const command = readLiteral(
|
|
6014
|
+
value.command,
|
|
6015
|
+
cloudlyLegacyDeploymentSettlementStdioCommands,
|
|
6016
|
+
'stdioRequest.command',
|
|
6017
|
+
);
|
|
6018
|
+
const payloadPath = 'stdioRequest.payload';
|
|
6019
|
+
let payload: TCloudlyLegacyDeploymentSettlementStdioRequestV1['payload'];
|
|
6020
|
+
if (command === 'settlement-plan') {
|
|
6021
|
+
const input = readRecord(value.payload, payloadPath);
|
|
6022
|
+
assertExactKeys(input, ['mongoDescriptor', 'authorityHandoff', 'effectiveAt'], payloadPath);
|
|
6023
|
+
const authorityHandoff = normalizeCloudlyLegacyDeploymentSettlementAuthorityHandoffPlaintext(
|
|
6024
|
+
input.authorityHandoff,
|
|
6025
|
+
);
|
|
6026
|
+
const sourceMetadata = normalizeFencedSourceAuthorityMetadata(
|
|
6027
|
+
authorityHandoff.authorityMetadata,
|
|
6028
|
+
`${payloadPath}.authorityHandoff.authorityMetadata`,
|
|
6029
|
+
);
|
|
6030
|
+
const effectiveAt = readInteger(input.effectiveAt, `${payloadPath}.effectiveAt`, 1);
|
|
6031
|
+
assertAuthorityTimestamp(effectiveAt, sourceMetadata, `${payloadPath}.effectiveAt`);
|
|
6032
|
+
payload = {
|
|
6033
|
+
mongoDescriptor: normalizeSettlementMongoDescriptor(
|
|
6034
|
+
input.mongoDescriptor,
|
|
6035
|
+
`${payloadPath}.mongoDescriptor`,
|
|
6036
|
+
),
|
|
6037
|
+
authorityHandoff,
|
|
6038
|
+
effectiveAt,
|
|
6039
|
+
};
|
|
6040
|
+
} else if (command === 'settlement-request') {
|
|
6041
|
+
const input = readRecord(value.payload, payloadPath);
|
|
6042
|
+
assertExactKeys(input, ['authorityHandoff', 'authenticatedPlan', 'requestedAt'], payloadPath);
|
|
6043
|
+
const authorityHandoff = normalizeCloudlyLegacyDeploymentSettlementAuthorityHandoffPlaintext(
|
|
6044
|
+
input.authorityHandoff,
|
|
6045
|
+
);
|
|
6046
|
+
const sourceMetadata = normalizeFencedSourceAuthorityMetadata(
|
|
6047
|
+
authorityHandoff.authorityMetadata,
|
|
6048
|
+
`${payloadPath}.authorityHandoff.authorityMetadata`,
|
|
6049
|
+
);
|
|
6050
|
+
const authenticatedPlan =
|
|
6051
|
+
normalizeCloudlyLegacyDeploymentSettlementAuthenticatedPlanStructure(
|
|
6052
|
+
input.authenticatedPlan,
|
|
6053
|
+
);
|
|
6054
|
+
assertAuthorityReferenceMatchesMetadata(
|
|
6055
|
+
authenticatedPlan.authority,
|
|
6056
|
+
sourceMetadata,
|
|
6057
|
+
`${payloadPath}.authenticatedPlan.authority`,
|
|
6058
|
+
);
|
|
6059
|
+
normalizeCloudlyLegacyDeploymentSettlementPlanForAuthority(
|
|
6060
|
+
authenticatedPlan.payload,
|
|
6061
|
+
sourceMetadata,
|
|
6062
|
+
);
|
|
6063
|
+
const requestedAt = readInteger(input.requestedAt, `${payloadPath}.requestedAt`, 1);
|
|
6064
|
+
assertAuthorityTimestamp(requestedAt, sourceMetadata, `${payloadPath}.requestedAt`);
|
|
6065
|
+
if (requestedAt < authenticatedPlan.payload.effectiveAt) {
|
|
6066
|
+
fail('CROSS_FIELD_MISMATCH', `${payloadPath}.requestedAt`);
|
|
6067
|
+
}
|
|
6068
|
+
payload = {
|
|
6069
|
+
authorityHandoff,
|
|
6070
|
+
authenticatedPlan,
|
|
6071
|
+
requestedAt,
|
|
6072
|
+
};
|
|
6073
|
+
} else if (command === 'settlement-scratch-check'
|
|
6074
|
+
|| command === 'settlement-scratch-apply') {
|
|
6075
|
+
payload = normalizeScratchStdioPayload(value.payload, payloadPath, false);
|
|
6076
|
+
} else if (command === 'settlement-scratch-resolve') {
|
|
6077
|
+
payload = normalizeScratchStdioPayload(value.payload, payloadPath, true) as
|
|
6078
|
+
ICloudlyLegacyDeploymentSettlementScratchResolveStdioRequestV1['payload'];
|
|
6079
|
+
} else if (command === 'settlement-production-authorize') {
|
|
6080
|
+
const input = readRecord(value.payload, payloadPath);
|
|
6081
|
+
assertExactKeys(input, [
|
|
6082
|
+
'sourceAuthorityHandoff',
|
|
6083
|
+
'productionAuthorityHandoff',
|
|
6084
|
+
'authenticatedPlan',
|
|
6085
|
+
'requestBundle',
|
|
6086
|
+
'scratchReceipt',
|
|
6087
|
+
'executionAttempt',
|
|
6088
|
+
'requestedAt',
|
|
6089
|
+
'approvedAt',
|
|
6090
|
+
], payloadPath);
|
|
6091
|
+
const sourceAuthorityHandoff =
|
|
6092
|
+
normalizeCloudlyLegacyDeploymentSettlementAuthorityHandoffPlaintext(
|
|
6093
|
+
input.sourceAuthorityHandoff,
|
|
6094
|
+
);
|
|
6095
|
+
const productionAuthorityHandoff =
|
|
6096
|
+
normalizeCloudlyLegacyDeploymentSettlementAuthorityHandoffPlaintext(
|
|
6097
|
+
input.productionAuthorityHandoff,
|
|
6098
|
+
);
|
|
6099
|
+
const authenticatedPlan =
|
|
6100
|
+
normalizeCloudlyLegacyDeploymentSettlementAuthenticatedPlanStructure(
|
|
6101
|
+
input.authenticatedPlan,
|
|
6102
|
+
);
|
|
6103
|
+
const requestBundle = normalizeCloudlyLegacyDeploymentSettlementRequestBundle(
|
|
6104
|
+
input.requestBundle,
|
|
6105
|
+
);
|
|
6106
|
+
const scratchReceipt = normalizeCloudlyLegacyDeploymentSettlementScratchReceipt(
|
|
6107
|
+
input.scratchReceipt,
|
|
6108
|
+
);
|
|
6109
|
+
const executionAttempt = normalizeExecutionAttemptIdentityInternal(
|
|
6110
|
+
input.executionAttempt,
|
|
6111
|
+
`${payloadPath}.executionAttempt`,
|
|
6112
|
+
);
|
|
6113
|
+
assertExecutionAttemptMatchesStdioArtifacts({
|
|
6114
|
+
attempt: executionAttempt,
|
|
6115
|
+
purpose: 'production',
|
|
6116
|
+
sourceHandoff: sourceAuthorityHandoff,
|
|
6117
|
+
executionHandoff: productionAuthorityHandoff,
|
|
6118
|
+
authenticatedPlan,
|
|
6119
|
+
requestBundle,
|
|
6120
|
+
scratchReceipt,
|
|
6121
|
+
path: payloadPath,
|
|
6122
|
+
});
|
|
6123
|
+
const requestedAt = readInteger(input.requestedAt, `${payloadPath}.requestedAt`, 1);
|
|
6124
|
+
const metadata = normalizeProductionAuthorityMetadataPair(
|
|
6125
|
+
productionAuthorityHandoff.authorityMetadata,
|
|
6126
|
+
sourceAuthorityHandoff.authorityMetadata,
|
|
6127
|
+
);
|
|
6128
|
+
const approvedAt = readInteger(input.approvedAt, `${payloadPath}.approvedAt`, requestedAt);
|
|
6129
|
+
assertAuthorityTimestamp(requestedAt, metadata.productionMetadata, `${payloadPath}.requestedAt`);
|
|
6130
|
+
assertAuthorityTimestamp(approvedAt, metadata.productionMetadata, `${payloadPath}.approvedAt`);
|
|
6131
|
+
if (metadata.productionMetadata.issuedAt <= scratchReceipt.completedAt
|
|
6132
|
+
|| requestedAt <= scratchReceipt.completedAt) {
|
|
6133
|
+
fail('CROSS_FIELD_MISMATCH', `${payloadPath}.requestedAt`);
|
|
6134
|
+
}
|
|
6135
|
+
payload = {
|
|
6136
|
+
sourceAuthorityHandoff,
|
|
6137
|
+
productionAuthorityHandoff,
|
|
6138
|
+
authenticatedPlan,
|
|
6139
|
+
requestBundle,
|
|
6140
|
+
scratchReceipt,
|
|
6141
|
+
executionAttempt: executionAttempt as
|
|
6142
|
+
TCloudlyLegacyDeploymentSettlementProductionExecutionAttemptIdentityV1,
|
|
6143
|
+
requestedAt,
|
|
6144
|
+
approvedAt,
|
|
6145
|
+
};
|
|
6146
|
+
} else if (command === 'settlement-production-resolve') {
|
|
6147
|
+
payload = normalizeProductionStdioPayload(value.payload, payloadPath, true) as
|
|
6148
|
+
ICloudlyLegacyDeploymentSettlementProductionResolveStdioRequestV1['payload'];
|
|
6149
|
+
} else {
|
|
6150
|
+
payload = normalizeProductionStdioPayload(value.payload, payloadPath, false);
|
|
6151
|
+
}
|
|
6152
|
+
assertStdioArtifactAggregate(payload, payloadPath);
|
|
6153
|
+
return finalize({
|
|
6154
|
+
schemaVersion: 1,
|
|
6155
|
+
kind: 'cloudly-legacy-deployment-settlement-stdio-request',
|
|
6156
|
+
requestId,
|
|
6157
|
+
command,
|
|
6158
|
+
payload,
|
|
6159
|
+
} as TCloudlyLegacyDeploymentSettlementStdioRequestV1,
|
|
6160
|
+
cloudlyLegacyDeploymentSettlementStdioLimits.maximumRequestFrameBytes - 1,
|
|
6161
|
+
'stdioRequest');
|
|
6162
|
+
};
|
|
6163
|
+
|
|
6164
|
+
const createCloudlyLegacyDeploymentSettlementStdioRequestHmacVerifier = (
|
|
6165
|
+
requestArg: TCloudlyLegacyDeploymentSettlementStdioRequestV1,
|
|
6166
|
+
): TCloudlyLegacyDeploymentSettlementHmacVerifier => {
|
|
6167
|
+
if (requestArg.command === 'settlement-plan'
|
|
6168
|
+
|| requestArg.command === 'settlement-request'
|
|
6169
|
+
|| requestArg.command === 'settlement-scratch-check'
|
|
6170
|
+
|| requestArg.command === 'settlement-scratch-apply'
|
|
6171
|
+
|| requestArg.command === 'settlement-scratch-resolve') {
|
|
6172
|
+
return createCloudlyLegacyDeploymentSettlementStdioHandoffHmacVerifier(
|
|
6173
|
+
requestArg.payload.authorityHandoff,
|
|
6174
|
+
);
|
|
6175
|
+
}
|
|
6176
|
+
const sourceVerifier = createCloudlyLegacyDeploymentSettlementStdioHandoffHmacVerifier(
|
|
6177
|
+
requestArg.payload.sourceAuthorityHandoff,
|
|
6178
|
+
);
|
|
6179
|
+
const executionVerifier = createCloudlyLegacyDeploymentSettlementStdioHandoffHmacVerifier(
|
|
6180
|
+
requestArg.payload.productionAuthorityHandoff,
|
|
6181
|
+
);
|
|
6182
|
+
return async (inputArg): Promise<boolean> => (
|
|
6183
|
+
await sourceVerifier(inputArg) || await executionVerifier(inputArg)
|
|
6184
|
+
);
|
|
6185
|
+
};
|
|
6186
|
+
|
|
6187
|
+
export const normalizeCloudlyLegacyDeploymentSettlementStdioRequestForAuthorities = async (
|
|
6188
|
+
valueArg: unknown,
|
|
6189
|
+
): Promise<Readonly<TCloudlyLegacyDeploymentSettlementStdioRequestV1>> => {
|
|
6190
|
+
const request = normalizeCloudlyLegacyDeploymentSettlementStdioRequest(valueArg);
|
|
6191
|
+
const verifier = createCloudlyLegacyDeploymentSettlementStdioRequestHmacVerifier(request);
|
|
6192
|
+
if (request.command === 'settlement-plan') {
|
|
6193
|
+
return request;
|
|
6194
|
+
}
|
|
6195
|
+
if (request.command === 'settlement-request') {
|
|
6196
|
+
await normalizeAuthenticatedCloudlyLegacyDeploymentSettlementPlanForAuthority(
|
|
6197
|
+
request.payload.authenticatedPlan,
|
|
6198
|
+
request.payload.authorityHandoff.authorityMetadata,
|
|
6199
|
+
verifier,
|
|
6200
|
+
);
|
|
6201
|
+
return request;
|
|
6202
|
+
}
|
|
6203
|
+
if (request.command === 'settlement-scratch-check'
|
|
6204
|
+
|| request.command === 'settlement-scratch-apply'
|
|
6205
|
+
|| request.command === 'settlement-scratch-resolve') {
|
|
6206
|
+
await normalizeExecutionAttemptProofArtifacts({
|
|
6207
|
+
executionAttempt: request.payload.executionAttempt,
|
|
6208
|
+
sourceMetadata: request.payload.authorityHandoff.authorityMetadata,
|
|
6209
|
+
executionMetadata: request.payload.authorityHandoff.authorityMetadata,
|
|
6210
|
+
authenticatedPlan: request.payload.authenticatedPlan,
|
|
6211
|
+
requestBundle: request.payload.requestBundle,
|
|
6212
|
+
scratchReceipt: null,
|
|
6213
|
+
productionAuthorization: null,
|
|
6214
|
+
requireProductionAuthorization: false,
|
|
6215
|
+
verifier,
|
|
6216
|
+
});
|
|
6217
|
+
return request;
|
|
6218
|
+
}
|
|
6219
|
+
await normalizeExecutionAttemptProofArtifacts({
|
|
6220
|
+
executionAttempt: request.payload.executionAttempt,
|
|
6221
|
+
sourceMetadata: request.payload.sourceAuthorityHandoff.authorityMetadata,
|
|
6222
|
+
executionMetadata: request.payload.productionAuthorityHandoff.authorityMetadata,
|
|
6223
|
+
authenticatedPlan: request.payload.authenticatedPlan,
|
|
6224
|
+
requestBundle: request.payload.requestBundle,
|
|
6225
|
+
scratchReceipt: request.payload.scratchReceipt,
|
|
6226
|
+
productionAuthorization: request.command === 'settlement-production-authorize'
|
|
6227
|
+
? null
|
|
6228
|
+
: request.payload.productionAuthorization,
|
|
6229
|
+
requireProductionAuthorization: request.command !== 'settlement-production-authorize',
|
|
6230
|
+
verifier,
|
|
6231
|
+
});
|
|
6232
|
+
return request;
|
|
6233
|
+
};
|
|
6234
|
+
|
|
6235
|
+
const normalizeStdioSuccessPayload = (
|
|
6236
|
+
commandArg: TCloudlyLegacyDeploymentSettlementStdioCommand,
|
|
6237
|
+
valueArg: unknown,
|
|
6238
|
+
): TCloudlyLegacyDeploymentSettlementStdioSuccessPayloadV1 => {
|
|
6239
|
+
const path = 'stdioResponse.payload';
|
|
6240
|
+
const value = readRecord(valueArg, path);
|
|
6241
|
+
if (commandArg === 'settlement-plan') {
|
|
6242
|
+
assertExactKeys(value, ['authenticatedPlan'], path);
|
|
6243
|
+
return {
|
|
6244
|
+
authenticatedPlan: normalizeCloudlyLegacyDeploymentSettlementAuthenticatedPlanStructure(
|
|
6245
|
+
value.authenticatedPlan,
|
|
6246
|
+
),
|
|
6247
|
+
};
|
|
6248
|
+
}
|
|
6249
|
+
if (commandArg === 'settlement-request') {
|
|
6250
|
+
assertExactKeys(value, ['requestBundle'], path);
|
|
6251
|
+
return { requestBundle: normalizeCloudlyLegacyDeploymentSettlementRequestBundle(
|
|
6252
|
+
value.requestBundle,
|
|
6253
|
+
) };
|
|
6254
|
+
}
|
|
6255
|
+
if (commandArg === 'settlement-scratch-check'
|
|
6256
|
+
|| commandArg === 'settlement-production-check') {
|
|
6257
|
+
assertExactKeys(value, ['authenticatedResult'], path);
|
|
6258
|
+
return {
|
|
6259
|
+
authenticatedResult:
|
|
6260
|
+
normalizeCloudlyLegacyDeploymentSettlementAuthenticatedCheckResultStructure(
|
|
6261
|
+
value.authenticatedResult,
|
|
6262
|
+
),
|
|
6263
|
+
};
|
|
6264
|
+
}
|
|
6265
|
+
if (commandArg === 'settlement-scratch-apply') {
|
|
6266
|
+
assertExactKeys(value, ['executionBundle'], path);
|
|
6267
|
+
return {
|
|
6268
|
+
executionBundle: normalizeCloudlyLegacyDeploymentSettlementScratchExecutionBundle(
|
|
6269
|
+
value.executionBundle,
|
|
6270
|
+
),
|
|
6271
|
+
};
|
|
6272
|
+
}
|
|
6273
|
+
if (commandArg === 'settlement-production-apply') {
|
|
6274
|
+
assertExactKeys(value, ['executionBundle'], path);
|
|
6275
|
+
return {
|
|
6276
|
+
executionBundle: normalizeCloudlyLegacyDeploymentSettlementProductionExecutionBundleV2(
|
|
6277
|
+
value.executionBundle,
|
|
6278
|
+
),
|
|
6279
|
+
};
|
|
6280
|
+
}
|
|
6281
|
+
if (commandArg === 'settlement-production-authorize') {
|
|
6282
|
+
assertExactKeys(value, ['productionAuthorization'], path);
|
|
6283
|
+
return {
|
|
6284
|
+
productionAuthorization:
|
|
6285
|
+
normalizeCloudlyLegacyDeploymentSettlementProductionExecutionAuthorization(
|
|
6286
|
+
value.productionAuthorization,
|
|
6287
|
+
),
|
|
6288
|
+
};
|
|
6289
|
+
}
|
|
6290
|
+
assertExactKeys(value, ['authenticatedResolution'], path);
|
|
6291
|
+
return {
|
|
6292
|
+
authenticatedResolution:
|
|
6293
|
+
normalizeCloudlyLegacyDeploymentSettlementAuthenticatedResolutionStructure(
|
|
6294
|
+
value.authenticatedResolution,
|
|
6295
|
+
),
|
|
6296
|
+
};
|
|
6297
|
+
};
|
|
6298
|
+
|
|
6299
|
+
const createCloudlyLegacyDeploymentSettlementStdioSafeError = (
|
|
6300
|
+
codeArg: TCloudlyLegacyDeploymentSettlementStdioErrorCode,
|
|
6301
|
+
): TCloudlyLegacyDeploymentSettlementStdioSafeErrorV1 => ({
|
|
6302
|
+
code: codeArg,
|
|
6303
|
+
retryable: cloudlyLegacyDeploymentSettlementStdioErrorMetadata[codeArg].retryable,
|
|
6304
|
+
} as TCloudlyLegacyDeploymentSettlementStdioSafeErrorV1);
|
|
6305
|
+
|
|
6306
|
+
/** Structural only; use the request-authority-aware variant before trusting artifacts. */
|
|
6307
|
+
export const normalizeCloudlyLegacyDeploymentSettlementStdioResponse = (
|
|
6308
|
+
valueArg: unknown,
|
|
6309
|
+
): Readonly<TCloudlyLegacyDeploymentSettlementStdioResponseV1> => {
|
|
6310
|
+
const value = readRecord(valueArg, 'stdioResponse');
|
|
6311
|
+
if (typeof value.ok !== 'boolean') fail('INVALID_VALUE', 'stdioResponse.ok');
|
|
6312
|
+
assertExactKeys(
|
|
6313
|
+
value,
|
|
6314
|
+
value.ok ? stdioResponseSuccessKeys : stdioResponseErrorKeys,
|
|
6315
|
+
'stdioResponse',
|
|
6316
|
+
);
|
|
6317
|
+
if (value.schemaVersion !== 1
|
|
6318
|
+
|| value.kind !== 'cloudly-legacy-deployment-settlement-stdio-response') {
|
|
6319
|
+
fail('INVALID_VALUE', 'stdioResponse.kind');
|
|
6320
|
+
}
|
|
6321
|
+
if (value.ok) {
|
|
6322
|
+
assertStdioArtifactAggregate(value.payload, 'stdioResponse.payload');
|
|
6323
|
+
}
|
|
6324
|
+
const requestId = readIdentifier(value.requestId, 'stdioResponse.requestId');
|
|
6325
|
+
const command = readLiteral(
|
|
6326
|
+
value.command,
|
|
6327
|
+
cloudlyLegacyDeploymentSettlementStdioCommands,
|
|
6328
|
+
'stdioResponse.command',
|
|
6329
|
+
);
|
|
6330
|
+
if (value.ok) {
|
|
6331
|
+
const payload = normalizeStdioSuccessPayload(command, value.payload);
|
|
6332
|
+
assertStdioArtifactAggregate(payload, 'stdioResponse.payload');
|
|
6333
|
+
return finalize({
|
|
6334
|
+
schemaVersion: 1,
|
|
6335
|
+
kind: 'cloudly-legacy-deployment-settlement-stdio-response',
|
|
6336
|
+
requestId,
|
|
6337
|
+
command,
|
|
6338
|
+
ok: true,
|
|
6339
|
+
payload,
|
|
6340
|
+
} as TCloudlyLegacyDeploymentSettlementStdioSuccessResponseV1,
|
|
6341
|
+
cloudlyLegacyDeploymentSettlementStdioLimits.maximumResponseFrameBytes - 1,
|
|
6342
|
+
'stdioResponse');
|
|
6343
|
+
}
|
|
6344
|
+
const error = readRecord(value.error, 'stdioResponse.error');
|
|
6345
|
+
assertExactKeys(error, ['code', 'retryable'], 'stdioResponse.error');
|
|
6346
|
+
if (typeof error.code !== 'string'
|
|
6347
|
+
|| !Object.hasOwn(cloudlyLegacyDeploymentSettlementStdioErrorMetadata, error.code)) {
|
|
6348
|
+
fail('INVALID_VALUE', 'stdioResponse.error.code');
|
|
6349
|
+
}
|
|
6350
|
+
const code = error.code as TCloudlyLegacyDeploymentSettlementStdioErrorCode;
|
|
6351
|
+
if (error.retryable !== cloudlyLegacyDeploymentSettlementStdioErrorMetadata[code].retryable) {
|
|
6352
|
+
fail('CROSS_FIELD_MISMATCH', 'stdioResponse.error.retryable');
|
|
6353
|
+
}
|
|
6354
|
+
return finalize({
|
|
6355
|
+
schemaVersion: 1,
|
|
6356
|
+
kind: 'cloudly-legacy-deployment-settlement-stdio-response',
|
|
6357
|
+
requestId,
|
|
6358
|
+
command,
|
|
6359
|
+
ok: false,
|
|
6360
|
+
error: createCloudlyLegacyDeploymentSettlementStdioSafeError(code),
|
|
6361
|
+
} as TCloudlyLegacyDeploymentSettlementStdioErrorResponseV1,
|
|
6362
|
+
cloudlyLegacyDeploymentSettlementStdioLimits.maximumResponseFrameBytes - 1,
|
|
6363
|
+
'stdioResponse');
|
|
6364
|
+
};
|
|
6365
|
+
|
|
6366
|
+
export const normalizeCloudlyLegacyDeploymentSettlementStdioResponseForRequestAuthorities = async (
|
|
6367
|
+
responseArg: unknown,
|
|
6368
|
+
requestArg: unknown,
|
|
6369
|
+
): Promise<Readonly<TCloudlyLegacyDeploymentSettlementStdioResponseV1>> => {
|
|
6370
|
+
const request = await normalizeCloudlyLegacyDeploymentSettlementStdioRequestForAuthorities(
|
|
6371
|
+
requestArg,
|
|
6372
|
+
);
|
|
6373
|
+
const verifier = createCloudlyLegacyDeploymentSettlementStdioRequestHmacVerifier(request);
|
|
6374
|
+
const response = normalizeCloudlyLegacyDeploymentSettlementStdioResponse(responseArg);
|
|
6375
|
+
if (response.requestId !== request.requestId || response.command !== request.command) {
|
|
6376
|
+
fail('CROSS_FIELD_MISMATCH', 'stdioResponse.request');
|
|
6377
|
+
}
|
|
6378
|
+
if (!response.ok) {
|
|
6379
|
+
return response;
|
|
6380
|
+
}
|
|
6381
|
+
if (request.command === 'settlement-plan') {
|
|
6382
|
+
const success = response as Extract<
|
|
6383
|
+
TCloudlyLegacyDeploymentSettlementStdioSuccessResponseV1,
|
|
6384
|
+
{ command: 'settlement-plan' }
|
|
6385
|
+
>;
|
|
6386
|
+
const plan = await normalizeAuthenticatedCloudlyLegacyDeploymentSettlementPlanForAuthority(
|
|
6387
|
+
success.payload.authenticatedPlan,
|
|
6388
|
+
request.payload.authorityHandoff.authorityMetadata,
|
|
6389
|
+
verifier,
|
|
6390
|
+
);
|
|
6391
|
+
if (plan.payload.effectiveAt !== request.payload.effectiveAt) {
|
|
6392
|
+
fail('CROSS_FIELD_MISMATCH', 'stdioResponse.payload.authenticatedPlan.effectiveAt');
|
|
6393
|
+
}
|
|
6394
|
+
return response;
|
|
6395
|
+
}
|
|
6396
|
+
if (request.command === 'settlement-request') {
|
|
6397
|
+
const success = response as Extract<
|
|
6398
|
+
TCloudlyLegacyDeploymentSettlementStdioSuccessResponseV1,
|
|
6399
|
+
{ command: 'settlement-request' }
|
|
6400
|
+
>;
|
|
6401
|
+
const requestBundle =
|
|
6402
|
+
await normalizeCloudlyLegacyDeploymentSettlementRequestBundleForAuthority(
|
|
6403
|
+
success.payload.requestBundle,
|
|
6404
|
+
request.payload.authenticatedPlan,
|
|
6405
|
+
request.payload.authorityHandoff.authorityMetadata,
|
|
6406
|
+
verifier,
|
|
6407
|
+
);
|
|
6408
|
+
if (requestBundle.authenticatedRequest.payload.requestedAt
|
|
6409
|
+
!== request.payload.requestedAt) {
|
|
6410
|
+
fail('CROSS_FIELD_MISMATCH', 'stdioResponse.payload.requestBundle.requestedAt');
|
|
6411
|
+
}
|
|
6412
|
+
return response;
|
|
6413
|
+
}
|
|
6414
|
+
if (request.command === 'settlement-scratch-check') {
|
|
6415
|
+
const success = response as Extract<
|
|
6416
|
+
TCloudlyLegacyDeploymentSettlementStdioSuccessResponseV1,
|
|
6417
|
+
{ command: 'settlement-scratch-check' }
|
|
6418
|
+
>;
|
|
6419
|
+
await normalizeAuthenticatedCloudlyLegacyDeploymentSettlementCheckResultForAuthority(
|
|
6420
|
+
success.payload.authenticatedResult,
|
|
6421
|
+
request.payload.authorityHandoff.authorityMetadata,
|
|
6422
|
+
request.payload.requestBundle.authenticatedRequest,
|
|
6423
|
+
verifier,
|
|
6424
|
+
);
|
|
6425
|
+
return response;
|
|
6426
|
+
}
|
|
6427
|
+
if (request.command === 'settlement-scratch-apply') {
|
|
6428
|
+
const success = response as Extract<
|
|
6429
|
+
TCloudlyLegacyDeploymentSettlementStdioSuccessResponseV1,
|
|
6430
|
+
{ command: 'settlement-scratch-apply' }
|
|
6431
|
+
>;
|
|
6432
|
+
await normalizeCloudlyLegacyDeploymentSettlementScratchExecutionBundleForAuthority(
|
|
6433
|
+
success.payload.executionBundle,
|
|
6434
|
+
request.payload.authorityHandoff.authorityMetadata,
|
|
6435
|
+
request.payload.authenticatedPlan,
|
|
6436
|
+
request.payload.requestBundle,
|
|
6437
|
+
verifier,
|
|
6438
|
+
);
|
|
6439
|
+
return response;
|
|
6440
|
+
}
|
|
6441
|
+
if (request.command === 'settlement-scratch-resolve') {
|
|
6442
|
+
const success = response as Extract<
|
|
6443
|
+
TCloudlyLegacyDeploymentSettlementStdioSuccessResponseV1,
|
|
6444
|
+
{ command: 'settlement-scratch-resolve' }
|
|
6445
|
+
>;
|
|
6446
|
+
const resolution =
|
|
6447
|
+
await normalizeAuthenticatedCloudlyLegacyDeploymentSettlementResolutionForAuthorities(
|
|
6448
|
+
success.payload.authenticatedResolution,
|
|
6449
|
+
request.payload.authorityHandoff.authorityMetadata,
|
|
6450
|
+
request.payload.authorityHandoff.authorityMetadata,
|
|
6451
|
+
request.payload.authenticatedPlan,
|
|
6452
|
+
request.payload.requestBundle,
|
|
6453
|
+
null,
|
|
6454
|
+
null,
|
|
6455
|
+
verifier,
|
|
6456
|
+
);
|
|
6457
|
+
if (resolution.payload.observedAt !== request.payload.observedAt) {
|
|
6458
|
+
fail('CROSS_FIELD_MISMATCH', 'stdioResponse.payload.authenticatedResolution.observedAt');
|
|
6459
|
+
}
|
|
6460
|
+
return response;
|
|
6461
|
+
}
|
|
6462
|
+
if (request.command === 'settlement-production-authorize') {
|
|
6463
|
+
const success = response as Extract<
|
|
6464
|
+
TCloudlyLegacyDeploymentSettlementStdioSuccessResponseV1,
|
|
6465
|
+
{ command: 'settlement-production-authorize' }
|
|
6466
|
+
>;
|
|
6467
|
+
const authorization =
|
|
6468
|
+
await normalizeCloudlyLegacyDeploymentSettlementProductionExecutionAuthorizationForAuthorities(
|
|
6469
|
+
success.payload.productionAuthorization,
|
|
6470
|
+
request.payload.productionAuthorityHandoff.authorityMetadata,
|
|
6471
|
+
request.payload.sourceAuthorityHandoff.authorityMetadata,
|
|
6472
|
+
request.payload.authenticatedPlan,
|
|
6473
|
+
request.payload.requestBundle,
|
|
6474
|
+
request.payload.scratchReceipt,
|
|
6475
|
+
verifier,
|
|
6476
|
+
);
|
|
6477
|
+
if (authorization.requestedAt !== request.payload.requestedAt
|
|
6478
|
+
|| authorization.approvedAt !== request.payload.approvedAt) {
|
|
6479
|
+
fail('CROSS_FIELD_MISMATCH', 'stdioResponse.payload.productionAuthorization.timestamp');
|
|
6480
|
+
}
|
|
6481
|
+
return response;
|
|
6482
|
+
}
|
|
6483
|
+
if (request.command === 'settlement-production-check') {
|
|
6484
|
+
const success = response as Extract<
|
|
6485
|
+
TCloudlyLegacyDeploymentSettlementStdioSuccessResponseV1,
|
|
6486
|
+
{ command: 'settlement-production-check' }
|
|
6487
|
+
>;
|
|
6488
|
+
await normalizeAuthenticatedCheckResultForExecutionAuthority(
|
|
6489
|
+
success.payload.authenticatedResult,
|
|
6490
|
+
request.payload.productionAuthorityHandoff.authorityMetadata,
|
|
6491
|
+
request.payload.requestBundle.authenticatedRequest,
|
|
6492
|
+
request.payload.productionAuthorization,
|
|
6493
|
+
verifier,
|
|
6494
|
+
);
|
|
6495
|
+
return response;
|
|
6496
|
+
}
|
|
6497
|
+
if (request.command === 'settlement-production-apply') {
|
|
6498
|
+
const success = response as Extract<
|
|
6499
|
+
TCloudlyLegacyDeploymentSettlementStdioSuccessResponseV1,
|
|
6500
|
+
{ command: 'settlement-production-apply' }
|
|
6501
|
+
>;
|
|
6502
|
+
await normalizeCloudlyLegacyDeploymentSettlementProductionExecutionBundleV2ForAuthorities(
|
|
6503
|
+
success.payload.executionBundle,
|
|
6504
|
+
request.payload.productionAuthorization,
|
|
6505
|
+
request.payload.productionAuthorityHandoff.authorityMetadata,
|
|
6506
|
+
request.payload.sourceAuthorityHandoff.authorityMetadata,
|
|
6507
|
+
request.payload.authenticatedPlan,
|
|
6508
|
+
request.payload.requestBundle,
|
|
6509
|
+
request.payload.scratchReceipt,
|
|
6510
|
+
verifier,
|
|
6511
|
+
);
|
|
6512
|
+
return response;
|
|
6513
|
+
}
|
|
6514
|
+
const success = response as Extract<
|
|
6515
|
+
TCloudlyLegacyDeploymentSettlementStdioSuccessResponseV1,
|
|
6516
|
+
{ command: 'settlement-production-resolve' }
|
|
6517
|
+
>;
|
|
6518
|
+
const resolution =
|
|
6519
|
+
await normalizeAuthenticatedCloudlyLegacyDeploymentSettlementResolutionForAuthorities(
|
|
6520
|
+
success.payload.authenticatedResolution,
|
|
6521
|
+
request.payload.sourceAuthorityHandoff.authorityMetadata,
|
|
6522
|
+
request.payload.productionAuthorityHandoff.authorityMetadata,
|
|
6523
|
+
request.payload.authenticatedPlan,
|
|
6524
|
+
request.payload.requestBundle,
|
|
6525
|
+
request.payload.scratchReceipt,
|
|
6526
|
+
request.payload.productionAuthorization,
|
|
6527
|
+
verifier,
|
|
6528
|
+
);
|
|
6529
|
+
if (resolution.payload.observedAt !== request.payload.observedAt) {
|
|
6530
|
+
fail('CROSS_FIELD_MISMATCH', 'stdioResponse.payload.authenticatedResolution.observedAt');
|
|
6531
|
+
}
|
|
6532
|
+
return response;
|
|
6533
|
+
};
|
|
6534
|
+
|
|
6535
|
+
const encodeStdioFrame = (
|
|
6536
|
+
valueArg: unknown,
|
|
6537
|
+
maximumBytesArg: number,
|
|
6538
|
+
pathArg: string,
|
|
6539
|
+
): Uint8Array => {
|
|
6540
|
+
const payload = encodeNormalized(valueArg, pathArg);
|
|
6541
|
+
try {
|
|
6542
|
+
if (payload.byteLength + 1 > maximumBytesArg) fail('LIMIT_EXCEEDED', pathArg);
|
|
6543
|
+
const output = new Uint8Array(payload.byteLength + 1);
|
|
6544
|
+
output.set(payload);
|
|
6545
|
+
output[payload.byteLength] = 0x0a;
|
|
6546
|
+
return output;
|
|
6547
|
+
} finally {
|
|
6548
|
+
payload.fill(0);
|
|
6549
|
+
}
|
|
6550
|
+
};
|
|
6551
|
+
|
|
6552
|
+
export const encodeCloudlyLegacyDeploymentSettlementStdioRequestFrame = (
|
|
6553
|
+
valueArg: unknown,
|
|
6554
|
+
): Uint8Array => encodeStdioFrame(
|
|
6555
|
+
normalizeCloudlyLegacyDeploymentSettlementStdioRequest(valueArg),
|
|
6556
|
+
cloudlyLegacyDeploymentSettlementStdioLimits.maximumRequestFrameBytes,
|
|
6557
|
+
'stdioRequest',
|
|
6558
|
+
);
|
|
6559
|
+
|
|
6560
|
+
export const encodeCloudlyLegacyDeploymentSettlementStdioResponseFrame = (
|
|
6561
|
+
valueArg: unknown,
|
|
6562
|
+
): Uint8Array => encodeStdioFrame(
|
|
6563
|
+
normalizeCloudlyLegacyDeploymentSettlementStdioResponse(valueArg),
|
|
6564
|
+
cloudlyLegacyDeploymentSettlementStdioLimits.maximumResponseFrameBytes,
|
|
6565
|
+
'stdioResponse',
|
|
6566
|
+
);
|
|
6567
|
+
|
|
6568
|
+
const decodeStdioFrame = <T>(
|
|
6569
|
+
frameArg: Uint8Array,
|
|
6570
|
+
maximumBytesArg: number,
|
|
6571
|
+
pathArg: string,
|
|
6572
|
+
normalizeArg: (valueArg: unknown) => Readonly<T>,
|
|
6573
|
+
encodeArg: (valueArg: unknown) => Uint8Array,
|
|
6574
|
+
): Readonly<T> => {
|
|
6575
|
+
if (!(frameArg instanceof Uint8Array)
|
|
6576
|
+
|| frameArg.byteLength < 3
|
|
6577
|
+
|| frameArg.byteLength > maximumBytesArg
|
|
6578
|
+
|| frameArg.at(-1) !== 0x0a
|
|
6579
|
+
|| frameArg.subarray(0, -1).some((byteArg) => byteArg === 0x0a || byteArg === 0x0d)) {
|
|
6580
|
+
fail('INVALID_DATA', pathArg);
|
|
6581
|
+
}
|
|
6582
|
+
const payloadBytes = new Uint8Array(frameArg.subarray(0, -1));
|
|
6583
|
+
let canonicalFrame: Uint8Array | undefined;
|
|
6584
|
+
try {
|
|
6585
|
+
let text: string;
|
|
6586
|
+
try {
|
|
6587
|
+
text = new TextDecoder('utf-8', { fatal: true }).decode(payloadBytes);
|
|
6588
|
+
} catch {
|
|
6589
|
+
return fail('INVALID_DATA', pathArg);
|
|
6590
|
+
}
|
|
6591
|
+
let value: unknown;
|
|
6592
|
+
try {
|
|
6593
|
+
value = JSON.parse(text) as unknown;
|
|
6594
|
+
} catch {
|
|
6595
|
+
return fail('INVALID_DATA', pathArg);
|
|
6596
|
+
}
|
|
6597
|
+
const normalized = normalizeArg(value);
|
|
6598
|
+
canonicalFrame = encodeArg(normalized);
|
|
6599
|
+
if (canonicalFrame.byteLength !== frameArg.byteLength
|
|
6600
|
+
|| canonicalFrame.some((byteArg, indexArg) => byteArg !== frameArg[indexArg])) {
|
|
6601
|
+
fail('INVALID_DATA', pathArg);
|
|
6602
|
+
}
|
|
6603
|
+
return normalized;
|
|
6604
|
+
} finally {
|
|
6605
|
+
payloadBytes.fill(0);
|
|
6606
|
+
canonicalFrame?.fill(0);
|
|
6607
|
+
}
|
|
6608
|
+
};
|
|
6609
|
+
|
|
6610
|
+
export const decodeCloudlyLegacyDeploymentSettlementStdioRequestFrame = (
|
|
6611
|
+
frameArg: Uint8Array,
|
|
6612
|
+
): Readonly<TCloudlyLegacyDeploymentSettlementStdioRequestV1> => decodeStdioFrame(
|
|
6613
|
+
frameArg,
|
|
6614
|
+
cloudlyLegacyDeploymentSettlementStdioLimits.maximumRequestFrameBytes,
|
|
6615
|
+
'stdioRequestFrame',
|
|
6616
|
+
normalizeCloudlyLegacyDeploymentSettlementStdioRequest,
|
|
6617
|
+
encodeCloudlyLegacyDeploymentSettlementStdioRequestFrame,
|
|
6618
|
+
);
|
|
6619
|
+
|
|
6620
|
+
export const decodeCloudlyLegacyDeploymentSettlementStdioResponseFrame = (
|
|
6621
|
+
frameArg: Uint8Array,
|
|
6622
|
+
): Readonly<TCloudlyLegacyDeploymentSettlementStdioResponseV1> => decodeStdioFrame(
|
|
6623
|
+
frameArg,
|
|
6624
|
+
cloudlyLegacyDeploymentSettlementStdioLimits.maximumResponseFrameBytes,
|
|
6625
|
+
'stdioResponseFrame',
|
|
6626
|
+
normalizeCloudlyLegacyDeploymentSettlementStdioResponse,
|
|
6627
|
+
encodeCloudlyLegacyDeploymentSettlementStdioResponseFrame,
|
|
6628
|
+
);
|
|
6629
|
+
|
|
2885
6630
|
export { cloudlyLegacyDeploymentSettlementGoldenVectors } from './runtime.cloudlylegacydeploymentsettlement.golden.js';
|