@serve.zone/interfaces 15.0.0 → 16.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/changelog.md +17 -0
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/data/deploymentadoption.d.ts +97 -0
- package/dist_ts/data/deploymentadoption.js +306 -0
- package/dist_ts/data/immutableimage.d.ts +3 -1
- package/dist_ts/data/immutableimage.js +16 -1
- package/dist_ts/data/index.d.ts +1 -0
- package/dist_ts/data/index.js +2 -1
- package/dist_ts/data/user.d.ts +1 -1
- package/dist_ts/data/user.js +6 -1
- package/dist_ts/requests/service.d.ts +20 -0
- package/package.json +1 -1
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/data/deploymentadoption.ts +450 -0
- package/ts/data/immutableimage.ts +17 -1
- package/ts/data/index.ts +1 -0
- package/ts/data/user.ts +6 -0
- package/ts/requests/service.ts +35 -0
package/changelog.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2026-07-20 - 16.0.1
|
|
4
|
+
|
|
5
|
+
### Security
|
|
6
|
+
|
|
7
|
+
- bind existing-service adoption to configuration and no-replacement runtime semantics (deployment)
|
|
8
|
+
- Add an explicit generation-one adoption rollout mode with a complete service configuration digest.
|
|
9
|
+
- Require adoption consumers to retain and attest the exact verified runtime instead of treating adoption as a promotion.
|
|
10
|
+
|
|
11
|
+
## 2026-07-20 - 16.0.0
|
|
12
|
+
|
|
13
|
+
### Breaking Changes
|
|
14
|
+
|
|
15
|
+
- add attested existing-service adoption contracts (deployment)
|
|
16
|
+
- Add a mutation-free adoption preflight and a digest-fenced, idempotent adoption request.
|
|
17
|
+
- Require explicit service-scoped deployment:adopt-existing authority.
|
|
18
|
+
- Bind registry, release, target-scope, and healthy runtime digest evidence before switching a mutable service to immutable rollout state.
|
|
19
|
+
|
|
3
20
|
## 2026-07-20 - 15.0.0
|
|
4
21
|
|
|
5
22
|
### Breaking Changes
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@serve.zone/interfaces',
|
|
6
|
-
version: '
|
|
6
|
+
version: '16.0.1',
|
|
7
7
|
description: 'Shared TypeScript interfaces and TypedRequest contracts for the serve.zone ecosystem.'
|
|
8
8
|
};
|
|
9
9
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSx3QkFBd0I7SUFDOUIsT0FBTyxFQUFFLFFBQVE7SUFDakIsV0FBVyxFQUFFLHVGQUF1RjtDQUNyRyxDQUFBIn0=
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import type { IDeploymentPreflightRuntimeTask, IOciPlatformDescriptorSummary } from './deploymentpreflight.js';
|
|
2
|
+
import type { IImmutableImageDeploymentPlan, IImmutableImageTargetScope, TOciManifestMediaType, TSha256Digest } from './immutableimage.js';
|
|
3
|
+
import type { IRegistryTarget } from './registry.js';
|
|
4
|
+
export type TServiceDeploymentAdoptionDecision = 'GO' | 'NO-GO';
|
|
5
|
+
/**
|
|
6
|
+
* Canonical sha256 hash of the complete adoption preflight snapshot. It is a
|
|
7
|
+
* state/TOCTOU fence and must never be substituted with the OCI image digest.
|
|
8
|
+
*/
|
|
9
|
+
export type TServiceDeploymentAdoptionDigest = TSha256Digest & {
|
|
10
|
+
readonly __serviceDeploymentAdoptionDigest: unique symbol;
|
|
11
|
+
};
|
|
12
|
+
export type TServiceDeploymentAdoptionBlockerCode = 'INVALID_REQUEST' | 'AUTHORIZATION_MISSING' | 'SERVICE_NOT_FOUND' | 'SERVICE_OWNERSHIP_MISMATCH' | 'SERVICE_ALREADY_IMMUTABLE' | 'SERVICE_STATE_CONFLICT' | 'REGISTRY_TARGET_MISSING' | 'REGISTRY_REFERENCE_INVALID' | 'REGISTRY_DIGEST_MISSING' | 'OCI_INDEX_REQUIRED' | 'OCI_PLATFORM_MISSING' | 'RELEASE_NOT_FOUND' | 'RELEASE_TAG_AMBIGUOUS' | 'TARGET_SCOPE_UNAVAILABLE' | 'RUNTIME_ATTESTATION_INCOMPLETE' | 'RUNTIME_DIGEST_MISMATCH';
|
|
13
|
+
export interface IServiceDeploymentAdoptionBlocker {
|
|
14
|
+
code: TServiceDeploymentAdoptionBlockerCode;
|
|
15
|
+
message: string;
|
|
16
|
+
}
|
|
17
|
+
export interface IServiceDeploymentAdoptionPreflightInput {
|
|
18
|
+
requestId: string;
|
|
19
|
+
organizationId: string;
|
|
20
|
+
serviceId: string;
|
|
21
|
+
}
|
|
22
|
+
export interface IServiceDeploymentAdoptionInput extends IServiceDeploymentAdoptionPreflightInput {
|
|
23
|
+
idempotencyKey: string;
|
|
24
|
+
expectedAdoptionDigest: TServiceDeploymentAdoptionDigest;
|
|
25
|
+
}
|
|
26
|
+
interface IServiceDeploymentAdoptionReportBase {
|
|
27
|
+
schemaVersion: 1;
|
|
28
|
+
mutationPerformed: false;
|
|
29
|
+
requestId: string;
|
|
30
|
+
generatedAt: number;
|
|
31
|
+
runtimeAttestation: {
|
|
32
|
+
requiredReplicaCount: number;
|
|
33
|
+
observedReplicaCount: number;
|
|
34
|
+
healthyReplicaCount: number;
|
|
35
|
+
observedDigestReplicaCount: number;
|
|
36
|
+
observedDigestConsistent: boolean;
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
interface IServiceDeploymentAdoptionServiceSnapshot {
|
|
40
|
+
organizationId: string;
|
|
41
|
+
serviceId: string;
|
|
42
|
+
serviceName: string;
|
|
43
|
+
imageId: string;
|
|
44
|
+
deployOnPush: boolean;
|
|
45
|
+
immutableImageRequired: boolean;
|
|
46
|
+
configuredReference: string;
|
|
47
|
+
/** Hash of the complete persisted pre-adoption service configuration. */
|
|
48
|
+
configurationDigest: TSha256Digest;
|
|
49
|
+
registryTarget: IRegistryTarget;
|
|
50
|
+
}
|
|
51
|
+
interface IServiceDeploymentAdoptionRegistrySnapshot {
|
|
52
|
+
tag?: string;
|
|
53
|
+
digest?: TSha256Digest;
|
|
54
|
+
mediaType?: TOciManifestMediaType;
|
|
55
|
+
platforms: IOciPlatformDescriptorSummary[];
|
|
56
|
+
releaseId?: string;
|
|
57
|
+
releaseTag?: string;
|
|
58
|
+
}
|
|
59
|
+
export interface IServiceDeploymentAdoptionGoReport extends IServiceDeploymentAdoptionReportBase {
|
|
60
|
+
decision: 'GO';
|
|
61
|
+
service: IServiceDeploymentAdoptionServiceSnapshot & {
|
|
62
|
+
deployOnPush: true;
|
|
63
|
+
immutableImageRequired: false;
|
|
64
|
+
};
|
|
65
|
+
registry: IServiceDeploymentAdoptionRegistrySnapshot & {
|
|
66
|
+
tag: string;
|
|
67
|
+
digest: TSha256Digest;
|
|
68
|
+
mediaType: 'application/vnd.oci.image.index.v1+json' | 'application/vnd.docker.distribution.manifest.list.v2+json';
|
|
69
|
+
platforms: [IOciPlatformDescriptorSummary, ...IOciPlatformDescriptorSummary[]];
|
|
70
|
+
releaseId: string;
|
|
71
|
+
releaseTag: string;
|
|
72
|
+
};
|
|
73
|
+
runtimeTasks: [IDeploymentPreflightRuntimeTask, ...IDeploymentPreflightRuntimeTask[]];
|
|
74
|
+
targetScope: IImmutableImageTargetScope;
|
|
75
|
+
adoptionDigest: TServiceDeploymentAdoptionDigest;
|
|
76
|
+
blockers: [];
|
|
77
|
+
}
|
|
78
|
+
export interface IServiceDeploymentAdoptionNoGoReport extends IServiceDeploymentAdoptionReportBase {
|
|
79
|
+
decision: 'NO-GO';
|
|
80
|
+
service?: IServiceDeploymentAdoptionServiceSnapshot;
|
|
81
|
+
registry: IServiceDeploymentAdoptionRegistrySnapshot;
|
|
82
|
+
runtimeTasks: IDeploymentPreflightRuntimeTask[];
|
|
83
|
+
targetScope?: IImmutableImageTargetScope;
|
|
84
|
+
adoptionDigest?: never;
|
|
85
|
+
blockers: [IServiceDeploymentAdoptionBlocker, ...IServiceDeploymentAdoptionBlocker[]];
|
|
86
|
+
}
|
|
87
|
+
export type IServiceDeploymentAdoptionReport = IServiceDeploymentAdoptionGoReport | IServiceDeploymentAdoptionNoGoReport;
|
|
88
|
+
export interface IServiceDeploymentAdoptionResult {
|
|
89
|
+
adoptionId: string;
|
|
90
|
+
adoptionDigest: TServiceDeploymentAdoptionDigest;
|
|
91
|
+
idempotentReplay: boolean;
|
|
92
|
+
plan: IImmutableImageDeploymentPlan;
|
|
93
|
+
}
|
|
94
|
+
export declare const validateServiceDeploymentAdoptionPreflightInput: (inputArg: unknown) => string[];
|
|
95
|
+
export declare const validateServiceDeploymentAdoptionInput: (inputArg: unknown) => string[];
|
|
96
|
+
export declare const validateServiceDeploymentAdoptionReport: (reportArg: unknown) => string[];
|
|
97
|
+
export {};
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
import { normalizeImmutableReleaseTag, normalizeSha256Digest } from './immutableimage.js';
|
|
2
|
+
const boundaryIdentifierRegex = /^[A-Za-z0-9][A-Za-z0-9:._-]{0,199}$/;
|
|
3
|
+
const indexMediaTypes = new Set([
|
|
4
|
+
'application/vnd.oci.image.index.v1+json',
|
|
5
|
+
'application/vnd.docker.distribution.manifest.list.v2+json',
|
|
6
|
+
]);
|
|
7
|
+
const adoptionBlockerCodes = new Set([
|
|
8
|
+
'INVALID_REQUEST',
|
|
9
|
+
'AUTHORIZATION_MISSING',
|
|
10
|
+
'SERVICE_NOT_FOUND',
|
|
11
|
+
'SERVICE_OWNERSHIP_MISMATCH',
|
|
12
|
+
'SERVICE_ALREADY_IMMUTABLE',
|
|
13
|
+
'SERVICE_STATE_CONFLICT',
|
|
14
|
+
'REGISTRY_TARGET_MISSING',
|
|
15
|
+
'REGISTRY_REFERENCE_INVALID',
|
|
16
|
+
'REGISTRY_DIGEST_MISSING',
|
|
17
|
+
'OCI_INDEX_REQUIRED',
|
|
18
|
+
'OCI_PLATFORM_MISSING',
|
|
19
|
+
'RELEASE_NOT_FOUND',
|
|
20
|
+
'RELEASE_TAG_AMBIGUOUS',
|
|
21
|
+
'TARGET_SCOPE_UNAVAILABLE',
|
|
22
|
+
'RUNTIME_ATTESTATION_INCOMPLETE',
|
|
23
|
+
'RUNTIME_DIGEST_MISMATCH',
|
|
24
|
+
]);
|
|
25
|
+
const isRecord = (valueArg) => Boolean(valueArg) && typeof valueArg === 'object' && !Array.isArray(valueArg);
|
|
26
|
+
const isBoundedIdentifier = (valueArg) => typeof valueArg === 'string' && boundaryIdentifierRegex.test(valueArg);
|
|
27
|
+
const isCanonicalDigest = (valueArg) => Boolean(normalizeSha256Digest(valueArg)) && normalizeSha256Digest(valueArg) === valueArg;
|
|
28
|
+
const isNonNegativeInteger = (valueArg) => Number.isSafeInteger(valueArg) && valueArg >= 0;
|
|
29
|
+
export const validateServiceDeploymentAdoptionPreflightInput = (inputArg) => {
|
|
30
|
+
if (!isRecord(inputArg))
|
|
31
|
+
return ['adoption preflight input must be an object'];
|
|
32
|
+
const errors = [];
|
|
33
|
+
if (!isBoundedIdentifier(inputArg.requestId)) {
|
|
34
|
+
errors.push('requestId must be a bounded canonical identifier');
|
|
35
|
+
}
|
|
36
|
+
for (const key of ['organizationId', 'serviceId']) {
|
|
37
|
+
if (!isBoundedIdentifier(inputArg[key])) {
|
|
38
|
+
errors.push(`${key} must be a bounded canonical identifier`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return errors;
|
|
42
|
+
};
|
|
43
|
+
export const validateServiceDeploymentAdoptionInput = (inputArg) => {
|
|
44
|
+
const errors = validateServiceDeploymentAdoptionPreflightInput(inputArg);
|
|
45
|
+
if (!isRecord(inputArg))
|
|
46
|
+
return errors;
|
|
47
|
+
if (!isBoundedIdentifier(inputArg.idempotencyKey)) {
|
|
48
|
+
errors.push('idempotencyKey must be a bounded canonical identifier');
|
|
49
|
+
}
|
|
50
|
+
if (!isCanonicalDigest(inputArg.expectedAdoptionDigest)) {
|
|
51
|
+
errors.push('expectedAdoptionDigest must be a canonical sha256 digest');
|
|
52
|
+
}
|
|
53
|
+
return errors;
|
|
54
|
+
};
|
|
55
|
+
export const validateServiceDeploymentAdoptionReport = (reportArg) => {
|
|
56
|
+
if (!isRecord(reportArg))
|
|
57
|
+
return ['adoption report must be an object'];
|
|
58
|
+
const errors = [];
|
|
59
|
+
if (reportArg.schemaVersion !== 1)
|
|
60
|
+
errors.push('schemaVersion must be 1');
|
|
61
|
+
if (reportArg.mutationPerformed !== false) {
|
|
62
|
+
errors.push('adoption preflight must be mutation-free');
|
|
63
|
+
}
|
|
64
|
+
if (!isBoundedIdentifier(reportArg.requestId)) {
|
|
65
|
+
errors.push('requestId must be a bounded canonical identifier');
|
|
66
|
+
}
|
|
67
|
+
if (!isNonNegativeInteger(reportArg.generatedAt)) {
|
|
68
|
+
errors.push('generatedAt must be a non-negative integer');
|
|
69
|
+
}
|
|
70
|
+
if (reportArg.decision !== 'GO' && reportArg.decision !== 'NO-GO') {
|
|
71
|
+
errors.push('decision must be GO or NO-GO');
|
|
72
|
+
}
|
|
73
|
+
const attestation = reportArg.runtimeAttestation;
|
|
74
|
+
if (!isRecord(attestation)) {
|
|
75
|
+
errors.push('runtimeAttestation must be an object');
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
for (const key of [
|
|
79
|
+
'requiredReplicaCount',
|
|
80
|
+
'observedReplicaCount',
|
|
81
|
+
'healthyReplicaCount',
|
|
82
|
+
'observedDigestReplicaCount',
|
|
83
|
+
]) {
|
|
84
|
+
if (!isNonNegativeInteger(attestation[key])) {
|
|
85
|
+
errors.push(`runtimeAttestation.${key} must be a non-negative integer`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (typeof attestation.observedDigestConsistent !== 'boolean') {
|
|
89
|
+
errors.push('runtimeAttestation.observedDigestConsistent must be boolean');
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
const blockers = reportArg.blockers;
|
|
93
|
+
if (!Array.isArray(blockers)) {
|
|
94
|
+
errors.push('blockers must be an array');
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
for (const blocker of blockers) {
|
|
98
|
+
if (!isRecord(blocker)
|
|
99
|
+
|| !adoptionBlockerCodes.has(blocker.code)
|
|
100
|
+
|| typeof blocker.message !== 'string'
|
|
101
|
+
|| !blocker.message.trim()) {
|
|
102
|
+
errors.push('each blocker must contain a supported code and non-empty message');
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (reportArg.decision === 'NO-GO') {
|
|
108
|
+
if (Array.isArray(blockers) && blockers.length === 0) {
|
|
109
|
+
errors.push('a NO-GO report must contain at least one blocker');
|
|
110
|
+
}
|
|
111
|
+
if (reportArg.adoptionDigest !== undefined) {
|
|
112
|
+
errors.push('a NO-GO report must not contain an adoption digest');
|
|
113
|
+
}
|
|
114
|
+
return errors;
|
|
115
|
+
}
|
|
116
|
+
if (reportArg.decision !== 'GO')
|
|
117
|
+
return errors;
|
|
118
|
+
if (Array.isArray(blockers) && blockers.length !== 0) {
|
|
119
|
+
errors.push('a GO report must not contain blockers');
|
|
120
|
+
}
|
|
121
|
+
if (!isCanonicalDigest(reportArg.adoptionDigest)) {
|
|
122
|
+
errors.push('a GO report requires a canonical adoption digest');
|
|
123
|
+
}
|
|
124
|
+
const service = reportArg.service;
|
|
125
|
+
const registry = reportArg.registry;
|
|
126
|
+
const targetScope = reportArg.targetScope;
|
|
127
|
+
const runtimeTasks = reportArg.runtimeTasks;
|
|
128
|
+
if (!isRecord(service)) {
|
|
129
|
+
errors.push('a GO report requires a service snapshot');
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
for (const key of ['organizationId', 'serviceId', 'serviceName', 'imageId']) {
|
|
133
|
+
if (!isBoundedIdentifier(service[key]))
|
|
134
|
+
errors.push(`service.${key} is invalid`);
|
|
135
|
+
}
|
|
136
|
+
if (service.deployOnPush !== true || service.immutableImageRequired !== false) {
|
|
137
|
+
errors.push('a GO report requires the legacy mutable service state');
|
|
138
|
+
}
|
|
139
|
+
if (typeof service.configuredReference !== 'string' || !service.configuredReference.trim()) {
|
|
140
|
+
errors.push('service.configuredReference must be non-empty');
|
|
141
|
+
}
|
|
142
|
+
if (!isCanonicalDigest(service.configurationDigest)) {
|
|
143
|
+
errors.push('service.configurationDigest must be a canonical sha256 digest');
|
|
144
|
+
}
|
|
145
|
+
if (!isRecord(service.registryTarget)) {
|
|
146
|
+
errors.push('service.registryTarget must be present');
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
let registryDigest;
|
|
150
|
+
if (!isRecord(registry)) {
|
|
151
|
+
errors.push('a GO report requires a registry snapshot');
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
if (!normalizeImmutableReleaseTag(registry.tag) || registry.tag !== registry.releaseTag) {
|
|
155
|
+
errors.push('registry tag and releaseTag must be the same immutable tag');
|
|
156
|
+
}
|
|
157
|
+
if (!isCanonicalDigest(registry.digest)) {
|
|
158
|
+
errors.push('registry.digest must be a canonical sha256 digest');
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
registryDigest = registry.digest;
|
|
162
|
+
if (reportArg.adoptionDigest === registry.digest) {
|
|
163
|
+
errors.push('adoption digest must be a distinct full-state fence, not the image digest');
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
if (!indexMediaTypes.has(registry.mediaType)) {
|
|
167
|
+
errors.push('registry.mediaType must identify an OCI image index');
|
|
168
|
+
}
|
|
169
|
+
if (!isBoundedIdentifier(registry.releaseId)) {
|
|
170
|
+
errors.push('registry.releaseId must be a bounded canonical identifier');
|
|
171
|
+
}
|
|
172
|
+
if (!Array.isArray(registry.platforms) || registry.platforms.length === 0) {
|
|
173
|
+
errors.push('registry.platforms must contain OCI platform evidence');
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
for (const architecture of ['amd64', 'arm64']) {
|
|
177
|
+
if (!registry.platforms.some((platformArg) => isRecord(platformArg)
|
|
178
|
+
&& platformArg.os === 'linux'
|
|
179
|
+
&& platformArg.architecture === architecture
|
|
180
|
+
&& platformArg.runnable === true
|
|
181
|
+
&& platformArg.manifestPresent === true
|
|
182
|
+
&& isCanonicalDigest(platformArg.digest))) {
|
|
183
|
+
errors.push(`registry.platforms must contain runnable linux/${architecture} evidence`);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
let requiredReplicaCount;
|
|
189
|
+
let targetNodeNames = [];
|
|
190
|
+
let replicasPerNode;
|
|
191
|
+
if (!isRecord(targetScope)) {
|
|
192
|
+
errors.push('a GO report requires an immutable target scope');
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
const clusterIds = targetScope.targetClusterIds;
|
|
196
|
+
const nodeNames = targetScope.targetNodeNames;
|
|
197
|
+
replicasPerNode = targetScope.replicasPerNode;
|
|
198
|
+
requiredReplicaCount = targetScope.requiredReplicaCount;
|
|
199
|
+
if (!Array.isArray(clusterIds) || clusterIds.length !== 1
|
|
200
|
+
|| clusterIds.some((valueArg) => !isBoundedIdentifier(valueArg))
|
|
201
|
+
|| new Set(clusterIds).size !== clusterIds.length) {
|
|
202
|
+
errors.push('targetScope.targetClusterIds must identify exactly one attested cluster');
|
|
203
|
+
}
|
|
204
|
+
if (!Array.isArray(nodeNames) || nodeNames.length === 0
|
|
205
|
+
|| nodeNames.some((valueArg) => !isBoundedIdentifier(valueArg))
|
|
206
|
+
|| new Set(nodeNames).size !== nodeNames.length) {
|
|
207
|
+
errors.push('targetScope.targetNodeNames must be non-empty and unique');
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
targetNodeNames = nodeNames;
|
|
211
|
+
}
|
|
212
|
+
if (!Number.isSafeInteger(replicasPerNode) || replicasPerNode < 1) {
|
|
213
|
+
errors.push('targetScope.replicasPerNode must be a positive integer');
|
|
214
|
+
}
|
|
215
|
+
if (!Number.isSafeInteger(requiredReplicaCount) || requiredReplicaCount < 1
|
|
216
|
+
|| requiredReplicaCount !== targetNodeNames.length * (replicasPerNode || 0)) {
|
|
217
|
+
errors.push('targetScope.requiredReplicaCount must match nodes times replicas');
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
if (!Array.isArray(runtimeTasks) || runtimeTasks.length === 0) {
|
|
221
|
+
errors.push('a GO report requires runtime task evidence');
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
if (requiredReplicaCount !== undefined && runtimeTasks.length !== requiredReplicaCount) {
|
|
225
|
+
errors.push('runtime task count must equal the required replica count');
|
|
226
|
+
}
|
|
227
|
+
const deploymentIds = new Set();
|
|
228
|
+
const taskCountsByNode = new Map();
|
|
229
|
+
for (const task of runtimeTasks) {
|
|
230
|
+
if (!isRecord(task)
|
|
231
|
+
|| !isBoundedIdentifier(task.deploymentId)
|
|
232
|
+
|| deploymentIds.has(task.deploymentId)) {
|
|
233
|
+
errors.push('runtime task deployment IDs must be valid and unique');
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
deploymentIds.add(task.deploymentId);
|
|
237
|
+
if (!isBoundedIdentifier(task.nodeName) || !targetNodeNames.includes(task.nodeName)) {
|
|
238
|
+
errors.push('every runtime task must belong to the exact target node scope');
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
taskCountsByNode.set(task.nodeName, (taskCountsByNode.get(task.nodeName) || 0) + 1);
|
|
242
|
+
}
|
|
243
|
+
if (task.status !== 'running' || task.healthStatus !== 'healthy') {
|
|
244
|
+
errors.push('every runtime task must be running and healthy');
|
|
245
|
+
}
|
|
246
|
+
if (!registryDigest || task.observedDigest !== registryDigest) {
|
|
247
|
+
errors.push('every runtime task must attest the exact registry digest');
|
|
248
|
+
}
|
|
249
|
+
if (typeof task.imageReference !== 'string' || !task.imageReference.trim()) {
|
|
250
|
+
errors.push('every runtime task must identify its image reference');
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
if (replicasPerNode !== undefined
|
|
254
|
+
&& targetNodeNames.some((nodeNameArg) => taskCountsByNode.get(nodeNameArg) !== replicasPerNode)) {
|
|
255
|
+
errors.push('runtime task evidence must cover every target node and replica');
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
if (isRecord(attestation) && requiredReplicaCount !== undefined) {
|
|
259
|
+
if (attestation.requiredReplicaCount !== requiredReplicaCount
|
|
260
|
+
|| attestation.observedReplicaCount !== requiredReplicaCount
|
|
261
|
+
|| attestation.healthyReplicaCount !== requiredReplicaCount
|
|
262
|
+
|| attestation.observedDigestReplicaCount !== requiredReplicaCount
|
|
263
|
+
|| attestation.observedDigestConsistent !== true) {
|
|
264
|
+
errors.push('runtime attestation must consistently cover every required replica');
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
if (isRecord(service) && isRecord(service.registryTarget) && isRecord(registry)) {
|
|
268
|
+
const target = service.registryTarget;
|
|
269
|
+
if (target.protocol !== 'oci'
|
|
270
|
+
|| target.tag !== registry.tag
|
|
271
|
+
|| target.serviceId !== service.serviceId
|
|
272
|
+
|| target.imageId !== service.imageId
|
|
273
|
+
|| typeof target.registryHost !== 'string'
|
|
274
|
+
|| !target.registryHost
|
|
275
|
+
|| typeof target.repository !== 'string'
|
|
276
|
+
|| !target.repository
|
|
277
|
+
|| target.imageUrl !== `${target.registryHost}/${target.repository}:${target.tag}`) {
|
|
278
|
+
errors.push('service registry target must exactly bind the adopted service, image, and tag');
|
|
279
|
+
}
|
|
280
|
+
if (registryDigest) {
|
|
281
|
+
const digestPinnedReference = `${target.registryHost}/${target.repository}@${registryDigest}`;
|
|
282
|
+
const tagAndDigestReference = `${target.imageUrl}@${registryDigest}`;
|
|
283
|
+
const configuredReferences = new Set([
|
|
284
|
+
target.tag,
|
|
285
|
+
target.imageUrl,
|
|
286
|
+
digestPinnedReference,
|
|
287
|
+
tagAndDigestReference,
|
|
288
|
+
]);
|
|
289
|
+
if (!configuredReferences.has(service.configuredReference)) {
|
|
290
|
+
errors.push('service configured reference must exactly bind the adopted registry target');
|
|
291
|
+
}
|
|
292
|
+
const runtimeReferences = new Set([
|
|
293
|
+
target.imageUrl,
|
|
294
|
+
digestPinnedReference,
|
|
295
|
+
tagAndDigestReference,
|
|
296
|
+
]);
|
|
297
|
+
if (Array.isArray(runtimeTasks)
|
|
298
|
+
&& runtimeTasks.some((taskArg) => !isRecord(taskArg)
|
|
299
|
+
|| !runtimeReferences.has(taskArg.imageReference))) {
|
|
300
|
+
errors.push('every runtime task image reference must exactly bind the adopted registry target');
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
return errors;
|
|
305
|
+
};
|
|
306
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVwbG95bWVudGFkb3B0aW9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdHMvZGF0YS9kZXBsb3ltZW50YWRvcHRpb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBVUEsT0FBTyxFQUFFLDRCQUE0QixFQUFFLHFCQUFxQixFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFpSTFGLE1BQU0sdUJBQXVCLEdBQUcscUNBQXFDLENBQUM7QUFDdEUsTUFBTSxlQUFlLEdBQUcsSUFBSSxHQUFHLENBQXdCO0lBQ3JELHlDQUF5QztJQUN6QywyREFBMkQ7Q0FDNUQsQ0FBQyxDQUFDO0FBQ0gsTUFBTSxvQkFBb0IsR0FBRyxJQUFJLEdBQUcsQ0FBd0M7SUFDMUUsaUJBQWlCO0lBQ2pCLHVCQUF1QjtJQUN2QixtQkFBbUI7SUFDbkIsNEJBQTRCO0lBQzVCLDJCQUEyQjtJQUMzQix3QkFBd0I7SUFDeEIseUJBQXlCO0lBQ3pCLDRCQUE0QjtJQUM1Qix5QkFBeUI7SUFDekIsb0JBQW9CO0lBQ3BCLHNCQUFzQjtJQUN0QixtQkFBbUI7SUFDbkIsdUJBQXVCO0lBQ3ZCLDBCQUEwQjtJQUMxQixnQ0FBZ0M7SUFDaEMseUJBQXlCO0NBQzFCLENBQUMsQ0FBQztBQUVILE1BQU0sUUFBUSxHQUFHLENBQUMsUUFBaUIsRUFBdUMsRUFBRSxDQUMxRSxPQUFPLENBQUMsUUFBUSxDQUFDLElBQUksT0FBTyxRQUFRLEtBQUssUUFBUSxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsQ0FBQztBQUVoRixNQUFNLG1CQUFtQixHQUFHLENBQUMsUUFBaUIsRUFBc0IsRUFBRSxDQUNwRSxPQUFPLFFBQVEsS0FBSyxRQUFRLElBQUksdUJBQXVCLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO0FBRXpFLE1BQU0saUJBQWlCLEdBQUcsQ0FBQyxRQUFpQixFQUE2QixFQUFFLENBQ3pFLE9BQU8sQ0FBQyxxQkFBcUIsQ0FBQyxRQUFRLENBQUMs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
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
export type TSha256Digest = `sha256:${string}`;
|
|
3
3
|
export type TImageDeploymentPolicy = 'legacy-tag' | 'immutable-digest';
|
|
4
4
|
export type TOciManifestMediaType = 'application/vnd.oci.image.index.v1+json' | 'application/vnd.oci.image.manifest.v1+json' | 'application/vnd.docker.distribution.manifest.list.v2+json' | 'application/vnd.docker.distribution.manifest.v2+json';
|
|
5
|
-
export type TImmutableImageRolloutMode = 'promotion' | 'automatic' | 'rollback';
|
|
5
|
+
export type TImmutableImageRolloutMode = 'promotion' | 'automatic' | 'rollback' | 'adoption';
|
|
6
6
|
export type TImmutableImageMismatchReason = 'immutable-plan-missing' | 'requested-digest-missing' | 'requested-digest-malformed' | 'registry-digest-inconsistent' | 'runtime-capability-missing' | 'pull-failed' | 'pulled-digest-missing' | 'pulled-digest-mismatch' | 'service-image-not-digest-pinned' | 'service-image-digest-mismatch' | 'task-image-not-digest-pinned' | 'task-image-digest-mismatch' | 'container-inspection-unavailable' | 'container-image-id-missing' | 'container-repodigest-missing' | 'container-repodigest-mismatch' | 'runtime-attestation-missing' | 'required-replica-missing' | 'replica-unhealthy' | 'replica-failed' | 'stale-rollout-report' | 'rollback-target-not-accepted';
|
|
7
7
|
export type TRuntimeImageVerificationStatus = 'not-required' | 'pending' | 'verified' | 'missing' | 'mismatched';
|
|
8
8
|
export type TImmutableImageRolloutStatus = 'pending' | 'deploying' | 'verifying' | 'succeeded' | 'failed' | 'mismatched' | 'rolling-back' | 'rolled-back';
|
|
@@ -85,6 +85,8 @@ export interface IImmutableImageDeploymentPlan {
|
|
|
85
85
|
manifestMediaType: TOciManifestMediaType;
|
|
86
86
|
createdAt: number;
|
|
87
87
|
mode: TImmutableImageRolloutMode;
|
|
88
|
+
/** Full pre-adoption service configuration fence, required only for adoption. */
|
|
89
|
+
adoptionConfigurationDigest?: TSha256Digest;
|
|
88
90
|
rollbackOfRolloutId?: string;
|
|
89
91
|
targetScope: IImmutableImageTargetScope;
|
|
90
92
|
}
|
|
@@ -113,6 +113,9 @@ export const validateImmutableImageDeploymentPlan = (planArg) => {
|
|
|
113
113
|
if (!normalizeImmutableReleaseTag(planArg.releaseTag)) {
|
|
114
114
|
errors.push('releaseTag must be a non-latest canonical OCI tag');
|
|
115
115
|
}
|
|
116
|
+
if (!['promotion', 'automatic', 'rollback', 'adoption'].includes(planArg.mode)) {
|
|
117
|
+
errors.push('mode must be a supported immutable rollout mode');
|
|
118
|
+
}
|
|
116
119
|
if (![
|
|
117
120
|
'application/vnd.oci.image.index.v1+json',
|
|
118
121
|
'application/vnd.docker.distribution.manifest.list.v2+json',
|
|
@@ -149,6 +152,18 @@ export const validateImmutableImageDeploymentPlan = (planArg) => {
|
|
|
149
152
|
if (planArg.mode !== 'rollback' && planArg.rollbackOfRolloutId) {
|
|
150
153
|
errors.push('only rollback rollouts may set rollbackOfRolloutId');
|
|
151
154
|
}
|
|
155
|
+
if (planArg.mode === 'adoption') {
|
|
156
|
+
if (planArg.rolloutGeneration !== 1) {
|
|
157
|
+
errors.push('adoption must create rollout generation one');
|
|
158
|
+
}
|
|
159
|
+
if (!planArg.adoptionConfigurationDigest
|
|
160
|
+
|| !isSha256Digest(planArg.adoptionConfigurationDigest)) {
|
|
161
|
+
errors.push('adoption must bind a canonical service configuration digest');
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
else if (planArg.adoptionConfigurationDigest !== undefined) {
|
|
165
|
+
errors.push('only adoption may bind a service configuration digest');
|
|
166
|
+
}
|
|
152
167
|
return errors;
|
|
153
168
|
};
|
|
154
169
|
export const validateImageRolloutStatus = (statusArg) => {
|
|
@@ -230,4 +245,4 @@ export const validateImageRolloutStatus = (statusArg) => {
|
|
|
230
245
|
}
|
|
231
246
|
return errors;
|
|
232
247
|
};
|
|
233
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW1tdXRhYmxlaW1hZ2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9kYXRhL2ltbXV0YWJsZWltYWdlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQW9HQSxNQUFNLENBQUMsTUFBTSxpQ0FBaUMsR0FBRyxDQUFDLE9BVWpELEVBQWlFLEVBQUU7SUFDbEUsTUFBTSxtQkFBbUIsR0FBRyxDQUFDLFdBQXlDLEVBQUUsRUFBRSxDQUFDO1FBQ3pFLFdBQVcsQ0FBQyxNQUFNO1FBQ2xCLFdBQVcsQ0FBQyxVQUFVO1FBQ3RCLFdBQVcsQ0FBQyxXQUFXO1FBQ3ZCLFdBQVcsQ0FBQyxXQUFXO1FBQ3ZCLFdBQVcsQ0FBQyxZQUFZO1FBQ3hCLFdBQVcsQ0FBQyxVQUFVO1FBQ3RCLFdBQVcsQ0FBQyxHQUFHO1FBQ2YsV0FBVyxDQUFDLGtCQUFrQjtRQUM5QixXQUFXLENBQUMsaUJBQWlCO1FBQzdCLFdBQVcsQ0FBQyxVQUFVO0tBQ3ZCLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQ2pCLE1BQU0sY0FBYyxHQUFHLElBQUksR0FBRyxFQUF3QyxDQUFDO0lBQ3ZFLE1BQU0sTUFBTSxHQUFhLEVBQUUsQ0FBQztJQUM1QixLQUFLLE1BQU0sUUFBUSxJQUFJLE9BQU8sQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLGVBQWUsSUFBSSxFQUFFLEVBQUUsQ0FBQztRQUNsRSxNQUFNLFFBQVEsR0FBRyxjQUFjLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUN6RCxJQUFJLFFBQVEsSUFBSSxtQkFBbUIsQ0FBQyxRQUFRLENBQUMsS0FBSyxtQkFBbUIsQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDO1lBQ2hGLE1BQU0sQ0FBQyxJQUFJLENBQUMsb0RBQW9ELENBQUMsQ0FBQztRQUNwRSxDQUFDO2FBQU0sQ0FBQztZQUNOLGNBQWMsQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLFVBQVUsRUFBRSxRQUFRLENBQUMsQ0FB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
|
|
248
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW1tdXRhYmxlaW1hZ2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9kYXRhL2ltbXV0YWJsZWltYWdlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQW9HQSxNQUFNLENBQUMsTUFBTSxpQ0FBaUMsR0FBRyxDQUFDLE9BVWpELEVBQWlFLEVBQUU7SUFDbEUsTUFBTSxtQkFBbUIsR0FBRyxDQUFDLFdBQXlDLEVBQUUsRUFBRSxDQUFDO1FBQ3pFLFdBQVcsQ0FBQyxNQUFNO1FBQ2xCLFdBQVcsQ0FBQyxVQUFVO1FBQ3RCLFdBQVcsQ0FBQyxXQUFXO1FBQ3ZCLFdBQVcsQ0FBQyxXQUFXO1FBQ3ZCLFdBQVcsQ0FBQyxZQUFZO1FBQ3hCLFdBQVcsQ0FBQyxVQUFVO1FBQ3RCLFdBQVcsQ0FBQyxHQUFHO1FBQ2YsV0FBVyxDQUFDLGtCQUFrQjtRQUM5QixXQUFXLENBQUMsaUJBQWlCO1FBQzdCLFdBQVcsQ0FBQyxVQUFVO0tBQ3ZCLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQ2pCLE1BQU0sY0FBYyxHQUFHLElBQUksR0FBRyxFQUF3QyxDQUFDO0lBQ3ZFLE1BQU0sTUFBTSxHQUFhLEVBQUUsQ0FBQztJQUM1QixLQUFLLE1BQU0sUUFBUSxJQUFJLE9BQU8sQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLGVBQWUsSUFBSSxFQUFFLEVBQUUsQ0FBQztRQUNsRSxNQUFNLFFBQVEsR0FBRyxjQUFjLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUN6RCxJQUFJLFFBQVEsSUFBSSxtQkFBbUIsQ0FBQyxRQUFRLENBQUMsS0FBSyxtQkFBbUIsQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDO1lBQ2hGLE1BQU0sQ0FBQyxJQUFJLENBQUMsb0RBQW9ELENBQUMsQ0FBQztRQUNwRSxDQUFDO2FBQU0sQ0FBQztZQUNOLGNBQWMsQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLFVBQVUsRUFBRSxRQUFRLENBQUMsQ0FB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
|
package/dist_ts/data/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export * from './cloudlyconfig.js';
|
|
|
2
2
|
export * from './cluster.js';
|
|
3
3
|
export * from './config.js';
|
|
4
4
|
export * from './deployment.js';
|
|
5
|
+
export * from './deploymentadoption.js';
|
|
5
6
|
export * from './deploymentoperation.js';
|
|
6
7
|
export * from './deploymentpreflight.js';
|
|
7
8
|
export * from './migration.js';
|
package/dist_ts/data/index.js
CHANGED
|
@@ -2,6 +2,7 @@ export * from './cloudlyconfig.js';
|
|
|
2
2
|
export * from './cluster.js';
|
|
3
3
|
export * from './config.js';
|
|
4
4
|
export * from './deployment.js';
|
|
5
|
+
export * from './deploymentadoption.js';
|
|
5
6
|
export * from './deploymentoperation.js';
|
|
6
7
|
export * from './deploymentpreflight.js';
|
|
7
8
|
export * from './migration.js';
|
|
@@ -32,4 +33,4 @@ export * from './taskexecution.js';
|
|
|
32
33
|
export * from './traffic.js';
|
|
33
34
|
export * from './user.js';
|
|
34
35
|
export * from './version.js';
|
|
35
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
36
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9kYXRhL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLGNBQWMsb0JBQW9CLENBQUM7QUFDbkMsY0FBYyxjQUFjLENBQUM7QUFDN0IsY0FBYyxhQUFhLENBQUM7QUFDNUIsY0FBYyxpQkFBaUIsQ0FBQztBQUNoQyxjQUFjLHlCQUF5QixDQUFDO0FBQ3hDLGNBQWMsMEJBQTBCLENBQUM7QUFDekMsY0FBYywwQkFBMEIsQ0FBQztBQUN6QyxjQUFjLGdCQUFnQixDQUFDO0FBQy9CLGNBQWMsVUFBVSxDQUFDO0FBQ3pCLGNBQWMsYUFBYSxDQUFDO0FBQzVCLGNBQWMsYUFBYSxDQUFDO0FBQzVCLGNBQWMsWUFBWSxDQUFDO0FBQzNCLGNBQWMsdUJBQXVCLENBQUM7QUFDdEMsY0FBYyxjQUFjLENBQUM7QUFDN0IsY0FBYyxnQkFBZ0IsQ0FBQztBQUMvQixjQUFjLFlBQVksQ0FBQztBQUMzQixjQUFjLHFCQUFxQixDQUFDO0FBQ3BDLGNBQWMsc0JBQXNCLENBQUM7QUFDckMsY0FBYyw2QkFBNkIsQ0FBQztBQUM1QyxjQUFjLFdBQVcsQ0FBQztBQUMxQixjQUFjLGVBQWUsQ0FBQztBQUM5QixjQUFjLG1CQUFtQixDQUFDO0FBQ2xDLGNBQWMsa0JBQWtCLENBQUM7QUFDakMsY0FBYyxnQkFBZ0IsQ0FBQztBQUMvQixjQUFjLGFBQWEsQ0FBQztBQUM1QixjQUFjLGFBQWEsQ0FBQztBQUM1QixjQUFjLGtCQUFrQixDQUFDO0FBQ2pDLGNBQWMsZUFBZSxDQUFDO0FBQzlCLGNBQWMsY0FBYyxDQUFDO0FBQzdCLGNBQWMsbUJBQW1CLENBQUM7QUFDbEMsY0FBYyxhQUFhLENBQUM7QUFDNUIsY0FBYyxvQkFBb0IsQ0FBQztBQUNuQyxjQUFjLGNBQWMsQ0FBQztBQUM3QixjQUFjLFdBQVcsQ0FBQztBQUMxQixjQUFjLGNBQWMsQ0FBQyJ9
|
package/dist_ts/data/user.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export interface IToken {
|
|
|
3
3
|
expiresAt: number;
|
|
4
4
|
assignedRoles: string[];
|
|
5
5
|
}
|
|
6
|
-
export type TServiceDeploymentCapability = 'deployment:preflight' | 'deployment:reserve' | 'deployment:registry-push' | 'deployment:release-read' | 'deployment:promote-image' | 'deployment:status' | 'deployment:create-greenfield' | 'deployment:promote-route' | 'deployment:rollback-image' | 'deployment:rollback-route' | 'deployment:retry' | 'deployment:cleanup';
|
|
6
|
+
export type TServiceDeploymentCapability = 'deployment:preflight' | 'deployment:reserve' | 'deployment:registry-push' | 'deployment:release-read' | 'deployment:promote-image' | 'deployment:adopt-existing' | 'deployment:status' | 'deployment:create-greenfield' | 'deployment:promote-route' | 'deployment:rollback-image' | 'deployment:rollback-route' | 'deployment:retry' | 'deployment:cleanup';
|
|
7
7
|
/**
|
|
8
8
|
* Server-persisted authority for one logical service. These grants are never
|
|
9
9
|
* accepted from the identity payload supplied by a caller; Cloudly reloads
|
package/dist_ts/data/user.js
CHANGED
|
@@ -4,6 +4,7 @@ const serviceDeploymentCapabilities = new Set([
|
|
|
4
4
|
'deployment:registry-push',
|
|
5
5
|
'deployment:release-read',
|
|
6
6
|
'deployment:promote-image',
|
|
7
|
+
'deployment:adopt-existing',
|
|
7
8
|
'deployment:status',
|
|
8
9
|
'deployment:create-greenfield',
|
|
9
10
|
'deployment:promote-route',
|
|
@@ -49,6 +50,10 @@ export const validateServiceDeploymentGrant = (grantArg) => {
|
|
|
49
50
|
&& !capabilities.includes('deployment:create-greenfield')) {
|
|
50
51
|
errors.push('an organization-service-slot grant must authorize greenfield creation');
|
|
51
52
|
}
|
|
53
|
+
if (capabilities && grant.scope !== 'service'
|
|
54
|
+
&& capabilities.includes('deployment:adopt-existing')) {
|
|
55
|
+
errors.push('deployment:adopt-existing requires an existing-service grant');
|
|
56
|
+
}
|
|
52
57
|
return errors;
|
|
53
58
|
};
|
|
54
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
59
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXNlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL2RhdGEvdXNlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUE4Q0EsTUFBTSw2QkFBNkIsR0FBRyxJQUFJLEdBQUcsQ0FBK0I7SUFDMUUsc0JBQXNCO0lBQ3RCLG9CQUFvQjtJQUNwQiwwQkFBMEI7SUFDMUIseUJBQXlCO0lBQ3pCLDBCQUEwQjtJQUMxQiwyQkFBMkI7SUFDM0IsbUJBQW1CO0lBQ25CLDhCQUE4QjtJQUM5QiwwQkFBMEI7SUFDMUIsMkJBQTJCO0lBQzNCLDJCQUEyQjtJQUMzQixrQkFBa0I7SUFDbEIsb0JBQW9CO0NBQ3JCLENBQUMsQ0FBQztBQUVILE1BQU0saUNBQWlDLEdBQUcscUNBQXFDLENBQUM7QUFFaEYsTUFBTSxDQUFDLE1BQU0sOEJBQThCLEdBQUcsQ0FDNUMsUUFBaUIsRUFDUCxFQUFFO0lBQ1osTUFBTSxNQUFNLEdBQWEsRUFBRSxDQUFDO0lBQzVCLElBQUksQ0FBQyxRQUFRLElBQUksT0FBTyxRQUFRLEtBQUssUUFBUSxJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQztRQUN6RSxPQUFPLENBQUMseUJBQXlCLENBQUMsQ0FBQztJQUNyQyxDQUFDO0lBQ0QsTUFBTSxLQUFLLEdBQUcsUUFBbUMsQ0FBQztJQUNsRCxJQUFJLEtBQUssQ0FBQyxLQUFLLEtBQUssU0FBUyxJQUFJLEtBQUssQ0FBQyxLQUFLLEtBQUssMkJBQTJCLEVBQUUsQ0FBQztRQUM3RSxNQUFNLENBQUMsSUFBSSxDQUFDLHlFQUF5RSxDQUFDLENBQUM7SUFDekYsQ0FBQztJQUNELElBQUksT0FBTyxLQUFLLENBQUMsY0FBYyxLQUFLLFFBQVE7V0FDdkMsQ0FBQyxpQ0FBaUMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLGNBQWMsQ0FBQyxFQUFFLENBQUM7UUFDbkUsTUFBTSxDQUFDLElBQUksQ0FBQyx1REFBdUQsQ0FBQyxDQUFDO0lBQ3ZFLENBQUM7SUFDRCxJQUFJLE9BQU8sS0FBSyxDQUFDLFNBQVMsS0FBSyxRQUFRO1dBQ2xDLENBQUMsaUNBQWlDLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDO1FBQzlELE1BQU0sQ0FBQyxJQUFJLENBQUMsa0RBQWtELENBQUMsQ0FBQztJQUNsRSxDQUFDO0lBQ0QsTUFBTSxZQUFZLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsWUFBWSxDQUFDO1FBQ3BELENBQUMsQ0FBQyxLQUFLLENBQUMsWUFBWTtRQUNwQixDQUFDLENBQUMsU0FBUyxDQUFDO0lBQ2QsSUFBSSxDQUFDLFlBQVk7V0FDWixZQUFZLENBQUMsTUFBTSxHQUFHLENBQUM7V0FDdkIsWUFBWSxDQUFDLE1BQU0sR0FBRyw2QkFBNkIsQ0FBQyxJQUFJO1dBQ3hELElBQUksR0FBRyxDQUFDLFlBQVksQ0FBQyxDQUFDLElBQUksS0FBSyxZQUFZLENBQUMsTUFBTTtXQUNsRCxZQUFZLENBQUMsSUFBSSxDQUFDLENBQUMsYUFBYSxFQUFFLEVBQUUsQ0FBQyxDQUN0QyxPQUFPLGFBQWEsS0FBSyxRQUFRO2VBQzlCLENBQUMsNkJBQTZCLENBQUMsR0FBRyxDQUFDLGFBQTZDLENBQUMsQ0FDckYsQ0FBQyxFQUFFLENBQUM7UUFDTCxNQUFNLENBQUMsSUFBSSxDQUFDLGtGQUFrRixDQUFDLENBQUM7SUFDbEcsQ0FBQztJQUNELElBQUksWUFBWSxJQUFJLEtBQUssQ0FBQyxLQUFLLEtBQUssU0FBUztXQUN4QyxZQUFZLENBQUMsUUFBUSxDQUFDLDhCQUE4QixDQUFDLEVBQUUsQ0FBQztRQUMzRCxNQUFNLENBQUMsSUFBSSxDQUFDLGdFQUFnRSxDQUFDLENBQUM7SUFDaEYsQ0FBQztJQUNELElBQUksWUFBWSxJQUFJLEtBQUssQ0FBQyxLQUFLLEtBQUssMkJBQTJCO1dBQzFELENBQUMsWUFBWSxDQUFDLFFBQVEsQ0FBQyw4QkFBOEIsQ0FBQyxFQUFFLENBQUM7UUFDNUQsTUFBTSxDQUFDLElBQUksQ0FBQyx1RUFBdUUsQ0FBQyxDQUFDO0lBQ3ZGLENBQUM7SUFDRCxJQUFJLFlBQVksSUFBSSxLQUFLLENBQUMsS0FBSyxLQUFLLFNBQVM7V0FDeEMsWUFBWSxDQUFDLFFBQVEsQ0FBQywyQkFBMkIsQ0FBQyxFQUFFLENBQUM7UUFDeEQsTUFBTSxDQUFDLElBQUksQ0FBQyw4REFBOEQsQ0FBQyxDQUFDO0lBQzlFLENBQUM7SUFDRCxPQUFPLE1BQU0sQ0FBQztBQUNoQixDQUFDLENBQUMifQ==
|
|
@@ -7,6 +7,26 @@ import type { IImageRelease } from '../data/immutableimage.js';
|
|
|
7
7
|
import type { IDeploymentPreflightReport, IDeploymentPreflightRequestData } from '../data/deploymentpreflight.js';
|
|
8
8
|
import type { IDeploymentReservationInput, IServiceDeploymentOperation, IServiceDeploymentStatus } from '../data/deploymentoperation.js';
|
|
9
9
|
import type { TSha256Digest } from '../data/immutableimage.js';
|
|
10
|
+
import type { IServiceDeploymentAdoptionInput, IServiceDeploymentAdoptionPreflightInput, IServiceDeploymentAdoptionReport, IServiceDeploymentAdoptionResult } from '../data/deploymentadoption.js';
|
|
11
|
+
export interface IRequest_Any_Cloudly_GetServiceDeploymentAdoptionPreflight extends plugins.typedrequestInterfaces.implementsTR<plugins.typedrequestInterfaces.ITypedRequest, IRequest_Any_Cloudly_GetServiceDeploymentAdoptionPreflight> {
|
|
12
|
+
method: 'getServiceDeploymentAdoptionPreflight';
|
|
13
|
+
request: IServiceDeploymentAdoptionPreflightInput & {
|
|
14
|
+
identity: IIdentityCredential;
|
|
15
|
+
};
|
|
16
|
+
response: {
|
|
17
|
+
report: IServiceDeploymentAdoptionReport;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export interface IRequest_Any_Cloudly_AdoptServiceDeployment extends plugins.typedrequestInterfaces.implementsTR<plugins.typedrequestInterfaces.ITypedRequest, IRequest_Any_Cloudly_AdoptServiceDeployment> {
|
|
21
|
+
method: 'adoptServiceDeployment';
|
|
22
|
+
request: IServiceDeploymentAdoptionInput & {
|
|
23
|
+
identity: IIdentityCredential;
|
|
24
|
+
};
|
|
25
|
+
response: {
|
|
26
|
+
service: IService;
|
|
27
|
+
result: IServiceDeploymentAdoptionResult;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
10
30
|
export interface IRequest_Any_Cloudly_GetDeploymentPreflight extends plugins.typedrequestInterfaces.implementsTR<plugins.typedrequestInterfaces.ITypedRequest, IRequest_Any_Cloudly_GetDeploymentPreflight> {
|
|
11
31
|
method: 'getDeploymentPreflight';
|
|
12
32
|
request: IDeploymentPreflightRequestData & {
|
package/package.json
CHANGED
package/ts/00_commitinfo_data.ts
CHANGED
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
IDeploymentPreflightRuntimeTask,
|
|
3
|
+
IOciPlatformDescriptorSummary,
|
|
4
|
+
} from './deploymentpreflight.js';
|
|
5
|
+
import type {
|
|
6
|
+
IImmutableImageDeploymentPlan,
|
|
7
|
+
IImmutableImageTargetScope,
|
|
8
|
+
TOciManifestMediaType,
|
|
9
|
+
TSha256Digest,
|
|
10
|
+
} from './immutableimage.js';
|
|
11
|
+
import { normalizeImmutableReleaseTag, normalizeSha256Digest } from './immutableimage.js';
|
|
12
|
+
import type { IRegistryTarget } from './registry.js';
|
|
13
|
+
|
|
14
|
+
export type TServiceDeploymentAdoptionDecision = 'GO' | 'NO-GO';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Canonical sha256 hash of the complete adoption preflight snapshot. It is a
|
|
18
|
+
* state/TOCTOU fence and must never be substituted with the OCI image digest.
|
|
19
|
+
*/
|
|
20
|
+
export type TServiceDeploymentAdoptionDigest = TSha256Digest & {
|
|
21
|
+
readonly __serviceDeploymentAdoptionDigest: unique symbol;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export type TServiceDeploymentAdoptionBlockerCode =
|
|
25
|
+
| 'INVALID_REQUEST'
|
|
26
|
+
| 'AUTHORIZATION_MISSING'
|
|
27
|
+
| 'SERVICE_NOT_FOUND'
|
|
28
|
+
| 'SERVICE_OWNERSHIP_MISMATCH'
|
|
29
|
+
| 'SERVICE_ALREADY_IMMUTABLE'
|
|
30
|
+
| 'SERVICE_STATE_CONFLICT'
|
|
31
|
+
| 'REGISTRY_TARGET_MISSING'
|
|
32
|
+
| 'REGISTRY_REFERENCE_INVALID'
|
|
33
|
+
| 'REGISTRY_DIGEST_MISSING'
|
|
34
|
+
| 'OCI_INDEX_REQUIRED'
|
|
35
|
+
| 'OCI_PLATFORM_MISSING'
|
|
36
|
+
| 'RELEASE_NOT_FOUND'
|
|
37
|
+
| 'RELEASE_TAG_AMBIGUOUS'
|
|
38
|
+
| 'TARGET_SCOPE_UNAVAILABLE'
|
|
39
|
+
| 'RUNTIME_ATTESTATION_INCOMPLETE'
|
|
40
|
+
| 'RUNTIME_DIGEST_MISMATCH';
|
|
41
|
+
|
|
42
|
+
export interface IServiceDeploymentAdoptionBlocker {
|
|
43
|
+
code: TServiceDeploymentAdoptionBlockerCode;
|
|
44
|
+
message: string;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface IServiceDeploymentAdoptionPreflightInput {
|
|
48
|
+
requestId: string;
|
|
49
|
+
organizationId: string;
|
|
50
|
+
serviceId: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface IServiceDeploymentAdoptionInput
|
|
54
|
+
extends IServiceDeploymentAdoptionPreflightInput {
|
|
55
|
+
idempotencyKey: string;
|
|
56
|
+
expectedAdoptionDigest: TServiceDeploymentAdoptionDigest;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
interface IServiceDeploymentAdoptionReportBase {
|
|
60
|
+
schemaVersion: 1;
|
|
61
|
+
mutationPerformed: false;
|
|
62
|
+
requestId: string;
|
|
63
|
+
generatedAt: number;
|
|
64
|
+
runtimeAttestation: {
|
|
65
|
+
requiredReplicaCount: number;
|
|
66
|
+
observedReplicaCount: number;
|
|
67
|
+
healthyReplicaCount: number;
|
|
68
|
+
observedDigestReplicaCount: number;
|
|
69
|
+
observedDigestConsistent: boolean;
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
interface IServiceDeploymentAdoptionServiceSnapshot {
|
|
74
|
+
organizationId: string;
|
|
75
|
+
serviceId: string;
|
|
76
|
+
serviceName: string;
|
|
77
|
+
imageId: string;
|
|
78
|
+
deployOnPush: boolean;
|
|
79
|
+
immutableImageRequired: boolean;
|
|
80
|
+
configuredReference: string;
|
|
81
|
+
/** Hash of the complete persisted pre-adoption service configuration. */
|
|
82
|
+
configurationDigest: TSha256Digest;
|
|
83
|
+
registryTarget: IRegistryTarget;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
interface IServiceDeploymentAdoptionRegistrySnapshot {
|
|
87
|
+
tag?: string;
|
|
88
|
+
digest?: TSha256Digest;
|
|
89
|
+
mediaType?: TOciManifestMediaType;
|
|
90
|
+
platforms: IOciPlatformDescriptorSummary[];
|
|
91
|
+
releaseId?: string;
|
|
92
|
+
releaseTag?: string;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface IServiceDeploymentAdoptionGoReport
|
|
96
|
+
extends IServiceDeploymentAdoptionReportBase {
|
|
97
|
+
decision: 'GO';
|
|
98
|
+
service: IServiceDeploymentAdoptionServiceSnapshot & {
|
|
99
|
+
deployOnPush: true;
|
|
100
|
+
immutableImageRequired: false;
|
|
101
|
+
};
|
|
102
|
+
registry: IServiceDeploymentAdoptionRegistrySnapshot & {
|
|
103
|
+
tag: string;
|
|
104
|
+
digest: TSha256Digest;
|
|
105
|
+
mediaType:
|
|
106
|
+
| 'application/vnd.oci.image.index.v1+json'
|
|
107
|
+
| 'application/vnd.docker.distribution.manifest.list.v2+json';
|
|
108
|
+
platforms: [IOciPlatformDescriptorSummary, ...IOciPlatformDescriptorSummary[]];
|
|
109
|
+
releaseId: string;
|
|
110
|
+
releaseTag: string;
|
|
111
|
+
};
|
|
112
|
+
runtimeTasks: [IDeploymentPreflightRuntimeTask, ...IDeploymentPreflightRuntimeTask[]];
|
|
113
|
+
targetScope: IImmutableImageTargetScope;
|
|
114
|
+
adoptionDigest: TServiceDeploymentAdoptionDigest;
|
|
115
|
+
blockers: [];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export interface IServiceDeploymentAdoptionNoGoReport
|
|
119
|
+
extends IServiceDeploymentAdoptionReportBase {
|
|
120
|
+
decision: 'NO-GO';
|
|
121
|
+
service?: IServiceDeploymentAdoptionServiceSnapshot;
|
|
122
|
+
registry: IServiceDeploymentAdoptionRegistrySnapshot;
|
|
123
|
+
runtimeTasks: IDeploymentPreflightRuntimeTask[];
|
|
124
|
+
targetScope?: IImmutableImageTargetScope;
|
|
125
|
+
adoptionDigest?: never;
|
|
126
|
+
blockers: [IServiceDeploymentAdoptionBlocker, ...IServiceDeploymentAdoptionBlocker[]];
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export type IServiceDeploymentAdoptionReport =
|
|
130
|
+
| IServiceDeploymentAdoptionGoReport
|
|
131
|
+
| IServiceDeploymentAdoptionNoGoReport;
|
|
132
|
+
|
|
133
|
+
export interface IServiceDeploymentAdoptionResult {
|
|
134
|
+
adoptionId: string;
|
|
135
|
+
adoptionDigest: TServiceDeploymentAdoptionDigest;
|
|
136
|
+
idempotentReplay: boolean;
|
|
137
|
+
plan: IImmutableImageDeploymentPlan;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const boundaryIdentifierRegex = /^[A-Za-z0-9][A-Za-z0-9:._-]{0,199}$/;
|
|
141
|
+
const indexMediaTypes = new Set<TOciManifestMediaType>([
|
|
142
|
+
'application/vnd.oci.image.index.v1+json',
|
|
143
|
+
'application/vnd.docker.distribution.manifest.list.v2+json',
|
|
144
|
+
]);
|
|
145
|
+
const adoptionBlockerCodes = new Set<TServiceDeploymentAdoptionBlockerCode>([
|
|
146
|
+
'INVALID_REQUEST',
|
|
147
|
+
'AUTHORIZATION_MISSING',
|
|
148
|
+
'SERVICE_NOT_FOUND',
|
|
149
|
+
'SERVICE_OWNERSHIP_MISMATCH',
|
|
150
|
+
'SERVICE_ALREADY_IMMUTABLE',
|
|
151
|
+
'SERVICE_STATE_CONFLICT',
|
|
152
|
+
'REGISTRY_TARGET_MISSING',
|
|
153
|
+
'REGISTRY_REFERENCE_INVALID',
|
|
154
|
+
'REGISTRY_DIGEST_MISSING',
|
|
155
|
+
'OCI_INDEX_REQUIRED',
|
|
156
|
+
'OCI_PLATFORM_MISSING',
|
|
157
|
+
'RELEASE_NOT_FOUND',
|
|
158
|
+
'RELEASE_TAG_AMBIGUOUS',
|
|
159
|
+
'TARGET_SCOPE_UNAVAILABLE',
|
|
160
|
+
'RUNTIME_ATTESTATION_INCOMPLETE',
|
|
161
|
+
'RUNTIME_DIGEST_MISMATCH',
|
|
162
|
+
]);
|
|
163
|
+
|
|
164
|
+
const isRecord = (valueArg: unknown): valueArg is Record<string, unknown> =>
|
|
165
|
+
Boolean(valueArg) && typeof valueArg === 'object' && !Array.isArray(valueArg);
|
|
166
|
+
|
|
167
|
+
const isBoundedIdentifier = (valueArg: unknown): valueArg is string =>
|
|
168
|
+
typeof valueArg === 'string' && boundaryIdentifierRegex.test(valueArg);
|
|
169
|
+
|
|
170
|
+
const isCanonicalDigest = (valueArg: unknown): valueArg is TSha256Digest =>
|
|
171
|
+
Boolean(normalizeSha256Digest(valueArg)) && normalizeSha256Digest(valueArg) === valueArg;
|
|
172
|
+
|
|
173
|
+
const isNonNegativeInteger = (valueArg: unknown): valueArg is number =>
|
|
174
|
+
Number.isSafeInteger(valueArg) && (valueArg as number) >= 0;
|
|
175
|
+
|
|
176
|
+
export const validateServiceDeploymentAdoptionPreflightInput = (
|
|
177
|
+
inputArg: unknown,
|
|
178
|
+
): string[] => {
|
|
179
|
+
if (!isRecord(inputArg)) return ['adoption preflight input must be an object'];
|
|
180
|
+
const errors: string[] = [];
|
|
181
|
+
if (!isBoundedIdentifier(inputArg.requestId)) {
|
|
182
|
+
errors.push('requestId must be a bounded canonical identifier');
|
|
183
|
+
}
|
|
184
|
+
for (const key of ['organizationId', 'serviceId'] as const) {
|
|
185
|
+
if (!isBoundedIdentifier(inputArg[key])) {
|
|
186
|
+
errors.push(`${key} must be a bounded canonical identifier`);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return errors;
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
export const validateServiceDeploymentAdoptionInput = (inputArg: unknown): string[] => {
|
|
193
|
+
const errors = validateServiceDeploymentAdoptionPreflightInput(inputArg);
|
|
194
|
+
if (!isRecord(inputArg)) return errors;
|
|
195
|
+
if (!isBoundedIdentifier(inputArg.idempotencyKey)) {
|
|
196
|
+
errors.push('idempotencyKey must be a bounded canonical identifier');
|
|
197
|
+
}
|
|
198
|
+
if (!isCanonicalDigest(inputArg.expectedAdoptionDigest)) {
|
|
199
|
+
errors.push('expectedAdoptionDigest must be a canonical sha256 digest');
|
|
200
|
+
}
|
|
201
|
+
return errors;
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
export const validateServiceDeploymentAdoptionReport = (reportArg: unknown): string[] => {
|
|
205
|
+
if (!isRecord(reportArg)) return ['adoption report must be an object'];
|
|
206
|
+
const errors: string[] = [];
|
|
207
|
+
if (reportArg.schemaVersion !== 1) errors.push('schemaVersion must be 1');
|
|
208
|
+
if (reportArg.mutationPerformed !== false) {
|
|
209
|
+
errors.push('adoption preflight must be mutation-free');
|
|
210
|
+
}
|
|
211
|
+
if (!isBoundedIdentifier(reportArg.requestId)) {
|
|
212
|
+
errors.push('requestId must be a bounded canonical identifier');
|
|
213
|
+
}
|
|
214
|
+
if (!isNonNegativeInteger(reportArg.generatedAt)) {
|
|
215
|
+
errors.push('generatedAt must be a non-negative integer');
|
|
216
|
+
}
|
|
217
|
+
if (reportArg.decision !== 'GO' && reportArg.decision !== 'NO-GO') {
|
|
218
|
+
errors.push('decision must be GO or NO-GO');
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const attestation = reportArg.runtimeAttestation;
|
|
222
|
+
if (!isRecord(attestation)) {
|
|
223
|
+
errors.push('runtimeAttestation must be an object');
|
|
224
|
+
} else {
|
|
225
|
+
for (const key of [
|
|
226
|
+
'requiredReplicaCount',
|
|
227
|
+
'observedReplicaCount',
|
|
228
|
+
'healthyReplicaCount',
|
|
229
|
+
'observedDigestReplicaCount',
|
|
230
|
+
] as const) {
|
|
231
|
+
if (!isNonNegativeInteger(attestation[key])) {
|
|
232
|
+
errors.push(`runtimeAttestation.${key} must be a non-negative integer`);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
if (typeof attestation.observedDigestConsistent !== 'boolean') {
|
|
236
|
+
errors.push('runtimeAttestation.observedDigestConsistent must be boolean');
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const blockers = reportArg.blockers;
|
|
241
|
+
if (!Array.isArray(blockers)) {
|
|
242
|
+
errors.push('blockers must be an array');
|
|
243
|
+
} else {
|
|
244
|
+
for (const blocker of blockers) {
|
|
245
|
+
if (!isRecord(blocker)
|
|
246
|
+
|| !adoptionBlockerCodes.has(blocker.code as TServiceDeploymentAdoptionBlockerCode)
|
|
247
|
+
|| typeof blocker.message !== 'string'
|
|
248
|
+
|| !blocker.message.trim()) {
|
|
249
|
+
errors.push('each blocker must contain a supported code and non-empty message');
|
|
250
|
+
break;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
if (reportArg.decision === 'NO-GO') {
|
|
256
|
+
if (Array.isArray(blockers) && blockers.length === 0) {
|
|
257
|
+
errors.push('a NO-GO report must contain at least one blocker');
|
|
258
|
+
}
|
|
259
|
+
if (reportArg.adoptionDigest !== undefined) {
|
|
260
|
+
errors.push('a NO-GO report must not contain an adoption digest');
|
|
261
|
+
}
|
|
262
|
+
return errors;
|
|
263
|
+
}
|
|
264
|
+
if (reportArg.decision !== 'GO') return errors;
|
|
265
|
+
|
|
266
|
+
if (Array.isArray(blockers) && blockers.length !== 0) {
|
|
267
|
+
errors.push('a GO report must not contain blockers');
|
|
268
|
+
}
|
|
269
|
+
if (!isCanonicalDigest(reportArg.adoptionDigest)) {
|
|
270
|
+
errors.push('a GO report requires a canonical adoption digest');
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const service = reportArg.service;
|
|
274
|
+
const registry = reportArg.registry;
|
|
275
|
+
const targetScope = reportArg.targetScope;
|
|
276
|
+
const runtimeTasks = reportArg.runtimeTasks;
|
|
277
|
+
if (!isRecord(service)) {
|
|
278
|
+
errors.push('a GO report requires a service snapshot');
|
|
279
|
+
} else {
|
|
280
|
+
for (const key of ['organizationId', 'serviceId', 'serviceName', 'imageId'] as const) {
|
|
281
|
+
if (!isBoundedIdentifier(service[key])) errors.push(`service.${key} is invalid`);
|
|
282
|
+
}
|
|
283
|
+
if (service.deployOnPush !== true || service.immutableImageRequired !== false) {
|
|
284
|
+
errors.push('a GO report requires the legacy mutable service state');
|
|
285
|
+
}
|
|
286
|
+
if (typeof service.configuredReference !== 'string' || !service.configuredReference.trim()) {
|
|
287
|
+
errors.push('service.configuredReference must be non-empty');
|
|
288
|
+
}
|
|
289
|
+
if (!isCanonicalDigest(service.configurationDigest)) {
|
|
290
|
+
errors.push('service.configurationDigest must be a canonical sha256 digest');
|
|
291
|
+
}
|
|
292
|
+
if (!isRecord(service.registryTarget)) {
|
|
293
|
+
errors.push('service.registryTarget must be present');
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
let registryDigest: TSha256Digest | undefined;
|
|
298
|
+
if (!isRecord(registry)) {
|
|
299
|
+
errors.push('a GO report requires a registry snapshot');
|
|
300
|
+
} else {
|
|
301
|
+
if (!normalizeImmutableReleaseTag(registry.tag) || registry.tag !== registry.releaseTag) {
|
|
302
|
+
errors.push('registry tag and releaseTag must be the same immutable tag');
|
|
303
|
+
}
|
|
304
|
+
if (!isCanonicalDigest(registry.digest)) {
|
|
305
|
+
errors.push('registry.digest must be a canonical sha256 digest');
|
|
306
|
+
} else {
|
|
307
|
+
registryDigest = registry.digest;
|
|
308
|
+
if (reportArg.adoptionDigest === registry.digest) {
|
|
309
|
+
errors.push('adoption digest must be a distinct full-state fence, not the image digest');
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
if (!indexMediaTypes.has(registry.mediaType as TOciManifestMediaType)) {
|
|
313
|
+
errors.push('registry.mediaType must identify an OCI image index');
|
|
314
|
+
}
|
|
315
|
+
if (!isBoundedIdentifier(registry.releaseId)) {
|
|
316
|
+
errors.push('registry.releaseId must be a bounded canonical identifier');
|
|
317
|
+
}
|
|
318
|
+
if (!Array.isArray(registry.platforms) || registry.platforms.length === 0) {
|
|
319
|
+
errors.push('registry.platforms must contain OCI platform evidence');
|
|
320
|
+
} else {
|
|
321
|
+
for (const architecture of ['amd64', 'arm64']) {
|
|
322
|
+
if (!registry.platforms.some((platformArg) => isRecord(platformArg)
|
|
323
|
+
&& platformArg.os === 'linux'
|
|
324
|
+
&& platformArg.architecture === architecture
|
|
325
|
+
&& platformArg.runnable === true
|
|
326
|
+
&& platformArg.manifestPresent === true
|
|
327
|
+
&& isCanonicalDigest(platformArg.digest))) {
|
|
328
|
+
errors.push(`registry.platforms must contain runnable linux/${architecture} evidence`);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
let requiredReplicaCount: number | undefined;
|
|
335
|
+
let targetNodeNames: string[] = [];
|
|
336
|
+
let replicasPerNode: number | undefined;
|
|
337
|
+
if (!isRecord(targetScope)) {
|
|
338
|
+
errors.push('a GO report requires an immutable target scope');
|
|
339
|
+
} else {
|
|
340
|
+
const clusterIds = targetScope.targetClusterIds;
|
|
341
|
+
const nodeNames = targetScope.targetNodeNames;
|
|
342
|
+
replicasPerNode = targetScope.replicasPerNode as number;
|
|
343
|
+
requiredReplicaCount = targetScope.requiredReplicaCount as number;
|
|
344
|
+
if (!Array.isArray(clusterIds) || clusterIds.length !== 1
|
|
345
|
+
|| clusterIds.some((valueArg) => !isBoundedIdentifier(valueArg))
|
|
346
|
+
|| new Set(clusterIds).size !== clusterIds.length) {
|
|
347
|
+
errors.push('targetScope.targetClusterIds must identify exactly one attested cluster');
|
|
348
|
+
}
|
|
349
|
+
if (!Array.isArray(nodeNames) || nodeNames.length === 0
|
|
350
|
+
|| nodeNames.some((valueArg) => !isBoundedIdentifier(valueArg))
|
|
351
|
+
|| new Set(nodeNames).size !== nodeNames.length) {
|
|
352
|
+
errors.push('targetScope.targetNodeNames must be non-empty and unique');
|
|
353
|
+
} else {
|
|
354
|
+
targetNodeNames = nodeNames as string[];
|
|
355
|
+
}
|
|
356
|
+
if (!Number.isSafeInteger(replicasPerNode) || replicasPerNode < 1) {
|
|
357
|
+
errors.push('targetScope.replicasPerNode must be a positive integer');
|
|
358
|
+
}
|
|
359
|
+
if (!Number.isSafeInteger(requiredReplicaCount) || requiredReplicaCount < 1
|
|
360
|
+
|| requiredReplicaCount !== targetNodeNames.length * (replicasPerNode || 0)) {
|
|
361
|
+
errors.push('targetScope.requiredReplicaCount must match nodes times replicas');
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
if (!Array.isArray(runtimeTasks) || runtimeTasks.length === 0) {
|
|
366
|
+
errors.push('a GO report requires runtime task evidence');
|
|
367
|
+
} else {
|
|
368
|
+
if (requiredReplicaCount !== undefined && runtimeTasks.length !== requiredReplicaCount) {
|
|
369
|
+
errors.push('runtime task count must equal the required replica count');
|
|
370
|
+
}
|
|
371
|
+
const deploymentIds = new Set<string>();
|
|
372
|
+
const taskCountsByNode = new Map<string, number>();
|
|
373
|
+
for (const task of runtimeTasks) {
|
|
374
|
+
if (!isRecord(task)
|
|
375
|
+
|| !isBoundedIdentifier(task.deploymentId)
|
|
376
|
+
|| deploymentIds.has(task.deploymentId as string)) {
|
|
377
|
+
errors.push('runtime task deployment IDs must be valid and unique');
|
|
378
|
+
continue;
|
|
379
|
+
}
|
|
380
|
+
deploymentIds.add(task.deploymentId as string);
|
|
381
|
+
if (!isBoundedIdentifier(task.nodeName) || !targetNodeNames.includes(task.nodeName)) {
|
|
382
|
+
errors.push('every runtime task must belong to the exact target node scope');
|
|
383
|
+
} else {
|
|
384
|
+
taskCountsByNode.set(task.nodeName, (taskCountsByNode.get(task.nodeName) || 0) + 1);
|
|
385
|
+
}
|
|
386
|
+
if (task.status !== 'running' || task.healthStatus !== 'healthy') {
|
|
387
|
+
errors.push('every runtime task must be running and healthy');
|
|
388
|
+
}
|
|
389
|
+
if (!registryDigest || task.observedDigest !== registryDigest) {
|
|
390
|
+
errors.push('every runtime task must attest the exact registry digest');
|
|
391
|
+
}
|
|
392
|
+
if (typeof task.imageReference !== 'string' || !task.imageReference.trim()) {
|
|
393
|
+
errors.push('every runtime task must identify its image reference');
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
if (replicasPerNode !== undefined
|
|
397
|
+
&& targetNodeNames.some((nodeNameArg) => taskCountsByNode.get(nodeNameArg) !== replicasPerNode)) {
|
|
398
|
+
errors.push('runtime task evidence must cover every target node and replica');
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
if (isRecord(attestation) && requiredReplicaCount !== undefined) {
|
|
403
|
+
if (attestation.requiredReplicaCount !== requiredReplicaCount
|
|
404
|
+
|| attestation.observedReplicaCount !== requiredReplicaCount
|
|
405
|
+
|| attestation.healthyReplicaCount !== requiredReplicaCount
|
|
406
|
+
|| attestation.observedDigestReplicaCount !== requiredReplicaCount
|
|
407
|
+
|| attestation.observedDigestConsistent !== true) {
|
|
408
|
+
errors.push('runtime attestation must consistently cover every required replica');
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
if (isRecord(service) && isRecord(service.registryTarget) && isRecord(registry)) {
|
|
413
|
+
const target = service.registryTarget;
|
|
414
|
+
if (target.protocol !== 'oci'
|
|
415
|
+
|| target.tag !== registry.tag
|
|
416
|
+
|| target.serviceId !== service.serviceId
|
|
417
|
+
|| target.imageId !== service.imageId
|
|
418
|
+
|| typeof target.registryHost !== 'string'
|
|
419
|
+
|| !target.registryHost
|
|
420
|
+
|| typeof target.repository !== 'string'
|
|
421
|
+
|| !target.repository
|
|
422
|
+
|| target.imageUrl !== `${target.registryHost}/${target.repository}:${target.tag}`) {
|
|
423
|
+
errors.push('service registry target must exactly bind the adopted service, image, and tag');
|
|
424
|
+
}
|
|
425
|
+
if (registryDigest) {
|
|
426
|
+
const digestPinnedReference = `${target.registryHost}/${target.repository}@${registryDigest}`;
|
|
427
|
+
const tagAndDigestReference = `${target.imageUrl}@${registryDigest}`;
|
|
428
|
+
const configuredReferences = new Set([
|
|
429
|
+
target.tag,
|
|
430
|
+
target.imageUrl,
|
|
431
|
+
digestPinnedReference,
|
|
432
|
+
tagAndDigestReference,
|
|
433
|
+
]);
|
|
434
|
+
if (!configuredReferences.has(service.configuredReference as string)) {
|
|
435
|
+
errors.push('service configured reference must exactly bind the adopted registry target');
|
|
436
|
+
}
|
|
437
|
+
const runtimeReferences = new Set([
|
|
438
|
+
target.imageUrl,
|
|
439
|
+
digestPinnedReference,
|
|
440
|
+
tagAndDigestReference,
|
|
441
|
+
]);
|
|
442
|
+
if (Array.isArray(runtimeTasks)
|
|
443
|
+
&& runtimeTasks.some((taskArg) => !isRecord(taskArg)
|
|
444
|
+
|| !runtimeReferences.has(taskArg.imageReference as string))) {
|
|
445
|
+
errors.push('every runtime task image reference must exactly bind the adopted registry target');
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
return errors;
|
|
450
|
+
};
|
|
@@ -9,7 +9,7 @@ export type TOciManifestMediaType =
|
|
|
9
9
|
| 'application/vnd.docker.distribution.manifest.list.v2+json'
|
|
10
10
|
| 'application/vnd.docker.distribution.manifest.v2+json';
|
|
11
11
|
|
|
12
|
-
export type TImmutableImageRolloutMode = 'promotion' | 'automatic' | 'rollback';
|
|
12
|
+
export type TImmutableImageRolloutMode = 'promotion' | 'automatic' | 'rollback' | 'adoption';
|
|
13
13
|
|
|
14
14
|
export type TImmutableImageMismatchReason =
|
|
15
15
|
| 'immutable-plan-missing'
|
|
@@ -206,6 +206,8 @@ export interface IImmutableImageDeploymentPlan {
|
|
|
206
206
|
manifestMediaType: TOciManifestMediaType;
|
|
207
207
|
createdAt: number;
|
|
208
208
|
mode: TImmutableImageRolloutMode;
|
|
209
|
+
/** Full pre-adoption service configuration fence, required only for adoption. */
|
|
210
|
+
adoptionConfigurationDigest?: TSha256Digest;
|
|
209
211
|
rollbackOfRolloutId?: string;
|
|
210
212
|
targetScope: IImmutableImageTargetScope;
|
|
211
213
|
}
|
|
@@ -359,6 +361,9 @@ export const validateImmutableImageDeploymentPlan = (
|
|
|
359
361
|
if (!normalizeImmutableReleaseTag(planArg.releaseTag)) {
|
|
360
362
|
errors.push('releaseTag must be a non-latest canonical OCI tag');
|
|
361
363
|
}
|
|
364
|
+
if (!['promotion', 'automatic', 'rollback', 'adoption'].includes(planArg.mode)) {
|
|
365
|
+
errors.push('mode must be a supported immutable rollout mode');
|
|
366
|
+
}
|
|
362
367
|
if (![
|
|
363
368
|
'application/vnd.oci.image.index.v1+json',
|
|
364
369
|
'application/vnd.docker.distribution.manifest.list.v2+json',
|
|
@@ -398,6 +403,17 @@ export const validateImmutableImageDeploymentPlan = (
|
|
|
398
403
|
if (planArg.mode !== 'rollback' && planArg.rollbackOfRolloutId) {
|
|
399
404
|
errors.push('only rollback rollouts may set rollbackOfRolloutId');
|
|
400
405
|
}
|
|
406
|
+
if (planArg.mode === 'adoption') {
|
|
407
|
+
if (planArg.rolloutGeneration !== 1) {
|
|
408
|
+
errors.push('adoption must create rollout generation one');
|
|
409
|
+
}
|
|
410
|
+
if (!planArg.adoptionConfigurationDigest
|
|
411
|
+
|| !isSha256Digest(planArg.adoptionConfigurationDigest)) {
|
|
412
|
+
errors.push('adoption must bind a canonical service configuration digest');
|
|
413
|
+
}
|
|
414
|
+
} else if (planArg.adoptionConfigurationDigest !== undefined) {
|
|
415
|
+
errors.push('only adoption may bind a service configuration digest');
|
|
416
|
+
}
|
|
401
417
|
return errors;
|
|
402
418
|
};
|
|
403
419
|
|
package/ts/data/index.ts
CHANGED
|
@@ -2,6 +2,7 @@ export * from './cloudlyconfig.js';
|
|
|
2
2
|
export * from './cluster.js';
|
|
3
3
|
export * from './config.js';
|
|
4
4
|
export * from './deployment.js';
|
|
5
|
+
export * from './deploymentadoption.js';
|
|
5
6
|
export * from './deploymentoperation.js';
|
|
6
7
|
export * from './deploymentpreflight.js';
|
|
7
8
|
export * from './migration.js';
|
package/ts/data/user.ts
CHANGED
|
@@ -10,6 +10,7 @@ export type TServiceDeploymentCapability =
|
|
|
10
10
|
| 'deployment:registry-push'
|
|
11
11
|
| 'deployment:release-read'
|
|
12
12
|
| 'deployment:promote-image'
|
|
13
|
+
| 'deployment:adopt-existing'
|
|
13
14
|
| 'deployment:status'
|
|
14
15
|
| 'deployment:create-greenfield'
|
|
15
16
|
| 'deployment:promote-route'
|
|
@@ -49,6 +50,7 @@ const serviceDeploymentCapabilities = new Set<TServiceDeploymentCapability>([
|
|
|
49
50
|
'deployment:registry-push',
|
|
50
51
|
'deployment:release-read',
|
|
51
52
|
'deployment:promote-image',
|
|
53
|
+
'deployment:adopt-existing',
|
|
52
54
|
'deployment:status',
|
|
53
55
|
'deployment:create-greenfield',
|
|
54
56
|
'deployment:promote-route',
|
|
@@ -100,6 +102,10 @@ export const validateServiceDeploymentGrant = (
|
|
|
100
102
|
&& !capabilities.includes('deployment:create-greenfield')) {
|
|
101
103
|
errors.push('an organization-service-slot grant must authorize greenfield creation');
|
|
102
104
|
}
|
|
105
|
+
if (capabilities && grant.scope !== 'service'
|
|
106
|
+
&& capabilities.includes('deployment:adopt-existing')) {
|
|
107
|
+
errors.push('deployment:adopt-existing requires an existing-service grant');
|
|
108
|
+
}
|
|
103
109
|
return errors;
|
|
104
110
|
};
|
|
105
111
|
|
package/ts/requests/service.ts
CHANGED
|
@@ -15,6 +15,41 @@ import type {
|
|
|
15
15
|
IServiceDeploymentStatus,
|
|
16
16
|
} from '../data/deploymentoperation.js';
|
|
17
17
|
import type { TSha256Digest } from '../data/immutableimage.js';
|
|
18
|
+
import type {
|
|
19
|
+
IServiceDeploymentAdoptionInput,
|
|
20
|
+
IServiceDeploymentAdoptionPreflightInput,
|
|
21
|
+
IServiceDeploymentAdoptionReport,
|
|
22
|
+
IServiceDeploymentAdoptionResult,
|
|
23
|
+
} from '../data/deploymentadoption.js';
|
|
24
|
+
|
|
25
|
+
export interface IRequest_Any_Cloudly_GetServiceDeploymentAdoptionPreflight
|
|
26
|
+
extends plugins.typedrequestInterfaces.implementsTR<
|
|
27
|
+
plugins.typedrequestInterfaces.ITypedRequest,
|
|
28
|
+
IRequest_Any_Cloudly_GetServiceDeploymentAdoptionPreflight
|
|
29
|
+
> {
|
|
30
|
+
method: 'getServiceDeploymentAdoptionPreflight';
|
|
31
|
+
request: IServiceDeploymentAdoptionPreflightInput & {
|
|
32
|
+
identity: IIdentityCredential;
|
|
33
|
+
};
|
|
34
|
+
response: {
|
|
35
|
+
report: IServiceDeploymentAdoptionReport;
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface IRequest_Any_Cloudly_AdoptServiceDeployment
|
|
40
|
+
extends plugins.typedrequestInterfaces.implementsTR<
|
|
41
|
+
plugins.typedrequestInterfaces.ITypedRequest,
|
|
42
|
+
IRequest_Any_Cloudly_AdoptServiceDeployment
|
|
43
|
+
> {
|
|
44
|
+
method: 'adoptServiceDeployment';
|
|
45
|
+
request: IServiceDeploymentAdoptionInput & {
|
|
46
|
+
identity: IIdentityCredential;
|
|
47
|
+
};
|
|
48
|
+
response: {
|
|
49
|
+
service: IService;
|
|
50
|
+
result: IServiceDeploymentAdoptionResult;
|
|
51
|
+
};
|
|
52
|
+
}
|
|
18
53
|
|
|
19
54
|
export interface IRequest_Any_Cloudly_GetDeploymentPreflight
|
|
20
55
|
extends plugins.typedrequestInterfaces.implementsTR<
|