@serve.zone/interfaces 31.8.0 → 32.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.smartconfig.json +1 -0
- package/changelog.md +512 -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/clusterruntime.d.ts +39 -0
- package/dist_ts/data/clusterruntime.js +11 -0
- 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 +5 -1
- package/dist_ts/data/index.js +5 -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 +78 -0
- package/dist_ts/data/networkaddressplan.js +114 -0
- package/dist_ts/data/networkauthority.d.ts +20 -22
- package/dist_ts/data/networkauthority.js +29 -43
- 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 +37 -0
- package/dist_ts/data/networknode.js +6 -0
- 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 +37 -100
- 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 +128 -0
- package/dist_ts/data/serviceruntime.js +92 -0
- 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 +6 -18
- 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 +14 -10
- package/dist_ts/private/networkcontract.js +15 -1
- package/dist_ts/private/producercontract.d.ts +11 -0
- package/dist_ts/private/producercontract.js +21 -0
- package/dist_ts/private/releaseversion.d.ts +37 -0
- package/dist_ts/private/releaseversion.js +48 -0
- package/dist_ts/private/runtimepolicy.d.ts +31 -0
- package/dist_ts/private/runtimepolicy.js +90 -0
- 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 +47 -10
- package/dist_ts/requests/cluster.js +1 -1
- 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 +87 -31
- 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/requests/service.d.ts +60 -0
- 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 +540 -269
- 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/clusterruntime.ts +45 -0
- 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 +5 -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 +175 -0
- package/ts/data/networkauthority.ts +45 -61
- 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 +37 -0
- 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 +62 -122
- 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 +208 -0
- 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 +36 -55
- 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 +23 -9
- package/ts/private/producercontract.ts +19 -0
- package/ts/private/releaseversion.ts +70 -0
- package/ts/private/runtimepolicy.ts +105 -0
- 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 +58 -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 +90 -41
- 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/requests/service.ts +81 -0
- 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
package/ts/data/runtimeconfig.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
IImmutableContainerInvocation,
|
|
3
|
+
IImmutableContainerInvocationPlatformEvidence,
|
|
4
4
|
TSha256Digest,
|
|
5
5
|
} from './immutableimage.js';
|
|
6
6
|
import {
|
|
@@ -9,12 +9,16 @@ import {
|
|
|
9
9
|
validateImmutableContainerInvocation,
|
|
10
10
|
verifyImmutableContainerInvocationDigest,
|
|
11
11
|
} from './immutableimage.js';
|
|
12
|
-
import type {
|
|
13
|
-
import {
|
|
12
|
+
import type { IRuntimeAssignment, IRuntimeAuthorityReference } from './runtimeassignment.js';
|
|
13
|
+
import { snapshotRuntimeAssignment, validateRuntimeAssignment } from './runtimeassignment.js';
|
|
14
14
|
import { canonicalizeStrictJson, createCanonicalJsonSha256Hex } from '../private/canonicaljson.js';
|
|
15
|
+
import {
|
|
16
|
+
assertRuntimeReadiness, isBoundedInteger, isExactRecord, isRuntimeCpuMillis, isRuntimeIdentityNumber,
|
|
17
|
+
isRuntimeLogPolicy, isRuntimeMemoryBytes, isRuntimePortName, runtimePolicyLimits,
|
|
18
|
+
} from '../private/runtimepolicy.js';
|
|
15
19
|
|
|
16
20
|
/** A container target only; declaration does not publish a host or gateway port. */
|
|
17
|
-
export interface
|
|
21
|
+
export interface IRuntimeConfigTargetPort {
|
|
18
22
|
name: string;
|
|
19
23
|
port: number;
|
|
20
24
|
/** Inclusive; equal to port for a single port. */
|
|
@@ -22,7 +26,7 @@ export interface IRuntimeConfigTargetPortV1 {
|
|
|
22
26
|
protocol: 'tcp' | 'udp';
|
|
23
27
|
}
|
|
24
28
|
|
|
25
|
-
export interface
|
|
29
|
+
export interface IRuntimeConfigReadinessTiming {
|
|
26
30
|
/** Measured from the evidenced container start; no probes before this delay. */
|
|
27
31
|
initialDelayMs: number;
|
|
28
32
|
/** Failures during this startup grace cannot mark the workload unhealthy. */
|
|
@@ -37,7 +41,7 @@ export interface IRuntimeConfigReadinessTimingV1 {
|
|
|
37
41
|
failureThreshold: number;
|
|
38
42
|
}
|
|
39
43
|
|
|
40
|
-
export type
|
|
44
|
+
export type TRuntimeConfigReadiness = IRuntimeConfigReadinessTiming & (
|
|
41
45
|
| { kind: 'process' }
|
|
42
46
|
| { kind: 'tcp'; targetPort: string; port: number }
|
|
43
47
|
| {
|
|
@@ -60,7 +64,7 @@ export type TRuntimeConfigReadinessV1 = IRuntimeConfigReadinessTimingV1 & (
|
|
|
60
64
|
}
|
|
61
65
|
);
|
|
62
66
|
|
|
63
|
-
export interface
|
|
67
|
+
export interface IRuntimeConfigLogPolicy {
|
|
64
68
|
/** Maximum UTF-8 bytes in one captured stdout/stderr line. */
|
|
65
69
|
maximumLineBytes: number;
|
|
66
70
|
/** Maximum bytes waiting for delivery; overflow requires explicit evidence. */
|
|
@@ -76,8 +80,7 @@ export interface IRuntimeConfigLogPolicyV1 {
|
|
|
76
80
|
* Secrets, network identity and storage claims remain separately assignment-bound
|
|
77
81
|
* owner references. This document contains no registry credentials or host paths.
|
|
78
82
|
*/
|
|
79
|
-
export interface
|
|
80
|
-
schemaVersion: 1;
|
|
83
|
+
export interface IRuntimeConfig extends IRuntimeAuthorityReference {
|
|
81
84
|
organizationId: string;
|
|
82
85
|
serviceId: string;
|
|
83
86
|
image: {
|
|
@@ -85,7 +88,7 @@ export interface IRuntimeConfigV1 extends IRuntimeAuthorityReferenceV1 {
|
|
|
85
88
|
repository: string;
|
|
86
89
|
/** Root descriptor digest, which may be an OCI platform index. */
|
|
87
90
|
imageDigest: TSha256Digest;
|
|
88
|
-
invocation:
|
|
91
|
+
invocation: IImmutableContainerInvocation;
|
|
89
92
|
};
|
|
90
93
|
/** Complete effective public environment; secret values must never be inlined. */
|
|
91
94
|
environment: Record<string, string>;
|
|
@@ -106,50 +109,38 @@ export interface IRuntimeConfigV1 extends IRuntimeAuthorityReferenceV1 {
|
|
|
106
109
|
/** Numeric override paired with runAsUser, or null for the image identity policy. */
|
|
107
110
|
runAsGroup: number | null;
|
|
108
111
|
/** Sorted unique names, with no overlapping ranges for the same transport. */
|
|
109
|
-
targetPorts:
|
|
110
|
-
readiness:
|
|
112
|
+
targetPorts: IRuntimeConfigTargetPort[];
|
|
113
|
+
readiness: TRuntimeConfigReadiness;
|
|
111
114
|
/**
|
|
112
115
|
* SmartData owns log metadata and SmartBucket owns archived payloads. This
|
|
113
116
|
* policy does not authorize persistent local files. Any CRI log capture uses
|
|
114
117
|
* disposable process-local transport artifacts and must evidence bounded
|
|
115
118
|
* buffering, backpressure and lost data; it must not silently truncate logs.
|
|
116
119
|
*/
|
|
117
|
-
logs:
|
|
120
|
+
logs: IRuntimeConfigLogPolicy;
|
|
118
121
|
}
|
|
119
122
|
|
|
120
|
-
export interface
|
|
121
|
-
config:
|
|
122
|
-
assignment:
|
|
123
|
-
platformEvidence:
|
|
123
|
+
export interface IRuntimeConfigAssignmentBinding {
|
|
124
|
+
config: IRuntimeConfig;
|
|
125
|
+
assignment: IRuntimeAssignment;
|
|
126
|
+
platformEvidence: IImmutableContainerInvocationPlatformEvidence;
|
|
124
127
|
}
|
|
125
128
|
|
|
126
|
-
export const
|
|
127
|
-
digestDomain: 'serve.zone/runtime-config
|
|
129
|
+
export const runtimeConfigContract = Object.freeze({
|
|
130
|
+
digestDomain: 'serve.zone/runtime-config',
|
|
128
131
|
maximumCanonicalBytes: 262_144,
|
|
129
132
|
maximumEnvironmentEntries: 128,
|
|
130
133
|
maximumTargetPorts: 64,
|
|
131
|
-
maximumReadinessDurationMs:
|
|
132
|
-
maximumLogRetentionMs:
|
|
134
|
+
maximumReadinessDurationMs: runtimePolicyLimits.maximumReadinessDurationMs,
|
|
135
|
+
maximumLogRetentionMs: runtimePolicyLimits.maximumLogRetentionMs,
|
|
133
136
|
} as const);
|
|
134
137
|
|
|
135
138
|
const fail: (messageArg: string) => never = (messageArg) => { throw new Error(messageArg); };
|
|
136
139
|
const encoder = new TextEncoder();
|
|
137
|
-
const isInteger = (valueArg: unknown, minimumArg: number, maximumArg: number): valueArg is number =>
|
|
138
|
-
typeof valueArg === 'number' && Number.isSafeInteger(valueArg) && !Object.is(valueArg, -0)
|
|
139
|
-
&& valueArg >= minimumArg && valueArg <= maximumArg;
|
|
140
140
|
const isIdentifier = (valueArg: unknown): valueArg is string =>
|
|
141
141
|
typeof valueArg === 'string' && /^[A-Za-z0-9][A-Za-z0-9:._-]{0,199}$/.test(valueArg);
|
|
142
142
|
const isDigest = (valueArg: unknown): valueArg is TSha256Digest =>
|
|
143
143
|
typeof valueArg === 'string' && isSha256Digest(valueArg);
|
|
144
|
-
const isPortName = (valueArg: unknown): valueArg is string =>
|
|
145
|
-
typeof valueArg === 'string' && /^[a-z0-9][a-z0-9_.-]{0,62}$/.test(valueArg);
|
|
146
|
-
const isExactRecord = (
|
|
147
|
-
valueArg: unknown, keysArg: readonly string[],
|
|
148
|
-
): valueArg is Record<string, unknown> => {
|
|
149
|
-
if (!valueArg || typeof valueArg !== 'object' || Array.isArray(valueArg)) return false;
|
|
150
|
-
const keys = Object.keys(valueArg);
|
|
151
|
-
return keys.length === keysArg.length && keys.every((keyArg) => keysArg.includes(keyArg));
|
|
152
|
-
};
|
|
153
144
|
|
|
154
145
|
/**
|
|
155
146
|
* Bound traversal before canonicalization and copy descriptor values so input
|
|
@@ -161,9 +152,9 @@ const snapshotBoundedJson = (valueArg: unknown): unknown => {
|
|
|
161
152
|
let stringBytes = 0;
|
|
162
153
|
const ancestors = new Set<object>();
|
|
163
154
|
const accountString = (value: string): void => {
|
|
164
|
-
if (value.length >
|
|
155
|
+
if (value.length > runtimeConfigContract.maximumCanonicalBytes) fail('runtime config string is oversized');
|
|
165
156
|
stringBytes += encoder.encode(value).byteLength;
|
|
166
|
-
if (stringBytes >
|
|
157
|
+
if (stringBytes > runtimeConfigContract.maximumCanonicalBytes) fail('runtime config is oversized');
|
|
167
158
|
};
|
|
168
159
|
const copy = (value: unknown, depth: number): unknown => {
|
|
169
160
|
if (++nodes > 8192 || depth > 12) fail('runtime config exceeds structural bounds');
|
|
@@ -183,7 +174,7 @@ const snapshotBoundedJson = (valueArg: unknown): unknown => {
|
|
|
183
174
|
if (array) {
|
|
184
175
|
const lengthDescriptor = Object.getOwnPropertyDescriptor(value, 'length');
|
|
185
176
|
const length = lengthDescriptor?.value;
|
|
186
|
-
if (!
|
|
177
|
+
if (!isBoundedInteger(length, 0, 256) || keys.length !== length + 1) {
|
|
187
178
|
fail('runtime config requires bounded dense arrays');
|
|
188
179
|
}
|
|
189
180
|
const result: unknown[] = [];
|
|
@@ -210,68 +201,20 @@ const snapshotBoundedJson = (valueArg: unknown): unknown => {
|
|
|
210
201
|
} finally { ancestors.delete(value); }
|
|
211
202
|
};
|
|
212
203
|
const canonical = canonicalizeStrictJson(copy(valueArg, 0), fail);
|
|
213
|
-
if (encoder.encode(canonical).byteLength >
|
|
204
|
+
if (encoder.encode(canonical).byteLength > runtimeConfigContract.maximumCanonicalBytes) {
|
|
214
205
|
fail('runtime config canonical JSON is oversized');
|
|
215
206
|
}
|
|
216
207
|
return JSON.parse(canonical);
|
|
217
208
|
};
|
|
218
209
|
|
|
219
|
-
const
|
|
220
|
-
'
|
|
221
|
-
const assertReadiness = (valueArg: unknown, portsArg: IRuntimeConfigTargetPortV1[]): void => {
|
|
222
|
-
if (!valueArg || typeof valueArg !== 'object') fail('runtime config readiness is required');
|
|
223
|
-
const value = valueArg as Record<string, unknown>;
|
|
224
|
-
const keys = value.kind === 'process' ? ['kind', ...timingKeys]
|
|
225
|
-
: value.kind === 'tcp' ? ['kind', ...timingKeys, 'targetPort', 'port']
|
|
226
|
-
: value.kind === 'http' ? ['kind', ...timingKeys, 'targetPort', 'port',
|
|
227
|
-
'scheme', 'host', 'path', 'expectedStatusCodes', 'followRedirects'] : [];
|
|
228
|
-
if (keys.length === 0 || !isExactRecord(value, keys)
|
|
229
|
-
|| !isInteger(value.initialDelayMs, 0, runtimeConfigV1Contract.maximumReadinessDurationMs)
|
|
230
|
-
|| !isInteger(value.startupGraceMs, 0, runtimeConfigV1Contract.maximumReadinessDurationMs)
|
|
231
|
-
|| !isInteger(value.intervalMs, 100, runtimeConfigV1Contract.maximumReadinessDurationMs)
|
|
232
|
-
|| !isInteger(value.timeoutMs, 1, 60_000)
|
|
233
|
-
|| !isInteger(value.successThreshold, 1, 100)
|
|
234
|
-
|| !isInteger(value.failureThreshold, 1, 100)
|
|
235
|
-
|| value.timeoutMs > value.intervalMs || value.initialDelayMs > value.startupGraceMs) {
|
|
236
|
-
fail('runtime config readiness must use explicit bounded timing and exact schema');
|
|
237
|
-
}
|
|
238
|
-
if (value.kind === 'process') return;
|
|
239
|
-
const target = portsArg.find((portArg) => portArg.name === value.targetPort);
|
|
240
|
-
if (!isPortName(value.targetPort) || !target || target.protocol !== 'tcp'
|
|
241
|
-
|| !isInteger(value.port, target.port, target.portEnd)) {
|
|
242
|
-
fail('runtime config readiness must select a declared TCP target and port');
|
|
243
|
-
}
|
|
244
|
-
if (value.kind === 'tcp') return;
|
|
245
|
-
if ((value.scheme !== 'http' && value.scheme !== 'https') || value.followRedirects !== false
|
|
246
|
-
|| typeof value.host !== 'string' || value.host.length > 253
|
|
247
|
-
|| !/^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*$/.test(value.host)
|
|
248
|
-
|| typeof value.path !== 'string' || value.path.length > 4096
|
|
249
|
-
|| !value.path.startsWith('/') || value.path.startsWith('//')
|
|
250
|
-
|| /[^\x21-\x7e]|[\\#]/.test(value.path)
|
|
251
|
-
|| /%(?![0-9A-F]{2})/.test(value.path)
|
|
252
|
-
|| !Array.isArray(value.expectedStatusCodes) || value.expectedStatusCodes.length === 0
|
|
253
|
-
|| value.expectedStatusCodes.length > 32) {
|
|
254
|
-
fail('runtime config HTTP readiness must use an exact bounded request policy');
|
|
255
|
-
}
|
|
256
|
-
const parsed = new URL(value.path, 'http://runtime.invalid');
|
|
257
|
-
if (`${parsed.pathname}${parsed.search}` !== value.path) fail('runtime config HTTP path must be canonical');
|
|
258
|
-
let previousCode = 0;
|
|
259
|
-
for (const code of value.expectedStatusCodes) {
|
|
260
|
-
if (!isInteger(code, 200, 599) || code <= previousCode) {
|
|
261
|
-
fail('runtime config HTTP status expectations must be sorted unique final codes');
|
|
262
|
-
}
|
|
263
|
-
previousCode = code;
|
|
264
|
-
}
|
|
265
|
-
};
|
|
266
|
-
|
|
267
|
-
const assertConfig = (valueArg: unknown): IRuntimeConfigV1 => {
|
|
268
|
-
if (!isExactRecord(valueArg, ['schemaVersion', 'id', 'generation', 'organizationId', 'serviceId',
|
|
210
|
+
const assertConfig = (valueArg: unknown): IRuntimeConfig => {
|
|
211
|
+
if (!isExactRecord(valueArg, ['id', 'generation', 'organizationId', 'serviceId',
|
|
269
212
|
'image', 'environment', 'workingDirectory', 'cpuMillis', 'memoryBytes', 'readonlyRootfs',
|
|
270
213
|
'runAsUser', 'runAsGroup', 'targetPorts', 'readiness', 'logs', 'digest'])
|
|
271
|
-
||
|
|
272
|
-
|| !
|
|
214
|
+
|| !isIdentifier(valueArg.id)
|
|
215
|
+
|| !isBoundedInteger(valueArg.generation, 1, Number.MAX_SAFE_INTEGER)
|
|
273
216
|
|| !isIdentifier(valueArg.organizationId) || !isIdentifier(valueArg.serviceId)
|
|
274
|
-
|| !isDigest(valueArg.digest)) fail('runtime config must use its exact
|
|
217
|
+
|| !isDigest(valueArg.digest)) fail('runtime config must use its exact schema');
|
|
275
218
|
const image = valueArg.image;
|
|
276
219
|
if (!isExactRecord(image, ['registryHost', 'repository', 'imageDigest', 'invocation'])
|
|
277
220
|
|| typeof image.registryHost !== 'string' || image.registryHost.length > 253
|
|
@@ -284,7 +227,7 @@ const assertConfig = (valueArg: unknown): IRuntimeConfigV1 => {
|
|
|
284
227
|
image.imageDigest as TSha256Digest);
|
|
285
228
|
const environment = valueArg.environment;
|
|
286
229
|
if (!environment || typeof environment !== 'object' || Array.isArray(environment)
|
|
287
|
-
|| Object.keys(environment).length >
|
|
230
|
+
|| Object.keys(environment).length > runtimeConfigContract.maximumEnvironmentEntries) {
|
|
288
231
|
fail('runtime config requires an explicit bounded nonsecret environment');
|
|
289
232
|
}
|
|
290
233
|
for (const [key, value] of Object.entries(environment)) {
|
|
@@ -297,69 +240,66 @@ const assertConfig = (valueArg: unknown): IRuntimeConfigV1 => {
|
|
|
297
240
|
if (typeof directory !== 'string' || !directory.startsWith('/')
|
|
298
241
|
|| encoder.encode(directory).byteLength > 4096 || /[\u0000-\u001f\u007f]/.test(directory)
|
|
299
242
|
|| (directory !== '/' && directory.split('/').slice(1).some((partArg) => !partArg || partArg === '.' || partArg === '..'))
|
|
300
|
-
|| !(valueArg.cpuMillis
|
|
301
|
-
|| !
|
|
243
|
+
|| !isRuntimeCpuMillis(valueArg.cpuMillis)
|
|
244
|
+
|| !isRuntimeMemoryBytes(valueArg.memoryBytes)
|
|
302
245
|
|| typeof valueArg.readonlyRootfs !== 'boolean'
|
|
303
246
|
|| !((valueArg.runAsUser === null && valueArg.runAsGroup === null)
|
|
304
|
-
|| (
|
|
247
|
+
|| (isRuntimeIdentityNumber(valueArg.runAsUser) && isRuntimeIdentityNumber(valueArg.runAsGroup)))) {
|
|
305
248
|
fail('runtime config requires canonical directory and explicit resource and identity policies');
|
|
306
249
|
}
|
|
307
250
|
const ports = valueArg.targetPorts;
|
|
308
|
-
if (!Array.isArray(ports) || ports.length >
|
|
251
|
+
if (!Array.isArray(ports) || ports.length > runtimeConfigContract.maximumTargetPorts) {
|
|
309
252
|
fail('runtime config target ports must be a bounded array');
|
|
310
253
|
}
|
|
311
254
|
let previousName = '';
|
|
312
|
-
const validatedPorts:
|
|
255
|
+
const validatedPorts: IRuntimeConfigTargetPort[] = [];
|
|
313
256
|
for (const port of ports) {
|
|
314
257
|
if (!isExactRecord(port, ['name', 'port', 'portEnd', 'protocol'])
|
|
315
|
-
|| !
|
|
316
|
-
|| !
|
|
258
|
+
|| !isRuntimePortName(port.name) || port.name <= previousName
|
|
259
|
+
|| !isBoundedInteger(port.port, 1, 65535) || !isBoundedInteger(port.portEnd, port.port, 65535)
|
|
317
260
|
|| (port.protocol !== 'tcp' && port.protocol !== 'udp')
|
|
318
261
|
|| validatedPorts.some((previousArg) => previousArg.protocol === port.protocol
|
|
319
262
|
&& (port.port as number) <= previousArg.portEnd && (port.portEnd as number) >= previousArg.port)) {
|
|
320
263
|
fail('runtime config target ports require sorted unique names and nonoverlapping transport ranges');
|
|
321
264
|
}
|
|
322
265
|
previousName = port.name;
|
|
323
|
-
validatedPorts.push(port as unknown as
|
|
266
|
+
validatedPorts.push(port as unknown as IRuntimeConfigTargetPort);
|
|
324
267
|
}
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|| !isInteger(logs.maximumBufferedBytes, 1, 67_108_864)
|
|
330
|
-
|| logs.maximumBufferedBytes < logs.maximumLineBytes
|
|
331
|
-
|| !isInteger(logs.retentionMs, 1, runtimeConfigV1Contract.maximumLogRetentionMs)) {
|
|
268
|
+
assertRuntimeReadiness(valueArg.readiness, (targetPortArg, portArg) => validatedPorts.some((targetArg) =>
|
|
269
|
+
targetArg.name === targetPortArg && targetArg.protocol === 'tcp'
|
|
270
|
+
&& portArg >= targetArg.port && portArg <= targetArg.portEnd), fail);
|
|
271
|
+
if (!isRuntimeLogPolicy(valueArg.logs)) {
|
|
332
272
|
fail('runtime config logs require explicit bounded line, buffer and retention limits');
|
|
333
273
|
}
|
|
334
|
-
return valueArg as unknown as
|
|
274
|
+
return valueArg as unknown as IRuntimeConfig;
|
|
335
275
|
};
|
|
336
276
|
|
|
337
277
|
/**
|
|
338
278
|
* Detached exact-schema snapshot for synchronous persistence assertions. Digest
|
|
339
279
|
* integrity, scope authorization, admission and runtime readiness are not implied.
|
|
340
280
|
*/
|
|
341
|
-
export const
|
|
281
|
+
export const snapshotRuntimeConfig = (valueArg: unknown): IRuntimeConfig =>
|
|
342
282
|
assertConfig(snapshotBoundedJson(valueArg));
|
|
343
283
|
|
|
344
284
|
/** Domain-separated canonical JSON excludes only the config's own digest. */
|
|
345
|
-
export const
|
|
346
|
-
const { digest: _digest, ...payload } =
|
|
285
|
+
export const computeRuntimeConfigDigest = async (configArg: IRuntimeConfig): Promise<TSha256Digest> => {
|
|
286
|
+
const { digest: _digest, ...payload } = snapshotRuntimeConfig(configArg);
|
|
347
287
|
return `sha256:${await createCanonicalJsonSha256Hex(canonicalizeStrictJson({
|
|
348
|
-
domain:
|
|
288
|
+
domain: runtimeConfigContract.digestDomain, payload,
|
|
349
289
|
}, fail), fail)}`;
|
|
350
290
|
};
|
|
351
291
|
|
|
352
|
-
const validateSnapshot = async (configArg:
|
|
292
|
+
const validateSnapshot = async (configArg: IRuntimeConfig): Promise<string[]> => {
|
|
353
293
|
if (!await verifyImmutableContainerInvocationDigest(configArg.image.invocation)) {
|
|
354
294
|
return ['runtime config immutable invocation digest does not match'];
|
|
355
295
|
}
|
|
356
|
-
return configArg.digest === await
|
|
296
|
+
return configArg.digest === await computeRuntimeConfigDigest(configArg)
|
|
357
297
|
? [] : ['runtime config digest does not match'];
|
|
358
298
|
};
|
|
359
299
|
|
|
360
|
-
export const
|
|
361
|
-
try { return await validateSnapshot(
|
|
362
|
-
catch { return ['runtime config must use its exact canonical
|
|
300
|
+
export const validateRuntimeConfig = async (valueArg: unknown): Promise<string[]> => {
|
|
301
|
+
try { return await validateSnapshot(snapshotRuntimeConfig(valueArg)); }
|
|
302
|
+
catch { return ['runtime config must use its exact canonical schema']; }
|
|
363
303
|
};
|
|
364
304
|
|
|
365
305
|
/**
|
|
@@ -369,13 +309,13 @@ export const validateRuntimeConfigV1 = async (valueArg: unknown): Promise<string
|
|
|
369
309
|
* controller, durably admit the attempt, resolve other owner references, and
|
|
370
310
|
* verify runtime and readiness evidence before effects or route publication.
|
|
371
311
|
*/
|
|
372
|
-
export const
|
|
312
|
+
export const bindRuntimeConfigToAssignment = async (
|
|
373
313
|
configArg: unknown, assignmentArg: unknown,
|
|
374
|
-
): Promise<
|
|
375
|
-
const config =
|
|
376
|
-
const assignment =
|
|
314
|
+
): Promise<IRuntimeConfigAssignmentBinding> => {
|
|
315
|
+
const config = snapshotRuntimeConfig(configArg);
|
|
316
|
+
const assignment = snapshotRuntimeAssignment(snapshotBoundedJson(assignmentArg));
|
|
377
317
|
if ((await validateSnapshot(config)).length !== 0
|
|
378
|
-
|| (await
|
|
318
|
+
|| (await validateRuntimeAssignment(assignment)).length !== 0) {
|
|
379
319
|
fail('runtime config binding requires valid config, invocation and assignment digests');
|
|
380
320
|
}
|
|
381
321
|
const reference = assignment.workload.config;
|