@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 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: '11.4.0',
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
- configurationDigest: string;
62
- proposedNamespace: string;
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: 1;
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
- configurationDigest?: TSha256Digest;
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
- namespaceBlank: boolean;
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 namespaceRegex = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
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' || !requestArg.requestId.trim() || requestArg.requestId.length > 200) {
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.version !== 'string' || !requestArg.version.trim() || requestArg.version.length > 100) {
27
- blockers.push({ code: 'VERSION_NOT_RESERVED', message: 'A bounded release version is required.' });
28
+ if (typeof requestArg.sourceDirty !== 'boolean') {
29
+ blockers.push({ code: 'INVALID_REQUEST', message: 'Source worktree state must be reported.' });
28
30
  }
29
- if (typeof requestArg.proposedNamespace !== 'string' || !namespaceRegex.test(requestArg.proposedNamespace)) {
30
- blockers.push({ code: 'NAMESPACE_NOT_RESERVED', message: 'The proposed namespace is missing or malformed.' });
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.configurationDigest !== 'string' || !normalizeSha256Digest(requestArg.configurationDigest)) {
33
- blockers.push({ code: 'CONFIGURATION_DIGEST_INVALID', message: 'Configuration digest must be a canonical sha256 digest.' });
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVwbG95bWVudHByZWZsaWdodC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL2RhdGEvZGVwbG95bWVudHByZWZsaWdodC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFJQSxPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQTBMNUQsTUFBTSxvQkFBb0IsR0FBRyxnQkFBZ0IsQ0FBQztBQUM5QyxNQUFNLGNBQWMsR0FBRyx3Q0FBd0MsQ0FBQztBQUNoRSxNQUFNLHFCQUFxQixHQUFHLElBQUksR0FBRyxDQUE4QztJQUNqRixZQUFZO0lBQ1osTUFBTTtJQUNOLFdBQVc7SUFDWCxzQkFBc0I7SUFDdEIsdUJBQXVCO0NBQ3hCLENBQUMsQ0FBQztBQUVILE1BQU0sUUFBUSxHQUFHLENBQUMsUUFBaUIsRUFBdUMsRUFBRSxDQUMxRSxPQUFPLENBQUMsUUFBUSxDQUFDLElBQUksT0FBTyxRQUFRLEtBQUssUUFBUSxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsQ0FBQztBQUVoRixNQUFNLENBQUMsTUFBTSxrQ0FBa0MsR0FBRyxDQUNoRCxVQUFtQixFQUNZLEVBQUU7SUFDakMsTUFBTSxRQUFRLEdBQWtDLEVBQUUsQ0FBQztJQUNuRCxJQUFJLENBQUMsUUFBUSxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUM7UUFDMUIsT0FBTyxDQUFDLEVBQUUsSUFBSSxFQUFFLGlCQUFpQixFQUFFLE9BQU8sRUFBRSxpREFBaUQsRUFBRSxDQUFDLENBQUM7SUFDbkcsQ0FBQztJQUNELElBQUksT0FBTyxVQUFVLENBQUMsU0FBUyxLQUFLLFFBQVEsSUFBSSxDQUFDLFVBQVUsQ0FBQyxTQUFTLENBQUMsSUFBSSxFQUFFLElBQUksVUFBVSxDQUFDLFNBQVMsQ0FBQyxNQUFNLEdBQUcsR0FBRyxFQUFFLENBQUM7UUFDbEgsUUFBUSxDQUFDLElBQUksQ0FBQyxFQUFFLElBQUksRUFBRSxpQkFBaUIsRUFBRSxP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
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@serve.zone/interfaces",
3
- "version": "11.4.0",
3
+ "version": "13.0.0",
4
4
  "private": false,
5
5
  "description": "Shared TypeScript interfaces and TypedRequest contracts for the serve.zone ecosystem.",
6
6
  "exports": {
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@serve.zone/interfaces',
6
- version: '11.4.0',
6
+ version: '13.0.0',
7
7
  description: 'Shared TypeScript interfaces and TypedRequest contracts for the serve.zone ecosystem.'
8
8
  }
@@ -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
- configurationDigest: string;
104
- proposedNamespace: string;
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: 1;
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
- configurationDigest?: TSha256Digest;
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
- namespaceBlank: boolean;
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 namespaceRegex = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
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' || !requestArg.requestId.trim() || requestArg.requestId.length > 200) {
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.version !== 'string' || !requestArg.version.trim() || requestArg.version.length > 100) {
221
- blockers.push({ code: 'VERSION_NOT_RESERVED', message: 'A bounded release version is required.' });
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.proposedNamespace !== 'string' || !namespaceRegex.test(requestArg.proposedNamespace)) {
224
- blockers.push({ code: 'NAMESPACE_NOT_RESERVED', message: 'The proposed namespace is missing or malformed.' });
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.configurationDigest !== 'string' || !normalizeSha256Digest(requestArg.configurationDigest)) {
227
- blockers.push({ code: 'CONFIGURATION_DIGEST_INVALID', message: 'Configuration digest must be a canonical sha256 digest.' });
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.' });
@@ -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[];