@serve.zone/interfaces 31.9.0 → 32.0.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 +476 -0
- package/dist_ts/00_commitinfo_data.js +3 -3
- package/dist_ts/appstore/types.d.ts +4 -6
- package/dist_ts/appstore/types.js +5 -5
- package/dist_ts/data/backup.d.ts +3 -26
- package/dist_ts/data/cluster.d.ts +36 -11
- package/dist_ts/data/cluster.js +33 -22
- package/dist_ts/data/clusteringress.d.ts +8 -0
- package/dist_ts/data/clusteringress.js +13 -8
- package/dist_ts/data/clusternode.d.ts +121 -74
- package/dist_ts/data/clusternode.js +109 -132
- package/dist_ts/data/coremail.d.ts +3 -7
- package/dist_ts/data/coremail.js +2 -2
- package/dist_ts/data/coremail.runtime.d.ts +0 -1
- package/dist_ts/data/coremail.runtime.js +5 -22
- package/dist_ts/data/deploymentadoption.d.ts +0 -2
- package/dist_ts/data/deploymentadoption.js +40 -6
- package/dist_ts/data/deploymentoperation.js +16 -3
- package/dist_ts/data/deploymentpreflight.d.ts +0 -2
- package/dist_ts/data/deploymentpreflight.js +1 -1
- package/dist_ts/data/immutableimage.d.ts +38 -21
- package/dist_ts/data/immutableimage.js +45 -5
- package/dist_ts/data/index.d.ts +1 -1
- package/dist_ts/data/isolatedrestore.d.ts +139 -21
- package/dist_ts/data/isolatedrestore.golden.d.ts +0 -1
- package/dist_ts/data/isolatedrestore.golden.js +6 -9
- package/dist_ts/data/isolatedrestore.js +176 -40
- package/dist_ts/data/mail.d.ts +1 -1
- package/dist_ts/data/networkaddressplan.d.ts +8 -8
- package/dist_ts/data/networkaddressplan.js +4 -4
- package/dist_ts/data/networkauthority.d.ts +20 -22
- package/dist_ts/data/networkauthority.js +26 -28
- package/dist_ts/data/networkcredential.d.ts +10 -10
- package/dist_ts/data/networkcredential.js +16 -16
- package/dist_ts/data/networkdelivery.d.ts +18 -18
- package/dist_ts/data/networkdelivery.js +16 -16
- package/dist_ts/data/networklease.d.ts +18 -7
- package/dist_ts/data/networklease.js +29 -7
- package/dist_ts/data/networknode.d.ts +2 -2
- package/dist_ts/data/networkprojection.d.ts +59 -60
- package/dist_ts/data/networkprojection.js +53 -57
- package/dist_ts/data/networkprotection.d.ts +27 -28
- package/dist_ts/data/networkprotection.js +36 -36
- package/dist_ts/data/networkrouter.d.ts +11 -11
- package/dist_ts/data/networkrouter.js +1 -1
- package/dist_ts/data/networksigning.d.ts +16 -18
- package/dist_ts/data/networksigning.js +20 -21
- package/dist_ts/data/nodecredential.d.ts +4 -6
- package/dist_ts/data/nodeenrollment.d.ts +35 -40
- package/dist_ts/data/nodeenrollment.js +57 -72
- package/dist_ts/data/privatenetwork.d.ts +21 -24
- package/dist_ts/data/privatenetwork.js +39 -54
- package/dist_ts/data/runtimeassignment.d.ts +50 -34
- package/dist_ts/data/runtimeassignment.js +79 -45
- package/dist_ts/data/runtimeconfig.d.ts +21 -22
- package/dist_ts/data/runtimeconfig.js +24 -24
- package/dist_ts/data/runtimesession.d.ts +100 -62
- package/dist_ts/data/runtimesession.js +98 -79
- package/dist_ts/data/runtimeterminalreceipt.d.ts +28 -29
- package/dist_ts/data/runtimeterminalreceipt.js +42 -42
- package/dist_ts/data/secret.d.ts +18 -25
- package/dist_ts/data/secret.js +12 -52
- package/dist_ts/data/servicecredential.d.ts +14 -16
- package/dist_ts/data/servicecredential.js +17 -28
- package/dist_ts/data/serviceruntime.d.ts +7 -7
- package/dist_ts/data/serviceruntime.js +4 -4
- package/dist_ts/data/sparknodereport.d.ts +27 -14
- package/dist_ts/data/sparknodereport.js +35 -28
- package/dist_ts/data/webpush.d.ts +0 -1
- package/dist_ts/index.d.ts +2 -1
- package/dist_ts/index.js +3 -2
- package/dist_ts/platform/objectstorageretention.d.ts +21 -24
- package/dist_ts/platform/objectstorageretention.js +10 -17
- package/dist_ts/platform/storage.d.ts +1 -3
- package/dist_ts/platform/storagemigration.d.ts +0 -7
- package/dist_ts/platform/storagemigration.golden.d.ts +0 -1
- package/dist_ts/platform/storagemigration.golden.js +8 -12
- package/dist_ts/platform/storagemigration.js +6 -51
- package/dist_ts/platform/types.d.ts +2 -2
- package/dist_ts/private/canonicaljson.d.ts +9 -1
- package/dist_ts/private/canonicaljson.js +14 -2
- package/dist_ts/private/dataproperties.d.ts +62 -0
- package/dist_ts/private/dataproperties.js +117 -0
- package/dist_ts/private/networkcontract.d.ts +10 -10
- package/dist_ts/private/networkcontract.js +1 -1
- package/dist_ts/private/releaseversion.d.ts +37 -0
- package/dist_ts/private/releaseversion.js +48 -0
- package/dist_ts/private/runtimepolicy.d.ts +2 -2
- package/dist_ts/private/runtimepolicy.js +1 -1
- package/dist_ts/private/tokenlist.d.ts +9 -0
- package/dist_ts/private/tokenlist.js +23 -0
- package/dist_ts/protocol.d.ts +137 -0
- package/dist_ts/protocol.js +255 -0
- package/dist_ts/requests/admin.d.ts +8 -8
- package/dist_ts/requests/backup.d.ts +102 -112
- package/dist_ts/requests/cluster.d.ts +10 -10
- package/dist_ts/requests/clusteringress.d.ts +9 -0
- package/dist_ts/requests/clusteringress.js +1 -1
- package/dist_ts/requests/config.d.ts +3 -3
- package/dist_ts/requests/corestore.d.ts +0 -3
- package/dist_ts/requests/corestore.js +5 -9
- package/dist_ts/requests/network.d.ts +30 -30
- package/dist_ts/requests/node.d.ts +15 -28
- package/dist_ts/requests/pallet.d.ts +13 -13
- package/dist_ts/requests/runtimesession.d.ts +53 -41
- package/dist_ts/requests/secret.d.ts +4 -5
- package/dist_ts/requests/secret.js +1 -5
- package/dist_ts/runtime.corestore.d.ts +56 -74
- package/dist_ts/runtime.corestore.databaseexportpackage.d.ts +30 -36
- package/dist_ts/runtime.corestore.databaseexportpackage.golden.d.ts +11 -12
- package/dist_ts/runtime.corestore.databaseexportpackage.golden.js +54 -71
- package/dist_ts/runtime.corestore.databaseexportpackage.js +9 -25
- package/dist_ts/runtime.corestore.js +35 -135
- package/dist_ts/runtime.corestore.relay.js +2 -7
- package/dist_ts/runtime.d.ts +38 -48
- package/dist_ts/runtime.js +20 -77
- package/dist_ts/runtime.networkprojection.d.ts +4 -4
- package/dist_ts/runtime.networkprojection.js +18 -18
- package/dist_ts/runtime.workloadinit.d.ts +23 -24
- package/dist_ts/runtime.workloadinit.js +6 -13
- package/package.json +2 -2
- package/readme.md +421 -270
- package/ts/00_commitinfo_data.ts +3 -3
- package/ts/appstore/types.ts +4 -6
- package/ts/data/backup.ts +3 -38
- package/ts/data/cluster.ts +51 -34
- package/ts/data/clusteringress.ts +12 -12
- package/ts/data/clusternode.ts +204 -232
- package/ts/data/coremail.runtime.ts +4 -21
- package/ts/data/coremail.ts +3 -7
- package/ts/data/deploymentadoption.ts +46 -4
- package/ts/data/deploymentoperation.ts +16 -1
- package/ts/data/deploymentpreflight.ts +0 -2
- package/ts/data/immutableimage.ts +71 -24
- package/ts/data/index.ts +1 -1
- package/ts/data/isolatedrestore.golden.ts +5 -9
- package/ts/data/isolatedrestore.ts +339 -54
- package/ts/data/mail.ts +1 -1
- package/ts/data/networkaddressplan.ts +13 -13
- package/ts/data/networkauthority.ts +42 -46
- package/ts/data/networkcredential.ts +24 -24
- package/ts/data/networkdelivery.ts +27 -27
- package/ts/data/networklease.ts +40 -13
- package/ts/data/networknode.ts +2 -2
- package/ts/data/networkprojection.ts +119 -124
- package/ts/data/networkprotection.ts +54 -55
- package/ts/data/networkrouter.ts +14 -14
- package/ts/data/networksigning.ts +29 -32
- package/ts/data/nodecredential.ts +4 -6
- package/ts/data/nodeenrollment.ts +96 -114
- package/ts/data/privatenetwork.ts +58 -74
- package/ts/data/runtimeassignment.ts +143 -94
- package/ts/data/runtimeconfig.ts +45 -46
- package/ts/data/runtimesession.ts +185 -138
- package/ts/data/runtimeterminalreceipt.ts +72 -73
- package/ts/data/secret.ts +28 -76
- package/ts/data/servicecredential.ts +33 -43
- package/ts/data/serviceruntime.ts +11 -11
- package/ts/data/sparknodereport.ts +48 -36
- package/ts/data/webpush.ts +0 -1
- package/ts/index.ts +2 -0
- package/ts/platform/objectstorageretention.ts +40 -54
- package/ts/platform/storage.ts +1 -3
- package/ts/platform/storagemigration.golden.ts +7 -11
- package/ts/platform/storagemigration.ts +5 -55
- package/ts/platform/types.ts +2 -2
- package/ts/private/canonicaljson.ts +13 -1
- package/ts/private/dataproperties.ts +139 -0
- package/ts/private/networkcontract.ts +9 -9
- package/ts/private/releaseversion.ts +70 -0
- package/ts/private/runtimepolicy.ts +2 -2
- package/ts/private/tokenlist.ts +30 -0
- package/ts/protocol.ts +364 -0
- package/ts/requests/admin.ts +11 -11
- package/ts/requests/backup.ts +112 -117
- package/ts/requests/cluster.ts +13 -13
- package/ts/requests/clusteringress.ts +9 -0
- package/ts/requests/config.ts +3 -3
- package/ts/requests/corestore.ts +4 -16
- package/ts/requests/network.ts +40 -40
- package/ts/requests/node.ts +21 -38
- package/ts/requests/pallet.ts +17 -17
- package/ts/requests/runtimesession.ts +63 -51
- package/ts/requests/secret.ts +5 -10
- package/ts/runtime.corestore.databaseexportpackage.golden.ts +77 -95
- package/ts/runtime.corestore.databaseexportpackage.ts +51 -73
- package/ts/runtime.corestore.relay.ts +1 -10
- package/ts/runtime.corestore.ts +118 -268
- package/ts/runtime.networkprojection.ts +30 -30
- package/ts/runtime.ts +83 -158
- package/ts/runtime.workloadinit.ts +36 -48
- package/dist_ts/runtime.cloudlylegacydeploymentsettlement.d.ts +0 -902
- package/dist_ts/runtime.cloudlylegacydeploymentsettlement.golden.d.ts +0 -35
- package/dist_ts/runtime.cloudlylegacydeploymentsettlement.golden.js +0 -315
- package/dist_ts/runtime.cloudlylegacydeploymentsettlement.js +0 -3315
- package/dist_ts/runtime.cloudlylegacydeploymentsettlement.offlineexport.d.ts +0 -291
- package/dist_ts/runtime.cloudlylegacydeploymentsettlement.offlineexport.golden.d.ts +0 -30
- package/dist_ts/runtime.cloudlylegacydeploymentsettlement.offlineexport.golden.js +0 -408
- package/dist_ts/runtime.cloudlylegacydeploymentsettlement.offlineexport.js +0 -1126
- package/ts/runtime.cloudlylegacydeploymentsettlement.golden.ts +0 -421
- package/ts/runtime.cloudlylegacydeploymentsettlement.offlineexport.golden.ts +0 -510
- package/ts/runtime.cloudlylegacydeploymentsettlement.offlineexport.ts +0 -2470
- package/ts/runtime.cloudlylegacydeploymentsettlement.ts +0 -6630
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import { isReleaseVersion } from '../private/releaseversion.js';
|
|
2
|
+
import { readExactDataRecord } from '../private/dataproperties.js';
|
|
3
|
+
import { protocolRefusalHttpStatus, readProtocolOffer, type IProtocolOffer } from '../protocol.js';
|
|
4
|
+
|
|
1
5
|
/** Host observations only. Container and workload readiness belong to Pallet. */
|
|
2
|
-
export interface
|
|
3
|
-
schemaVersion: 2;
|
|
6
|
+
export interface ISparkNodeReport {
|
|
4
7
|
observedAt: number;
|
|
5
8
|
metrics: {
|
|
6
9
|
cpuUsagePercent: number;
|
|
@@ -21,51 +24,55 @@ export interface ISparkNodeReportV2 {
|
|
|
21
24
|
}
|
|
22
25
|
|
|
23
26
|
/** HTTPS POST body. Never log, persist, or return nodeToken. */
|
|
24
|
-
export interface
|
|
27
|
+
export interface ISparkNodeHeartbeatRequest {
|
|
25
28
|
nodeId: string;
|
|
26
29
|
nodeToken: string;
|
|
27
|
-
|
|
30
|
+
/** Read and negotiated before the node is authenticated; see `sparkNodeHeartbeatContract`. */
|
|
31
|
+
protocol: IProtocolOffer;
|
|
32
|
+
report: ISparkNodeReport;
|
|
28
33
|
}
|
|
29
34
|
|
|
30
35
|
/** Historical acceptance evidence, not current authority or workload readiness. */
|
|
31
|
-
export interface
|
|
32
|
-
schemaVersion: 2;
|
|
36
|
+
export interface ISparkNodeHeartbeatReceipt {
|
|
33
37
|
accepted: true;
|
|
34
38
|
nodeId: string;
|
|
35
39
|
credentialGeneration: number;
|
|
36
40
|
sessionEpoch: number;
|
|
37
41
|
acceptedAt: number;
|
|
42
|
+
/** The controller's offer, so an accepted node judges the session it just reported into. */
|
|
43
|
+
protocol: IProtocolOffer;
|
|
38
44
|
}
|
|
39
45
|
|
|
40
46
|
/** Persist only after the server's current Spark credential transaction commits. */
|
|
41
|
-
export interface
|
|
42
|
-
report:
|
|
43
|
-
receipt:
|
|
47
|
+
export interface ISparkNodeReportRecord {
|
|
48
|
+
report: ISparkNodeReport;
|
|
49
|
+
receipt: ISparkNodeHeartbeatReceipt;
|
|
44
50
|
}
|
|
45
51
|
|
|
46
|
-
|
|
47
|
-
|
|
52
|
+
/**
|
|
53
|
+
* The node runtime's own heartbeat route.
|
|
54
|
+
*
|
|
55
|
+
* Judged in the one server order `protocol.readProtocolOffer` states, against this server's
|
|
56
|
+
* `sparkNode` offer and within `maxRequestBytes`. The route carries no typed error, so a refusal
|
|
57
|
+
* is answered with `protocolRefusalStatus` and an `IProtocolRefusal` body — before the report is
|
|
58
|
+
* snapshotted and before the node is authenticated, because a route that authenticated first would
|
|
59
|
+
* answer a peer of another major with a credential verdict it cannot act on.
|
|
60
|
+
*/
|
|
61
|
+
export const sparkNodeHeartbeatContract = Object.freeze({
|
|
62
|
+
endpoint: '/spark/nodes/heartbeat',
|
|
48
63
|
maxRequestBytes: 8192,
|
|
49
64
|
maxResponseBytes: 2048,
|
|
65
|
+
protocolRefusalStatus: protocolRefusalHttpStatus,
|
|
50
66
|
} as const);
|
|
51
67
|
|
|
52
68
|
const fail = (): never => { throw new Error('Spark node heartbeat contract rejected.'); };
|
|
53
69
|
function requireValue(valueArg: unknown): asserts valueArg {
|
|
54
70
|
if (!valueArg) fail();
|
|
55
71
|
}
|
|
72
|
+
/** Exactly these keys, carrying data: the shared reader refuses an accessor instead of running it. */
|
|
56
73
|
const record = (valueArg: unknown, keysArg: readonly string[]): Record<string, unknown> => {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
requireValue(prototype === Object.prototype || prototype === null);
|
|
60
|
-
const keys = Reflect.ownKeys(valueArg);
|
|
61
|
-
requireValue(keys.length === keysArg.length);
|
|
62
|
-
const result: Record<string, unknown> = Object.create(null);
|
|
63
|
-
for (const key of keys) {
|
|
64
|
-
requireValue(typeof key === 'string' && keysArg.includes(key));
|
|
65
|
-
const descriptor = Object.getOwnPropertyDescriptor(valueArg, key);
|
|
66
|
-
requireValue(descriptor?.enumerable && Object.hasOwn(descriptor, 'value'));
|
|
67
|
-
result[key] = descriptor.value;
|
|
68
|
-
}
|
|
74
|
+
const result = readExactDataRecord(valueArg, keysArg);
|
|
75
|
+
requireValue(result !== null);
|
|
69
76
|
return result;
|
|
70
77
|
};
|
|
71
78
|
const text = (valueArg: unknown, patternArg: RegExp, maxLengthArg: number): string => {
|
|
@@ -73,6 +80,11 @@ const text = (valueArg: unknown, patternArg: RegExp, maxLengthArg: number): stri
|
|
|
73
80
|
&& valueArg.match(patternArg)?.[0] === valueArg);
|
|
74
81
|
return valueArg;
|
|
75
82
|
};
|
|
83
|
+
// The shared grammar, not a copy of it: a stored bundle version has to be one the release
|
|
84
|
+
// comparison can order, and a second rule here would be a second answer to that question.
|
|
85
|
+
const releaseVersion = (valueArg: unknown): string => (
|
|
86
|
+
isReleaseVersion(valueArg) ? valueArg : fail()
|
|
87
|
+
);
|
|
76
88
|
const number = (valueArg: unknown, maxArg = Number.MAX_SAFE_INTEGER): number => {
|
|
77
89
|
requireValue(typeof valueArg === 'number' && Number.isFinite(valueArg)
|
|
78
90
|
&& !Object.is(valueArg, -0) && valueArg >= 0 && valueArg <= maxArg);
|
|
@@ -85,9 +97,8 @@ const integer = (valueArg: unknown, minimumArg: number): number => {
|
|
|
85
97
|
};
|
|
86
98
|
|
|
87
99
|
/** Exact inert JSON records; detaches and freezes before any consumer awaits. */
|
|
88
|
-
export const
|
|
89
|
-
const value = record(valueArg, ['
|
|
90
|
-
requireValue(value.schemaVersion === 2);
|
|
100
|
+
export const snapshotSparkNodeReport = (valueArg: unknown): ISparkNodeReport => {
|
|
101
|
+
const value = record(valueArg, ['observedAt', 'metrics', 'runtime']);
|
|
91
102
|
const metrics = record(value.metrics, ['cpuUsagePercent', 'memoryUsedMB', 'memoryAvailableMB',
|
|
92
103
|
'diskUsedGB', 'diskAvailableGB']);
|
|
93
104
|
const runtime = record(value.runtime, ['hostname', 'platform', 'arch', 'osRelease', 'bundle',
|
|
@@ -98,7 +109,6 @@ export const snapshotSparkNodeReportV2 = (valueArg: unknown): ISparkNodeReportV2
|
|
|
98
109
|
requireValue(hostname.split('.').every((label) => /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/.test(label)));
|
|
99
110
|
const bundle = record(runtime.bundle, ['version', 'sourceCommit', 'manifestSha256']);
|
|
100
111
|
return Object.freeze({
|
|
101
|
-
schemaVersion: 2,
|
|
102
112
|
observedAt: integer(value.observedAt, 1),
|
|
103
113
|
metrics: Object.freeze({
|
|
104
114
|
cpuUsagePercent: number(metrics.cpuUsagePercent, 100),
|
|
@@ -109,7 +119,7 @@ export const snapshotSparkNodeReportV2 = (valueArg: unknown): ISparkNodeReportV2
|
|
|
109
119
|
hostname, platform: 'linux', arch: runtime.arch as 'x86_64' | 'aarch64',
|
|
110
120
|
osRelease: text(runtime.osRelease, /^[\x20-\x7e]+$/, 256),
|
|
111
121
|
bundle: Object.freeze({
|
|
112
|
-
version:
|
|
122
|
+
version: releaseVersion(bundle.version),
|
|
113
123
|
sourceCommit: text(bundle.sourceCommit, /^[a-f0-9]{40}$/, 40),
|
|
114
124
|
manifestSha256: text(bundle.manifestSha256, /^[a-f0-9]{64}$/, 64),
|
|
115
125
|
}),
|
|
@@ -118,23 +128,25 @@ export const snapshotSparkNodeReportV2 = (valueArg: unknown): ISparkNodeReportV2
|
|
|
118
128
|
});
|
|
119
129
|
};
|
|
120
130
|
|
|
121
|
-
export const
|
|
122
|
-
const value = record(valueArg, ['nodeId', 'nodeToken', 'report']);
|
|
131
|
+
export const snapshotSparkNodeHeartbeatRequest = (valueArg: unknown): ISparkNodeHeartbeatRequest => {
|
|
132
|
+
const value = record(valueArg, ['nodeId', 'nodeToken', 'protocol', 'report']);
|
|
123
133
|
return Object.freeze({
|
|
124
134
|
nodeId: text(value.nodeId, /^[A-Za-z0-9_-]+$/, 128),
|
|
125
135
|
// Both freshly enrolled and explicitly adopted credentials use this bearer format.
|
|
126
136
|
nodeToken: text(value.nodeToken, /^secureToken[a-f0-9]{64}$/, 75),
|
|
127
|
-
|
|
137
|
+
protocol: readProtocolOffer(value),
|
|
138
|
+
report: snapshotSparkNodeReport(value.report),
|
|
128
139
|
});
|
|
129
140
|
};
|
|
130
141
|
|
|
131
|
-
export const
|
|
132
|
-
const value = record(valueArg, ['
|
|
133
|
-
'sessionEpoch', 'acceptedAt']);
|
|
134
|
-
requireValue(value.
|
|
142
|
+
export const snapshotSparkNodeHeartbeatReceipt = (valueArg: unknown): ISparkNodeHeartbeatReceipt => {
|
|
143
|
+
const value = record(valueArg, ['accepted', 'nodeId', 'credentialGeneration',
|
|
144
|
+
'sessionEpoch', 'acceptedAt', 'protocol']);
|
|
145
|
+
requireValue(value.accepted === true);
|
|
135
146
|
return Object.freeze({
|
|
136
|
-
|
|
147
|
+
accepted: true, nodeId: text(value.nodeId, /^[A-Za-z0-9_-]+$/, 128),
|
|
137
148
|
credentialGeneration: integer(value.credentialGeneration, 1),
|
|
138
149
|
sessionEpoch: integer(value.sessionEpoch, 0), acceptedAt: integer(value.acceptedAt, 1),
|
|
150
|
+
protocol: readProtocolOffer(value),
|
|
139
151
|
});
|
|
140
152
|
};
|
package/ts/data/webpush.ts
CHANGED
|
@@ -101,7 +101,6 @@ export interface IWebPushBinding {
|
|
|
101
101
|
* from their authenticated API after receiving this event.
|
|
102
102
|
*/
|
|
103
103
|
export interface IWebPushNotificationPayload {
|
|
104
|
-
schemaVersion: 1;
|
|
105
104
|
event: 'notificationAvailable';
|
|
106
105
|
eventId: string;
|
|
107
106
|
/** Same-origin application route beginning with a single slash. */
|
package/ts/index.ts
CHANGED
|
@@ -2,6 +2,7 @@ import * as data from './data/index.js';
|
|
|
2
2
|
import * as appstore from './appstore/index.js';
|
|
3
3
|
import * as platform from './platform/index.js';
|
|
4
4
|
import * as platformservice from './platformservice/index.js';
|
|
5
|
+
import * as protocol from './protocol.js';
|
|
5
6
|
import * as requests from './requests/index.js';
|
|
6
7
|
|
|
7
8
|
export {
|
|
@@ -9,5 +10,6 @@ export {
|
|
|
9
10
|
data,
|
|
10
11
|
platform,
|
|
11
12
|
platformservice,
|
|
13
|
+
protocol,
|
|
12
14
|
requests
|
|
13
15
|
}
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import { createCanonicalJsonSha256Hex } from '../private/canonicaljson.js';
|
|
2
2
|
import { validatePlatformObjectStorageBucketName } from './objectstorage.js';
|
|
3
|
+
import { hasExactKeys } from '../private/dataproperties.js';
|
|
3
4
|
|
|
4
5
|
export const objectStorageRetentionLimits = Object.freeze({
|
|
5
6
|
maximumPolicyIdLength: 96,
|
|
6
7
|
maximumRetentionDurationSeconds: 100 * 366 * 24 * 60 * 60,
|
|
7
8
|
});
|
|
8
9
|
|
|
9
|
-
export interface
|
|
10
|
+
export interface IObjectStorageRetentionIntent {
|
|
10
11
|
mode: 'compliance';
|
|
11
12
|
policyId: string;
|
|
12
13
|
retentionDurationSeconds: number;
|
|
13
14
|
}
|
|
14
15
|
|
|
15
|
-
export interface
|
|
16
|
-
version: 1;
|
|
16
|
+
export interface IObjectStorageRetentionCapabilityEvidence {
|
|
17
17
|
supported: true;
|
|
18
18
|
backend: 'standalone' | 'clustered';
|
|
19
19
|
modes: ['compliance'];
|
|
@@ -21,16 +21,15 @@ export interface IObjectStorageRetentionCapabilityEvidenceV1 {
|
|
|
21
21
|
retainedMultipartSupported: false;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
export interface
|
|
24
|
+
export interface IObjectStorageRetentionAuthority {
|
|
25
25
|
serviceId: string;
|
|
26
26
|
bindingId: string;
|
|
27
27
|
reconciliationGeneration: number;
|
|
28
28
|
bindingRequestDigest: string;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
export interface
|
|
32
|
-
extends
|
|
33
|
-
version: 1;
|
|
31
|
+
export interface IObjectStorageRetentionSentinelEvidence
|
|
32
|
+
extends IObjectStorageRetentionIntent {
|
|
34
33
|
createdAt: number;
|
|
35
34
|
retainUntil: number;
|
|
36
35
|
payloadSha256: string;
|
|
@@ -38,33 +37,32 @@ extends IObjectStorageRetentionIntentV1 {
|
|
|
38
37
|
etag: string;
|
|
39
38
|
}
|
|
40
39
|
|
|
41
|
-
export interface
|
|
42
|
-
extends
|
|
40
|
+
export interface IObjectStorageRetentionReceipt
|
|
41
|
+
extends IObjectStorageRetentionIntent {
|
|
43
42
|
bucketName: string;
|
|
44
43
|
configuredAt: number;
|
|
45
44
|
sentinelKey: string;
|
|
46
|
-
sentinel:
|
|
45
|
+
sentinel: IObjectStorageRetentionSentinelEvidence;
|
|
47
46
|
}
|
|
48
47
|
|
|
49
|
-
export interface
|
|
50
|
-
intent:
|
|
48
|
+
export interface IObjectStorageRetentionEvidence {
|
|
49
|
+
intent: IObjectStorageRetentionIntent;
|
|
51
50
|
intentSha256: string;
|
|
52
|
-
authority:
|
|
53
|
-
capability:
|
|
54
|
-
receipt:
|
|
51
|
+
authority: IObjectStorageRetentionAuthority;
|
|
52
|
+
capability: IObjectStorageRetentionCapabilityEvidence;
|
|
53
|
+
receipt: IObjectStorageRetentionReceipt;
|
|
55
54
|
verifiedAt: number;
|
|
56
55
|
}
|
|
57
56
|
|
|
58
57
|
/** Value-free desired intent with optional exact provider evidence. */
|
|
59
|
-
export interface
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
evidence?: IObjectStorageRetentionEvidenceV1;
|
|
58
|
+
export interface IObjectStorageRetentionBinding {
|
|
59
|
+
intent: IObjectStorageRetentionIntent;
|
|
60
|
+
evidence?: IObjectStorageRetentionEvidence;
|
|
63
61
|
}
|
|
64
62
|
|
|
65
|
-
export interface
|
|
66
|
-
extends
|
|
67
|
-
intent:
|
|
63
|
+
export interface IObjectStorageRetentionEvidenceExpectation
|
|
64
|
+
extends IObjectStorageRetentionAuthority {
|
|
65
|
+
intent: IObjectStorageRetentionIntent;
|
|
68
66
|
bucketName: string;
|
|
69
67
|
}
|
|
70
68
|
|
|
@@ -72,6 +70,11 @@ const policyIdPattern = /^[A-Za-z0-9._-]{1,96}$/;
|
|
|
72
70
|
const identifierPattern = /^[A-Za-z0-9][A-Za-z0-9:._-]{0,199}$/;
|
|
73
71
|
const sha256Pattern = /^[a-f0-9]{64}$/;
|
|
74
72
|
const etagPattern = /^[a-f0-9]{32}$/;
|
|
73
|
+
/**
|
|
74
|
+
* ObjectStorage's own on-disk sentinel key, pinned verbatim: `@lossless.org/objectstorage` writes
|
|
75
|
+
* `.smartstorage-retention/v1/sentinel-<sha256>.json`, so the `v1` segment belongs to that
|
|
76
|
+
* package's object layout and is not a serve.zone name (naming rule N10 — foreign bytes stay).
|
|
77
|
+
*/
|
|
75
78
|
const sentinelKeyPattern = /^\.smartstorage-retention\/v1\/sentinel-[a-f0-9]{64}\.json$/;
|
|
76
79
|
|
|
77
80
|
const isRecord = (valueArg: unknown): valueArg is Record<string, unknown> => (
|
|
@@ -82,16 +85,6 @@ const isRecord = (valueArg: unknown): valueArg is Record<string, unknown> => (
|
|
|
82
85
|
|| Object.getPrototypeOf(valueArg) === null)
|
|
83
86
|
);
|
|
84
87
|
|
|
85
|
-
const hasExactKeys = (
|
|
86
|
-
valueArg: Record<string, unknown>,
|
|
87
|
-
keysArg: readonly string[],
|
|
88
|
-
): boolean => {
|
|
89
|
-
const actualKeys = Object.keys(valueArg).sort();
|
|
90
|
-
const expectedKeys = [...keysArg].sort();
|
|
91
|
-
return actualKeys.length === expectedKeys.length
|
|
92
|
-
&& actualKeys.every((keyArg, indexArg) => keyArg === expectedKeys[indexArg]);
|
|
93
|
-
};
|
|
94
|
-
|
|
95
88
|
const isPositiveSafeInteger = (valueArg: unknown): valueArg is number => (
|
|
96
89
|
Number.isSafeInteger(valueArg) && (valueArg as number) > 0
|
|
97
90
|
);
|
|
@@ -135,7 +128,7 @@ export const createObjectStorageRetentionRetainUntil = (
|
|
|
135
128
|
};
|
|
136
129
|
|
|
137
130
|
export const createObjectStorageRetentionIntentDigestInput = (
|
|
138
|
-
intentArg:
|
|
131
|
+
intentArg: IObjectStorageRetentionIntent,
|
|
139
132
|
): string => {
|
|
140
133
|
const errors = validateObjectStorageRetentionIntent(intentArg);
|
|
141
134
|
if (errors.length > 0) throw new Error(errors[0]);
|
|
@@ -146,12 +139,11 @@ export const createObjectStorageRetentionIntentDigestInput = (
|
|
|
146
139
|
policyId: intentArg.policyId,
|
|
147
140
|
retentionDurationSeconds: intentArg.retentionDurationSeconds,
|
|
148
141
|
},
|
|
149
|
-
version: 1,
|
|
150
142
|
});
|
|
151
143
|
};
|
|
152
144
|
|
|
153
145
|
export const computeObjectStorageRetentionIntentSha256 = async (
|
|
154
|
-
intentArg:
|
|
146
|
+
intentArg: IObjectStorageRetentionIntent,
|
|
155
147
|
): Promise<string> => createCanonicalJsonSha256Hex(
|
|
156
148
|
createObjectStorageRetentionIntentDigestInput(intentArg),
|
|
157
149
|
(reasonArg) => { throw new Error(reasonArg); },
|
|
@@ -162,12 +154,12 @@ export const objectStorageRetentionIntentsEqual = (
|
|
|
162
154
|
rightArg: unknown,
|
|
163
155
|
): boolean => validateObjectStorageRetentionIntent(leftArg).length === 0
|
|
164
156
|
&& validateObjectStorageRetentionIntent(rightArg).length === 0
|
|
165
|
-
&& (leftArg as
|
|
166
|
-
=== (rightArg as
|
|
167
|
-
&& (leftArg as
|
|
168
|
-
=== (rightArg as
|
|
169
|
-
&& (leftArg as
|
|
170
|
-
=== (rightArg as
|
|
157
|
+
&& (leftArg as IObjectStorageRetentionIntent).mode
|
|
158
|
+
=== (rightArg as IObjectStorageRetentionIntent).mode
|
|
159
|
+
&& (leftArg as IObjectStorageRetentionIntent).policyId
|
|
160
|
+
=== (rightArg as IObjectStorageRetentionIntent).policyId
|
|
161
|
+
&& (leftArg as IObjectStorageRetentionIntent).retentionDurationSeconds
|
|
162
|
+
=== (rightArg as IObjectStorageRetentionIntent).retentionDurationSeconds;
|
|
171
163
|
|
|
172
164
|
const retentionIntentFieldsEqual = (
|
|
173
165
|
leftArg: unknown,
|
|
@@ -183,7 +175,7 @@ const retentionIntentFieldsEqual = (
|
|
|
183
175
|
|
|
184
176
|
export const validateObjectStorageRetentionEvidence = async (
|
|
185
177
|
evidenceArg: unknown,
|
|
186
|
-
expectedArg:
|
|
178
|
+
expectedArg: IObjectStorageRetentionEvidenceExpectation,
|
|
187
179
|
): Promise<string[]> => {
|
|
188
180
|
if (!isRecord(evidenceArg)
|
|
189
181
|
|| !hasExactKeys(evidenceArg, [
|
|
@@ -197,7 +189,7 @@ export const validateObjectStorageRetentionEvidence = async (
|
|
|
197
189
|
return ['objectstorage retention evidence must use its exact schema'];
|
|
198
190
|
}
|
|
199
191
|
const errors = validateObjectStorageRetentionIntent(evidenceArg.intent);
|
|
200
|
-
const intent = evidenceArg.intent as
|
|
192
|
+
const intent = evidenceArg.intent as IObjectStorageRetentionIntent;
|
|
201
193
|
if (!retentionIntentFieldsEqual(intent, expectedArg.intent)) {
|
|
202
194
|
errors.push('objectstorage retention evidence intent must equal the expected intent');
|
|
203
195
|
}
|
|
@@ -233,14 +225,12 @@ export const validateObjectStorageRetentionEvidence = async (
|
|
|
233
225
|
const capability = evidenceArg.capability;
|
|
234
226
|
if (!isRecord(capability)
|
|
235
227
|
|| !hasExactKeys(capability, [
|
|
236
|
-
'version',
|
|
237
228
|
'supported',
|
|
238
229
|
'backend',
|
|
239
230
|
'modes',
|
|
240
231
|
'atomicCreateOnly',
|
|
241
232
|
'retainedMultipartSupported',
|
|
242
233
|
])
|
|
243
|
-
|| capability.version !== 1
|
|
244
234
|
|| capability.supported !== true
|
|
245
235
|
|| (capability.backend !== 'standalone' && capability.backend !== 'clustered')
|
|
246
236
|
|| !Array.isArray(capability.modes)
|
|
@@ -283,7 +273,6 @@ export const validateObjectStorageRetentionEvidence = async (
|
|
|
283
273
|
const sentinel = receipt.sentinel;
|
|
284
274
|
if (!isRecord(sentinel)
|
|
285
275
|
|| !hasExactKeys(sentinel, [
|
|
286
|
-
'version',
|
|
287
276
|
'mode',
|
|
288
277
|
'policyId',
|
|
289
278
|
'retentionDurationSeconds',
|
|
@@ -296,7 +285,7 @@ export const validateObjectStorageRetentionEvidence = async (
|
|
|
296
285
|
errors.push('objectstorage retention sentinel evidence must use its exact schema');
|
|
297
286
|
return errors;
|
|
298
287
|
}
|
|
299
|
-
if (
|
|
288
|
+
if (!retentionIntentFieldsEqual(sentinel, intent)) {
|
|
300
289
|
errors.push('objectstorage retention sentinel intent must equal its evidence intent');
|
|
301
290
|
}
|
|
302
291
|
if (!isPositiveSafeInteger(sentinel.createdAt)
|
|
@@ -331,17 +320,14 @@ export const validateObjectStorageRetentionEvidence = async (
|
|
|
331
320
|
|
|
332
321
|
export const validateObjectStorageRetentionBinding = async (
|
|
333
322
|
bindingArg: unknown,
|
|
334
|
-
expectedArg:
|
|
323
|
+
expectedArg: IObjectStorageRetentionEvidenceExpectation,
|
|
335
324
|
): Promise<string[]> => {
|
|
336
325
|
if (!isRecord(bindingArg)
|
|
337
|
-
|| !Object.hasOwn(bindingArg, 'schemaVersion')
|
|
338
326
|
|| !Object.hasOwn(bindingArg, 'intent')
|
|
339
|
-
|| Object.keys(bindingArg).some((keyArg) => !['
|
|
327
|
+
|| Object.keys(bindingArg).some((keyArg) => !['intent', 'evidence'].includes(keyArg))) {
|
|
340
328
|
return ['objectstorage retention binding must use its exact schema'];
|
|
341
329
|
}
|
|
342
|
-
const errors = bindingArg.
|
|
343
|
-
? validateObjectStorageRetentionIntent(bindingArg.intent)
|
|
344
|
-
: ['objectstorage retention binding schemaVersion must be 1'];
|
|
330
|
+
const errors = validateObjectStorageRetentionIntent(bindingArg.intent);
|
|
345
331
|
if (!retentionIntentFieldsEqual(bindingArg.intent, expectedArg.intent)) {
|
|
346
332
|
errors.push('objectstorage retention binding intent must equal the trusted expected intent');
|
|
347
333
|
}
|
|
@@ -356,7 +342,7 @@ export const validateObjectStorageRetentionBinding = async (
|
|
|
356
342
|
|
|
357
343
|
export const validatePlatformBindingObjectStorageRetention = async (
|
|
358
344
|
bindingArg: unknown,
|
|
359
|
-
expectedArg:
|
|
345
|
+
expectedArg: IObjectStorageRetentionEvidenceExpectation,
|
|
360
346
|
): Promise<string[]> => {
|
|
361
347
|
if (!isRecord(bindingArg)) {
|
|
362
348
|
return ['platform objectstorage retention binding must be an object'];
|
package/ts/platform/storage.ts
CHANGED
|
@@ -102,7 +102,6 @@ export type TStorageClassCapabilities =
|
|
|
102
102
|
* addresses, mount options, principals, and credential values are private.
|
|
103
103
|
*/
|
|
104
104
|
export interface IStorageCapabilityAdvertisement {
|
|
105
|
-
schemaVersion: 2;
|
|
106
105
|
featureIds: string[];
|
|
107
106
|
classes: TStorageClassCapabilities[];
|
|
108
107
|
}
|
|
@@ -131,7 +130,7 @@ export interface IObjectStorageFileDelivery {
|
|
|
131
130
|
* JSON object with endpoint, bucket, region, accessKeyId,
|
|
132
131
|
* secretAccessKey, and optional sessionToken fields.
|
|
133
132
|
*/
|
|
134
|
-
format: 'servezone-object-storage
|
|
133
|
+
format: 'servezone-object-storage';
|
|
135
134
|
uid: number;
|
|
136
135
|
gid: number;
|
|
137
136
|
mode: 0o400 | 0o440;
|
|
@@ -181,7 +180,6 @@ export interface IResolvedStorageCapacity {
|
|
|
181
180
|
}
|
|
182
181
|
|
|
183
182
|
export interface IResolvedStorageBindingBase {
|
|
184
|
-
schemaVersion: 2;
|
|
185
183
|
/** Stable binding/allocation identity. */
|
|
186
184
|
id: string;
|
|
187
185
|
serviceId: string;
|
|
@@ -37,7 +37,6 @@ const delivery = {
|
|
|
37
37
|
const credentialManagementScope = 'platform:object-storage-binding';
|
|
38
38
|
|
|
39
39
|
const sourceBinding: TActiveObjectStorageBinding = {
|
|
40
|
-
schemaVersion: 2,
|
|
41
40
|
id: 'binding-object',
|
|
42
41
|
serviceId: 'service-app',
|
|
43
42
|
requestId: 'object-data',
|
|
@@ -97,7 +96,6 @@ const target = {
|
|
|
97
96
|
|
|
98
97
|
const preparationSnapshotPayload:
|
|
99
98
|
TUnfencedObjectStorageBindingControlSnapshotDigestPayload = {
|
|
100
|
-
schemaVersion: 2,
|
|
101
99
|
binding: sourceBinding,
|
|
102
100
|
recordRevision: 12,
|
|
103
101
|
capturedAt: 1_700_000_000_010,
|
|
@@ -106,11 +104,10 @@ TUnfencedObjectStorageBindingControlSnapshotDigestPayload = {
|
|
|
106
104
|
const preparationSnapshot: IUnfencedObjectStorageBindingControlSnapshot = {
|
|
107
105
|
...preparationSnapshotPayload,
|
|
108
106
|
snapshotDigest:
|
|
109
|
-
'
|
|
107
|
+
'59e518dd446cde4ff8899d628f017e9410674e3d52ce6be5f7965c1ec04c80a3',
|
|
110
108
|
};
|
|
111
109
|
|
|
112
110
|
const prepareRequest: IObjectStorageMigrationPrepareRequest = {
|
|
113
|
-
schemaVersion: 2,
|
|
114
111
|
migrationId: 'migration-object-capacity',
|
|
115
112
|
sourceControlSnapshot: preparationSnapshot,
|
|
116
113
|
workloadGeneration: 8,
|
|
@@ -140,7 +137,6 @@ const candidateBinding: TStagedObjectStorageBinding = {
|
|
|
140
137
|
};
|
|
141
138
|
|
|
142
139
|
export const storageMigrationCanonicalDigestGoldenVectors = deepFreezeValue({
|
|
143
|
-
version: 2 as const,
|
|
144
140
|
targetRequest: {
|
|
145
141
|
input: target.request,
|
|
146
142
|
canonicalJson: '{"accessMode":"readWrite","capacity":{"limit":"1TiB","request":"500GiB"},"delivery":{"keys":{"accessKeyId":"APP_S3_ACCESS_KEY","bucket":"APP_S3_BUCKET","endpoint":"APP_S3_ENDPOINT","region":"APP_S3_REGION","secretAccessKey":"APP_S3_SECRET_KEY"},"type":"launcher-environment"},"id":"object-data","kind":"objectStorage","reclaimPolicy":"retain","storageClass":"backupCapacity"}',
|
|
@@ -148,17 +144,17 @@ export const storageMigrationCanonicalDigestGoldenVectors = deepFreezeValue({
|
|
|
148
144
|
},
|
|
149
145
|
preparationSnapshot: {
|
|
150
146
|
input: preparationSnapshotPayload,
|
|
151
|
-
canonicalJson: '{"binding":{"accessMode":"readWrite","capabilities":{"backup":true,"durability":"persistent","encryptedInTransit":true,"hardQuota":true,"performanceTier":"capacity","snapshots":"none","topology":"singleNode"},"connection":{"bucket":"source-bucket","endpoint":"https://source.example.test","region":"local"},"createdAt":1700000000000,"credentialManagementScope":"platform:object-storage-binding","delivery":{"keys":{"accessKeyId":"APP_S3_ACCESS_KEY","bucket":"APP_S3_BUCKET","endpoint":"APP_S3_ENDPOINT","region":"APP_S3_REGION","secretAccessKey":"APP_S3_SECRET_KEY"},"type":"launcher-environment"},"generation":3,"id":"binding-object","kind":"objectStorage","observedGeneration":3,"policy":{"classId":"source-object","revision":"1"},"requestDigest":"1111111111111111111111111111111111111111111111111111111111111111","requestId":"object-data","resourceRef":"source-resource","
|
|
152
|
-
sha256: '
|
|
147
|
+
canonicalJson: '{"binding":{"accessMode":"readWrite","capabilities":{"backup":true,"durability":"persistent","encryptedInTransit":true,"hardQuota":true,"performanceTier":"capacity","snapshots":"none","topology":"singleNode"},"connection":{"bucket":"source-bucket","endpoint":"https://source.example.test","region":"local"},"createdAt":1700000000000,"credentialManagementScope":"platform:object-storage-binding","delivery":{"keys":{"accessKeyId":"APP_S3_ACCESS_KEY","bucket":"APP_S3_BUCKET","endpoint":"APP_S3_ENDPOINT","region":"APP_S3_REGION","secretAccessKey":"APP_S3_SECRET_KEY"},"type":"launcher-environment"},"generation":3,"id":"binding-object","kind":"objectStorage","observedGeneration":3,"policy":{"classId":"source-object","revision":"1"},"requestDigest":"1111111111111111111111111111111111111111111111111111111111111111","requestId":"object-data","resourceRef":"source-resource","serviceId":"service-app","status":"ready","updatedAt":1700000000001,"versioning":false},"capturedAt":1700000000010,"recordRevision":12}',
|
|
148
|
+
sha256: '59e518dd446cde4ff8899d628f017e9410674e3d52ce6be5f7965c1ec04c80a3',
|
|
153
149
|
},
|
|
154
150
|
prepareRequest: {
|
|
155
151
|
input: prepareRequest,
|
|
156
|
-
canonicalJson: '{"migrationId":"migration-object-capacity","
|
|
157
|
-
sha256: '
|
|
152
|
+
canonicalJson: '{"migrationId":"migration-object-capacity","sourceControlSnapshot":{"binding":{"accessMode":"readWrite","capabilities":{"backup":true,"durability":"persistent","encryptedInTransit":true,"hardQuota":true,"performanceTier":"capacity","snapshots":"none","topology":"singleNode"},"connection":{"bucket":"source-bucket","endpoint":"https://source.example.test","region":"local"},"createdAt":1700000000000,"credentialManagementScope":"platform:object-storage-binding","delivery":{"keys":{"accessKeyId":"APP_S3_ACCESS_KEY","bucket":"APP_S3_BUCKET","endpoint":"APP_S3_ENDPOINT","region":"APP_S3_REGION","secretAccessKey":"APP_S3_SECRET_KEY"},"type":"launcher-environment"},"generation":3,"id":"binding-object","kind":"objectStorage","observedGeneration":3,"policy":{"classId":"source-object","revision":"1"},"requestDigest":"1111111111111111111111111111111111111111111111111111111111111111","requestId":"object-data","resourceRef":"source-resource","serviceId":"service-app","status":"ready","updatedAt":1700000000001,"versioning":false},"capturedAt":1700000000010,"recordRevision":12,"snapshotDigest":"59e518dd446cde4ff8899d628f017e9410674e3d52ce6be5f7965c1ec04c80a3"},"target":{"credentialManagementScope":"platform:object-storage-binding","policy":{"classId":"capacity-object","revision":"4"},"request":{"accessMode":"readWrite","capacity":{"limit":"1TiB","request":"500GiB"},"delivery":{"keys":{"accessKeyId":"APP_S3_ACCESS_KEY","bucket":"APP_S3_BUCKET","endpoint":"APP_S3_ENDPOINT","region":"APP_S3_REGION","secretAccessKey":"APP_S3_SECRET_KEY"},"type":"launcher-environment"},"id":"object-data","kind":"objectStorage","reclaimPolicy":"retain","storageClass":"backupCapacity"},"storageClass":{"kind":"objectStorage","purpose":"backup","required":{"backup":true,"durability":"persistent","performanceTier":"capacity"}}},"workloadGeneration":8}',
|
|
153
|
+
sha256: '549cc9ec83ec3ce1b17c9379448a869d43eba911d540973e207672e4f2d82644',
|
|
158
154
|
},
|
|
159
155
|
candidateBinding: {
|
|
160
156
|
input: candidateBinding,
|
|
161
|
-
canonicalJson: '{"accessMode":"readWrite","capabilities":{"backup":true,"durability":"persistent","encryptedInTransit":true,"hardQuota":true,"performanceTier":"capacity","snapshots":"none","topology":"singleNode"},"capacity":{"granted":"500GiB","limit":"1TiB","requested":"500GiB"},"connection":{"bucket":"destination-bucket","endpoint":"https://destination.example.test","region":"local"},"createdAt":1700000000000,"credentialManagementScope":"platform:object-storage-binding","delivery":{"keys":{"accessKeyId":"APP_S3_ACCESS_KEY","bucket":"APP_S3_BUCKET","endpoint":"APP_S3_ENDPOINT","region":"APP_S3_REGION","secretAccessKey":"APP_S3_SECRET_KEY"},"type":"launcher-environment"},"generation":4,"id":"binding-object","kind":"objectStorage","observedGeneration":3,"policy":{"classId":"capacity-object","revision":"4"},"requestDigest":"3f864862041002e25b790b3bc7afbe37c399a006f385e1def9f679a93d4fa173","requestId":"object-data","resourceRef":"destination-resource","
|
|
162
|
-
sha256: '
|
|
157
|
+
canonicalJson: '{"accessMode":"readWrite","capabilities":{"backup":true,"durability":"persistent","encryptedInTransit":true,"hardQuota":true,"performanceTier":"capacity","snapshots":"none","topology":"singleNode"},"capacity":{"granted":"500GiB","limit":"1TiB","requested":"500GiB"},"connection":{"bucket":"destination-bucket","endpoint":"https://destination.example.test","region":"local"},"createdAt":1700000000000,"credentialManagementScope":"platform:object-storage-binding","delivery":{"keys":{"accessKeyId":"APP_S3_ACCESS_KEY","bucket":"APP_S3_BUCKET","endpoint":"APP_S3_ENDPOINT","region":"APP_S3_REGION","secretAccessKey":"APP_S3_SECRET_KEY"},"type":"launcher-environment"},"generation":4,"id":"binding-object","kind":"objectStorage","observedGeneration":3,"policy":{"classId":"capacity-object","revision":"4"},"requestDigest":"3f864862041002e25b790b3bc7afbe37c399a006f385e1def9f679a93d4fa173","requestId":"object-data","resourceRef":"destination-resource","serviceId":"service-app","status":"provisioning","updatedAt":1700000000020,"versioning":false}',
|
|
158
|
+
sha256: '30ccf8221dea7cf7d26b062edf64b6cba29ef809cc1a213fd6428ee95ff92179',
|
|
163
159
|
},
|
|
164
160
|
});
|