@serve.zone/interfaces 32.35.0 → 32.36.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 +63 -0
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/data/backup.d.ts +7 -1
- package/dist_ts/data/deploymentlegacyimport.d.ts +92 -0
- package/dist_ts/data/deploymentlegacyimport.js +237 -0
- package/dist_ts/data/deploymentoperation.d.ts +63 -38
- package/dist_ts/data/deploymentoperation.js +12 -2
- package/dist_ts/data/deploymentpreflight.d.ts +42 -10
- package/dist_ts/data/deploymentpreflight.js +47 -10
- package/dist_ts/data/immutableimage.d.ts +26 -2
- package/dist_ts/data/immutableimage.js +12 -2
- package/dist_ts/data/index.d.ts +5 -0
- package/dist_ts/data/index.js +6 -1
- package/dist_ts/data/runtimeassignmentexec.d.ts +110 -0
- package/dist_ts/data/runtimeassignmentexec.js +164 -0
- package/dist_ts/data/runtimeassignmentlogs.d.ts +121 -0
- package/dist_ts/data/runtimeassignmentlogs.js +139 -0
- package/dist_ts/data/runtimeassignmentstats.d.ts +60 -0
- package/dist_ts/data/runtimeassignmentstats.js +93 -0
- package/dist_ts/data/runtimelocalvolumearchive.d.ts +103 -0
- package/dist_ts/data/runtimelocalvolumearchive.js +111 -0
- package/dist_ts/data/user.d.ts +6 -1
- package/dist_ts/data/user.js +6 -1
- package/dist_ts/requests/runtimesession.d.ts +81 -0
- package/dist_ts/requests/service.d.ts +51 -0
- package/package.json +1 -1
- package/readme.md +105 -0
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/data/backup.ts +7 -1
- package/ts/data/deploymentlegacyimport.ts +371 -0
- package/ts/data/deploymentoperation.ts +83 -39
- package/ts/data/deploymentpreflight.ts +86 -18
- package/ts/data/immutableimage.ts +42 -3
- package/ts/data/index.ts +5 -0
- package/ts/data/runtimeassignmentexec.ts +271 -0
- package/ts/data/runtimeassignmentlogs.ts +249 -0
- package/ts/data/runtimeassignmentstats.ts +149 -0
- package/ts/data/runtimelocalvolumearchive.ts +207 -0
- package/ts/data/user.ts +10 -0
- package/ts/requests/runtimesession.ts +102 -0
- package/ts/requests/service.ts +66 -0
|
@@ -2,6 +2,8 @@ import type { IDeploymentPreflightProposedConfiguration, IDeploymentPreflightRun
|
|
|
2
2
|
import type { IGatewayRouteDnsResult } from './gateway.js';
|
|
3
3
|
import type { IImageRolloutStatus, IImmutableImageDeploymentPlan, TSha256Digest } from './immutableimage.js';
|
|
4
4
|
import { normalizeImmutableReleaseTag, normalizeSha256Digest } from './immutableimage.js';
|
|
5
|
+
import type { ILegacyImageImportReference } from './deploymentlegacyimport.js';
|
|
6
|
+
import { validateLegacyImageImportReference } from './deploymentlegacyimport.js';
|
|
5
7
|
import type { IRegistryTarget } from './registry.js';
|
|
6
8
|
import { hasExactKeys } from '../private/dataproperties.js';
|
|
7
9
|
import { normalizeServiceAbsolutePath, validateServiceContainerArgs } from './service.js';
|
|
@@ -14,7 +16,6 @@ interface IDeploymentReservationInputBase {
|
|
|
14
16
|
organizationId: string;
|
|
15
17
|
serviceId: string;
|
|
16
18
|
idempotencyKey: string;
|
|
17
|
-
sourceRevision: string;
|
|
18
19
|
version: string;
|
|
19
20
|
intentDigest: TSha256Digest;
|
|
20
21
|
proposedConfiguration: IDeploymentPreflightProposedConfiguration;
|
|
@@ -22,15 +23,38 @@ interface IDeploymentReservationInputBase {
|
|
|
22
23
|
routes: IDeploymentRouteRequest[];
|
|
23
24
|
}
|
|
24
25
|
|
|
26
|
+
/** A deployment whose image its deployer builds and pushes from one source revision. */
|
|
27
|
+
interface ISourceDeploymentOrigin {
|
|
28
|
+
sourceRevision: string;
|
|
29
|
+
legacyImport?: never;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* A greenfield deployment whose image Cloudly imports from an attested legacy service instead:
|
|
34
|
+
* there is no source revision, so none is stated.
|
|
35
|
+
*/
|
|
36
|
+
interface ILegacyImportDeploymentOrigin {
|
|
37
|
+
legacyImport: ILegacyImageImportReference;
|
|
38
|
+
sourceRevision?: never;
|
|
39
|
+
}
|
|
40
|
+
|
|
25
41
|
export interface IExistingServiceDeploymentReservationInput
|
|
26
|
-
extends IDeploymentReservationInputBase {
|
|
42
|
+
extends IDeploymentReservationInputBase, ISourceDeploymentOrigin {
|
|
27
43
|
mode: 'existing-service';
|
|
28
44
|
expectedRolloutGeneration: number;
|
|
29
45
|
expectedCurrentRolloutId?: string;
|
|
30
46
|
}
|
|
31
47
|
|
|
32
48
|
export interface IGreenfieldServiceDeploymentReservationInput
|
|
33
|
-
extends IDeploymentReservationInputBase {
|
|
49
|
+
extends IDeploymentReservationInputBase, ISourceDeploymentOrigin {
|
|
50
|
+
mode: 'greenfield';
|
|
51
|
+
expectedRolloutGeneration?: never;
|
|
52
|
+
expectedCurrentRolloutId?: never;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** A greenfield successor slot whose image is a legacy service's attested image. */
|
|
56
|
+
export interface ILegacyImportServiceDeploymentReservationInput
|
|
57
|
+
extends IDeploymentReservationInputBase, ILegacyImportDeploymentOrigin {
|
|
34
58
|
mode: 'greenfield';
|
|
35
59
|
expectedRolloutGeneration?: never;
|
|
36
60
|
expectedCurrentRolloutId?: never;
|
|
@@ -38,7 +62,8 @@ extends IDeploymentReservationInputBase {
|
|
|
38
62
|
|
|
39
63
|
export type IDeploymentReservationInput =
|
|
40
64
|
| IExistingServiceDeploymentReservationInput
|
|
41
|
-
| IGreenfieldServiceDeploymentReservationInput
|
|
65
|
+
| IGreenfieldServiceDeploymentReservationInput
|
|
66
|
+
| ILegacyImportServiceDeploymentReservationInput;
|
|
42
67
|
|
|
43
68
|
export type TDeploymentOperationState =
|
|
44
69
|
| 'reserving'
|
|
@@ -240,7 +265,15 @@ export const validateDeploymentReservationInput = (inputArg: unknown): string[]
|
|
|
240
265
|
errors.push(`${field} must be a bounded canonical identifier`);
|
|
241
266
|
}
|
|
242
267
|
}
|
|
243
|
-
if (
|
|
268
|
+
if (inputArg.legacyImport !== undefined) {
|
|
269
|
+
errors.push(...validateLegacyImageImportReference(inputArg.legacyImport));
|
|
270
|
+
if (inputArg.mode !== 'greenfield') {
|
|
271
|
+
errors.push('a legacy import reserves a greenfield successor');
|
|
272
|
+
}
|
|
273
|
+
if (inputArg.sourceRevision !== undefined) {
|
|
274
|
+
errors.push('a legacy import has no source revision');
|
|
275
|
+
}
|
|
276
|
+
} else if (typeof inputArg.sourceRevision !== 'string'
|
|
244
277
|
|| !fullGitRevisionRegex.test(inputArg.sourceRevision)) {
|
|
245
278
|
errors.push('sourceRevision must be a full lowercase git revision');
|
|
246
279
|
}
|
|
@@ -394,40 +427,51 @@ export interface IDeploymentOperationFailure {
|
|
|
394
427
|
export interface IServiceDeploymentOperation {
|
|
395
428
|
id: string;
|
|
396
429
|
revision: number;
|
|
397
|
-
data:
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
430
|
+
data: IServiceDeploymentOperationData;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* An operation's durable state. It states where its image comes from exactly as its reservation
|
|
435
|
+
* did: a `sourceRevision` for an image its deployer builds, or a `legacyImport` (greenfield only)
|
|
436
|
+
* for a legacy service's attested image Cloudly imports.
|
|
437
|
+
*/
|
|
438
|
+
export type IServiceDeploymentOperationData = IServiceDeploymentOperationStateData & (
|
|
439
|
+
| ISourceDeploymentOrigin
|
|
440
|
+
| ILegacyImportDeploymentOrigin
|
|
441
|
+
);
|
|
442
|
+
|
|
443
|
+
interface IServiceDeploymentOperationStateData {
|
|
444
|
+
mode: TDeploymentOperationMode;
|
|
445
|
+
organizationId: string;
|
|
446
|
+
serviceId: string;
|
|
447
|
+
actorUserId: string;
|
|
448
|
+
idempotencyKey: string;
|
|
449
|
+
requestDigest: TSha256Digest;
|
|
450
|
+
version: string;
|
|
451
|
+
intentDigest: TSha256Digest;
|
|
452
|
+
configurationDigest: TSha256Digest;
|
|
453
|
+
proposedConfiguration: IDeploymentPreflightProposedConfiguration;
|
|
454
|
+
namespace: string;
|
|
455
|
+
registryTarget: IRegistryTarget;
|
|
456
|
+
releaseTag: string;
|
|
457
|
+
routes: IDeploymentRouteRequest[];
|
|
458
|
+
claimKeys: string[];
|
|
459
|
+
state: TDeploymentOperationState;
|
|
460
|
+
releaseId?: string;
|
|
461
|
+
registryRootDigest?: TSha256Digest;
|
|
462
|
+
rolloutId?: string;
|
|
463
|
+
rolloutGeneration?: number;
|
|
464
|
+
routeGeneration?: number;
|
|
465
|
+
routeVerification?: IDeploymentRouteVerificationEvidence[];
|
|
466
|
+
/**
|
|
467
|
+
* Most recent failure record. Set when the operation fails and retained
|
|
468
|
+
* as audit history through 'cleaning' and 'cleaned'; cleared only by a
|
|
469
|
+
* forward transition such as a successful retry. A populated failure does
|
|
470
|
+
* therefore NOT imply state === 'failed'.
|
|
471
|
+
*/
|
|
472
|
+
failure?: IDeploymentOperationFailure;
|
|
473
|
+
createdAt: number;
|
|
474
|
+
updatedAt: number;
|
|
431
475
|
}
|
|
432
476
|
|
|
433
477
|
export interface IServiceDeploymentStatus {
|
|
@@ -5,6 +5,8 @@ import type {
|
|
|
5
5
|
} from './immutableimage.js';
|
|
6
6
|
import { normalizeImmutableReleaseTag, normalizeSha256Digest } from './immutableimage.js';
|
|
7
7
|
import type { TServiceDeploymentCapability } from './user.js';
|
|
8
|
+
import type { ILegacyImageImportReference } from './deploymentlegacyimport.js';
|
|
9
|
+
import { validateLegacyImageImportReference } from './deploymentlegacyimport.js';
|
|
8
10
|
import { validateProtocolOfferOn, type IProtocolOffer } from '../protocol.js';
|
|
9
11
|
import type {
|
|
10
12
|
IDeploymentRouteRequest,
|
|
@@ -84,6 +86,19 @@ export const deploymentPreflightBlockerCodes = [
|
|
|
84
86
|
'RELAY_NAME_RESERVED',
|
|
85
87
|
'ROUTE_VERIFICATION_FAILED',
|
|
86
88
|
'TLS_VERIFICATION_FAILED',
|
|
89
|
+
/**
|
|
90
|
+
* A legacy import names no attestation Cloudly holds for that legacy service in the requested
|
|
91
|
+
* organization. Evidence is captured only while the legacy runtime runs, so there is no later
|
|
92
|
+
* substitute for a missing one.
|
|
93
|
+
*/
|
|
94
|
+
'LEGACY_IMPORT_ATTESTATION_MISSING',
|
|
95
|
+
/**
|
|
96
|
+
* The attested legacy image is no longer what the request or the registry states: the asserted
|
|
97
|
+
* root digest differs, the legacy tag moved, or a manifest the attestation names is gone.
|
|
98
|
+
*/
|
|
99
|
+
'LEGACY_IMPORT_SOURCE_MISMATCH',
|
|
100
|
+
/** The declared target platforms are not exactly the platforms the attested image carries. */
|
|
101
|
+
'LEGACY_IMPORT_PLATFORM_MISMATCH',
|
|
87
102
|
] as const;
|
|
88
103
|
|
|
89
104
|
export type TDeploymentPreflightBlockerCode = typeof deploymentPreflightBlockerCodes[number];
|
|
@@ -93,7 +108,9 @@ export interface IDeploymentPreflightBlocker {
|
|
|
93
108
|
message: string;
|
|
94
109
|
}
|
|
95
110
|
|
|
96
|
-
export type TDeploymentPreflightWarningCode =
|
|
111
|
+
export type TDeploymentPreflightWarningCode =
|
|
112
|
+
| 'RECOVERY_REDEPLOY_OVER_FAILED_RUNTIME'
|
|
113
|
+
| 'PLATFORM_BINDING_READINESS_DEFERRED';
|
|
97
114
|
|
|
98
115
|
/**
|
|
99
116
|
* Auditable non-blocking preflight finding. Warnings never veto a decision.
|
|
@@ -102,7 +119,16 @@ export type TDeploymentPreflightWarningCode = 'RECOVERY_REDEPLOY_OVER_FAILED_RUN
|
|
|
102
119
|
* RUNTIME_ATTESTATION_MISMATCH blockers because the current runtime provides
|
|
103
120
|
* no consistent attested digest and the service's most recent deployment
|
|
104
121
|
* operation ended 'failed' or 'cleaned' (a recovery redeploy over a known-bad
|
|
105
|
-
* runtime).
|
|
122
|
+
* runtime).
|
|
123
|
+
* `PLATFORM_BINDING_READINESS_DEFERRED` documents that the promote preflight
|
|
124
|
+
* of a held greenfield service that was never promoted accepted a Corestore
|
|
125
|
+
* `database` or `objectstorage` binding that is enabled but not yet `ready`.
|
|
126
|
+
* A held service receives no credential material, so its binding can become
|
|
127
|
+
* ready only after promotion releases the hold; for a binding that adopts a
|
|
128
|
+
* legacy resource the Corestore inventory proved the resource authorized for
|
|
129
|
+
* exactly that binding. The route preflight still requires the binding
|
|
130
|
+
* `ready`, so no traffic reaches the service before its binding is.
|
|
131
|
+
* No other blocker is ever relaxed.
|
|
106
132
|
*/
|
|
107
133
|
export interface IDeploymentPreflightWarning {
|
|
108
134
|
code: TDeploymentPreflightWarningCode;
|
|
@@ -193,21 +219,39 @@ export interface IDeploymentReleaseEvidence {
|
|
|
193
219
|
attestations: IDeploymentReleaseEvidenceReference[];
|
|
194
220
|
}
|
|
195
221
|
|
|
196
|
-
|
|
222
|
+
/**
|
|
223
|
+
* A preflight states where the deployment's image comes from, exactly as its reservation will:
|
|
224
|
+
* a clean source revision with its release evidence, or — for a greenfield successor only — a
|
|
225
|
+
* legacy import naming an attested legacy image, which has no revision, worktree or build
|
|
226
|
+
* evidence to state.
|
|
227
|
+
*/
|
|
228
|
+
export type IDeploymentPreflightRequestData = IDeploymentPreflightRequestDataBase & (
|
|
229
|
+
| {
|
|
230
|
+
sourceRevision: string;
|
|
231
|
+
sourceDirty: boolean;
|
|
232
|
+
releaseEvidence?: IDeploymentReleaseEvidence;
|
|
233
|
+
legacyImport?: never;
|
|
234
|
+
}
|
|
235
|
+
| {
|
|
236
|
+
legacyImport: ILegacyImageImportReference;
|
|
237
|
+
sourceRevision?: never;
|
|
238
|
+
sourceDirty?: never;
|
|
239
|
+
releaseEvidence?: never;
|
|
240
|
+
}
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
interface IDeploymentPreflightRequestDataBase {
|
|
197
244
|
requestId: string;
|
|
198
245
|
serviceId: string;
|
|
199
246
|
organizationId?: string;
|
|
200
247
|
mode?: TDeploymentOperationMode;
|
|
201
248
|
phase?: TDeploymentOperationPhase;
|
|
202
249
|
operationId?: string;
|
|
203
|
-
sourceRevision: string;
|
|
204
|
-
sourceDirty: boolean;
|
|
205
250
|
version: string;
|
|
206
251
|
intentDigest: string;
|
|
207
252
|
proposedConfiguration: IDeploymentPreflightProposedConfiguration;
|
|
208
253
|
ociIndexDigest?: string;
|
|
209
254
|
releaseTag?: string;
|
|
210
|
-
releaseEvidence?: IDeploymentReleaseEvidence;
|
|
211
255
|
routes?: IDeploymentRouteRequest[];
|
|
212
256
|
/** Legacy v14 discriminator. Equivalent to mode: 'greenfield'. */
|
|
213
257
|
greenfield?: true;
|
|
@@ -249,13 +293,15 @@ export interface IDeploymentPreflightReport {
|
|
|
249
293
|
mode?: TDeploymentOperationMode;
|
|
250
294
|
phase?: TDeploymentOperationPhase;
|
|
251
295
|
operation?: IServiceDeploymentOperation;
|
|
296
|
+
/** The request's image origin as judged: a source revision, or a legacy import. */
|
|
252
297
|
source: {
|
|
253
|
-
revision: string;
|
|
254
|
-
dirty: boolean;
|
|
255
298
|
version: string;
|
|
256
299
|
intentDigest: TSha256Digest;
|
|
257
300
|
configurationDigest: TSha256Digest;
|
|
258
|
-
}
|
|
301
|
+
} & (
|
|
302
|
+
| { revision: string; dirty: boolean; legacyImport?: never }
|
|
303
|
+
| { legacyImport: ILegacyImageImportReference; revision?: never; dirty?: never }
|
|
304
|
+
);
|
|
259
305
|
currentImage: {
|
|
260
306
|
tag?: string;
|
|
261
307
|
digest?: TSha256Digest;
|
|
@@ -339,16 +385,35 @@ export const validateDeploymentPreflightRequest = (
|
|
|
339
385
|
if (typeof requestArg.serviceId !== 'string' || !requestArg.serviceId.trim() || requestArg.serviceId.length > 200) {
|
|
340
386
|
blockers.push({ code: 'INVALID_REQUEST', message: 'A bounded service identifier is required.' });
|
|
341
387
|
}
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
388
|
+
const legacyImport = requestArg.legacyImport !== undefined;
|
|
389
|
+
if (legacyImport) {
|
|
390
|
+
const referenceErrors = validateLegacyImageImportReference(requestArg.legacyImport);
|
|
391
|
+
if (referenceErrors.length > 0) {
|
|
392
|
+
blockers.push({
|
|
393
|
+
code: 'INVALID_REQUEST',
|
|
394
|
+
message: `The legacy import reference is malformed: ${referenceErrors.join('; ')}.`,
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
if (requestArg.sourceRevision !== undefined
|
|
398
|
+
|| requestArg.sourceDirty !== undefined
|
|
399
|
+
|| requestArg.releaseEvidence !== undefined) {
|
|
400
|
+
blockers.push({
|
|
401
|
+
code: 'INVALID_REQUEST',
|
|
402
|
+
message: 'A legacy import states no source revision, worktree state or release evidence.',
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
} else {
|
|
406
|
+
if (typeof requestArg.sourceRevision !== 'string' || !fullGitRevisionRegex.test(requestArg.sourceRevision)) {
|
|
407
|
+
blockers.push({ code: 'SOURCE_REVISION_INVALID', message: 'Source revision must be a full lower-case Git commit SHA.' });
|
|
408
|
+
if (typeof requestArg.sourceRevision !== 'string') {
|
|
409
|
+
blockers.push({ code: 'INVALID_REQUEST', message: 'Source revision is malformed.' });
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
if (typeof requestArg.sourceDirty !== 'boolean') {
|
|
413
|
+
blockers.push({ code: 'INVALID_REQUEST', message: 'Source worktree state must be reported.' });
|
|
414
|
+
} else if (requestArg.sourceDirty) {
|
|
415
|
+
blockers.push({ code: 'SOURCE_WORKTREE_DIRTY', message: 'The source worktree contains uncommitted changes.' });
|
|
346
416
|
}
|
|
347
|
-
}
|
|
348
|
-
if (typeof requestArg.sourceDirty !== 'boolean') {
|
|
349
|
-
blockers.push({ code: 'INVALID_REQUEST', message: 'Source worktree state must be reported.' });
|
|
350
|
-
} else if (requestArg.sourceDirty) {
|
|
351
|
-
blockers.push({ code: 'SOURCE_WORKTREE_DIRTY', message: 'The source worktree contains uncommitted changes.' });
|
|
352
417
|
}
|
|
353
418
|
if (typeof requestArg.version !== 'string'
|
|
354
419
|
|| requestArg.version.length > 100
|
|
@@ -397,6 +462,9 @@ export const validateDeploymentPreflightRequest = (
|
|
|
397
462
|
&& (requestArg.greenfield !== true || mode !== 'greenfield')) {
|
|
398
463
|
blockers.push({ code: 'INVALID_REQUEST', message: 'Legacy greenfield mode is contradictory.' });
|
|
399
464
|
}
|
|
465
|
+
if (legacyImport && mode !== 'greenfield') {
|
|
466
|
+
blockers.push({ code: 'INVALID_REQUEST', message: 'A legacy import reserves a greenfield successor.' });
|
|
467
|
+
}
|
|
400
468
|
if (requestArg.phase !== undefined
|
|
401
469
|
&& requestArg.phase !== 'reserve'
|
|
402
470
|
&& requestArg.phase !== 'promote'
|
|
@@ -173,8 +173,7 @@ export interface IImageRelease {
|
|
|
173
173
|
};
|
|
174
174
|
}
|
|
175
175
|
|
|
176
|
-
|
|
177
|
-
source: 'cloudly-registry';
|
|
176
|
+
interface IImageReleaseTrustedEvidenceBase {
|
|
178
177
|
/** Deterministic ID for an authenticated registry acceptance event/retry. */
|
|
179
178
|
evidenceId: string;
|
|
180
179
|
operationId: string;
|
|
@@ -187,6 +186,30 @@ export interface IImageReleaseTrustedEvidence {
|
|
|
187
186
|
recordedAt: number;
|
|
188
187
|
}
|
|
189
188
|
|
|
189
|
+
/** The deployment machine user's own authenticated registry push to its operation's tag. */
|
|
190
|
+
export interface IImageReleaseRegistryPushEvidence extends IImageReleaseTrustedEvidenceBase {
|
|
191
|
+
source: 'cloudly-registry';
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Cloudly's own import of an attested legacy image into a legacy-import operation's tag.
|
|
196
|
+
*
|
|
197
|
+
* Nothing was built or pushed: the source fields name the legacy registry root the attestation
|
|
198
|
+
* proved ran, and `registryRootDigest` is that root or the index Cloudly wrapped around it.
|
|
199
|
+
*/
|
|
200
|
+
export interface IImageReleaseLegacyImportEvidence extends IImageReleaseTrustedEvidenceBase {
|
|
201
|
+
source: 'cloudly-legacy-import';
|
|
202
|
+
legacyServiceId: string;
|
|
203
|
+
attestationId: string;
|
|
204
|
+
sourceRepository: string;
|
|
205
|
+
sourceTag: string;
|
|
206
|
+
sourceRootDigest: TSha256Digest;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export type IImageReleaseTrustedEvidence =
|
|
210
|
+
| IImageReleaseRegistryPushEvidence
|
|
211
|
+
| IImageReleaseLegacyImportEvidence;
|
|
212
|
+
|
|
190
213
|
export const selectTrustedImageReleaseEvidence = (argsArg: {
|
|
191
214
|
release: IImageRelease;
|
|
192
215
|
operationId: string;
|
|
@@ -197,7 +220,14 @@ export const selectTrustedImageReleaseEvidence = (argsArg: {
|
|
|
197
220
|
repository: string;
|
|
198
221
|
tag: string;
|
|
199
222
|
digest: TSha256Digest;
|
|
223
|
+
/**
|
|
224
|
+
* The one evidence source the operation's image may have come from: a legacy-import operation
|
|
225
|
+
* accepts only Cloudly's import, every other operation only its actor's registry push. Omitted,
|
|
226
|
+
* it is the registry push, the only source an operation without a legacy import has.
|
|
227
|
+
*/
|
|
228
|
+
evidenceSource?: IImageReleaseTrustedEvidence['source'];
|
|
200
229
|
}): { evidence?: IImageReleaseTrustedEvidence; errors: string[] } => {
|
|
230
|
+
const evidenceSource = argsArg.evidenceSource ?? 'cloudly-registry';
|
|
201
231
|
const evidenceFingerprint = (evidenceArg: IImageReleaseTrustedEvidence) => [
|
|
202
232
|
evidenceArg.source,
|
|
203
233
|
evidenceArg.evidenceId,
|
|
@@ -209,6 +239,15 @@ export const selectTrustedImageReleaseEvidence = (argsArg: {
|
|
|
209
239
|
evidenceArg.registryRootDigest,
|
|
210
240
|
evidenceArg.manifestMediaType,
|
|
211
241
|
evidenceArg.recordedAt,
|
|
242
|
+
...(evidenceArg.source === 'cloudly-legacy-import'
|
|
243
|
+
? [
|
|
244
|
+
evidenceArg.legacyServiceId,
|
|
245
|
+
evidenceArg.attestationId,
|
|
246
|
+
evidenceArg.sourceRepository,
|
|
247
|
+
evidenceArg.sourceTag,
|
|
248
|
+
evidenceArg.sourceRootDigest,
|
|
249
|
+
]
|
|
250
|
+
: []),
|
|
212
251
|
].join('\u0000');
|
|
213
252
|
const uniqueEvidence = new Map<string, IImageReleaseTrustedEvidence>();
|
|
214
253
|
const errors: string[] = [];
|
|
@@ -221,7 +260,7 @@ export const selectTrustedImageReleaseEvidence = (argsArg: {
|
|
|
221
260
|
}
|
|
222
261
|
}
|
|
223
262
|
const evidenceMatches = [...uniqueEvidence.values()].filter((evidenceArg) => (
|
|
224
|
-
evidenceArg.source ===
|
|
263
|
+
evidenceArg.source === evidenceSource
|
|
225
264
|
&& evidenceArg.operationId === argsArg.operationId
|
|
226
265
|
&& evidenceArg.actorUserId === argsArg.actorUserId
|
|
227
266
|
&& evidenceArg.registryHost === argsArg.registryHost
|
package/ts/data/index.ts
CHANGED
|
@@ -12,6 +12,7 @@ export * from './coremail.js';
|
|
|
12
12
|
export * from './coremail.runtime.js';
|
|
13
13
|
export * from './deployment.js';
|
|
14
14
|
export * from './deploymentadoption.js';
|
|
15
|
+
export * from './deploymentlegacyimport.js';
|
|
15
16
|
export * from './deploymentmachineuser.js';
|
|
16
17
|
export * from './deploymentoperation.js';
|
|
17
18
|
export * from './deploymentpreflight.js';
|
|
@@ -52,9 +53,13 @@ export * from './privatenetwork.js';
|
|
|
52
53
|
export * from './registry.js';
|
|
53
54
|
export * from './releaseversion.js';
|
|
54
55
|
export * from './runtimeassignment.js';
|
|
56
|
+
export * from './runtimeassignmentexec.js';
|
|
57
|
+
export * from './runtimeassignmentlogs.js';
|
|
58
|
+
export * from './runtimeassignmentstats.js';
|
|
55
59
|
export * from './runtimeconfig.js';
|
|
56
60
|
export * from './runtimestorageclaim.js';
|
|
57
61
|
export * from './runtimelocalstorageclaim.js';
|
|
62
|
+
export * from './runtimelocalvolumearchive.js';
|
|
58
63
|
export * from './runtimesession.js';
|
|
59
64
|
export * from './runtimeterminalreceipt.js';
|
|
60
65
|
export * from './secret.js';
|