@serve.zone/interfaces 13.0.1 → 15.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/changelog.md +17 -0
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/data/deploymentoperation.d.ts +161 -0
- package/dist_ts/data/deploymentoperation.js +213 -0
- package/dist_ts/data/deploymentpreflight.d.ts +18 -16
- package/dist_ts/data/deploymentpreflight.js +75 -42
- package/dist_ts/data/immutableimage.d.ts +35 -1
- package/dist_ts/data/immutableimage.js +88 -1
- package/dist_ts/data/index.d.ts +1 -0
- package/dist_ts/data/index.js +2 -1
- package/dist_ts/data/service.d.ts +3 -1
- package/dist_ts/data/user.d.ts +14 -2
- package/dist_ts/data/user.js +54 -2
- package/dist_ts/requests/admin.d.ts +4 -6
- package/dist_ts/requests/service.d.ts +80 -5
- package/package.json +1 -1
- package/readme.md +14 -0
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/data/deploymentoperation.ts +441 -0
- package/ts/data/deploymentpreflight.ts +128 -73
- package/ts/data/immutableimage.ts +120 -1
- package/ts/data/index.ts +1 -0
- package/ts/data/service.ts +3 -1
- package/ts/data/user.ts +85 -2
- package/ts/requests/admin.ts +4 -6
- package/ts/requests/service.ts +109 -5
package/changelog.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2026-07-20 - 15.0.0
|
|
4
|
+
|
|
5
|
+
### Breaking Changes
|
|
6
|
+
|
|
7
|
+
- add scoped immutable deployment operation contracts (deployment)
|
|
8
|
+
- Replace machine deployment grant fields with an exact organization/service or organization/service-slot grant and use JWT-only credentials on scoped deployment RPCs.
|
|
9
|
+
- Add revisioned reserve, status, route promotion, retry, and cleanup contracts with complete configuration, rollout, wildcard-route, readiness, and TLS evidence validation.
|
|
10
|
+
- Require authenticated registry evidence bound to the operation, actor, service, image, registry host, repository, exact tag, root digest, and OCI index media type.
|
|
11
|
+
- Require promotion and rollback requests to carry exact operation/repository/tag/digest fences and immutable plans and verified runtime tasks to expose exact rollout and digest evidence.
|
|
12
|
+
|
|
13
|
+
## 2026-07-19 - 14.0.0
|
|
14
|
+
|
|
15
|
+
### Breaking Changes
|
|
16
|
+
|
|
17
|
+
- distinguish read-only observed runtime digests from verified immutable rollout digests (deployment)
|
|
18
|
+
- Report explicit observed-digest replica counts without promoting mutable workloads to verified status.
|
|
19
|
+
|
|
3
20
|
## 2026-07-19 - 13.0.1
|
|
4
21
|
|
|
5
22
|
### Fixes
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@serve.zone/interfaces',
|
|
6
|
-
version: '
|
|
6
|
+
version: '15.0.0',
|
|
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,161 @@
|
|
|
1
|
+
import type { IDeploymentPreflightProposedConfiguration, IDeploymentPreflightRuntimeTask } from './deploymentpreflight.js';
|
|
2
|
+
import type { IImageRolloutStatus, IImmutableImageDeploymentPlan, TSha256Digest } from './immutableimage.js';
|
|
3
|
+
import type { IRegistryTarget } from './registry.js';
|
|
4
|
+
import type { TServiceTargetPortRef } from './serviceports.js';
|
|
5
|
+
export type TDeploymentOperationMode = 'existing-service' | 'greenfield';
|
|
6
|
+
export type TDeploymentOperationPhase = 'reserve' | 'promote' | 'route';
|
|
7
|
+
interface IDeploymentReservationInputBase {
|
|
8
|
+
organizationId: string;
|
|
9
|
+
serviceId: string;
|
|
10
|
+
idempotencyKey: string;
|
|
11
|
+
sourceRevision: string;
|
|
12
|
+
version: string;
|
|
13
|
+
intentDigest: TSha256Digest;
|
|
14
|
+
proposedConfiguration: IDeploymentPreflightProposedConfiguration;
|
|
15
|
+
releaseTag: string;
|
|
16
|
+
routes: IDeploymentRouteRequest[];
|
|
17
|
+
}
|
|
18
|
+
export interface IExistingServiceDeploymentReservationInput extends IDeploymentReservationInputBase {
|
|
19
|
+
mode: 'existing-service';
|
|
20
|
+
expectedRolloutGeneration: number;
|
|
21
|
+
expectedCurrentRolloutId?: string;
|
|
22
|
+
}
|
|
23
|
+
export interface IGreenfieldServiceDeploymentReservationInput extends IDeploymentReservationInputBase {
|
|
24
|
+
mode: 'greenfield';
|
|
25
|
+
expectedRolloutGeneration?: never;
|
|
26
|
+
expectedCurrentRolloutId?: never;
|
|
27
|
+
}
|
|
28
|
+
export type IDeploymentReservationInput = IExistingServiceDeploymentReservationInput | IGreenfieldServiceDeploymentReservationInput;
|
|
29
|
+
export type TDeploymentOperationState = 'reserving' | 'reserved' | 'provisioning' | 'awaiting-image' | 'image-recorded' | 'promoting-image' | 'rolling-out' | 'ready-for-route' | 'promoting-route' | 'verifying-route' | 'succeeded' | 'rolling-back' | 'rolled-back' | 'failed' | 'cleaning' | 'cleaned';
|
|
30
|
+
export interface IDeploymentRouteRequest {
|
|
31
|
+
hostname: string;
|
|
32
|
+
targetPort: Extract<TServiceTargetPortRef, number>;
|
|
33
|
+
/** Required exact one-label hostname used to verify a wildcard route. */
|
|
34
|
+
verificationHostname?: string;
|
|
35
|
+
readinessPath?: string;
|
|
36
|
+
expectedStatusCodes?: number[];
|
|
37
|
+
}
|
|
38
|
+
export interface IDeploymentRouteClaimTarget {
|
|
39
|
+
hostname: string;
|
|
40
|
+
bucketHostname: string;
|
|
41
|
+
wildcard: boolean;
|
|
42
|
+
}
|
|
43
|
+
export declare const canonicalizeDeploymentHostname: (hostnameArg: unknown) => string | undefined;
|
|
44
|
+
/**
|
|
45
|
+
* Wildcards match exactly one label. Exact siblings share a bucket document
|
|
46
|
+
* but may coexist; a wildcard claim excludes every exact name in its bucket.
|
|
47
|
+
*/
|
|
48
|
+
export declare const getDeploymentRouteClaimTarget: (hostnameArg: string) => IDeploymentRouteClaimTarget | undefined;
|
|
49
|
+
export declare const getDeploymentRouteVerificationHostname: (routeArg: IDeploymentRouteRequest) => string | undefined;
|
|
50
|
+
export declare const normalizeDeploymentReadinessPath: (pathArg?: unknown) => string | undefined;
|
|
51
|
+
export declare const validateDeploymentProposedConfiguration: (configurationArg: unknown) => string[];
|
|
52
|
+
export declare const validateDeploymentReservationInput: (inputArg: unknown) => string[];
|
|
53
|
+
interface IDeploymentRouteVerificationEvidenceBase {
|
|
54
|
+
hostname: string;
|
|
55
|
+
url: string;
|
|
56
|
+
checkedAt: number;
|
|
57
|
+
resolvedAddresses: string[];
|
|
58
|
+
rolloutId: string;
|
|
59
|
+
rolloutGeneration: number;
|
|
60
|
+
expectedDigest: TSha256Digest;
|
|
61
|
+
}
|
|
62
|
+
export interface IDeploymentRouteVerificationSuccessEvidence extends IDeploymentRouteVerificationEvidenceBase {
|
|
63
|
+
outcome: 'succeeded';
|
|
64
|
+
tls: {
|
|
65
|
+
authorized: true;
|
|
66
|
+
servername: string;
|
|
67
|
+
subjectAlternativeNames: string[];
|
|
68
|
+
validFrom?: string;
|
|
69
|
+
validTo?: string;
|
|
70
|
+
};
|
|
71
|
+
http: {
|
|
72
|
+
statusCode: number;
|
|
73
|
+
redirected: false;
|
|
74
|
+
};
|
|
75
|
+
readiness: {
|
|
76
|
+
path: string;
|
|
77
|
+
expectedStatusCodes: number[];
|
|
78
|
+
ready: true;
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
export interface IDeploymentRouteVerificationFailureEvidence extends IDeploymentRouteVerificationEvidenceBase {
|
|
82
|
+
outcome: 'failed';
|
|
83
|
+
stage: 'dns' | 'address-policy' | 'connect' | 'tls' | 'http' | 'readiness';
|
|
84
|
+
code: string;
|
|
85
|
+
message: string;
|
|
86
|
+
tls?: IDeploymentRouteVerificationSuccessEvidence['tls'];
|
|
87
|
+
http?: IDeploymentRouteVerificationSuccessEvidence['http'];
|
|
88
|
+
readiness?: IDeploymentRouteVerificationSuccessEvidence['readiness'];
|
|
89
|
+
}
|
|
90
|
+
export type IDeploymentRouteVerificationEvidence = IDeploymentRouteVerificationSuccessEvidence | IDeploymentRouteVerificationFailureEvidence;
|
|
91
|
+
export interface IDeploymentOperationFailure {
|
|
92
|
+
code: string;
|
|
93
|
+
message: string;
|
|
94
|
+
retryable: boolean;
|
|
95
|
+
failedAt: number;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Durable deployment fence. All state transitions compare-and-set both id and
|
|
99
|
+
* revision. Claim keys are server-generated and never accepted as authority.
|
|
100
|
+
*/
|
|
101
|
+
export interface IServiceDeploymentOperation {
|
|
102
|
+
id: string;
|
|
103
|
+
revision: number;
|
|
104
|
+
data: {
|
|
105
|
+
mode: TDeploymentOperationMode;
|
|
106
|
+
organizationId: string;
|
|
107
|
+
serviceId: string;
|
|
108
|
+
actorUserId: string;
|
|
109
|
+
idempotencyKey: string;
|
|
110
|
+
requestDigest: TSha256Digest;
|
|
111
|
+
sourceRevision: string;
|
|
112
|
+
version: string;
|
|
113
|
+
intentDigest: TSha256Digest;
|
|
114
|
+
configurationDigest: TSha256Digest;
|
|
115
|
+
proposedConfiguration: IDeploymentPreflightProposedConfiguration;
|
|
116
|
+
namespace: string;
|
|
117
|
+
registryTarget: IRegistryTarget;
|
|
118
|
+
releaseTag: string;
|
|
119
|
+
routes: IDeploymentRouteRequest[];
|
|
120
|
+
claimKeys: string[];
|
|
121
|
+
state: TDeploymentOperationState;
|
|
122
|
+
releaseId?: string;
|
|
123
|
+
registryRootDigest?: TSha256Digest;
|
|
124
|
+
rolloutId?: string;
|
|
125
|
+
rolloutGeneration?: number;
|
|
126
|
+
routeGeneration?: number;
|
|
127
|
+
routeVerification?: IDeploymentRouteVerificationEvidence[];
|
|
128
|
+
failure?: IDeploymentOperationFailure;
|
|
129
|
+
createdAt: number;
|
|
130
|
+
updatedAt: number;
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
export interface IServiceDeploymentStatus {
|
|
134
|
+
operation: IServiceDeploymentOperation;
|
|
135
|
+
imageDeployment?: IImmutableImageDeploymentPlan;
|
|
136
|
+
imageRolloutStatus?: IImageRolloutStatus;
|
|
137
|
+
runtimeTasks: IDeploymentRuntimeTaskEvidence[];
|
|
138
|
+
routeVerification: IDeploymentRouteVerificationEvidence[];
|
|
139
|
+
immutableRolloutSucceeded: boolean;
|
|
140
|
+
runtimeDigestVerified: boolean;
|
|
141
|
+
routeVerified: boolean;
|
|
142
|
+
succeeded: boolean;
|
|
143
|
+
}
|
|
144
|
+
interface IDeploymentRuntimeTaskEvidenceBase extends Omit<IDeploymentPreflightRuntimeTask, 'verificationStatus' | 'observedDigest' | 'reportedDigest'> {
|
|
145
|
+
rolloutId: string;
|
|
146
|
+
rolloutGeneration: number;
|
|
147
|
+
expectedDigest: TSha256Digest;
|
|
148
|
+
observedAt: number;
|
|
149
|
+
}
|
|
150
|
+
export interface IVerifiedDeploymentRuntimeTaskEvidence extends IDeploymentRuntimeTaskEvidenceBase {
|
|
151
|
+
verificationStatus: 'verified';
|
|
152
|
+
observedDigest: TSha256Digest;
|
|
153
|
+
reportedDigest: TSha256Digest;
|
|
154
|
+
}
|
|
155
|
+
export interface IUnverifiedDeploymentRuntimeTaskEvidence extends IDeploymentRuntimeTaskEvidenceBase {
|
|
156
|
+
verificationStatus: 'missing' | 'mismatched';
|
|
157
|
+
observedDigest?: TSha256Digest;
|
|
158
|
+
reportedDigest?: TSha256Digest;
|
|
159
|
+
}
|
|
160
|
+
export type IDeploymentRuntimeTaskEvidence = IVerifiedDeploymentRuntimeTaskEvidence | IUnverifiedDeploymentRuntimeTaskEvidence;
|
|
161
|
+
export {};
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { normalizeImmutableReleaseTag, normalizeSha256Digest } from './immutableimage.js';
|
|
2
|
+
const canonicalHostnameRegex = /^(?:\*\.)?[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)+$/;
|
|
3
|
+
export const canonicalizeDeploymentHostname = (hostnameArg) => {
|
|
4
|
+
if (typeof hostnameArg !== 'string')
|
|
5
|
+
return undefined;
|
|
6
|
+
const hostname = hostnameArg.trim().toLowerCase().replace(/\.$/, '');
|
|
7
|
+
return hostname.length <= 253 && canonicalHostnameRegex.test(hostname)
|
|
8
|
+
? hostname
|
|
9
|
+
: undefined;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Wildcards match exactly one label. Exact siblings share a bucket document
|
|
13
|
+
* but may coexist; a wildcard claim excludes every exact name in its bucket.
|
|
14
|
+
*/
|
|
15
|
+
export const getDeploymentRouteClaimTarget = (hostnameArg) => {
|
|
16
|
+
const hostname = canonicalizeDeploymentHostname(hostnameArg);
|
|
17
|
+
if (!hostname)
|
|
18
|
+
return undefined;
|
|
19
|
+
const wildcard = hostname.startsWith('*.');
|
|
20
|
+
const labels = (wildcard ? hostname.slice(2) : hostname).split('.');
|
|
21
|
+
const bucketHostname = wildcard ? labels.join('.') : labels.slice(1).join('.');
|
|
22
|
+
if (!bucketHostname || (wildcard && labels.length < 2))
|
|
23
|
+
return undefined;
|
|
24
|
+
return { hostname, bucketHostname, wildcard };
|
|
25
|
+
};
|
|
26
|
+
export const getDeploymentRouteVerificationHostname = (routeArg) => {
|
|
27
|
+
const target = getDeploymentRouteClaimTarget(routeArg.hostname);
|
|
28
|
+
if (!target)
|
|
29
|
+
return undefined;
|
|
30
|
+
if (!target.wildcard) {
|
|
31
|
+
return routeArg.verificationHostname === undefined
|
|
32
|
+
|| routeArg.verificationHostname === target.hostname
|
|
33
|
+
? target.hostname
|
|
34
|
+
: undefined;
|
|
35
|
+
}
|
|
36
|
+
if (!routeArg.verificationHostname)
|
|
37
|
+
return undefined;
|
|
38
|
+
const verificationTarget = getDeploymentRouteClaimTarget(routeArg.verificationHostname);
|
|
39
|
+
return verificationTarget
|
|
40
|
+
&& !verificationTarget.wildcard
|
|
41
|
+
&& verificationTarget.bucketHostname === target.bucketHostname
|
|
42
|
+
? verificationTarget.hostname
|
|
43
|
+
: undefined;
|
|
44
|
+
};
|
|
45
|
+
export const normalizeDeploymentReadinessPath = (pathArg) => {
|
|
46
|
+
if (pathArg !== undefined && typeof pathArg !== 'string')
|
|
47
|
+
return undefined;
|
|
48
|
+
const path = pathArg || '/';
|
|
49
|
+
return /^\/(?!\/)[A-Za-z0-9._~!$&'()*+,;=:@%\/-]{0,1023}$/.test(path)
|
|
50
|
+
? path
|
|
51
|
+
: undefined;
|
|
52
|
+
};
|
|
53
|
+
const deploymentIdentifierRegex = /^[A-Za-z0-9][A-Za-z0-9:._-]{0,199}$/;
|
|
54
|
+
const fullGitRevisionRegex = /^[a-f0-9]{40}$/;
|
|
55
|
+
const semanticVersionRegex = /^(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)(?:-(?:0|[1-9][0-9]*|[0-9]*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9][0-9]*|[0-9]*[A-Za-z-][0-9A-Za-z-]*))*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
|
|
56
|
+
const isRecord = (valueArg) => (Boolean(valueArg) && typeof valueArg === 'object' && !Array.isArray(valueArg));
|
|
57
|
+
const validateStringArray = (valueArg, maxItemsArg, validatorArg) => Array.isArray(valueArg)
|
|
58
|
+
&& valueArg.length <= maxItemsArg
|
|
59
|
+
&& valueArg.every((itemArg) => typeof itemArg === 'string'
|
|
60
|
+
&& itemArg.length > 0
|
|
61
|
+
&& itemArg.length <= 253
|
|
62
|
+
&& validatorArg(itemArg))
|
|
63
|
+
&& new Set(valueArg).size === valueArg.length;
|
|
64
|
+
export const validateDeploymentProposedConfiguration = (configurationArg) => {
|
|
65
|
+
if (!isRecord(configurationArg))
|
|
66
|
+
return ['proposedConfiguration must be an object'];
|
|
67
|
+
const errors = [];
|
|
68
|
+
if (configurationArg.schemaVersion !== 1)
|
|
69
|
+
errors.push('schemaVersion must be 1');
|
|
70
|
+
if (typeof configurationArg.declarationComplete !== 'boolean') {
|
|
71
|
+
errors.push('declarationComplete must be boolean');
|
|
72
|
+
}
|
|
73
|
+
if (typeof configurationArg.projectName !== 'string'
|
|
74
|
+
|| !configurationArg.projectName.trim()
|
|
75
|
+
|| configurationArg.projectName.length > 200) {
|
|
76
|
+
errors.push('projectName must be bounded and non-empty');
|
|
77
|
+
}
|
|
78
|
+
if (!validateStringArray(configurationArg.targetPlatforms, 8, (platformArg) => (/^[a-z0-9][a-z0-9._-]*\/[a-z0-9][a-z0-9._-]*$/.test(platformArg)))) {
|
|
79
|
+
errors.push('targetPlatforms must be unique canonical platform identifiers');
|
|
80
|
+
}
|
|
81
|
+
if (!validateStringArray(configurationArg.publicDomains, 32, (domainArg) => (canonicalizeDeploymentHostname(domainArg) === domainArg))) {
|
|
82
|
+
errors.push('publicDomains must be unique canonical exact or wildcard hostnames');
|
|
83
|
+
}
|
|
84
|
+
if (!validateStringArray(configurationArg.environmentVariableNames, 256, (nameArg) => (nameArg.length <= 253 && /^[A-Z_][A-Z0-9_]*$/.test(nameArg)))) {
|
|
85
|
+
errors.push('environmentVariableNames must be unique canonical names');
|
|
86
|
+
}
|
|
87
|
+
if (!validateStringArray(configurationArg.secretReferenceIds, 64, (idArg) => (idArg.length <= 253 && /^[A-Za-z0-9][A-Za-z0-9:._-]*$/.test(idArg)))) {
|
|
88
|
+
errors.push('secretReferenceIds must be unique canonical identifiers');
|
|
89
|
+
}
|
|
90
|
+
if (!Array.isArray(configurationArg.containerPorts)
|
|
91
|
+
|| configurationArg.containerPorts.length > 64
|
|
92
|
+
|| configurationArg.containerPorts.some((portArg) => !Number.isSafeInteger(portArg)
|
|
93
|
+
|| portArg < 1 || portArg > 65535)
|
|
94
|
+
|| new Set(configurationArg.containerPorts).size !== configurationArg.containerPorts.length) {
|
|
95
|
+
errors.push('containerPorts must be unique valid ports');
|
|
96
|
+
}
|
|
97
|
+
if (!Array.isArray(configurationArg.volumeMounts)
|
|
98
|
+
|| configurationArg.volumeMounts.length > 32
|
|
99
|
+
|| configurationArg.volumeMounts.some((mountArg) => !isRecord(mountArg)
|
|
100
|
+
|| typeof mountArg.mountPath !== 'string'
|
|
101
|
+
|| !/^\/[A-Za-z0-9._/-]{0,254}$/.test(mountArg.mountPath)
|
|
102
|
+
|| (mountArg.storageClass !== 'corestore' && mountArg.storageClass !== 'ephemeral')
|
|
103
|
+
|| (mountArg.capability !== undefined
|
|
104
|
+
&& mountArg.capability !== 'database'
|
|
105
|
+
&& mountArg.capability !== 'objectstorage'))) {
|
|
106
|
+
errors.push('volumeMounts must be canonical supported declarations');
|
|
107
|
+
}
|
|
108
|
+
if (!Array.isArray(configurationArg.requiredCapabilities)
|
|
109
|
+
|| configurationArg.requiredCapabilities.length > 2
|
|
110
|
+
|| configurationArg.requiredCapabilities.some((capabilityArg) => (capabilityArg !== 'database' && capabilityArg !== 'objectstorage'))
|
|
111
|
+
|| new Set(configurationArg.requiredCapabilities).size
|
|
112
|
+
!== configurationArg.requiredCapabilities.length) {
|
|
113
|
+
errors.push('requiredCapabilities must be a unique supported capability set');
|
|
114
|
+
}
|
|
115
|
+
return errors;
|
|
116
|
+
};
|
|
117
|
+
export const validateDeploymentReservationInput = (inputArg) => {
|
|
118
|
+
if (!isRecord(inputArg))
|
|
119
|
+
return ['reservation input must be an object'];
|
|
120
|
+
const errors = [];
|
|
121
|
+
if (inputArg.mode !== 'existing-service' && inputArg.mode !== 'greenfield') {
|
|
122
|
+
errors.push('mode must identify an existing-service or greenfield deployment');
|
|
123
|
+
}
|
|
124
|
+
for (const field of ['organizationId', 'serviceId', 'idempotencyKey']) {
|
|
125
|
+
if (typeof inputArg[field] !== 'string'
|
|
126
|
+
|| !deploymentIdentifierRegex.test(inputArg[field])) {
|
|
127
|
+
errors.push(`${field} must be a bounded canonical identifier`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
if (typeof inputArg.sourceRevision !== 'string'
|
|
131
|
+
|| !fullGitRevisionRegex.test(inputArg.sourceRevision)) {
|
|
132
|
+
errors.push('sourceRevision must be a full lowercase git revision');
|
|
133
|
+
}
|
|
134
|
+
if (typeof inputArg.version !== 'string' || !semanticVersionRegex.test(inputArg.version)) {
|
|
135
|
+
errors.push('version must be a canonical semantic version');
|
|
136
|
+
}
|
|
137
|
+
if (!normalizeSha256Digest(inputArg.intentDigest)) {
|
|
138
|
+
errors.push('intentDigest must be a canonical sha256 digest');
|
|
139
|
+
}
|
|
140
|
+
if (!normalizeImmutableReleaseTag(inputArg.releaseTag)) {
|
|
141
|
+
errors.push('releaseTag must be a canonical non-latest OCI tag');
|
|
142
|
+
}
|
|
143
|
+
const configuration = isRecord(inputArg.proposedConfiguration)
|
|
144
|
+
? inputArg.proposedConfiguration
|
|
145
|
+
: undefined;
|
|
146
|
+
errors.push(...validateDeploymentProposedConfiguration(inputArg.proposedConfiguration));
|
|
147
|
+
const containerPorts = configuration && Array.isArray(configuration.containerPorts)
|
|
148
|
+
? configuration.containerPorts
|
|
149
|
+
: undefined;
|
|
150
|
+
const publicDomains = configuration && Array.isArray(configuration.publicDomains)
|
|
151
|
+
? configuration.publicDomains.filter((domainArg) => (typeof domainArg === 'string'))
|
|
152
|
+
: undefined;
|
|
153
|
+
if (configuration?.declarationComplete !== true) {
|
|
154
|
+
errors.push('proposedConfiguration must declare itself complete');
|
|
155
|
+
}
|
|
156
|
+
const routes = Array.isArray(inputArg.routes) ? inputArg.routes : undefined;
|
|
157
|
+
const routeHostnames = routes?.map((routeArg) => (isRecord(routeArg) && typeof routeArg.hostname === 'string' ? routeArg.hostname : undefined));
|
|
158
|
+
if (!routes
|
|
159
|
+
|| routes.length > 32
|
|
160
|
+
|| !routeHostnames
|
|
161
|
+
|| new Set(routeHostnames).size !== routeHostnames.length
|
|
162
|
+
|| routes.some((routeArg) => {
|
|
163
|
+
if (!isRecord(routeArg)
|
|
164
|
+
|| typeof routeArg.hostname !== 'string'
|
|
165
|
+
|| canonicalizeDeploymentHostname(routeArg.hostname) !== routeArg.hostname
|
|
166
|
+
|| !Number.isSafeInteger(routeArg.targetPort)
|
|
167
|
+
|| routeArg.targetPort < 1
|
|
168
|
+
|| routeArg.targetPort > 65535
|
|
169
|
+
|| !containerPorts?.includes(routeArg.targetPort)) {
|
|
170
|
+
return true;
|
|
171
|
+
}
|
|
172
|
+
const typedRoute = routeArg;
|
|
173
|
+
return getDeploymentRouteVerificationHostname(typedRoute) === undefined
|
|
174
|
+
|| (routeArg.readinessPath !== undefined
|
|
175
|
+
&& (typeof routeArg.readinessPath !== 'string'
|
|
176
|
+
|| normalizeDeploymentReadinessPath(routeArg.readinessPath) !== routeArg.readinessPath))
|
|
177
|
+
|| (routeArg.expectedStatusCodes !== undefined
|
|
178
|
+
&& (!Array.isArray(routeArg.expectedStatusCodes)
|
|
179
|
+
|| routeArg.expectedStatusCodes.length < 1
|
|
180
|
+
|| routeArg.expectedStatusCodes.length > 16
|
|
181
|
+
|| new Set(routeArg.expectedStatusCodes).size !== routeArg.expectedStatusCodes.length
|
|
182
|
+
|| routeArg.expectedStatusCodes.some((statusArg) => !Number.isSafeInteger(statusArg)
|
|
183
|
+
|| statusArg < 200 || statusArg > 299)));
|
|
184
|
+
})) {
|
|
185
|
+
errors.push('routes must be unique canonical declarations over declared numeric ports');
|
|
186
|
+
}
|
|
187
|
+
if (inputArg.mode === 'greenfield') {
|
|
188
|
+
if (inputArg.expectedRolloutGeneration !== undefined
|
|
189
|
+
|| inputArg.expectedCurrentRolloutId !== undefined) {
|
|
190
|
+
errors.push('greenfield reservation must not carry an existing rollout fence');
|
|
191
|
+
}
|
|
192
|
+
if (publicDomains && routeHostnames) {
|
|
193
|
+
const declared = [...new Set(publicDomains)].sort();
|
|
194
|
+
const routed = [...new Set(routeHostnames.filter((valueArg) => (typeof valueArg === 'string')))].sort();
|
|
195
|
+
if (JSON.stringify(declared) !== JSON.stringify(routed)) {
|
|
196
|
+
errors.push('greenfield routes must exactly match proposed publicDomains');
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
if (inputArg.mode === 'existing-service') {
|
|
201
|
+
if (!Number.isSafeInteger(inputArg.expectedRolloutGeneration)
|
|
202
|
+
|| inputArg.expectedRolloutGeneration < 0) {
|
|
203
|
+
errors.push('existing-service reservation requires an explicit rollout generation fence');
|
|
204
|
+
}
|
|
205
|
+
if (inputArg.expectedCurrentRolloutId !== undefined
|
|
206
|
+
&& (typeof inputArg.expectedCurrentRolloutId !== 'string'
|
|
207
|
+
|| !deploymentIdentifierRegex.test(inputArg.expectedCurrentRolloutId))) {
|
|
208
|
+
errors.push('expectedCurrentRolloutId must be a bounded canonical identifier');
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return errors;
|
|
212
|
+
};
|
|
213
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVwbG95bWVudG9wZXJhdGlvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL2RhdGEvZGVwbG95bWVudG9wZXJhdGlvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFFQSxPQUFPLEVBQUUsNEJBQTRCLEVBQUUscUJBQXFCLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQXNFMUYsTUFBTSxzQkFBc0IsR0FBRyw0RkFBNEYsQ0FBQztBQUU1SCxNQUFNLENBQUMsTUFBTSw4QkFBOEIsR0FBRyxDQUFDLFdBQW9CLEVBQXNCLEVBQUU7SUFDekYsSUFBSSxPQUFPLFdBQVcsS0FBSyxRQUFRO1FBQUUsT0FBTyxTQUFTLENBQUM7SUFDdEQsTUFBTSxRQUFRLEdBQUcsV0FBVyxDQUFDLElBQUksRUFBRSxDQUFDLFdBQVcsRUFBRSxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDckUsT0FBTyxRQUFRLENBQUMsTUFBTSxJQUFJLEdBQUcsSUFBSSxzQkFBc0IsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDO1FBQ3BFLENBQUMsQ0FBQyxRQUFRO1FBQ1YsQ0FBQyxDQUFDLFNBQVMsQ0FBQztBQUNoQixDQUFDLENBQUM7QUFFRjs7O0dBR0c7QUFDSCxNQUFNLENBQUMsTUFBTSw2QkFBNkIsR0FBRyxDQUMzQyxXQUFtQixFQUNzQixFQUFFO0lBQzNDLE1BQU0sUUFBUSxHQUFHLDhCQUE4QixDQUFDLFdBQVcsQ0FBQyxDQUFDO0lBQzdELElBQUksQ0FBQyxRQUFRO1FBQUUsT0FBTyxTQUFTLENBQUM7SUFDaEMsTUFBTSxRQUFRLEdBQUcsUUFBUSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUMzQyxNQUFNLE1BQU0sR0FBRyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FB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
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { TOciManifestMediaType, TSha256Digest } from './immutableimage.js';
|
|
2
2
|
import type { TServiceDeploymentCapability } from './user.js';
|
|
3
|
+
import type { IDeploymentRouteRequest, IServiceDeploymentOperation, TDeploymentOperationMode, TDeploymentOperationPhase } from './deploymentoperation.js';
|
|
3
4
|
export type TDeploymentPreflightDecision = 'GO' | 'NO-GO';
|
|
4
|
-
export type TDeploymentPreflightBlockerCode = 'INVALID_REQUEST' | 'AUTHORIZATION_MISSING' | 'SOURCE_REVISION_INVALID' | 'SOURCE_WORKTREE_DIRTY' | 'VERSION_NOT_RESERVED' | 'VERSION_COLLISION' | 'NAMESPACE_NOT_RESERVED' | 'NAMESPACE_COLLISION' | 'NAMESPACE_NOT_PROVEN_BLANK' | 'CONFIGURATION_DIGEST_INVALID' | 'INTENT_DIGEST_INVALID' | 'PROPOSED_CONFIGURATION_INCOMPLETE' | 'CURRENT_REFERENCE_MUTABLE' | 'CURRENT_RUNTIME_DIGEST_MISSING' | 'OCI_INDEX_DIGEST_REQUIRED' | 'OCI_INDEX_NOT_FOUND' | 'OCI_INDEX_MEDIA_TYPE_REQUIRED' | 'OCI_PLATFORM_MISSING' | 'OCI_PLATFORM_MANIFEST_MISSING' | 'IMMUTABLE_RELEASE_TAG_REQUIRED' | 'IMMUTABLE_RELEASE_TAG_NOT_RESERVED' | 'RELEASE_EVIDENCE_MISSING' | 'RELEASE_EVIDENCE_INVALID' | 'RELEASE_NOT_AUTHORIZED' | 'GREENFIELD_EXECUTION_UNAVAILABLE' | 'ROUTE_PROMOTION_FENCE_UNAVAILABLE' | 'POST_DEPLOYMENT_VERIFICATION_UNAVAILABLE' | 'WOULD_REPLACE_EXISTING_STATE' | 'CORESTORE_INVENTORY_UNAVAILABLE' | 'RUNTIME_ATTESTATION_MISMATCH';
|
|
5
|
+
export type TDeploymentPreflightBlockerCode = 'INVALID_REQUEST' | 'AUTHORIZATION_MISSING' | 'ORGANIZATION_SCOPE_MISSING' | 'SERVICE_OWNERSHIP_MISMATCH' | 'DEPLOYMENT_OPERATION_NOT_FOUND' | 'DEPLOYMENT_OPERATION_CONFLICT' | 'DEPLOY_ON_PUSH_MUST_BE_DISABLED' | 'REGISTRY_AUTHENTICATION_UNAVAILABLE' | 'REGISTRY_REPOSITORY_MISMATCH' | 'REGISTRY_TAG_CONFLICT' | 'SOURCE_REVISION_INVALID' | 'SOURCE_WORKTREE_DIRTY' | 'VERSION_NOT_RESERVED' | 'VERSION_COLLISION' | 'NAMESPACE_NOT_RESERVED' | 'NAMESPACE_COLLISION' | 'NAMESPACE_NOT_PROVEN_BLANK' | 'CONFIGURATION_DIGEST_INVALID' | 'INTENT_DIGEST_INVALID' | 'PROPOSED_CONFIGURATION_INCOMPLETE' | 'CURRENT_REFERENCE_MUTABLE' | 'CURRENT_RUNTIME_DIGEST_MISSING' | 'OCI_INDEX_DIGEST_REQUIRED' | 'OCI_INDEX_NOT_FOUND' | 'OCI_INDEX_MEDIA_TYPE_REQUIRED' | 'OCI_PLATFORM_MISSING' | 'OCI_PLATFORM_MANIFEST_MISSING' | 'IMMUTABLE_RELEASE_TAG_REQUIRED' | 'IMMUTABLE_RELEASE_TAG_NOT_RESERVED' | 'RELEASE_EVIDENCE_MISSING' | 'RELEASE_EVIDENCE_INVALID' | 'RELEASE_EVIDENCE_AMBIGUOUS' | 'RELEASE_NOT_AUTHORIZED' | 'GREENFIELD_EXECUTION_UNAVAILABLE' | 'ROUTE_PROMOTION_FENCE_UNAVAILABLE' | 'POST_DEPLOYMENT_VERIFICATION_UNAVAILABLE' | 'WOULD_REPLACE_EXISTING_STATE' | 'CORESTORE_INVENTORY_UNAVAILABLE' | 'RUNTIME_ATTESTATION_MISMATCH' | 'ROLLOUT_ACTIVE_CONFLICT' | 'ROLLOUT_NOT_SUCCEEDED' | 'ROUTE_UNAVAILABLE' | 'ROUTE_VERIFICATION_FAILED' | 'TLS_VERIFICATION_FAILED';
|
|
5
6
|
export interface IDeploymentPreflightBlocker {
|
|
6
7
|
code: TDeploymentPreflightBlockerCode;
|
|
7
8
|
message: string;
|
|
@@ -24,6 +25,7 @@ export interface IDeploymentPreflightRuntimeTask {
|
|
|
24
25
|
status: string;
|
|
25
26
|
healthStatus?: string;
|
|
26
27
|
imageReference?: string;
|
|
28
|
+
observedDigest?: TSha256Digest;
|
|
27
29
|
reportedDigest?: TSha256Digest;
|
|
28
30
|
verificationStatus?: 'not-required' | 'pending' | 'verified' | 'missing' | 'mismatched';
|
|
29
31
|
}
|
|
@@ -82,6 +84,10 @@ export interface IDeploymentReleaseEvidence {
|
|
|
82
84
|
export interface IDeploymentPreflightRequestData {
|
|
83
85
|
requestId: string;
|
|
84
86
|
serviceId: string;
|
|
87
|
+
organizationId?: string;
|
|
88
|
+
mode?: TDeploymentOperationMode;
|
|
89
|
+
phase?: TDeploymentOperationPhase;
|
|
90
|
+
operationId?: string;
|
|
85
91
|
sourceRevision: string;
|
|
86
92
|
sourceDirty: boolean;
|
|
87
93
|
version: string;
|
|
@@ -90,7 +96,9 @@ export interface IDeploymentPreflightRequestData {
|
|
|
90
96
|
ociIndexDigest?: string;
|
|
91
97
|
releaseTag?: string;
|
|
92
98
|
releaseEvidence?: IDeploymentReleaseEvidence;
|
|
93
|
-
|
|
99
|
+
routes?: IDeploymentRouteRequest[];
|
|
100
|
+
/** Legacy v14 discriminator. Equivalent to mode: 'greenfield'. */
|
|
101
|
+
greenfield?: true;
|
|
94
102
|
}
|
|
95
103
|
export interface IDeploymentPreflightReport {
|
|
96
104
|
schemaVersion: 2;
|
|
@@ -98,6 +106,7 @@ export interface IDeploymentPreflightReport {
|
|
|
98
106
|
mutationPerformed: false;
|
|
99
107
|
generatedAt: number;
|
|
100
108
|
service: {
|
|
109
|
+
organizationId?: string;
|
|
101
110
|
serviceId: string;
|
|
102
111
|
serviceName: string;
|
|
103
112
|
workspaceIdentity: string;
|
|
@@ -105,6 +114,9 @@ export interface IDeploymentPreflightReport {
|
|
|
105
114
|
registryRepository: string;
|
|
106
115
|
deployOnPush: boolean;
|
|
107
116
|
};
|
|
117
|
+
mode?: TDeploymentOperationMode;
|
|
118
|
+
phase?: TDeploymentOperationPhase;
|
|
119
|
+
operation?: IServiceDeploymentOperation;
|
|
108
120
|
source: {
|
|
109
121
|
revision: string;
|
|
110
122
|
dirty: boolean;
|
|
@@ -133,6 +145,8 @@ export interface IDeploymentPreflightReport {
|
|
|
133
145
|
observedReplicaCount: number;
|
|
134
146
|
healthyReplicaCount: number;
|
|
135
147
|
verifiedReplicaCount: number;
|
|
148
|
+
observedDigestReplicaCount: number;
|
|
149
|
+
observedDigestConsistent: boolean;
|
|
136
150
|
consistentDigest: boolean;
|
|
137
151
|
};
|
|
138
152
|
platformBindings: IDeploymentPreflightPlatformBinding[];
|
|
@@ -158,20 +172,8 @@ export interface IGreenfieldDeploymentFence {
|
|
|
158
172
|
configurationDigest: TSha256Digest;
|
|
159
173
|
targetNamespace: string;
|
|
160
174
|
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
data: {
|
|
164
|
-
idempotencyKey: string;
|
|
165
|
-
requestDigest: TSha256Digest;
|
|
166
|
-
fence: IGreenfieldDeploymentFence;
|
|
167
|
-
candidateServiceId?: string;
|
|
168
|
-
state: 'reserved' | 'provisioning' | 'deploying' | 'verifying' | 'ready-for-promotion' | 'promoting' | 'promoted' | 'rolling-back' | 'rolled-back' | 'failed';
|
|
169
|
-
routeGeneration?: number;
|
|
170
|
-
createdAt: number;
|
|
171
|
-
updatedAt: number;
|
|
172
|
-
failureCode?: string;
|
|
173
|
-
};
|
|
174
|
-
}
|
|
175
|
+
/** @deprecated Use IServiceDeploymentOperation. */
|
|
176
|
+
export type IGreenfieldDeploymentOperation = IServiceDeploymentOperation;
|
|
175
177
|
export declare const validateDeploymentPreflightRequest: (requestArg: unknown) => IDeploymentPreflightBlocker[];
|
|
176
178
|
export declare const validateDeploymentReleaseEvidence: (argsArg: {
|
|
177
179
|
evidence: unknown;
|