@serve.zone/interfaces 11.4.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 +18 -0
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/data/deploymentpreflight.d.ts +47 -7
- package/dist_ts/data/deploymentpreflight.js +63 -9
- package/dist_ts/requests/admin.d.ts +16 -1
- package/package.json +1 -1
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/data/deploymentpreflight.ts +119 -14
- package/ts/requests/admin.ts +21 -1
package/changelog.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
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
|
+
|
|
12
|
+
## 2026-07-19 - 12.0.0
|
|
13
|
+
|
|
14
|
+
### Fixes
|
|
15
|
+
|
|
16
|
+
- make greenfield deployment preflight evidence fail closed (deployment)
|
|
17
|
+
- Distinguish the client intent digest from Cloudly's server-computed configuration digest.
|
|
18
|
+
- Report dirty source, registry host, complete replica counts, explicit proposed storage resources, and unknown namespace safety.
|
|
19
|
+
- Define an admin-only, idempotent machine-user grant normalization request without returning token material.
|
|
20
|
+
|
|
3
21
|
## 2026-07-19 - 11.4.0
|
|
4
22
|
|
|
5
23
|
### Features
|
|
@@ -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' | 'VERSION_NOT_RESERVED' | 'VERSION_COLLISION' | 'NAMESPACE_NOT_RESERVED' | 'NAMESPACE_COLLISION' | 'NAMESPACE_NOT_PROVEN_BLANK' | 'CONFIGURATION_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;
|
|
@@ -37,6 +37,32 @@ export interface IDeploymentPreflightCorestoreResource {
|
|
|
37
37
|
provider: string;
|
|
38
38
|
resourceName: string;
|
|
39
39
|
}
|
|
40
|
+
export interface IDeploymentPreflightProposedCorestoreResource {
|
|
41
|
+
capability: 'database' | 'objectstorage';
|
|
42
|
+
resourceName: string;
|
|
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
|
+
}
|
|
40
66
|
export interface IDeploymentReleaseEvidenceReference {
|
|
41
67
|
kind: 'provenance' | 'sbom' | 'signature' | 'vulnerability-policy' | 'release-authorization';
|
|
42
68
|
statementDigest: TSha256Digest;
|
|
@@ -57,16 +83,17 @@ export interface IDeploymentPreflightRequestData {
|
|
|
57
83
|
requestId: string;
|
|
58
84
|
serviceId: string;
|
|
59
85
|
sourceRevision: string;
|
|
86
|
+
sourceDirty: boolean;
|
|
60
87
|
version: string;
|
|
61
|
-
|
|
62
|
-
|
|
88
|
+
intentDigest: string;
|
|
89
|
+
proposedConfiguration: IDeploymentPreflightProposedConfiguration;
|
|
63
90
|
ociIndexDigest?: string;
|
|
64
91
|
releaseTag?: string;
|
|
65
92
|
releaseEvidence?: IDeploymentReleaseEvidence;
|
|
66
93
|
greenfield: true;
|
|
67
94
|
}
|
|
68
95
|
export interface IDeploymentPreflightReport {
|
|
69
|
-
schemaVersion:
|
|
96
|
+
schemaVersion: 2;
|
|
70
97
|
decision: TDeploymentPreflightDecision;
|
|
71
98
|
mutationPerformed: false;
|
|
72
99
|
generatedAt: number;
|
|
@@ -74,13 +101,16 @@ export interface IDeploymentPreflightReport {
|
|
|
74
101
|
serviceId: string;
|
|
75
102
|
serviceName: string;
|
|
76
103
|
workspaceIdentity: string;
|
|
104
|
+
registryHost: string;
|
|
77
105
|
registryRepository: string;
|
|
78
106
|
deployOnPush: boolean;
|
|
79
107
|
};
|
|
80
108
|
source: {
|
|
81
109
|
revision: string;
|
|
110
|
+
dirty: boolean;
|
|
82
111
|
version: string;
|
|
83
|
-
|
|
112
|
+
intentDigest: TSha256Digest;
|
|
113
|
+
configurationDigest: TSha256Digest;
|
|
84
114
|
};
|
|
85
115
|
currentImage: {
|
|
86
116
|
tag?: string;
|
|
@@ -98,14 +128,24 @@ export interface IDeploymentPreflightReport {
|
|
|
98
128
|
platforms: IOciPlatformDescriptorSummary[];
|
|
99
129
|
};
|
|
100
130
|
runtimeTasks: IDeploymentPreflightRuntimeTask[];
|
|
131
|
+
runtimeAttestation: {
|
|
132
|
+
requiredReplicaCount: number;
|
|
133
|
+
observedReplicaCount: number;
|
|
134
|
+
healthyReplicaCount: number;
|
|
135
|
+
verifiedReplicaCount: number;
|
|
136
|
+
consistentDigest: boolean;
|
|
137
|
+
};
|
|
101
138
|
platformBindings: IDeploymentPreflightPlatformBinding[];
|
|
102
139
|
corestoreResources: IDeploymentPreflightCorestoreResource[];
|
|
103
140
|
proposed: {
|
|
104
141
|
namespace: string;
|
|
142
|
+
configuration: IDeploymentPreflightProposedConfiguration;
|
|
143
|
+
corestoreResources: IDeploymentPreflightProposedCorestoreResource[];
|
|
105
144
|
namespaceReserved: boolean;
|
|
106
|
-
|
|
145
|
+
inventoryComplete: boolean;
|
|
146
|
+
namespaceBlank: boolean | 'unknown';
|
|
107
147
|
versionReserved: boolean;
|
|
108
|
-
wouldReplaceExistingState: boolean;
|
|
148
|
+
wouldReplaceExistingState: boolean | 'unknown';
|
|
109
149
|
};
|
|
110
150
|
authorizationChecks: IDeploymentPreflightAuthorizationCheck[];
|
|
111
151
|
compatibilityBlockers: IDeploymentPreflightBlocker[];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { normalizeSha256Digest } from './immutableimage.js';
|
|
2
2
|
const fullGitRevisionRegex = /^[a-f0-9]{40}$/;
|
|
3
|
-
const
|
|
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-]+)*)?$/;
|
|
4
4
|
const requiredEvidenceKinds = new Set([
|
|
5
5
|
'provenance',
|
|
6
6
|
'sbom',
|
|
@@ -14,7 +14,9 @@ export const validateDeploymentPreflightRequest = (requestArg) => {
|
|
|
14
14
|
if (!isRecord(requestArg)) {
|
|
15
15
|
return [{ code: 'INVALID_REQUEST', message: 'Deployment preflight request must be an object.' }];
|
|
16
16
|
}
|
|
17
|
-
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)) {
|
|
18
20
|
blockers.push({ code: 'INVALID_REQUEST', message: 'A bounded request identifier is required.' });
|
|
19
21
|
}
|
|
20
22
|
if (typeof requestArg.serviceId !== 'string' || !requestArg.serviceId.trim() || requestArg.serviceId.length > 200) {
|
|
@@ -23,18 +25,70 @@ export const validateDeploymentPreflightRequest = (requestArg) => {
|
|
|
23
25
|
if (typeof requestArg.sourceRevision !== 'string' || !fullGitRevisionRegex.test(requestArg.sourceRevision)) {
|
|
24
26
|
blockers.push({ code: 'SOURCE_REVISION_INVALID', message: 'Source revision must be a full lower-case Git commit SHA.' });
|
|
25
27
|
}
|
|
26
|
-
if (typeof requestArg.
|
|
27
|
-
blockers.push({ code: '
|
|
28
|
+
if (typeof requestArg.sourceDirty !== 'boolean') {
|
|
29
|
+
blockers.push({ code: 'INVALID_REQUEST', message: 'Source worktree state must be reported.' });
|
|
28
30
|
}
|
|
29
|
-
if (
|
|
30
|
-
blockers.push({ code: '
|
|
31
|
+
else if (requestArg.sourceDirty) {
|
|
32
|
+
blockers.push({ code: 'SOURCE_WORKTREE_DIRTY', message: 'The source worktree contains uncommitted changes.' });
|
|
31
33
|
}
|
|
32
|
-
if (typeof requestArg.
|
|
33
|
-
|
|
34
|
+
if (typeof requestArg.version !== 'string'
|
|
35
|
+
|| requestArg.version.length > 100
|
|
36
|
+
|| !semanticVersionRegex.test(requestArg.version)) {
|
|
37
|
+
blockers.push({ code: 'VERSION_NOT_RESERVED', message: 'A canonical semantic release version is required.' });
|
|
38
|
+
}
|
|
39
|
+
if (typeof requestArg.intentDigest !== 'string' || !normalizeSha256Digest(requestArg.intentDigest)) {
|
|
40
|
+
blockers.push({ code: 'INTENT_DIGEST_INVALID', message: 'Deployment intent digest must be a canonical sha256 digest.' });
|
|
41
|
+
}
|
|
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.' });
|
|
34
82
|
}
|
|
35
83
|
if (requestArg.ociIndexDigest !== undefined
|
|
36
84
|
&& (typeof requestArg.ociIndexDigest !== 'string' || !normalizeSha256Digest(requestArg.ociIndexDigest))) {
|
|
37
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.' });
|
|
38
92
|
}
|
|
39
93
|
if (requestArg.greenfield !== true) {
|
|
40
94
|
blockers.push({ code: 'WOULD_REPLACE_EXISTING_STATE', message: 'Only greenfield deployment preflight is supported.' });
|
|
@@ -90,4 +144,4 @@ export const validateDeploymentReleaseEvidence = (argsArg) => {
|
|
|
90
144
|
}
|
|
91
145
|
return blockers;
|
|
92
146
|
};
|
|
93
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
147
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVwbG95bWVudHByZWZsaWdodC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL2RhdGEvZGVwbG95bWVudHByZWZsaWdodC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFJQSxPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQXdPNUQsTUFBTSxvQkFBb0IsR0FBRyxnQkFBZ0IsQ0FBQztBQUM5QyxNQUFNLG9CQUFvQixHQUFHLDRNQUE0TSxDQUFDO0FBQzFPLE1BQU0scUJBQXFCLEdBQUcsSUFBSSxHQUFHLENBQThDO0lBQ2pGLFlBQVk7SUFDWixNQUFNO0lBQ04sV0FBVztJQUNYLHNCQUFzQjtJQUN0Qix1QkFBdUI7Q0FDeEIsQ0FBQyxDQUFDO0FBRUgsTUFBTSxRQUFRLEdBQUcsQ0FBQyxRQUFpQixFQUF1QyxFQUFFLENBQzFFLE9BQU8sQ0FBQyxRQUFRLENBQUMsSUFBSSxPQUFPLFFBQVEsS0FBSyxRQUFRLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDO0FBRWhGLE1BQU0sQ0FBQyxNQUFNLGtDQUFrQyxHQUFHLENBQ2hELFVBQW1CLEVBQ1ksRUFBRTtJQUNqQyxNQUFNLFFBQVEsR0FBa0MsRUFBRSxDQUFDO0lBQ25ELElBQUksQ0FBQyxRQUFRLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQztRQUMxQixPQUFPLENBQUMsRUFBRSxJQUFJLEVBQUUsaUJBQWlCLEVBQUUsT0FBTyxFQUFFLGlEQUFpRCxFQUFFLENBQUMsQ0FBQztJQUNuRyxDQUFDO0lBQ0QsSUFBSSxPQUFPLFVBQVUsQ0FBQyxTQUFTLEtBQUssUUFBUTtXQUN2QyxVQUFVLENBQUMsU0FBUyxDQUFDLE1BQU0sR0FBRyxHQUFHO1dBQ2pDLENBQUMsK0JBQStCLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDO1FBQ2pFLFFBQVEsQ0FBQyxJQUFJLENBQUMsRUFBRSxJQUFJLEVB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
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as plugins from '../plugins.js';
|
|
2
|
-
import type { IIdentity } from '../data/user.js';
|
|
2
|
+
import type { IIdentity, TServiceDeploymentCapability } from '../data/user.js';
|
|
3
3
|
export interface IReq_Admin_LoginWithUsernameAndPassword extends plugins.typedrequestInterfaces.implementsTR<plugins.typedrequestInterfaces.ITypedRequest, IReq_Admin_LoginWithUsernameAndPassword> {
|
|
4
4
|
method: 'adminLoginWithUsernameAndPassword';
|
|
5
5
|
request: {
|
|
@@ -10,6 +10,21 @@ export interface IReq_Admin_LoginWithUsernameAndPassword extends plugins.typedre
|
|
|
10
10
|
identity: IIdentity;
|
|
11
11
|
};
|
|
12
12
|
}
|
|
13
|
+
export interface IReq_Admin_ConfigureServiceDeploymentMachineUser extends plugins.typedrequestInterfaces.implementsTR<plugins.typedrequestInterfaces.ITypedRequest, IReq_Admin_ConfigureServiceDeploymentMachineUser> {
|
|
14
|
+
method: 'configureServiceDeploymentMachineUser';
|
|
15
|
+
request: {
|
|
16
|
+
identity: IIdentity;
|
|
17
|
+
userId: string;
|
|
18
|
+
serviceId: string;
|
|
19
|
+
capabilities: TServiceDeploymentCapability[];
|
|
20
|
+
};
|
|
21
|
+
response: {
|
|
22
|
+
userId: string;
|
|
23
|
+
serviceId: string;
|
|
24
|
+
capabilities: TServiceDeploymentCapability[];
|
|
25
|
+
tokenRolesNormalized: true;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
13
28
|
export interface ICoreflowBaseServiceReconciliationResult {
|
|
14
29
|
status: 'fulfilled' | 'rejected';
|
|
15
30
|
nodeNames: string[];
|
package/package.json
CHANGED
package/ts/00_commitinfo_data.ts
CHANGED
|
@@ -11,12 +11,15 @@ export type TDeploymentPreflightBlockerCode =
|
|
|
11
11
|
| 'INVALID_REQUEST'
|
|
12
12
|
| 'AUTHORIZATION_MISSING'
|
|
13
13
|
| 'SOURCE_REVISION_INVALID'
|
|
14
|
+
| 'SOURCE_WORKTREE_DIRTY'
|
|
14
15
|
| 'VERSION_NOT_RESERVED'
|
|
15
16
|
| 'VERSION_COLLISION'
|
|
16
17
|
| 'NAMESPACE_NOT_RESERVED'
|
|
17
18
|
| 'NAMESPACE_COLLISION'
|
|
18
19
|
| 'NAMESPACE_NOT_PROVEN_BLANK'
|
|
19
20
|
| 'CONFIGURATION_DIGEST_INVALID'
|
|
21
|
+
| 'INTENT_DIGEST_INVALID'
|
|
22
|
+
| 'PROPOSED_CONFIGURATION_INCOMPLETE'
|
|
20
23
|
| 'CURRENT_REFERENCE_MUTABLE'
|
|
21
24
|
| 'CURRENT_RUNTIME_DIGEST_MISSING'
|
|
22
25
|
| 'OCI_INDEX_DIGEST_REQUIRED'
|
|
@@ -77,6 +80,35 @@ export interface IDeploymentPreflightCorestoreResource {
|
|
|
77
80
|
resourceName: string;
|
|
78
81
|
}
|
|
79
82
|
|
|
83
|
+
export interface IDeploymentPreflightProposedCorestoreResource {
|
|
84
|
+
capability: 'database' | 'objectstorage';
|
|
85
|
+
resourceName: string;
|
|
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
|
+
|
|
80
112
|
export interface IDeploymentReleaseEvidenceReference {
|
|
81
113
|
kind: 'provenance' | 'sbom' | 'signature' | 'vulnerability-policy' | 'release-authorization';
|
|
82
114
|
statementDigest: TSha256Digest;
|
|
@@ -99,9 +131,10 @@ export interface IDeploymentPreflightRequestData {
|
|
|
99
131
|
requestId: string;
|
|
100
132
|
serviceId: string;
|
|
101
133
|
sourceRevision: string;
|
|
134
|
+
sourceDirty: boolean;
|
|
102
135
|
version: string;
|
|
103
|
-
|
|
104
|
-
|
|
136
|
+
intentDigest: string;
|
|
137
|
+
proposedConfiguration: IDeploymentPreflightProposedConfiguration;
|
|
105
138
|
ociIndexDigest?: string;
|
|
106
139
|
releaseTag?: string;
|
|
107
140
|
releaseEvidence?: IDeploymentReleaseEvidence;
|
|
@@ -109,7 +142,7 @@ export interface IDeploymentPreflightRequestData {
|
|
|
109
142
|
}
|
|
110
143
|
|
|
111
144
|
export interface IDeploymentPreflightReport {
|
|
112
|
-
schemaVersion:
|
|
145
|
+
schemaVersion: 2;
|
|
113
146
|
decision: TDeploymentPreflightDecision;
|
|
114
147
|
mutationPerformed: false;
|
|
115
148
|
generatedAt: number;
|
|
@@ -117,13 +150,16 @@ export interface IDeploymentPreflightReport {
|
|
|
117
150
|
serviceId: string;
|
|
118
151
|
serviceName: string;
|
|
119
152
|
workspaceIdentity: string;
|
|
153
|
+
registryHost: string;
|
|
120
154
|
registryRepository: string;
|
|
121
155
|
deployOnPush: boolean;
|
|
122
156
|
};
|
|
123
157
|
source: {
|
|
124
158
|
revision: string;
|
|
159
|
+
dirty: boolean;
|
|
125
160
|
version: string;
|
|
126
|
-
|
|
161
|
+
intentDigest: TSha256Digest;
|
|
162
|
+
configurationDigest: TSha256Digest;
|
|
127
163
|
};
|
|
128
164
|
currentImage: {
|
|
129
165
|
tag?: string;
|
|
@@ -141,14 +177,24 @@ export interface IDeploymentPreflightReport {
|
|
|
141
177
|
platforms: IOciPlatformDescriptorSummary[];
|
|
142
178
|
};
|
|
143
179
|
runtimeTasks: IDeploymentPreflightRuntimeTask[];
|
|
180
|
+
runtimeAttestation: {
|
|
181
|
+
requiredReplicaCount: number;
|
|
182
|
+
observedReplicaCount: number;
|
|
183
|
+
healthyReplicaCount: number;
|
|
184
|
+
verifiedReplicaCount: number;
|
|
185
|
+
consistentDigest: boolean;
|
|
186
|
+
};
|
|
144
187
|
platformBindings: IDeploymentPreflightPlatformBinding[];
|
|
145
188
|
corestoreResources: IDeploymentPreflightCorestoreResource[];
|
|
146
189
|
proposed: {
|
|
147
190
|
namespace: string;
|
|
191
|
+
configuration: IDeploymentPreflightProposedConfiguration;
|
|
192
|
+
corestoreResources: IDeploymentPreflightProposedCorestoreResource[];
|
|
148
193
|
namespaceReserved: boolean;
|
|
149
|
-
|
|
194
|
+
inventoryComplete: boolean;
|
|
195
|
+
namespaceBlank: boolean | 'unknown';
|
|
150
196
|
versionReserved: boolean;
|
|
151
|
-
wouldReplaceExistingState: boolean;
|
|
197
|
+
wouldReplaceExistingState: boolean | 'unknown';
|
|
152
198
|
};
|
|
153
199
|
authorizationChecks: IDeploymentPreflightAuthorizationCheck[];
|
|
154
200
|
compatibilityBlockers: IDeploymentPreflightBlocker[];
|
|
@@ -189,7 +235,7 @@ export interface IGreenfieldDeploymentOperation {
|
|
|
189
235
|
}
|
|
190
236
|
|
|
191
237
|
const fullGitRevisionRegex = /^[a-f0-9]{40}$/;
|
|
192
|
-
const
|
|
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-]+)*)?$/;
|
|
193
239
|
const requiredEvidenceKinds = new Set<IDeploymentReleaseEvidenceReference['kind']>([
|
|
194
240
|
'provenance',
|
|
195
241
|
'sbom',
|
|
@@ -208,7 +254,9 @@ export const validateDeploymentPreflightRequest = (
|
|
|
208
254
|
if (!isRecord(requestArg)) {
|
|
209
255
|
return [{ code: 'INVALID_REQUEST', message: 'Deployment preflight request must be an object.' }];
|
|
210
256
|
}
|
|
211
|
-
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)) {
|
|
212
260
|
blockers.push({ code: 'INVALID_REQUEST', message: 'A bounded request identifier is required.' });
|
|
213
261
|
}
|
|
214
262
|
if (typeof requestArg.serviceId !== 'string' || !requestArg.serviceId.trim() || requestArg.serviceId.length > 200) {
|
|
@@ -217,18 +265,75 @@ export const validateDeploymentPreflightRequest = (
|
|
|
217
265
|
if (typeof requestArg.sourceRevision !== 'string' || !fullGitRevisionRegex.test(requestArg.sourceRevision)) {
|
|
218
266
|
blockers.push({ code: 'SOURCE_REVISION_INVALID', message: 'Source revision must be a full lower-case Git commit SHA.' });
|
|
219
267
|
}
|
|
220
|
-
if (typeof requestArg.
|
|
221
|
-
blockers.push({ code: '
|
|
268
|
+
if (typeof requestArg.sourceDirty !== 'boolean') {
|
|
269
|
+
blockers.push({ code: 'INVALID_REQUEST', message: 'Source worktree state must be reported.' });
|
|
270
|
+
} else if (requestArg.sourceDirty) {
|
|
271
|
+
blockers.push({ code: 'SOURCE_WORKTREE_DIRTY', message: 'The source worktree contains uncommitted changes.' });
|
|
222
272
|
}
|
|
223
|
-
if (typeof requestArg.
|
|
224
|
-
|
|
273
|
+
if (typeof requestArg.version !== 'string'
|
|
274
|
+
|| requestArg.version.length > 100
|
|
275
|
+
|| !semanticVersionRegex.test(requestArg.version)) {
|
|
276
|
+
blockers.push({ code: 'VERSION_NOT_RESERVED', message: 'A canonical semantic release version is required.' });
|
|
225
277
|
}
|
|
226
|
-
if (typeof requestArg.
|
|
227
|
-
blockers.push({ code: '
|
|
278
|
+
if (typeof requestArg.intentDigest !== 'string' || !normalizeSha256Digest(requestArg.intentDigest)) {
|
|
279
|
+
blockers.push({ code: 'INTENT_DIGEST_INVALID', message: 'Deployment intent digest must be a canonical sha256 digest.' });
|
|
280
|
+
}
|
|
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.' });
|
|
228
327
|
}
|
|
229
328
|
if (requestArg.ociIndexDigest !== undefined
|
|
230
329
|
&& (typeof requestArg.ociIndexDigest !== 'string' || !normalizeSha256Digest(requestArg.ociIndexDigest))) {
|
|
231
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.' });
|
|
232
337
|
}
|
|
233
338
|
if (requestArg.greenfield !== true) {
|
|
234
339
|
blockers.push({ code: 'WOULD_REPLACE_EXISTING_STATE', message: 'Only greenfield deployment preflight is supported.' });
|
package/ts/requests/admin.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as plugins from '../plugins.js';
|
|
2
|
-
import type { IIdentity } from '../data/user.js';
|
|
2
|
+
import type { IIdentity, TServiceDeploymentCapability } from '../data/user.js';
|
|
3
3
|
|
|
4
4
|
export interface IReq_Admin_LoginWithUsernameAndPassword extends plugins.typedrequestInterfaces.implementsTR<
|
|
5
5
|
plugins.typedrequestInterfaces.ITypedRequest,
|
|
@@ -15,6 +15,26 @@ export interface IReq_Admin_LoginWithUsernameAndPassword extends plugins.typedre
|
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
export interface IReq_Admin_ConfigureServiceDeploymentMachineUser
|
|
19
|
+
extends plugins.typedrequestInterfaces.implementsTR<
|
|
20
|
+
plugins.typedrequestInterfaces.ITypedRequest,
|
|
21
|
+
IReq_Admin_ConfigureServiceDeploymentMachineUser
|
|
22
|
+
> {
|
|
23
|
+
method: 'configureServiceDeploymentMachineUser';
|
|
24
|
+
request: {
|
|
25
|
+
identity: IIdentity;
|
|
26
|
+
userId: string;
|
|
27
|
+
serviceId: string;
|
|
28
|
+
capabilities: TServiceDeploymentCapability[];
|
|
29
|
+
};
|
|
30
|
+
response: {
|
|
31
|
+
userId: string;
|
|
32
|
+
serviceId: string;
|
|
33
|
+
capabilities: TServiceDeploymentCapability[];
|
|
34
|
+
tokenRolesNormalized: true;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
18
38
|
export interface ICoreflowBaseServiceReconciliationResult {
|
|
19
39
|
status: 'fulfilled' | 'rejected';
|
|
20
40
|
nodeNames: string[];
|