@serve.zone/interfaces 12.0.0 → 13.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
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2026-07-19 - 13.0.0
|
|
4
|
+
|
|
5
|
+
### Breaking Changes
|
|
6
|
+
|
|
7
|
+
- bind greenfield preflight to a sanitized candidate configuration (deployment)
|
|
8
|
+
- Derive namespace and storage resource names in Cloudly instead of accepting caller-selected cluster names.
|
|
9
|
+
- Require an explicit completeness marker and secret-reference identifiers without secret values.
|
|
10
|
+
- Reject malformed transport digests, release tags, and log-unsafe request identifiers deterministically.
|
|
11
|
+
|
|
3
12
|
## 2026-07-19 - 12.0.0
|
|
4
13
|
|
|
5
14
|
### Fixes
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@serve.zone/interfaces',
|
|
6
|
-
version: '
|
|
6
|
+
version: '13.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=
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { TOciManifestMediaType, TSha256Digest } from './immutableimage.js';
|
|
2
2
|
import type { TServiceDeploymentCapability } from './user.js';
|
|
3
3
|
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' | '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';
|
|
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
5
|
export interface IDeploymentPreflightBlocker {
|
|
6
6
|
code: TDeploymentPreflightBlockerCode;
|
|
7
7
|
message: string;
|
|
@@ -41,6 +41,28 @@ export interface IDeploymentPreflightProposedCorestoreResource {
|
|
|
41
41
|
capability: 'database' | 'objectstorage';
|
|
42
42
|
resourceName: string;
|
|
43
43
|
}
|
|
44
|
+
export interface IDeploymentPreflightProposedVolumeMount {
|
|
45
|
+
mountPath: string;
|
|
46
|
+
storageClass: 'corestore' | 'ephemeral';
|
|
47
|
+
capability?: 'database' | 'objectstorage';
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Secret-free candidate configuration declared by the source checkout.
|
|
51
|
+
* Cloudly derives namespace and resource names; callers may not probe arbitrary
|
|
52
|
+
* cluster names through this contract.
|
|
53
|
+
*/
|
|
54
|
+
export interface IDeploymentPreflightProposedConfiguration {
|
|
55
|
+
schemaVersion: 1;
|
|
56
|
+
declarationComplete: boolean;
|
|
57
|
+
projectName: string;
|
|
58
|
+
targetPlatforms: string[];
|
|
59
|
+
publicDomains: string[];
|
|
60
|
+
environmentVariableNames: string[];
|
|
61
|
+
secretReferenceIds: string[];
|
|
62
|
+
containerPorts: number[];
|
|
63
|
+
volumeMounts: IDeploymentPreflightProposedVolumeMount[];
|
|
64
|
+
requiredCapabilities: Array<'database' | 'objectstorage'>;
|
|
65
|
+
}
|
|
44
66
|
export interface IDeploymentReleaseEvidenceReference {
|
|
45
67
|
kind: 'provenance' | 'sbom' | 'signature' | 'vulnerability-policy' | 'release-authorization';
|
|
46
68
|
statementDigest: TSha256Digest;
|
|
@@ -64,8 +86,7 @@ export interface IDeploymentPreflightRequestData {
|
|
|
64
86
|
sourceDirty: boolean;
|
|
65
87
|
version: string;
|
|
66
88
|
intentDigest: string;
|
|
67
|
-
|
|
68
|
-
proposedCorestoreResources: IDeploymentPreflightProposedCorestoreResource[];
|
|
89
|
+
proposedConfiguration: IDeploymentPreflightProposedConfiguration;
|
|
69
90
|
ociIndexDigest?: string;
|
|
70
91
|
releaseTag?: string;
|
|
71
92
|
releaseEvidence?: IDeploymentReleaseEvidence;
|
|
@@ -118,6 +139,7 @@ export interface IDeploymentPreflightReport {
|
|
|
118
139
|
corestoreResources: IDeploymentPreflightCorestoreResource[];
|
|
119
140
|
proposed: {
|
|
120
141
|
namespace: string;
|
|
142
|
+
configuration: IDeploymentPreflightProposedConfiguration;
|
|
121
143
|
corestoreResources: IDeploymentPreflightProposedCorestoreResource[];
|
|
122
144
|
namespaceReserved: boolean;
|
|
123
145
|
inventoryComplete: boolean;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { normalizeSha256Digest } from './immutableimage.js';
|
|
2
2
|
const fullGitRevisionRegex = /^[a-f0-9]{40}$/;
|
|
3
|
-
const namespaceRegex = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
|
|
4
3
|
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-]+)*)?$/;
|
|
5
4
|
const requiredEvidenceKinds = new Set([
|
|
6
5
|
'provenance',
|
|
@@ -15,7 +14,9 @@ export const validateDeploymentPreflightRequest = (requestArg) => {
|
|
|
15
14
|
if (!isRecord(requestArg)) {
|
|
16
15
|
return [{ code: 'INVALID_REQUEST', message: 'Deployment preflight request must be an object.' }];
|
|
17
16
|
}
|
|
18
|
-
if (typeof requestArg.requestId !== 'string'
|
|
17
|
+
if (typeof requestArg.requestId !== 'string'
|
|
18
|
+
|| requestArg.requestId.length > 200
|
|
19
|
+
|| !/^[A-Za-z0-9][A-Za-z0-9._:-]*$/.test(requestArg.requestId)) {
|
|
19
20
|
blockers.push({ code: 'INVALID_REQUEST', message: 'A bounded request identifier is required.' });
|
|
20
21
|
}
|
|
21
22
|
if (typeof requestArg.serviceId !== 'string' || !requestArg.serviceId.trim() || requestArg.serviceId.length > 200) {
|
|
@@ -35,32 +36,59 @@ export const validateDeploymentPreflightRequest = (requestArg) => {
|
|
|
35
36
|
|| !semanticVersionRegex.test(requestArg.version)) {
|
|
36
37
|
blockers.push({ code: 'VERSION_NOT_RESERVED', message: 'A canonical semantic release version is required.' });
|
|
37
38
|
}
|
|
38
|
-
if (typeof requestArg.proposedNamespace !== 'string' || !namespaceRegex.test(requestArg.proposedNamespace)) {
|
|
39
|
-
blockers.push({ code: 'NAMESPACE_NOT_RESERVED', message: 'The proposed namespace is missing or malformed.' });
|
|
40
|
-
}
|
|
41
39
|
if (typeof requestArg.intentDigest !== 'string' || !normalizeSha256Digest(requestArg.intentDigest)) {
|
|
42
40
|
blockers.push({ code: 'INTENT_DIGEST_INVALID', message: 'Deployment intent digest must be a canonical sha256 digest.' });
|
|
43
41
|
}
|
|
44
|
-
const
|
|
45
|
-
? requestArg.
|
|
46
|
-
:
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
.
|
|
58
|
-
|
|
59
|
-
|
|
42
|
+
const configuration = isRecord(requestArg.proposedConfiguration)
|
|
43
|
+
? requestArg.proposedConfiguration
|
|
44
|
+
: undefined;
|
|
45
|
+
const stringArrayValid = (valueArg, maxItemsArg, patternArg) => Array.isArray(valueArg)
|
|
46
|
+
&& valueArg.length <= maxItemsArg
|
|
47
|
+
&& valueArg.every((itemArg) => typeof itemArg === 'string'
|
|
48
|
+
&& itemArg.length > 0
|
|
49
|
+
&& itemArg.length <= 253
|
|
50
|
+
&& patternArg.test(itemArg))
|
|
51
|
+
&& new Set(valueArg).size === valueArg.length;
|
|
52
|
+
const capabilities = configuration?.requiredCapabilities;
|
|
53
|
+
const volumeMounts = configuration?.volumeMounts;
|
|
54
|
+
if (!configuration
|
|
55
|
+
|| configuration.schemaVersion !== 1
|
|
56
|
+
|| typeof configuration.declarationComplete !== 'boolean'
|
|
57
|
+
|| typeof configuration.projectName !== 'string'
|
|
58
|
+
|| !configuration.projectName.trim()
|
|
59
|
+
|| configuration.projectName.length > 200
|
|
60
|
+
|| !stringArrayValid(configuration.targetPlatforms, 8, /^[a-z0-9][a-z0-9._-]*\/[a-z0-9][a-z0-9._-]*$/)
|
|
61
|
+
|| !stringArrayValid(configuration.publicDomains, 32, /^[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?$/)
|
|
62
|
+
|| !stringArrayValid(configuration.environmentVariableNames, 256, /^[A-Z_][A-Z0-9_]*$/)
|
|
63
|
+
|| !stringArrayValid(configuration.secretReferenceIds, 64, /^[A-Za-z0-9][A-Za-z0-9:._-]*$/)
|
|
64
|
+
|| !Array.isArray(configuration.containerPorts)
|
|
65
|
+
|| configuration.containerPorts.length > 64
|
|
66
|
+
|| configuration.containerPorts.some((portArg) => !Number.isSafeInteger(portArg) || portArg < 1 || portArg > 65535)
|
|
67
|
+
|| new Set(configuration.containerPorts).size !== configuration.containerPorts.length
|
|
68
|
+
|| !Array.isArray(volumeMounts)
|
|
69
|
+
|| volumeMounts.length > 32
|
|
70
|
+
|| volumeMounts.some((mountArg) => !isRecord(mountArg)
|
|
71
|
+
|| typeof mountArg.mountPath !== 'string'
|
|
72
|
+
|| !/^\/[A-Za-z0-9._/-]{0,254}$/.test(mountArg.mountPath)
|
|
73
|
+
|| (mountArg.storageClass !== 'corestore' && mountArg.storageClass !== 'ephemeral')
|
|
74
|
+
|| (mountArg.capability !== undefined
|
|
75
|
+
&& mountArg.capability !== 'database'
|
|
76
|
+
&& mountArg.capability !== 'objectstorage'))
|
|
77
|
+
|| !Array.isArray(capabilities)
|
|
78
|
+
|| capabilities.length > 2
|
|
79
|
+
|| capabilities.some((capabilityArg) => capabilityArg !== 'database' && capabilityArg !== 'objectstorage')
|
|
80
|
+
|| new Set(capabilities).size !== capabilities.length) {
|
|
81
|
+
blockers.push({ code: 'INVALID_REQUEST', message: 'The proposed deployment configuration is malformed.' });
|
|
60
82
|
}
|
|
61
83
|
if (requestArg.ociIndexDigest !== undefined
|
|
62
84
|
&& (typeof requestArg.ociIndexDigest !== 'string' || !normalizeSha256Digest(requestArg.ociIndexDigest))) {
|
|
63
85
|
blockers.push({ code: 'OCI_INDEX_DIGEST_REQUIRED', message: 'OCI index digest must be a canonical sha256 digest.' });
|
|
86
|
+
blockers.push({ code: 'INVALID_REQUEST', message: 'OCI index digest is malformed.' });
|
|
87
|
+
}
|
|
88
|
+
if (requestArg.releaseTag !== undefined
|
|
89
|
+
&& (typeof requestArg.releaseTag !== 'string'
|
|
90
|
+
|| !/^[A-Za-z0-9_][A-Za-z0-9._-]{0,127}$/.test(requestArg.releaseTag))) {
|
|
91
|
+
blockers.push({ code: 'INVALID_REQUEST', message: 'Release tag is malformed.' });
|
|
64
92
|
}
|
|
65
93
|
if (requestArg.greenfield !== true) {
|
|
66
94
|
blockers.push({ code: 'WOULD_REPLACE_EXISTING_STATE', message: 'Only greenfield deployment preflight is supported.' });
|
|
@@ -116,4 +144,4 @@ export const validateDeploymentReleaseEvidence = (argsArg) => {
|
|
|
116
144
|
}
|
|
117
145
|
return blockers;
|
|
118
146
|
};
|
|
119
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
147
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVwbG95bWVudHByZWZsaWdodC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL2RhdGEvZGVwbG95bWVudHByZWZsaWdodC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFJQSxPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQXdPNUQsTUFBTSxvQkFBb0IsR0FBRyxnQkFBZ0IsQ0FBQztBQUM5QyxNQUFNLG9CQUFvQixHQUFHLDRNQUE0TSxDQUFDO0FBQzFPLE1BQU0scUJBQXFCLEdBQUcsSUFBSSxHQUFHLENBQThDO0lBQ2pGLFlBQVk7SUFDWixNQUFNO0lBQ04sV0FBVztJQUNYLHNCQUFzQjtJQUN0Qix1QkFBdUI7Q0FDeEIsQ0FBQyxDQUFDO0FBRUgsTUFBTSxRQUFRLEdBQUcsQ0FBQyxRQUFpQixFQUF1QyxFQUFFLENBQzFFLE9BQU8sQ0FBQyxRQUFRLENBQUMsSUFBSSxPQUFPLFFBQVEsS0FBSyxRQUFRLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDO0FBRWhGLE1BQU0sQ0FBQyxNQUFNLGtDQUFrQyxHQUFHLENBQ2hELFVBQW1CLEVBQ1ksRUFBRTtJQUNqQyxNQUFNLFFBQVEsR0FBa0MsRUFBRSxDQUFDO0lBQ25ELElBQUksQ0FBQyxRQUFRLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQztRQUMxQixPQUFPLENBQUMsRUFBRSxJQUFJLEVBQUUsaUJBQWlCLEVBQUUsT0FBTyxFQUFFLGlEQUFpRCxFQUFFLENBQUMsQ0FBQztJQUNuRyxDQUFDO0lBQ0QsSUFBSSxPQUFPLFVBQVUsQ0FBQyxTQUFTLEtBQUssUUFBUTtXQUN2QyxVQUFVLENBQUMsU0FBUyxDQUFDLE1BQU0sR0FBRyxHQUFHO1dBQ2pDLENBQUMsK0JBQStCLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDO1FBQ2pFLFFBQVEsQ0FBQyxJQUFJLENBQUMsRUFBRSxJQUFJLEVB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
|
package/package.json
CHANGED
package/ts/00_commitinfo_data.ts
CHANGED
|
@@ -19,6 +19,7 @@ export type TDeploymentPreflightBlockerCode =
|
|
|
19
19
|
| 'NAMESPACE_NOT_PROVEN_BLANK'
|
|
20
20
|
| 'CONFIGURATION_DIGEST_INVALID'
|
|
21
21
|
| 'INTENT_DIGEST_INVALID'
|
|
22
|
+
| 'PROPOSED_CONFIGURATION_INCOMPLETE'
|
|
22
23
|
| 'CURRENT_REFERENCE_MUTABLE'
|
|
23
24
|
| 'CURRENT_RUNTIME_DIGEST_MISSING'
|
|
24
25
|
| 'OCI_INDEX_DIGEST_REQUIRED'
|
|
@@ -84,6 +85,30 @@ export interface IDeploymentPreflightProposedCorestoreResource {
|
|
|
84
85
|
resourceName: string;
|
|
85
86
|
}
|
|
86
87
|
|
|
88
|
+
export interface IDeploymentPreflightProposedVolumeMount {
|
|
89
|
+
mountPath: string;
|
|
90
|
+
storageClass: 'corestore' | 'ephemeral';
|
|
91
|
+
capability?: 'database' | 'objectstorage';
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Secret-free candidate configuration declared by the source checkout.
|
|
96
|
+
* Cloudly derives namespace and resource names; callers may not probe arbitrary
|
|
97
|
+
* cluster names through this contract.
|
|
98
|
+
*/
|
|
99
|
+
export interface IDeploymentPreflightProposedConfiguration {
|
|
100
|
+
schemaVersion: 1;
|
|
101
|
+
declarationComplete: boolean;
|
|
102
|
+
projectName: string;
|
|
103
|
+
targetPlatforms: string[];
|
|
104
|
+
publicDomains: string[];
|
|
105
|
+
environmentVariableNames: string[];
|
|
106
|
+
secretReferenceIds: string[];
|
|
107
|
+
containerPorts: number[];
|
|
108
|
+
volumeMounts: IDeploymentPreflightProposedVolumeMount[];
|
|
109
|
+
requiredCapabilities: Array<'database' | 'objectstorage'>;
|
|
110
|
+
}
|
|
111
|
+
|
|
87
112
|
export interface IDeploymentReleaseEvidenceReference {
|
|
88
113
|
kind: 'provenance' | 'sbom' | 'signature' | 'vulnerability-policy' | 'release-authorization';
|
|
89
114
|
statementDigest: TSha256Digest;
|
|
@@ -109,8 +134,7 @@ export interface IDeploymentPreflightRequestData {
|
|
|
109
134
|
sourceDirty: boolean;
|
|
110
135
|
version: string;
|
|
111
136
|
intentDigest: string;
|
|
112
|
-
|
|
113
|
-
proposedCorestoreResources: IDeploymentPreflightProposedCorestoreResource[];
|
|
137
|
+
proposedConfiguration: IDeploymentPreflightProposedConfiguration;
|
|
114
138
|
ociIndexDigest?: string;
|
|
115
139
|
releaseTag?: string;
|
|
116
140
|
releaseEvidence?: IDeploymentReleaseEvidence;
|
|
@@ -164,6 +188,7 @@ export interface IDeploymentPreflightReport {
|
|
|
164
188
|
corestoreResources: IDeploymentPreflightCorestoreResource[];
|
|
165
189
|
proposed: {
|
|
166
190
|
namespace: string;
|
|
191
|
+
configuration: IDeploymentPreflightProposedConfiguration;
|
|
167
192
|
corestoreResources: IDeploymentPreflightProposedCorestoreResource[];
|
|
168
193
|
namespaceReserved: boolean;
|
|
169
194
|
inventoryComplete: boolean;
|
|
@@ -210,7 +235,6 @@ export interface IGreenfieldDeploymentOperation {
|
|
|
210
235
|
}
|
|
211
236
|
|
|
212
237
|
const fullGitRevisionRegex = /^[a-f0-9]{40}$/;
|
|
213
|
-
const namespaceRegex = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
|
|
214
238
|
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-]+)*)?$/;
|
|
215
239
|
const requiredEvidenceKinds = new Set<IDeploymentReleaseEvidenceReference['kind']>([
|
|
216
240
|
'provenance',
|
|
@@ -230,7 +254,9 @@ export const validateDeploymentPreflightRequest = (
|
|
|
230
254
|
if (!isRecord(requestArg)) {
|
|
231
255
|
return [{ code: 'INVALID_REQUEST', message: 'Deployment preflight request must be an object.' }];
|
|
232
256
|
}
|
|
233
|
-
if (typeof requestArg.requestId !== 'string'
|
|
257
|
+
if (typeof requestArg.requestId !== 'string'
|
|
258
|
+
|| requestArg.requestId.length > 200
|
|
259
|
+
|| !/^[A-Za-z0-9][A-Za-z0-9._:-]*$/.test(requestArg.requestId)) {
|
|
234
260
|
blockers.push({ code: 'INVALID_REQUEST', message: 'A bounded request identifier is required.' });
|
|
235
261
|
}
|
|
236
262
|
if (typeof requestArg.serviceId !== 'string' || !requestArg.serviceId.trim() || requestArg.serviceId.length > 200) {
|
|
@@ -249,34 +275,65 @@ export const validateDeploymentPreflightRequest = (
|
|
|
249
275
|
|| !semanticVersionRegex.test(requestArg.version)) {
|
|
250
276
|
blockers.push({ code: 'VERSION_NOT_RESERVED', message: 'A canonical semantic release version is required.' });
|
|
251
277
|
}
|
|
252
|
-
if (typeof requestArg.proposedNamespace !== 'string' || !namespaceRegex.test(requestArg.proposedNamespace)) {
|
|
253
|
-
blockers.push({ code: 'NAMESPACE_NOT_RESERVED', message: 'The proposed namespace is missing or malformed.' });
|
|
254
|
-
}
|
|
255
278
|
if (typeof requestArg.intentDigest !== 'string' || !normalizeSha256Digest(requestArg.intentDigest)) {
|
|
256
279
|
blockers.push({ code: 'INTENT_DIGEST_INVALID', message: 'Deployment intent digest must be a canonical sha256 digest.' });
|
|
257
280
|
}
|
|
258
|
-
const
|
|
259
|
-
? requestArg.
|
|
260
|
-
:
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
if (
|
|
275
|
-
|
|
281
|
+
const configuration = isRecord(requestArg.proposedConfiguration)
|
|
282
|
+
? requestArg.proposedConfiguration
|
|
283
|
+
: undefined;
|
|
284
|
+
const stringArrayValid = (
|
|
285
|
+
valueArg: unknown,
|
|
286
|
+
maxItemsArg: number,
|
|
287
|
+
patternArg: RegExp,
|
|
288
|
+
): valueArg is string[] => Array.isArray(valueArg)
|
|
289
|
+
&& valueArg.length <= maxItemsArg
|
|
290
|
+
&& valueArg.every((itemArg) => typeof itemArg === 'string'
|
|
291
|
+
&& itemArg.length > 0
|
|
292
|
+
&& itemArg.length <= 253
|
|
293
|
+
&& patternArg.test(itemArg))
|
|
294
|
+
&& new Set(valueArg).size === valueArg.length;
|
|
295
|
+
const capabilities = configuration?.requiredCapabilities;
|
|
296
|
+
const volumeMounts = configuration?.volumeMounts;
|
|
297
|
+
if (
|
|
298
|
+
!configuration
|
|
299
|
+
|| configuration.schemaVersion !== 1
|
|
300
|
+
|| typeof configuration.declarationComplete !== 'boolean'
|
|
301
|
+
|| typeof configuration.projectName !== 'string'
|
|
302
|
+
|| !configuration.projectName.trim()
|
|
303
|
+
|| configuration.projectName.length > 200
|
|
304
|
+
|| !stringArrayValid(configuration.targetPlatforms, 8, /^[a-z0-9][a-z0-9._-]*\/[a-z0-9][a-z0-9._-]*$/)
|
|
305
|
+
|| !stringArrayValid(configuration.publicDomains, 32, /^[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?$/)
|
|
306
|
+
|| !stringArrayValid(configuration.environmentVariableNames, 256, /^[A-Z_][A-Z0-9_]*$/)
|
|
307
|
+
|| !stringArrayValid(configuration.secretReferenceIds, 64, /^[A-Za-z0-9][A-Za-z0-9:._-]*$/)
|
|
308
|
+
|| !Array.isArray(configuration.containerPorts)
|
|
309
|
+
|| configuration.containerPorts.length > 64
|
|
310
|
+
|| configuration.containerPorts.some((portArg) => !Number.isSafeInteger(portArg) || portArg < 1 || portArg > 65535)
|
|
311
|
+
|| new Set(configuration.containerPorts).size !== configuration.containerPorts.length
|
|
312
|
+
|| !Array.isArray(volumeMounts)
|
|
313
|
+
|| volumeMounts.length > 32
|
|
314
|
+
|| volumeMounts.some((mountArg) => !isRecord(mountArg)
|
|
315
|
+
|| typeof mountArg.mountPath !== 'string'
|
|
316
|
+
|| !/^\/[A-Za-z0-9._/-]{0,254}$/.test(mountArg.mountPath)
|
|
317
|
+
|| (mountArg.storageClass !== 'corestore' && mountArg.storageClass !== 'ephemeral')
|
|
318
|
+
|| (mountArg.capability !== undefined
|
|
319
|
+
&& mountArg.capability !== 'database'
|
|
320
|
+
&& mountArg.capability !== 'objectstorage'))
|
|
321
|
+
|| !Array.isArray(capabilities)
|
|
322
|
+
|| capabilities.length > 2
|
|
323
|
+
|| capabilities.some((capabilityArg) => capabilityArg !== 'database' && capabilityArg !== 'objectstorage')
|
|
324
|
+
|| new Set(capabilities).size !== capabilities.length
|
|
325
|
+
) {
|
|
326
|
+
blockers.push({ code: 'INVALID_REQUEST', message: 'The proposed deployment configuration is malformed.' });
|
|
276
327
|
}
|
|
277
328
|
if (requestArg.ociIndexDigest !== undefined
|
|
278
329
|
&& (typeof requestArg.ociIndexDigest !== 'string' || !normalizeSha256Digest(requestArg.ociIndexDigest))) {
|
|
279
330
|
blockers.push({ code: 'OCI_INDEX_DIGEST_REQUIRED', message: 'OCI index digest must be a canonical sha256 digest.' });
|
|
331
|
+
blockers.push({ code: 'INVALID_REQUEST', message: 'OCI index digest is malformed.' });
|
|
332
|
+
}
|
|
333
|
+
if (requestArg.releaseTag !== undefined
|
|
334
|
+
&& (typeof requestArg.releaseTag !== 'string'
|
|
335
|
+
|| !/^[A-Za-z0-9_][A-Za-z0-9._-]{0,127}$/.test(requestArg.releaseTag))) {
|
|
336
|
+
blockers.push({ code: 'INVALID_REQUEST', message: 'Release tag is malformed.' });
|
|
280
337
|
}
|
|
281
338
|
if (requestArg.greenfield !== true) {
|
|
282
339
|
blockers.push({ code: 'WOULD_REPLACE_EXISTING_STATE', message: 'Only greenfield deployment preflight is supported.' });
|