@serve.zone/interfaces 32.23.0 → 32.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/changelog.md +55 -0
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/data/clusternode.d.ts +16 -1
- package/dist_ts/data/clusternode.js +1 -1
- package/dist_ts/data/corestorelegacyadoption.d.ts +6 -2
- package/dist_ts/data/corestorelegacyadoption.js +11 -8
- package/dist_ts/data/runtimelocalstorageclaim.d.ts +73 -10
- package/dist_ts/data/runtimelocalstorageclaim.js +89 -2
- package/dist_ts/platform/index.d.ts +3 -1
- package/dist_ts/platform/index.js +4 -2
- package/dist_ts/platform/objectstorage.d.ts +58 -0
- package/dist_ts/platform/objectstorage.js +136 -1
- package/dist_ts/platform/objectstorageenvironment.d.ts +49 -0
- package/dist_ts/platform/objectstorageenvironment.js +119 -0
- package/dist_ts/platform/objectstorageretention.d.ts +40 -0
- package/dist_ts/platform/objectstorageretention.js +121 -1
- package/dist_ts/requests/node.d.ts +29 -0
- package/package.json +1 -1
- package/readme.md +130 -13
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/data/clusternode.ts +17 -1
- package/ts/data/corestorelegacyadoption.ts +19 -9
- package/ts/data/runtimelocalstorageclaim.ts +169 -10
- package/ts/platform/index.ts +3 -0
- package/ts/platform/objectstorage.ts +180 -0
- package/ts/platform/objectstorageenvironment.ts +176 -0
- package/ts/platform/objectstorageretention.ts +141 -0
- package/ts/requests/node.ts +33 -0
|
@@ -65,3 +65,43 @@ export declare const objectStorageRetentionIntentsEqual: (leftArg: unknown, righ
|
|
|
65
65
|
export declare const validateObjectStorageRetentionEvidence: (evidenceArg: unknown, expectedArg: IObjectStorageRetentionEvidenceExpectation) => Promise<string[]>;
|
|
66
66
|
export declare const validateObjectStorageRetentionBinding: (bindingArg: unknown, expectedArg: IObjectStorageRetentionEvidenceExpectation) => Promise<string[]>;
|
|
67
67
|
export declare const validatePlatformBindingObjectStorageRetention: (bindingArg: unknown, expectedArg: IObjectStorageRetentionEvidenceExpectation) => Promise<string[]>;
|
|
68
|
+
/**
|
|
69
|
+
* The non-secret environment names that tell a workload which retention its bucket carries.
|
|
70
|
+
*
|
|
71
|
+
* The names are the ones the cluster relay handed workloads on the Docker path, so an application
|
|
72
|
+
* that read them keeps working unchanged. Every value is a projection of verified
|
|
73
|
+
* `IObjectStorageRetentionEvidence`; none is a credential.
|
|
74
|
+
*
|
|
75
|
+
* - `S3_RETENTION_MODE`: `intent.mode`, always `compliance`.
|
|
76
|
+
* - `S3_RETENTION_POLICY_ID`: `intent.policyId`.
|
|
77
|
+
* - `S3_RETENTION_DURATION_SECONDS`: `intent.retentionDurationSeconds` in decimal.
|
|
78
|
+
* - `S3_RETENTION_INTENT_SHA256`: `intentSha256`.
|
|
79
|
+
* - `S3_RETENTION_SENTINEL_KEY`: `receipt.sentinelKey`.
|
|
80
|
+
* - `S3_RETENTION_CONFIGURED_AT`: `receipt.configuredAt`, Unix milliseconds in decimal.
|
|
81
|
+
* - `S3_RETENTION_SENTINEL_CREATED_AT`: `receipt.sentinel.createdAt`, Unix milliseconds in decimal.
|
|
82
|
+
* - `S3_RETENTION_SENTINEL_RETAIN_UNTIL`: `receipt.sentinel.retainUntil`, Unix milliseconds in
|
|
83
|
+
* decimal.
|
|
84
|
+
* - `S3_RETENTION_SENTINEL_PAYLOAD_SHA256`: `receipt.sentinel.payloadSha256`.
|
|
85
|
+
* - `S3_RETENTION_SENTINEL_METADATA_SHA256`: `receipt.sentinel.metadataSha256`.
|
|
86
|
+
* - `S3_RETENTION_SENTINEL_ETAG`: `receipt.sentinel.etag`.
|
|
87
|
+
*/
|
|
88
|
+
export declare const objectStorageRetentionEnvironmentKeys: readonly ["S3_RETENTION_MODE", "S3_RETENTION_POLICY_ID", "S3_RETENTION_DURATION_SECONDS", "S3_RETENTION_INTENT_SHA256", "S3_RETENTION_SENTINEL_KEY", "S3_RETENTION_CONFIGURED_AT", "S3_RETENTION_SENTINEL_CREATED_AT", "S3_RETENTION_SENTINEL_RETAIN_UNTIL", "S3_RETENTION_SENTINEL_PAYLOAD_SHA256", "S3_RETENTION_SENTINEL_METADATA_SHA256", "S3_RETENTION_SENTINEL_ETAG"];
|
|
89
|
+
export type TObjectStorageRetentionEnvironmentKey = typeof objectStorageRetentionEnvironmentKeys[number];
|
|
90
|
+
export type TObjectStorageRetentionEnvironment = {
|
|
91
|
+
[TKey in TObjectStorageRetentionEnvironmentKey]: string;
|
|
92
|
+
};
|
|
93
|
+
/**
|
|
94
|
+
* The retention environment of evidence that proves `expectedArg`.
|
|
95
|
+
*
|
|
96
|
+
* The evidence is validated against the expectation first, with the same validator every other
|
|
97
|
+
* consumer of retention evidence uses; the first reason it is refused is thrown. A workload is
|
|
98
|
+
* never told about a retention nobody proved.
|
|
99
|
+
*/
|
|
100
|
+
export declare const createObjectStorageRetentionEnvironment: (evidenceArg: IObjectStorageRetentionEvidence, expectedArg: IObjectStorageRetentionEvidenceExpectation) => Promise<TObjectStorageRetentionEnvironment>;
|
|
101
|
+
/**
|
|
102
|
+
* Validates a retention environment on its own: exactly its eleven keys, canonical values, an
|
|
103
|
+
* intent digest that matches the stated intent, and sentinel timestamps that agree with the
|
|
104
|
+
* duration. It cannot prove the authority or the bucket the evidence was bound to — the
|
|
105
|
+
* environment does not carry them — so it judges the shape a workload reads, not the proof.
|
|
106
|
+
*/
|
|
107
|
+
export declare const validateObjectStorageRetentionEnvironment: (environmentArg: unknown, pathArg?: string) => Promise<string[]>;
|
|
@@ -249,4 +249,124 @@ export const validatePlatformBindingObjectStorageRetention = async (bindingArg,
|
|
|
249
249
|
}
|
|
250
250
|
return validateObjectStorageRetentionBinding(bindingArg.objectstorageRetention, expectedArg);
|
|
251
251
|
};
|
|
252
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib2JqZWN0c3RvcmFnZXJldGVudGlvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL3BsYXRmb3JtL29iamVjdHN0b3JhZ2VyZXRlbnRpb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLDRCQUE0QixFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDM0UsT0FBTyxFQUFFLHVDQUF1QyxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDN0UsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBRTVELE1BQU0sQ0FBQyxNQUFNLDRCQUE0QixHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUM7SUFDeEQscUJBQXFCLEVBQUUsRUFBRTtJQUN6QiwrQkFBK0IsRUFBRSxHQUFHLEdBQUcsR0FBRyxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRTtDQUMxRCxDQUFDLENBQUM7QUFvRUgsTUFBTSxlQUFlLEdBQUcsd0JBQXdCLENBQUM7QUFDakQsTUFBTSxpQkFBaUIsR0FBRyxxQ0FBcUMsQ0FBQztBQUNoRSxNQUFNLGFBQWEsR0FBRyxnQkFBZ0IsQ0FBQztBQUN2QyxNQUFNLFdBQVcsR0FBRyxnQkFBZ0IsQ0FBQztBQUNyQzs7OztHQUlHO0FBQ0gsTUFBTSxrQkFBa0IsR0FBRyw2REFBNkQsQ0FBQztBQUV6RixNQUFNLFFBQVEsR0FBRyxDQUFDLFFBQWlCLEVBQXVDLEVBQUUsQ0FBQyxDQUMzRSxPQUFPLENBQUMsUUFBUSxDQUFDO09BQ2QsT0FBTyxRQUFRLEtBQUssUUFBUTtPQUM1QixDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDO09BQ3hCLENBQUMsTUFBTSxDQUFDLGNBQWMsQ0FBQyxRQUFRLENBQUMsS0FBSyxNQUFNLENBQUMsU0FBUztXQUNuRCxNQUFNLENBQUMsY0FBYyxDQUFDLFFBQVEsQ0FBQyxLQUFLLElBQUksQ0FBQyxDQUMvQyxDQUFDO0FBRUYsTUFBTSxxQkFBcUIsR0FBRyxD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
|
|
252
|
+
/**
|
|
253
|
+
* The non-secret environment names that tell a workload which retention its bucket carries.
|
|
254
|
+
*
|
|
255
|
+
* The names are the ones the cluster relay handed workloads on the Docker path, so an application
|
|
256
|
+
* that read them keeps working unchanged. Every value is a projection of verified
|
|
257
|
+
* `IObjectStorageRetentionEvidence`; none is a credential.
|
|
258
|
+
*
|
|
259
|
+
* - `S3_RETENTION_MODE`: `intent.mode`, always `compliance`.
|
|
260
|
+
* - `S3_RETENTION_POLICY_ID`: `intent.policyId`.
|
|
261
|
+
* - `S3_RETENTION_DURATION_SECONDS`: `intent.retentionDurationSeconds` in decimal.
|
|
262
|
+
* - `S3_RETENTION_INTENT_SHA256`: `intentSha256`.
|
|
263
|
+
* - `S3_RETENTION_SENTINEL_KEY`: `receipt.sentinelKey`.
|
|
264
|
+
* - `S3_RETENTION_CONFIGURED_AT`: `receipt.configuredAt`, Unix milliseconds in decimal.
|
|
265
|
+
* - `S3_RETENTION_SENTINEL_CREATED_AT`: `receipt.sentinel.createdAt`, Unix milliseconds in decimal.
|
|
266
|
+
* - `S3_RETENTION_SENTINEL_RETAIN_UNTIL`: `receipt.sentinel.retainUntil`, Unix milliseconds in
|
|
267
|
+
* decimal.
|
|
268
|
+
* - `S3_RETENTION_SENTINEL_PAYLOAD_SHA256`: `receipt.sentinel.payloadSha256`.
|
|
269
|
+
* - `S3_RETENTION_SENTINEL_METADATA_SHA256`: `receipt.sentinel.metadataSha256`.
|
|
270
|
+
* - `S3_RETENTION_SENTINEL_ETAG`: `receipt.sentinel.etag`.
|
|
271
|
+
*/
|
|
272
|
+
export const objectStorageRetentionEnvironmentKeys = Object.freeze([
|
|
273
|
+
'S3_RETENTION_MODE',
|
|
274
|
+
'S3_RETENTION_POLICY_ID',
|
|
275
|
+
'S3_RETENTION_DURATION_SECONDS',
|
|
276
|
+
'S3_RETENTION_INTENT_SHA256',
|
|
277
|
+
'S3_RETENTION_SENTINEL_KEY',
|
|
278
|
+
'S3_RETENTION_CONFIGURED_AT',
|
|
279
|
+
'S3_RETENTION_SENTINEL_CREATED_AT',
|
|
280
|
+
'S3_RETENTION_SENTINEL_RETAIN_UNTIL',
|
|
281
|
+
'S3_RETENTION_SENTINEL_PAYLOAD_SHA256',
|
|
282
|
+
'S3_RETENTION_SENTINEL_METADATA_SHA256',
|
|
283
|
+
'S3_RETENTION_SENTINEL_ETAG',
|
|
284
|
+
]);
|
|
285
|
+
/**
|
|
286
|
+
* The retention environment of evidence that proves `expectedArg`.
|
|
287
|
+
*
|
|
288
|
+
* The evidence is validated against the expectation first, with the same validator every other
|
|
289
|
+
* consumer of retention evidence uses; the first reason it is refused is thrown. A workload is
|
|
290
|
+
* never told about a retention nobody proved.
|
|
291
|
+
*/
|
|
292
|
+
export const createObjectStorageRetentionEnvironment = async (evidenceArg, expectedArg) => {
|
|
293
|
+
const errors = await validateObjectStorageRetentionEvidence(evidenceArg, expectedArg);
|
|
294
|
+
if (errors.length > 0)
|
|
295
|
+
throw new Error(errors[0]);
|
|
296
|
+
return {
|
|
297
|
+
S3_RETENTION_MODE: evidenceArg.intent.mode,
|
|
298
|
+
S3_RETENTION_POLICY_ID: evidenceArg.intent.policyId,
|
|
299
|
+
S3_RETENTION_DURATION_SECONDS: String(evidenceArg.intent.retentionDurationSeconds),
|
|
300
|
+
S3_RETENTION_INTENT_SHA256: evidenceArg.intentSha256,
|
|
301
|
+
S3_RETENTION_SENTINEL_KEY: evidenceArg.receipt.sentinelKey,
|
|
302
|
+
S3_RETENTION_CONFIGURED_AT: String(evidenceArg.receipt.configuredAt),
|
|
303
|
+
S3_RETENTION_SENTINEL_CREATED_AT: String(evidenceArg.receipt.sentinel.createdAt),
|
|
304
|
+
S3_RETENTION_SENTINEL_RETAIN_UNTIL: String(evidenceArg.receipt.sentinel.retainUntil),
|
|
305
|
+
S3_RETENTION_SENTINEL_PAYLOAD_SHA256: evidenceArg.receipt.sentinel.payloadSha256,
|
|
306
|
+
S3_RETENTION_SENTINEL_METADATA_SHA256: evidenceArg.receipt.sentinel.metadataSha256,
|
|
307
|
+
S3_RETENTION_SENTINEL_ETAG: evidenceArg.receipt.sentinel.etag,
|
|
308
|
+
};
|
|
309
|
+
};
|
|
310
|
+
const canonicalDecimalPattern = /^[1-9][0-9]*$/;
|
|
311
|
+
const readCanonicalPositiveInteger = (valueArg) => (typeof valueArg === 'string'
|
|
312
|
+
&& canonicalDecimalPattern.test(valueArg)
|
|
313
|
+
&& Number.isSafeInteger(Number(valueArg))
|
|
314
|
+
? Number(valueArg)
|
|
315
|
+
: undefined);
|
|
316
|
+
/**
|
|
317
|
+
* Validates a retention environment on its own: exactly its eleven keys, canonical values, an
|
|
318
|
+
* intent digest that matches the stated intent, and sentinel timestamps that agree with the
|
|
319
|
+
* duration. It cannot prove the authority or the bucket the evidence was bound to — the
|
|
320
|
+
* environment does not carry them — so it judges the shape a workload reads, not the proof.
|
|
321
|
+
*/
|
|
322
|
+
export const validateObjectStorageRetentionEnvironment = async (environmentArg, pathArg = 'objectstorage retention environment') => {
|
|
323
|
+
if (!isRecord(environmentArg)
|
|
324
|
+
|| !hasExactKeys(environmentArg, objectStorageRetentionEnvironmentKeys)
|
|
325
|
+
|| objectStorageRetentionEnvironmentKeys.some((keyArg) => (typeof environmentArg[keyArg] !== 'string'))) {
|
|
326
|
+
return [`${pathArg} must contain exactly its string keys`];
|
|
327
|
+
}
|
|
328
|
+
const environment = environmentArg;
|
|
329
|
+
const errors = [];
|
|
330
|
+
const duration = readCanonicalPositiveInteger(environment.S3_RETENTION_DURATION_SECONDS);
|
|
331
|
+
const intent = {
|
|
332
|
+
mode: environment.S3_RETENTION_MODE,
|
|
333
|
+
policyId: environment.S3_RETENTION_POLICY_ID,
|
|
334
|
+
retentionDurationSeconds: duration,
|
|
335
|
+
};
|
|
336
|
+
const intentErrors = validateObjectStorageRetentionIntent(intent, `${pathArg} intent`);
|
|
337
|
+
errors.push(...intentErrors);
|
|
338
|
+
if (!sha256Pattern.test(environment.S3_RETENTION_INTENT_SHA256)
|
|
339
|
+
|| intentErrors.length === 0
|
|
340
|
+
&& environment.S3_RETENTION_INTENT_SHA256 !== await computeObjectStorageRetentionIntentSha256(intent)) {
|
|
341
|
+
errors.push(`${pathArg} S3_RETENTION_INTENT_SHA256 must be the digest of the stated intent`);
|
|
342
|
+
}
|
|
343
|
+
if (!sentinelKeyPattern.test(environment.S3_RETENTION_SENTINEL_KEY)) {
|
|
344
|
+
errors.push(`${pathArg} S3_RETENTION_SENTINEL_KEY must be canonical`);
|
|
345
|
+
}
|
|
346
|
+
const configuredAt = readCanonicalPositiveInteger(environment.S3_RETENTION_CONFIGURED_AT);
|
|
347
|
+
const createdAt = readCanonicalPositiveInteger(environment.S3_RETENTION_SENTINEL_CREATED_AT);
|
|
348
|
+
const retainUntil = readCanonicalPositiveInteger(environment.S3_RETENTION_SENTINEL_RETAIN_UNTIL);
|
|
349
|
+
if (configuredAt === undefined
|
|
350
|
+
|| createdAt === undefined
|
|
351
|
+
|| retainUntil === undefined
|
|
352
|
+
|| createdAt < configuredAt) {
|
|
353
|
+
errors.push(`${pathArg} timestamps must be canonical positive decimals in order`);
|
|
354
|
+
}
|
|
355
|
+
else if (intentErrors.length === 0) {
|
|
356
|
+
try {
|
|
357
|
+
if (retainUntil !== createObjectStorageRetentionRetainUntil(createdAt, duration)) {
|
|
358
|
+
errors.push(`${pathArg} S3_RETENTION_SENTINEL_RETAIN_UNTIL must equal createdAt plus duration`);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
catch {
|
|
362
|
+
errors.push(`${pathArg} S3_RETENTION_SENTINEL_RETAIN_UNTIL arithmetic must be safe`);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
if (!sha256Pattern.test(environment.S3_RETENTION_SENTINEL_PAYLOAD_SHA256)
|
|
366
|
+
|| !sha256Pattern.test(environment.S3_RETENTION_SENTINEL_METADATA_SHA256)
|
|
367
|
+
|| !etagPattern.test(environment.S3_RETENTION_SENTINEL_ETAG)) {
|
|
368
|
+
errors.push(`${pathArg} sentinel digests and ETag must be canonical`);
|
|
369
|
+
}
|
|
370
|
+
return errors;
|
|
371
|
+
};
|
|
372
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib2JqZWN0c3RvcmFnZXJldGVudGlvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL3BsYXRmb3JtL29iamVjdHN0b3JhZ2VyZXRlbnRpb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLDRCQUE0QixFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDM0UsT0FBTyxFQUFFLHVDQUF1QyxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDN0UsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBRTVELE1BQU0sQ0FBQyxNQUFNLDRCQUE0QixHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUM7SUFDeEQscUJBQXFCLEVBQUUsRUFBRTtJQUN6QiwrQkFBK0IsRUFBRSxHQUFHLEdBQUcsR0FBRyxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRTtDQUMxRCxDQUFDLENBQUM7QUFvRUgsTUFBTSxlQUFlLEdBQUcsd0JBQXdCLENBQUM7QUFDakQsTUFBTSxpQkFBaUIsR0FBRyxxQ0FBcUMsQ0FBQztBQUNoRSxNQUFNLGFBQWEsR0FBRyxnQkFBZ0IsQ0FBQztBQUN2QyxNQUFNLFdBQVcsR0FBRyxnQkFBZ0IsQ0FBQztBQUNyQzs7OztHQUlHO0FBQ0gsTUFBTSxrQkFBa0IsR0FBRyw2REFBNkQsQ0FBQztBQUV6RixNQUFNLFFBQVEsR0FBRyxDQUFDLFFBQWlCLEVBQXVDLEVBQUUsQ0FBQyxDQUMzRSxPQUFPLENBQUMsUUFBUSxDQUFDO09BQ2QsT0FBTyxRQUFRLEtBQUssUUFBUTtPQUM1QixDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDO09BQ3hCLENBQUMsTUFBTSxDQUFDLGNBQWMsQ0FBQyxRQUFRLENBQUMsS0FBSyxNQUFNLENBQUMsU0FBUztXQUNuRCxNQUFNLENBQUMsY0FBYyxDQUFDLFFBQVEsQ0FBQyxLQUFLLElBQUksQ0FBQyxDQUMvQyxDQUFDO0FBRUYsTUFBTSxxQkFBcUIsR0FBRyxD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
|
|
@@ -4,6 +4,7 @@ import type { ICluster } from '../data/cluster.js';
|
|
|
4
4
|
import type { IClusterNode, INodeAction, INodeMetricsSample, TNodeActionName } from '../data/clusternode.js';
|
|
5
5
|
import type { IDeployment } from '../data/deployment.js';
|
|
6
6
|
import type { IIdentity } from '../data/user.js';
|
|
7
|
+
import type { IPlatformObjectStorageEndpoint } from '../platform/objectstorage.js';
|
|
7
8
|
import type { INodeCredentialMetadata, INodeCredentialMutationPreconditions, INodeCredentialMutationResult, TNodeCredentialPurpose } from '../data/nodecredential.js';
|
|
8
9
|
import type { INodeRuntimeRetirement } from '../data/noderetirement.js';
|
|
9
10
|
import type { INodeRuntimeBindingRead, INodeRuntimeBindingRequest } from '../data/noderuntimebinding.js';
|
|
@@ -217,6 +218,34 @@ export interface IReq_Any_Cloudly_SetClusterNodeCorestoreEndpoint extends plugin
|
|
|
217
218
|
node: IClusterNode;
|
|
218
219
|
};
|
|
219
220
|
}
|
|
221
|
+
/**
|
|
222
|
+
* An administrator states where a workload on one node reaches the node's Corestore object
|
|
223
|
+
* storage, and the region it signs for: `IClusterNode.data.corestoreObjectStorage`.
|
|
224
|
+
*
|
|
225
|
+
* A request of its own, separate from `setClusterNodeCorestoreEndpoint`, because the two are
|
|
226
|
+
* separate facts with separate readers — the relay dials the control endpoint, a workload dials
|
|
227
|
+
* this one — and setting one never touches the other. A caller that states only the control
|
|
228
|
+
* endpoint leaves this one as it stands.
|
|
229
|
+
*
|
|
230
|
+
* Cloudly validates it with `validatePlatformObjectStorageEndpoint` before it writes and takes the
|
|
231
|
+
* node's own real-write fence inside the writing transaction, as for the control endpoint.
|
|
232
|
+
* `objectStorage: null` clears it, which is the same fact as never having set one: no
|
|
233
|
+
* object-storage environment can be composed for a binding on this node. The endpoint says where,
|
|
234
|
+
* never with what — no credential travels in this request or in the node document.
|
|
235
|
+
*/
|
|
236
|
+
export interface IReq_Any_Cloudly_SetClusterNodeCorestoreObjectStorageEndpoint extends plugins.typedrequestInterfaces.implementsTR<plugins.typedrequestInterfaces.ITypedRequest, IReq_Any_Cloudly_SetClusterNodeCorestoreObjectStorageEndpoint> {
|
|
237
|
+
method: 'setClusterNodeCorestoreObjectStorageEndpoint';
|
|
238
|
+
request: {
|
|
239
|
+
identity: IIdentity;
|
|
240
|
+
nodeId: string;
|
|
241
|
+
/** The node's object-storage endpoint and region, or `null` to state that it has none. */
|
|
242
|
+
objectStorage: IPlatformObjectStorageEndpoint | null;
|
|
243
|
+
};
|
|
244
|
+
response: {
|
|
245
|
+
/** The node as it now stands, so a caller needs no second read to see what it set. */
|
|
246
|
+
node: IClusterNode;
|
|
247
|
+
};
|
|
248
|
+
}
|
|
220
249
|
export interface IReq_Any_Cloudly_CreateNodeAction extends plugins.typedrequestInterfaces.implementsTR<plugins.typedrequestInterfaces.ITypedRequest, IReq_Any_Cloudly_CreateNodeAction> {
|
|
221
250
|
method: 'createNodeAction';
|
|
222
251
|
request: {
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -1984,25 +1984,64 @@ native fence.
|
|
|
1984
1984
|
|
|
1985
1985
|
### Runtime local storage claims
|
|
1986
1986
|
|
|
1987
|
-
`data.IRuntimeLocalStorageClaim` is a controller's authority for one retained
|
|
1988
|
-
one
|
|
1989
|
-
the claim revision (`id`, `generation`, `previous`), the organization, cluster, node,
|
|
1990
|
-
namespace, service and the service's own `volumeId`, and it states:
|
|
1991
|
-
|
|
1992
|
-
- `source
|
|
1993
|
-
|
|
1994
|
-
|
|
1987
|
+
`data.IRuntimeLocalStorageClaim` is a controller's authority for one retained volume of one service,
|
|
1988
|
+
mounted on one node. Cloudly and Onebox issue it alike (`controller.kind` is `cloudly` or `onebox`).
|
|
1989
|
+
It names the claim revision (`id`, `generation`, `previous`), the organization, cluster, node,
|
|
1990
|
+
runtime namespace, service and the service's own `volumeId`, and it states:
|
|
1991
|
+
|
|
1992
|
+
- `source` (`TRuntimeLocalStorageSource`), one of:
|
|
1993
|
+
- `{ kind: 'directory' }` (`TRuntimeLocalStorageDirectorySource`), a node-local directory the node
|
|
1994
|
+
derives from the claim's identity under a root only the node knows;
|
|
1995
|
+
- `{ kind: 'nfs', server, export, subPath, version }` (`TRuntimeLocalStorageNfsSource`), the
|
|
1996
|
+
directory `subPath` below the NFS export `server:export`;
|
|
1997
|
+
- `{ kind: 'smb', server, share, subPath, version, credential }` (`TRuntimeLocalStorageSmbSource`),
|
|
1998
|
+
the directory `subPath` below the SMB share `//server/share`. `credential` is an
|
|
1999
|
+
`IRuntimeAuthorityReference { id, generation, digest }` naming the credential the node
|
|
2000
|
+
authenticates with; the claim never carries a user name, password or domain, and the node
|
|
2001
|
+
resolves the material through the controller's secret delivery. NFS authenticates the node's
|
|
2002
|
+
host, so an `nfs` source names no credential;
|
|
1995
2003
|
- `initialization`: `empty` creates an empty root with `initialOwnership { uid, gid, mode }`, which
|
|
1996
2004
|
an `empty` claim must state, so a workload without `runAs` never meets a root-owned directory by
|
|
1997
2005
|
accident; `import` waits for the volume's bytes to be imported and states `initialOwnership: null`,
|
|
1998
2006
|
because an imported tree keeps its own ownership. `mode` holds directory permission bits only
|
|
1999
|
-
(`runtimeLocalStorageClaimContract.directoryModeBits`, `0o3777`; setuid is refused)
|
|
2007
|
+
(`runtimeLocalStorageClaimContract.directoryModeBits`, `0o3777`; setuid is refused). SMB carries no
|
|
2008
|
+
POSIX ownership, so the node presents an SMB volume with `initialOwnership`, and an `smb` claim is
|
|
2009
|
+
always `empty`;
|
|
2000
2010
|
- `mount { mountPath, readOnly }`, judged by the storage request's own mount path rule: canonical,
|
|
2001
2011
|
absolute, not `/`, and never overlapping `/run/secrets`;
|
|
2002
2012
|
- `accessMode: 'ReadWriteOnce'`, `reclaimPolicy: 'retain'`, and `lifecycle`: `bound` keeps the
|
|
2003
2013
|
volume, `purge` orders its bytes deleted and always follows a bound generation of the same claim.
|
|
2004
2014
|
|
|
2005
|
-
|
|
2015
|
+
A network source names the remote directory and nothing about how to mount it, so the node derives
|
|
2016
|
+
every mount parameter from these fields alone and a claim cannot smuggle an option in:
|
|
2017
|
+
|
|
2018
|
+
| Field | Rule |
|
|
2019
|
+
| --- | --- |
|
|
2020
|
+
| `server` | a lowercase fully qualified hostname of two or more labels whose last label is not numeric (a single label would resolve through each node's own search domains), or a canonical IP literal (a dotted quad without leading zeros, or RFC 5952 IPv6 without brackets or zone). No scheme, user info or port: the node connects to the protocol's standard port |
|
|
2021
|
+
| `export` | `/`, or `/` and canonical segments without a trailing slash |
|
|
2022
|
+
| `subPath` | `.` for the export or share itself, or canonical relative segments |
|
|
2023
|
+
| `share` | one segment of at most 80 characters, without `+`, `;`, `[` or `]` |
|
|
2024
|
+
| `version` | `nfs`: `3`, `4.0`, `4.1` or `4.2`; `smb`: `3.0`, `3.02` or `3.1.1` |
|
|
2025
|
+
|
|
2026
|
+
A segment is printable ASCII without a space, at most 255 characters, never `.` or `..`, and holds
|
|
2027
|
+
none of `"`, `*`, `,`, `/`, `:`, `<`, `=`, `>`, `?`, `\` or `|`: a comma or `=` would read as a mount
|
|
2028
|
+
option, and the rest have meaning in a mount source or an SMB name. `export` and `subPath` are at
|
|
2029
|
+
most 1024 characters. ASCII keeps one spelling per segment, but one remote directory can still be
|
|
2030
|
+
named several ways: a hostname and an address of the same server, a different `export`/`subPath`
|
|
2031
|
+
split, or a nested `subPath`. The contract cannot detect these aliases, so the controller must refuse
|
|
2032
|
+
overlapping bound claims itself. The versions are the kernel's own `vers=` spellings, and each pins one protocol version: a
|
|
2033
|
+
bare NFS `4` or SMB `3` negotiates one, which a claim that must mean the same mount on every node
|
|
2034
|
+
cannot allow. NFS version 2 and the SMB 1 and 2 dialects are refused; SMB 3 is the first dialect
|
|
2035
|
+
that encrypts. The bounds and version lists
|
|
2036
|
+
are `runtimeLocalStorageClaimContract.nfsVersions`, `smbVersions`, `maximumServerLength`,
|
|
2037
|
+
`maximumPathLength`, `maximumSegmentLength` and `maximumShareLength`.
|
|
2038
|
+
|
|
2039
|
+
`ReadWriteOnce` holds on the node that mounts the claim. A network directory is reachable from more
|
|
2040
|
+
than one node, so the controller issues at most one bound claim per remote directory; a node cannot
|
|
2041
|
+
see another node's mounts. A `purge` of a network claim deletes everything below `subPath`, the
|
|
2042
|
+
whole export or share for `.`.
|
|
2043
|
+
|
|
2044
|
+
The claim carries no host path, device, mount option or credential value.
|
|
2006
2045
|
`snapshotRuntimeLocalStorageClaim` makes a detached exact-schema snapshot,
|
|
2007
2046
|
`computeRuntimeLocalStorageClaimDigest` hashes it under `serve.zone/runtime-local-storage-claim`,
|
|
2008
2047
|
`validateRuntimeLocalStorageClaim` verifies the stated digest, and
|
|
@@ -3394,9 +3433,13 @@ Coreflow, all exported from `data` and `platform`:
|
|
|
3394
3433
|
`{ state: 'authorized', bindingId }`. The blocker names what would stop the offline adoption,
|
|
3395
3434
|
`null` when nothing would: `not-adoptable` (an allocation-managed database, another provider, a
|
|
3396
3435
|
resource name that is not its database or bucket name, or a bucket name that is not a canonical S3
|
|
3397
|
-
name), `ordinary-credentials-rotated
|
|
3398
|
-
|
|
3399
|
-
|
|
3436
|
+
name), `ordinary-credentials-rotated`, `owned-by-binding` or `fence-lineage-conflict` (the
|
|
3437
|
+
bucket's object-storage fence lineage cannot move to the adopting binding: the bucket has more than
|
|
3438
|
+
one lineage, or its lineage does not validate, belongs to another authority or has an unfinished
|
|
3439
|
+
mutation).
|
|
3440
|
+
Only a bucket has a fence lineage, so a database never names `fence-lineage-conflict`. An
|
|
3441
|
+
adoptable bucket must have a canonical S3 name, because a binding request carries only such a
|
|
3442
|
+
name. A consumed adoption removes the legacy entry, so it never appears.
|
|
3400
3443
|
2. **Relay.** `getClusterCorestoreLegacyResources { nodeId }` asks the relay for one node's
|
|
3401
3444
|
inventory, answered as `TClusterCorestoreLegacyResourceInventory`: `reachable: true` with the
|
|
3402
3445
|
services, or `reachable: false` with `errorCode` `CORESTORE_ENDPOINT_UNKNOWN` or
|
|
@@ -3443,6 +3486,78 @@ Coreflow, all exported from `data` and `platform`:
|
|
|
3443
3486
|
While a binding of a service reports `legacy-adoption-pending`, the service's runtime status waits as
|
|
3444
3487
|
`legacy-adoption-pending` instead of `bindings-pending`.
|
|
3445
3488
|
|
|
3489
|
+
### Object-Storage Binding Environment
|
|
3490
|
+
|
|
3491
|
+
An object-storage binding gives its workload two things. The access key and the secret reach it
|
|
3492
|
+
only as Secrets: the six aliases `createCorestoreCredentialSecretValues()` expands
|
|
3493
|
+
(`S3_ACCESS_KEY`, `S3_ACCESS_KEY_ID`, `S3_SECRET_KEY`, `S3_SECRET_ACCESS_KEY`,
|
|
3494
|
+
`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`), published through the sealed Secret set. Where the
|
|
3495
|
+
bucket is, and which retention it carries, is non-secret and reaches it through the runtime
|
|
3496
|
+
configuration: Cloudly composes it into `IRuntimeConfig.environment`, the complete public
|
|
3497
|
+
environment, so no further runtime spec or assignment field carries it. The names are the ones
|
|
3498
|
+
Corestore and the cluster relay handed workloads before, so an application that read them keeps
|
|
3499
|
+
working unchanged.
|
|
3500
|
+
|
|
3501
|
+
| Name | Value |
|
|
3502
|
+
| --- | --- |
|
|
3503
|
+
| `S3_ENDPOINT`, `AWS_ENDPOINT_URL` | The endpoint origin, for example `http://192.0.2.15:9000`. |
|
|
3504
|
+
| `S3_ENDPOINT_HOST` | The origin's host; an IPv6 literal keeps its brackets. |
|
|
3505
|
+
| `S3_PORT` | The origin's port, `80` or `443` when the origin states none. |
|
|
3506
|
+
| `S3_USE_SSL` | `true` for `https:`, `false` for `http:`. |
|
|
3507
|
+
| `S3_REGION`, `AWS_REGION` | The signing region. |
|
|
3508
|
+
| `S3_BUCKET` | `IPlatformBinding.objectstorageBucketName`. |
|
|
3509
|
+
| `AWS_S3_FORCE_PATH_STYLE` | Always `true`: a node-local origin has no wildcard DNS. |
|
|
3510
|
+
| `S3_RETENTION_MODE` | `intent.mode`, always `compliance`. |
|
|
3511
|
+
| `S3_RETENTION_POLICY_ID` | `intent.policyId`. |
|
|
3512
|
+
| `S3_RETENTION_DURATION_SECONDS` | `intent.retentionDurationSeconds`. |
|
|
3513
|
+
| `S3_RETENTION_INTENT_SHA256` | `intentSha256`. |
|
|
3514
|
+
| `S3_RETENTION_SENTINEL_KEY` | `receipt.sentinelKey`. |
|
|
3515
|
+
| `S3_RETENTION_CONFIGURED_AT` | `receipt.configuredAt`, Unix milliseconds. |
|
|
3516
|
+
| `S3_RETENTION_SENTINEL_CREATED_AT` | `receipt.sentinel.createdAt`, Unix milliseconds. |
|
|
3517
|
+
| `S3_RETENTION_SENTINEL_RETAIN_UNTIL` | `receipt.sentinel.retainUntil`, Unix milliseconds. |
|
|
3518
|
+
| `S3_RETENTION_SENTINEL_PAYLOAD_SHA256` | `receipt.sentinel.payloadSha256`. |
|
|
3519
|
+
| `S3_RETENTION_SENTINEL_METADATA_SHA256` | `receipt.sentinel.metadataSha256`. |
|
|
3520
|
+
| `S3_RETENTION_SENTINEL_ETAG` | `receipt.sentinel.etag`. |
|
|
3521
|
+
|
|
3522
|
+
Every number is a canonical decimal. `objectStorageEndpointEnvironmentKeys`,
|
|
3523
|
+
`objectStorageRetentionEnvironmentKeys` and `objectStorageBindingEnvironmentKeys` publish the
|
|
3524
|
+
lists in this order, with the matching `T…EnvironmentKey` and `T…Environment` types.
|
|
3525
|
+
|
|
3526
|
+
**Where the endpoint comes from.** Corestore is node-local, so the endpoint is a fact about the
|
|
3527
|
+
node that holds the bucket: `IClusterNode.data.corestoreObjectStorage` is an optional
|
|
3528
|
+
`IPlatformObjectStorageEndpoint { endpoint, region }`, checked by
|
|
3529
|
+
`validatePlatformObjectStorageEndpoint()` (a canonical `http:` or `https:` origin and a lowercase
|
|
3530
|
+
region). It sits beside `corestore`, not inside it: the relay dials the control endpoint and a
|
|
3531
|
+
workload dials this one, and `IClusterNodeCorestore` keeps its exact schema, so a relay that
|
|
3532
|
+
validates it goes on accepting every node document. An administrator sets it with
|
|
3533
|
+
`setClusterNodeCorestoreObjectStorageEndpoint { identity; nodeId; objectStorage }`, answered by
|
|
3534
|
+
Cloudly with the node as it now stands; `objectStorage: null` clears it. The request is separate
|
|
3535
|
+
from `setClusterNodeCorestoreEndpoint`, so setting the control endpoint never touches it. A node
|
|
3536
|
+
without it cannot give a workload an object-storage environment; nothing derives a port, a scheme
|
|
3537
|
+
or a region.
|
|
3538
|
+
|
|
3539
|
+
**Composing.** `createObjectStorageBindingEnvironment(binding, endpoint)` returns the nine endpoint
|
|
3540
|
+
names for a binding that declares no retention, and all twenty when it declares retention with
|
|
3541
|
+
evidence. It refuses by name, and never guesses, when the binding is not `objectstorage`, carries
|
|
3542
|
+
no canonical bucket, or declares retention without `evidence`: a bucket whose immutability is not
|
|
3543
|
+
proven yet must not be handed to its workload as if it were ordinary storage, so the workload
|
|
3544
|
+
waits for the evidence. The evidence is validated with `validateObjectStorageRetentionEvidence()`
|
|
3545
|
+
against the binding's own service, binding id, bucket and intent, and the reconciliation
|
|
3546
|
+
generation and request digest it states. The split helpers are
|
|
3547
|
+
`createObjectStorageEndpointEnvironment(endpoint, bucketName)` and
|
|
3548
|
+
`createObjectStorageRetentionEnvironment(evidence, expectation)`.
|
|
3549
|
+
`mergeObjectStorageBindingEnvironment(environment, bindingEnvironment)` adds one binding's names
|
|
3550
|
+
to a workload environment and refuses, naming every key, a name that is already set — by the
|
|
3551
|
+
service itself or by a second object-storage binding — instead of letting one value replace
|
|
3552
|
+
another.
|
|
3553
|
+
|
|
3554
|
+
**Validating.** `validateObjectStorageBindingEnvironment()` accepts exactly the endpoint names and
|
|
3555
|
+
all or none of the retention names, each value the one its endpoint and evidence derive, and
|
|
3556
|
+
refuses any other name — so a credential alias in the public environment is refused by name.
|
|
3557
|
+
`validateObjectStorageEndpointEnvironment()` and `validateObjectStorageRetentionEnvironment()`
|
|
3558
|
+
judge each half on its own. The environment does not carry the evidence's authority, so
|
|
3559
|
+
validating it checks what a workload reads, not the proof behind it.
|
|
3560
|
+
|
|
3446
3561
|
### Launcher Environment Delivery
|
|
3447
3562
|
|
|
3448
3563
|
Launcher environment delivery uses stable `szsv-<base32-sha256>` Docker
|
|
@@ -3484,6 +3599,8 @@ Available platform modules:
|
|
|
3484
3599
|
- `platform.objectstorageretention` for value-free immutable-retention intent,
|
|
3485
3600
|
capability and sentinel evidence, authority binding, digest helpers, and
|
|
3486
3601
|
strict validators.
|
|
3602
|
+
- `platform.objectstorageenvironment` for the non-secret workload environment of an
|
|
3603
|
+
object-storage binding; see Object-Storage Binding Environment.
|
|
3487
3604
|
- `platform.storagemigration` for fenced object-storage migration intent, status, consumer acknowledgements, canonical digests, and strict normalizers.
|
|
3488
3605
|
- `platform.types` provider and binding metadata is value-free. Provider-specific
|
|
3489
3606
|
operational config stays adapter-internal, while public DTOs expose typed
|
package/ts/00_commitinfo_data.ts
CHANGED
package/ts/data/clusternode.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as plugins from '../plugins.js';
|
|
2
2
|
import { isSha256Digest, type TSha256Digest, type TImmutableContainerPlatform } from './immutableimage.js';
|
|
3
3
|
import type { ISparkNodeReportRecord } from './sparknodereport.js';
|
|
4
|
+
import type { IPlatformObjectStorageEndpoint } from '../platform/objectstorage.js';
|
|
4
5
|
import {
|
|
5
6
|
fleetCutoverContract,
|
|
6
7
|
snapshotFleetCutoverPreparedVolumeHandoffAggregate,
|
|
@@ -1773,6 +1774,21 @@ export interface IClusterNode {
|
|
|
1773
1774
|
* while Docker Swarm resolved it is exactly what stops resolving.
|
|
1774
1775
|
*/
|
|
1775
1776
|
corestore?: IClusterNodeCorestore;
|
|
1777
|
+
|
|
1778
|
+
/**
|
|
1779
|
+
* Where a workload on this node reaches the node's Corestore object storage, and the region
|
|
1780
|
+
* it signs for.
|
|
1781
|
+
*
|
|
1782
|
+
* Cloudly owns it, sets it with `setClusterNodeCorestoreObjectStorageEndpoint`, and composes
|
|
1783
|
+
* it into the environment of every object-storage binding placed on this node with
|
|
1784
|
+
* `createObjectStorageBindingEnvironment()`. It is a sibling of `corestore`, not a member:
|
|
1785
|
+
* the control API and the S3 API listen on different ports and have different readers — the
|
|
1786
|
+
* relay dials `corestore`, a workload dials this — and `corestore` keeps its exact schema.
|
|
1787
|
+
* Absent means no object-storage environment can be composed for this node, and a binding's
|
|
1788
|
+
* workload waits rather than being handed a guessed port, scheme or region. Value-free like
|
|
1789
|
+
* `corestore`: it says where, never with what.
|
|
1790
|
+
*/
|
|
1791
|
+
corestoreObjectStorage?: IPlatformObjectStorageEndpoint;
|
|
1776
1792
|
};
|
|
1777
1793
|
}
|
|
1778
1794
|
|
|
@@ -1789,7 +1805,7 @@ export interface IClusterNode {
|
|
|
1789
1805
|
export interface IClusterNodeCorestore {
|
|
1790
1806
|
/**
|
|
1791
1807
|
* The canonical origin of the control API, for example
|
|
1792
|
-
* `http://
|
|
1808
|
+
* `http://192.0.2.15:3000`.
|
|
1793
1809
|
*
|
|
1794
1810
|
* `http:` is admitted because Corestore terminates no TLS today — it binds a
|
|
1795
1811
|
* plain control port and advertises no transport-encryption guarantee — and
|
|
@@ -42,12 +42,17 @@ export type TCorestoreLegacyCapability = 'database' | 'objectstorage';
|
|
|
42
42
|
* - `ordinary-credentials-rotated`: its credentials were rotated, so the delivered ones are no
|
|
43
43
|
* longer the generation a binding adopts;
|
|
44
44
|
* - `owned-by-binding`: a credential binding or a named storage binding already owns the service
|
|
45
|
-
* capability, the resource or the bucket
|
|
45
|
+
* capability, the resource or the bucket;
|
|
46
|
+
* - `fence-lineage-conflict`: the bucket's object-storage fence lineage cannot move to the adopting
|
|
47
|
+
* binding, because the bucket has more than one lineage, or its lineage does not validate,
|
|
48
|
+
* belongs to another authority or has an unfinished mutation. Only a bucket has a fence lineage,
|
|
49
|
+
* so a database never names it.
|
|
46
50
|
*/
|
|
47
51
|
export type TCorestoreLegacyResourceBlocker =
|
|
48
52
|
| 'not-adoptable'
|
|
49
53
|
| 'ordinary-credentials-rotated'
|
|
50
|
-
| 'owned-by-binding'
|
|
54
|
+
| 'owned-by-binding'
|
|
55
|
+
| 'fence-lineage-conflict';
|
|
51
56
|
|
|
52
57
|
/**
|
|
53
58
|
* `unadopted` names what would stop the offline adoption, or `null` when nothing would;
|
|
@@ -155,7 +160,7 @@ const identifierPattern = /^[A-Za-z0-9][A-Za-z0-9:._-]{0,199}$/;
|
|
|
155
160
|
const printableNamePattern = /^[\x21-\x7e]+$/;
|
|
156
161
|
const bareSha256Pattern = /^[a-f0-9]{64}$/;
|
|
157
162
|
const blockers: readonly TCorestoreLegacyResourceBlocker[] = [
|
|
158
|
-
'not-adoptable', 'ordinary-credentials-rotated', 'owned-by-binding',
|
|
163
|
+
'not-adoptable', 'ordinary-credentials-rotated', 'owned-by-binding', 'fence-lineage-conflict',
|
|
159
164
|
];
|
|
160
165
|
|
|
161
166
|
const isIdentifier = (valueArg: unknown): valueArg is string => (
|
|
@@ -172,13 +177,18 @@ const isCapability = (valueArg: unknown): valueArg is TCorestoreLegacyCapability
|
|
|
172
177
|
valueArg === 'database' || valueArg === 'objectstorage'
|
|
173
178
|
);
|
|
174
179
|
|
|
175
|
-
const validateAdoption = (
|
|
180
|
+
const validateAdoption = (
|
|
181
|
+
valueArg: unknown, capabilityArg: TCorestoreLegacyCapability, pathArg: string,
|
|
182
|
+
): string[] => {
|
|
176
183
|
if (!isPlainRecord(valueArg)) return [`${pathArg} must use its exact schema`];
|
|
177
184
|
if (valueArg.state === 'unadopted') {
|
|
178
185
|
if (!hasExactKeys(valueArg, ['state', 'blocker'])) return [`${pathArg} must use its exact schema`];
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
186
|
+
if (valueArg.blocker !== null && !(blockers as readonly unknown[]).includes(valueArg.blocker)) {
|
|
187
|
+
return [`${pathArg} blocker must be null or a named blocker`];
|
|
188
|
+
}
|
|
189
|
+
return valueArg.blocker === 'fence-lineage-conflict' && capabilityArg !== 'objectstorage'
|
|
190
|
+
? [`${pathArg} blocker fence-lineage-conflict must name a bucket`]
|
|
191
|
+
: [];
|
|
182
192
|
}
|
|
183
193
|
if (valueArg.state === 'authorized') {
|
|
184
194
|
if (!hasExactKeys(valueArg, ['state', 'bindingId'])) return [`${pathArg} must use its exact schema`];
|
|
@@ -198,7 +208,7 @@ const validateResource = (valueArg: unknown, pathArg: string): string[] => {
|
|
|
198
208
|
if (!hasExactKeys(valueArg, ['capability', 'databaseName', 'adoption'])) {
|
|
199
209
|
return [`${pathArg} must use its exact schema`];
|
|
200
210
|
}
|
|
201
|
-
const errors = validateAdoption(valueArg.adoption, `${pathArg} adoption`);
|
|
211
|
+
const errors = validateAdoption(valueArg.adoption, 'database', `${pathArg} adoption`);
|
|
202
212
|
if (!isLegacyName(valueArg.databaseName)) errors.push(`${pathArg} databaseName must be a bounded printable name`);
|
|
203
213
|
return errors;
|
|
204
214
|
}
|
|
@@ -206,7 +216,7 @@ const validateResource = (valueArg: unknown, pathArg: string): string[] => {
|
|
|
206
216
|
if (!hasExactKeys(valueArg, ['capability', 'bucketName', 'retention', 'adoption'])) {
|
|
207
217
|
return [`${pathArg} must use its exact schema`];
|
|
208
218
|
}
|
|
209
|
-
const errors = validateAdoption(valueArg.adoption, `${pathArg} adoption`);
|
|
219
|
+
const errors = validateAdoption(valueArg.adoption, 'objectstorage', `${pathArg} adoption`);
|
|
210
220
|
if (!isLegacyName(valueArg.bucketName)) {
|
|
211
221
|
errors.push(`${pathArg} bucketName must be a bounded printable name`);
|
|
212
222
|
} else if (errors.length === 0 && isAdoptable(valueArg.adoption)) {
|