@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: '12.0.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' | '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
- proposedNamespace: string;
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' || !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)) {
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 proposedResources = Array.isArray(requestArg.proposedCorestoreResources)
45
- ? requestArg.proposedCorestoreResources
46
- : [];
47
- if (!Array.isArray(requestArg.proposedCorestoreResources)
48
- || proposedResources.length > 8
49
- || proposedResources.some((resourceArg) => (!isRecord(resourceArg)
50
- || (resourceArg.capability !== 'database' && resourceArg.capability !== 'objectstorage')
51
- || typeof resourceArg.resourceName !== 'string'
52
- || !namespaceRegex.test(resourceArg.resourceName)))) {
53
- blockers.push({ code: 'INVALID_REQUEST', message: 'Proposed Corestore resources are malformed.' });
54
- }
55
- const proposedResourceKeys = proposedResources
56
- .filter(isRecord)
57
- .map((resourceArg) => `${String(resourceArg.capability)}:${String(resourceArg.resourceName)}`);
58
- if (new Set(proposedResourceKeys).size !== proposedResourceKeys.length) {
59
- blockers.push({ code: 'INVALID_REQUEST', message: 'Proposed Corestore resources must be unique.' });
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVwbG95bWVudHByZWZsaWdodC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL2RhdGEvZGVwbG95bWVudHByZWZsaWdodC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFJQSxPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQStNNUQsTUFBTSxvQkFBb0IsR0FBRyxnQkFBZ0IsQ0FBQztBQUM5QyxNQUFNLGNBQWMsR0FBRyx3Q0FBd0MsQ0FBQztBQUNoRSxNQUFNLG9CQUFvQixHQUFHLDRNQUE0TSxDQUFDO0FBQzFPLE1BQU0scUJBQXFCLEdBQUcsSUFBSSxHQUFHLENBQThDO0lBQ2pGLFlBQVk7SUFDWixNQUFNO0lBQ04sV0FBVztJQUNYLHNCQUFzQjtJQUN0Qix1QkFBdUI7Q0FDeEIsQ0FBQyxDQUFDO0FBRUgsTUFBTSxRQUFRLEdBQUcsQ0FBQyxRQUFpQixFQUF1QyxFQUFFLENBQzFFLE9BQU8sQ0FBQyxRQUFRLENBQUMsSUFBSSxPQUFPLFFBQVEsS0FBSyxRQUFRLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDO0FBRWhGLE1BQU0sQ0FBQyxNQUFNLGtDQUFrQyxHQUFHLENBQ2hELFVBQW1CLEVBQ1ksRUFBRTtJQUNqQyxNQUFNLFFBQVEsR0FBa0MsRUFBRSxDQUFDO0lBQ25ELElBQUksQ0FBQyxRQUFRLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQztRQUMxQixPQUFPLENBQUMsRUFBRSxJQUFJLEVBQUUsaUJBQWlCLEVBQUUsT0FBTyxFQUFFLGlEQUFpRCxFQUFFLENBQUMsQ0FBQztJQUNuRyxDQUFDO0lBQ0QsSUFBSSxPQUFPLFVBQVUsQ0FBQyxTQUFTLEtBQUssUUFBUSxJQUFJLENBQUMsVUFBVSxDQUFDLFNBQVMsQ0FBQyxJQUFJLEVBQUUsSUFBSSxVQUFVLENBQUMsU0FBUyxDQUFDLE1BQU0sR0FBRyxHQUFHLEVBQUUsQ0FBQztRQUNsSCxRQUFRLENBQUMsSUFB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
147
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVwbG95bWVudHByZWZsaWdodC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL2RhdGEvZGVwbG95bWVudHByZWZsaWdodC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFJQSxPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQXdPNUQsTUFBTSxvQkFBb0IsR0FBRyxnQkFBZ0IsQ0FBQztBQUM5QyxNQUFNLG9CQUFvQixHQUFHLDRNQUE0TSxDQUFDO0FBQzFPLE1BQU0scUJBQXFCLEdBQUcsSUFBSSxHQUFHLENBQThDO0lBQ2pGLFlBQVk7SUFDWixNQUFNO0lBQ04sV0FBVztJQUNYLHNCQUFzQjtJQUN0Qix1QkFBdUI7Q0FDeEIsQ0FBQyxDQUFDO0FBRUgsTUFBTSxRQUFRLEdBQUcsQ0FBQyxRQUFpQixFQUF1QyxFQUFFLENBQzFFLE9BQU8sQ0FBQyxRQUFRLENBQUMsSUFBSSxPQUFPLFFBQVEsS0FBSyxRQUFRLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDO0FBRWhGLE1BQU0sQ0FBQyxNQUFNLGtDQUFrQyxHQUFHLENBQ2hELFVBQW1CLEVBQ1ksRUFBRTtJQUNqQyxNQUFNLFFBQVEsR0FBa0MsRUFBRSxDQUFDO0lBQ25ELElBQUksQ0FBQyxRQUFRLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQztRQUMxQixPQUFPLENBQUMsRUFBRSxJQUFJLEVBQUUsaUJBQWlCLEVBQUUsT0FBTyxFQUFFLGlEQUFpRCxFQUFFLENBQUMsQ0FBQztJQUNuRyxDQUFDO0lBQ0QsSUFBSSxPQUFPLFVBQVUsQ0FBQyxTQUFTLEtBQUssUUFBUTtXQUN2QyxVQUFVLENBQUMsU0FBUyxDQUFDLE1BQU0sR0FBRyxHQUFHO1dBQ2pDLENBQUMsK0JBQStCLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDO1FBQ2pFLFFBQVEsQ0FBQyxJQUFJLENBQUMsRUFBRSxJQUFJLEVB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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@serve.zone/interfaces",
3
- "version": "12.0.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: '12.0.0',
6
+ version: '13.0.0',
7
7
  description: 'Shared TypeScript interfaces and TypedRequest contracts for the serve.zone ecosystem.'
8
8
  }
@@ -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
- proposedNamespace: string;
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' || !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)) {
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 proposedResources = Array.isArray(requestArg.proposedCorestoreResources)
259
- ? requestArg.proposedCorestoreResources
260
- : [];
261
- if (!Array.isArray(requestArg.proposedCorestoreResources)
262
- || proposedResources.length > 8
263
- || proposedResources.some((resourceArg) => (
264
- !isRecord(resourceArg)
265
- || (resourceArg.capability !== 'database' && resourceArg.capability !== 'objectstorage')
266
- || typeof resourceArg.resourceName !== 'string'
267
- || !namespaceRegex.test(resourceArg.resourceName)
268
- ))) {
269
- blockers.push({ code: 'INVALID_REQUEST', message: 'Proposed Corestore resources are malformed.' });
270
- }
271
- const proposedResourceKeys = proposedResources
272
- .filter(isRecord)
273
- .map((resourceArg) => `${String(resourceArg.capability)}:${String(resourceArg.resourceName)}`);
274
- if (new Set(proposedResourceKeys).size !== proposedResourceKeys.length) {
275
- blockers.push({ code: 'INVALID_REQUEST', message: 'Proposed Corestore resources must be unique.' });
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.' });