@serve.zone/interfaces 21.1.0 → 23.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.
Files changed (83) hide show
  1. package/changelog.md +23 -0
  2. package/dist_ts/00_commitinfo_data.js +1 -1
  3. package/dist_ts/appstore/types.d.ts +31 -16
  4. package/dist_ts/appstore/types.js +208 -11
  5. package/dist_ts/data/coremail.d.ts +83 -9
  6. package/dist_ts/data/coremail.js +67 -1
  7. package/dist_ts/data/coremail.runtime.d.ts +27 -1
  8. package/dist_ts/data/coremail.runtime.js +800 -36
  9. package/dist_ts/data/deploymentoperation.js +6 -20
  10. package/dist_ts/data/deploymentpreflight.d.ts +2 -6
  11. package/dist_ts/data/deploymentpreflight.js +1 -1
  12. package/dist_ts/data/hostedapp.d.ts +40 -14
  13. package/dist_ts/data/hostedapp.js +90 -1
  14. package/dist_ts/data/immutableimage.d.ts +30 -1
  15. package/dist_ts/data/immutableimage.js +103 -1
  16. package/dist_ts/data/index.d.ts +0 -2
  17. package/dist_ts/data/index.js +1 -3
  18. package/dist_ts/data/secret.d.ts +186 -13
  19. package/dist_ts/data/secret.js +543 -45
  20. package/dist_ts/data/service.d.ts +0 -39
  21. package/dist_ts/data/service.js +1 -77
  22. package/dist_ts/data/settings.d.ts +62 -43
  23. package/dist_ts/data/settings.js +34 -2
  24. package/dist_ts/platform/storage.d.ts +13 -14
  25. package/dist_ts/platform/storage.js +1 -1
  26. package/dist_ts/platform/storagemigration.d.ts +8 -8
  27. package/dist_ts/platform/storagemigration.golden.d.ts +2 -2
  28. package/dist_ts/platform/storagemigration.golden.js +19 -88
  29. package/dist_ts/platform/storagemigration.js +46 -58
  30. package/dist_ts/platform/types.d.ts +5 -19
  31. package/dist_ts/plugins.d.ts +2 -1
  32. package/dist_ts/plugins.js +3 -2
  33. package/dist_ts/requests/coremail.d.ts +12 -5
  34. package/dist_ts/requests/hostedapp.d.ts +12 -9
  35. package/dist_ts/requests/hostedapp.js +38 -1
  36. package/dist_ts/requests/index.d.ts +1 -3
  37. package/dist_ts/requests/index.js +2 -4
  38. package/dist_ts/requests/platform.d.ts +0 -1
  39. package/dist_ts/requests/secret.d.ts +23 -17
  40. package/dist_ts/requests/secret.js +161 -2
  41. package/dist_ts/requests/service.d.ts +0 -13
  42. package/dist_ts/requests/settings.d.ts +3 -3
  43. package/dist_ts/runtime.d.ts +78 -26
  44. package/dist_ts/runtime.js +219 -19
  45. package/package.json +2 -1
  46. package/readme.md +163 -38
  47. package/ts/00_commitinfo_data.ts +1 -1
  48. package/ts/appstore/types.ts +251 -25
  49. package/ts/data/coremail.runtime.ts +1212 -38
  50. package/ts/data/coremail.ts +120 -8
  51. package/ts/data/deploymentoperation.ts +7 -31
  52. package/ts/data/deploymentpreflight.ts +2 -5
  53. package/ts/data/hostedapp.ts +144 -18
  54. package/ts/data/immutableimage.ts +150 -1
  55. package/ts/data/index.ts +0 -2
  56. package/ts/data/secret.ts +775 -53
  57. package/ts/data/service.ts +0 -118
  58. package/ts/data/settings.ts +70 -80
  59. package/ts/platform/storage.ts +15 -16
  60. package/ts/platform/storagemigration.golden.ts +18 -95
  61. package/ts/platform/storagemigration.ts +57 -87
  62. package/ts/platform/types.ts +6 -19
  63. package/ts/plugins.ts +2 -0
  64. package/ts/requests/coremail.ts +13 -4
  65. package/ts/requests/hostedapp.ts +50 -9
  66. package/ts/requests/index.ts +0 -4
  67. package/ts/requests/platform.ts +0 -1
  68. package/ts/requests/secret.ts +204 -9
  69. package/ts/requests/service.ts +0 -16
  70. package/ts/requests/settings.ts +3 -3
  71. package/ts/runtime.ts +314 -41
  72. package/dist_ts/data/secretbundle.d.ts +0 -57
  73. package/dist_ts/data/secretbundle.js +0 -2
  74. package/dist_ts/data/secretgroup.d.ts +0 -52
  75. package/dist_ts/data/secretgroup.js +0 -2
  76. package/dist_ts/requests/secretbundle.d.ts +0 -75
  77. package/dist_ts/requests/secretbundle.js +0 -4
  78. package/dist_ts/requests/secretgroup.d.ts +0 -52
  79. package/dist_ts/requests/secretgroup.js +0 -4
  80. package/ts/data/secretbundle.ts +0 -65
  81. package/ts/data/secretgroup.ts +0 -58
  82. package/ts/requests/secretbundle.ts +0 -103
  83. package/ts/requests/secretgroup.ts +0 -74
@@ -34,36 +34,12 @@ export interface IServiceVolume {
34
34
  options?: Record<string, string>;
35
35
  }
36
36
 
37
- /**
38
- * A single secret-bundle key delivered as a file instead of an environment
39
- * variable. Targets are intentionally restricted to Docker's secret tmpfs so
40
- * a deployment declaration cannot overwrite application or system files.
41
- */
42
- export interface IServiceSecretFile {
43
- /** Key in the service's merged secret bundles. */
44
- sourceKey: string;
45
- /** Absolute file path below /run/secrets/. */
46
- targetPath: string;
47
- /** Numeric container user identity. */
48
- uid: number;
49
- /** Numeric container group identity. */
50
- gid: number;
51
- /** Read-only POSIX mode. Supported values are 0400 and 0440. */
52
- mode: number;
53
- }
54
-
55
37
  export const serviceContainerArgLimits = {
56
38
  maximumArgs: 64,
57
39
  maximumArgBytes: 4096,
58
40
  maximumTotalBytes: 32 * 1024,
59
41
  } as const;
60
42
 
61
- export const serviceSecretFileLimits = {
62
- maximumFiles: 32,
63
- maximumValueBytes: 500 * 1024,
64
- maximumIdentity: 2_147_483_647,
65
- } as const;
66
-
67
43
  export const normalizeServiceAbsolutePath = (pathArg: string): string | undefined => {
68
44
  if (typeof pathArg !== 'string'
69
45
  || !pathArg.startsWith('/')
@@ -85,85 +61,6 @@ export const normalizeServiceAbsolutePath = (pathArg: string): string | undefine
85
61
  return `/${segments.join('/')}`;
86
62
  };
87
63
 
88
- const isCanonicalSecretTargetPath = (targetPathArg: string): boolean => (
89
- normalizeServiceAbsolutePath(targetPathArg) === targetPathArg
90
- && /^\/run\/secrets\/[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(targetPathArg)
91
- && targetPathArg !== '/run/secrets/secret.json'
92
- );
93
-
94
- const pathsOverlap = (leftArg: string, rightArg: string): boolean => {
95
- const left = normalizeServiceAbsolutePath(leftArg);
96
- const right = normalizeServiceAbsolutePath(rightArg);
97
- if (!left || !right) return false;
98
- if (left === '/' || right === '/') return true;
99
- return left === right || left.startsWith(`${right}/`) || right.startsWith(`${left}/`);
100
- };
101
-
102
- /** Pure, secret-value-free validation shared by Cloudly and Coreflow. */
103
- export const validateServiceSecretFiles = (
104
- secretFilesArg: unknown,
105
- volumeMountPathsArg: string[] = [],
106
- ): string[] => {
107
- if (secretFilesArg === undefined) return [];
108
- if (!Array.isArray(secretFilesArg)) return ['secretFiles must be an array'];
109
- if (secretFilesArg.length > serviceSecretFileLimits.maximumFiles) {
110
- return [`secretFiles must contain at most ${serviceSecretFileLimits.maximumFiles} entries`];
111
- }
112
- const errors: string[] = [];
113
- if (volumeMountPathsArg.some((mountPathArg) => (
114
- normalizeServiceAbsolutePath(mountPathArg) !== mountPathArg
115
- ))) {
116
- errors.push('volume mount paths must be canonical absolute paths');
117
- }
118
- const sourceKeys: string[] = [];
119
- const targetPaths: string[] = [];
120
- for (const [index, candidate] of secretFilesArg.entries()) {
121
- if (!candidate || typeof candidate !== 'object' || Array.isArray(candidate)) {
122
- errors.push(`secretFiles[${index}] must be an object`);
123
- continue;
124
- }
125
- const mapping = candidate as Partial<IServiceSecretFile>;
126
- if (typeof mapping.sourceKey !== 'string'
127
- || mapping.sourceKey.length > 253
128
- || !/^[A-Z_][A-Z0-9_]*$/.test(mapping.sourceKey)) {
129
- errors.push(`secretFiles[${index}].sourceKey must be a canonical environment key`);
130
- } else {
131
- sourceKeys.push(mapping.sourceKey);
132
- }
133
- if (typeof mapping.targetPath !== 'string'
134
- || !isCanonicalSecretTargetPath(mapping.targetPath)) {
135
- errors.push(
136
- `secretFiles[${index}].targetPath must be a unique canonical file below /run/secrets and may not be secret.json`,
137
- );
138
- } else {
139
- targetPaths.push(mapping.targetPath);
140
- if (volumeMountPathsArg.some((mountPathArg) => (
141
- typeof mountPathArg === 'string' && pathsOverlap(mapping.targetPath as string, mountPathArg)
142
- ))) {
143
- errors.push(`secretFiles[${index}].targetPath overlaps a declared volume mount`);
144
- }
145
- }
146
- for (const identityField of ['uid', 'gid'] as const) {
147
- const identity = mapping[identityField];
148
- if (!Number.isSafeInteger(identity)
149
- || (identity as number) < 0
150
- || (identity as number) > serviceSecretFileLimits.maximumIdentity) {
151
- errors.push(`secretFiles[${index}].${identityField} must be a bounded numeric identity`);
152
- }
153
- }
154
- if (mapping.mode !== 0o400 && mapping.mode !== 0o440) {
155
- errors.push(`secretFiles[${index}].mode must be 0400 or 0440`);
156
- }
157
- }
158
- if (new Set(sourceKeys).size !== sourceKeys.length) {
159
- errors.push('secretFiles sourceKey values must be unique');
160
- }
161
- if (new Set(targetPaths).size !== targetPaths.length) {
162
- errors.push('secretFiles targetPath values must be unique');
163
- }
164
- return errors;
165
- };
166
-
167
64
  /** Pure validation for the exact OCI/Docker argument vector after image entrypoint. */
168
65
  export const validateServiceContainerArgs = (containerArgsArg: unknown): string[] => {
169
66
  if (containerArgsArg === undefined) return [];
@@ -261,27 +158,12 @@ export interface IService {
261
158
  hostedAppLifecycle?: IHostedAppLifecycleState;
262
159
  reconciliationStatus?: IServiceReconciliationStatus;
263
160
  environment: { [key: string]: string };
264
- /**
265
- * Legacy main SecretBundle ID. New services use secretConfiguration and
266
- * the server-managed secretDeployment manifest pointer.
267
- *
268
- * @deprecated Compatibility-only until the versioned SecretBundle migration completes.
269
- */
270
- secretBundleId?: string;
271
- /**
272
- * Legacy additional SecretBundle IDs.
273
- *
274
- * @deprecated Use explicit same-organization SecretSet attachments.
275
- */
276
- additionalSecretBundleIds?: string[];
277
161
  /** Value-free, caller-managed SecretSet attachment configuration. */
278
162
  secretConfiguration?: IServiceSecretConfiguration;
279
163
  /** Server-managed immutable manifest authority pointer. */
280
164
  secretDeployment?: IServiceSecretDeploymentPlan;
281
165
  /** Exact OCI/Docker argument vector appended after the image entrypoint. */
282
166
  containerArgs?: string[];
283
- /** Secret keys mounted as files and excluded from Env and secret.json. */
284
- secretFiles?: IServiceSecretFile[];
285
167
 
286
168
  /**
287
169
  * Service category determines deployment behavior
@@ -1,94 +1,84 @@
1
- import * as plugins from '../plugins.js';
1
+ import type { ISystemSecretOwner, TSecretManagementScope } from './secret.js';
2
2
 
3
- /**
4
- * Interface for Cloudly settings stored in EasyStore
5
- * These are runtime-configurable settings that can be modified via the UI
6
- */
7
- export interface ICloudlySettings {
8
- // Cloud Provider Tokens
9
- hetznerToken?: string;
10
- cloudflareToken?: string;
3
+ export interface ICloudlyS3BackupTargetDescriptor {
4
+ type: 's3';
5
+ endpoint: string;
6
+ bucket: string;
7
+ region?: string;
8
+ port?: number;
9
+ useSsl?: boolean;
10
+ }
11
11
 
12
- // Retention for archived deployment records in days (default 90)
13
- deploymentArchiveRetentionDays?: string;
12
+ export interface ICloudlyNfsBackupTargetDescriptor {
13
+ type: 'nfs';
14
+ path: string;
15
+ }
14
16
 
15
- // Long-term backup target. Type 's3' | 'nfs' | 'smb'; config is a JSON
16
- // object string with the matching connection fields (s3: endpoint,
17
- // accessKey, secretKey, bucket, port?, useSsl?, region?; nfs: path
18
- // mounted into the cloudly container; smb: host, share, username?,
19
- // password?, domain?, port?). Absent = no offload, backups stay on the
20
- // cache tier.
21
- backupExternalTargetType?: string;
22
- backupExternalTargetConfig?: string;
17
+ export interface ICloudlySmbBackupTargetDescriptor {
18
+ type: 'smb';
19
+ host: string;
20
+ share: string;
21
+ domain?: string;
22
+ port?: number;
23
+ }
23
24
 
24
- // Node-local archive cache retention in days (corestore prune; default 30)
25
- backupNodeCacheKeepDays?: string;
25
+ export type TCloudlyBackupTargetDescriptor =
26
+ | ICloudlyS3BackupTargetDescriptor
27
+ | ICloudlyNfsBackupTargetDescriptor
28
+ | ICloudlySmbBackupTargetDescriptor;
26
29
 
27
- // JSON map of swarm node hostname -> gateway-reachable IP/host. Routes for
28
- // services pinned to a node target that node's coretraffic instead of the
29
- // static dcrouterTargetHost (e.g. {"worker-a":"192.0.2.10"}).
30
+ /** Public runtime-configurable settings. No serialized credential belongs here. */
31
+ export interface ICloudlySettings {
32
+ deploymentArchiveRetentionDays?: number;
33
+ backupExternalTarget?: TCloudlyBackupTargetDescriptor;
34
+ backupNodeCacheKeepDays?: number;
30
35
  dcrouterGatewayUrl?: string;
31
- dcrouterGatewayApiToken?: string;
32
36
  dcrouterGatewayClientId?: string;
33
37
  dcrouterTargetHost?: string;
34
- dcrouterTargetPort?: string;
35
- dcrouterTargetHostsByNode?: string;
36
-
37
- // External dcrouter mail integration. Submission settings are injected into
38
- // service secret bundles; forward targets are used for inbound smtpForward.
38
+ dcrouterTargetPort?: number;
39
+ dcrouterTargetHostsByNode?: Record<string, string>;
39
40
  dcrouterMailSubmissionHost?: string;
40
- dcrouterMailSubmissionPort?: string;
41
+ dcrouterMailSubmissionPort?: number;
41
42
  dcrouterMailSubmissionTlsMode?: 'plain' | 'starttls' | 'implicitTls';
42
43
  dcrouterMailForwardTargetHost?: string;
43
- dcrouterMailForwardTargetHostsByNode?: string;
44
-
45
- // BaseOS enrollment
46
- baseosJoinToken?: string;
47
-
48
- // CoreBuild worker used for image generation
44
+ dcrouterMailForwardTargetHostsByNode?: Record<string, string>;
49
45
  corebuildWorkerUrl?: string;
50
- corebuildWorkerToken?: string;
51
- corebuildWorkersJson?: string;
52
-
53
- // AWS Credentials
54
- awsAccessKey?: string;
55
- awsSecretKey?: string;
56
- awsRegion?: string;
57
-
58
- // DigitalOcean
59
- digitalOceanToken?: string;
60
-
61
- // Azure Credentials
62
- azureClientId?: string;
63
- azureClientSecret?: string;
64
- azureTenantId?: string;
65
- azureSubscriptionId?: string;
66
-
67
- // Google Cloud
68
- googleCloudKeyJson?: string;
69
- googleCloudProjectId?: string;
70
-
71
- // Vultr
72
- vultrApiKey?: string;
73
-
74
- // Linode
75
- linodeToken?: string;
76
-
77
- // OVH
78
- ovhApplicationKey?: string;
79
- ovhApplicationSecret?: string;
80
- ovhConsumerKey?: string;
81
-
82
- // Scaleway
83
- scalewayAccessKey?: string;
84
- scalewaySecretKey?: string;
85
- scalewayOrganizationId?: string;
46
+ corebuildWorkerUrls?: string[];
86
47
  }
87
48
 
88
- /**
89
- * Interface for masked settings (used in API responses)
90
- * Shows only last 4 characters of sensitive tokens
91
- */
92
- export type ICloudlySettingsMasked = {
93
- [K in keyof ICloudlySettings]: string | undefined;
94
- };
49
+ export const cloudlySystemSecretOwner = Object.freeze({
50
+ kind: 'system',
51
+ systemId: 'cloudly-settings',
52
+ } as const satisfies ISystemSecretOwner);
53
+
54
+ export const cloudlySystemSecretManagementScope =
55
+ 'system:cloudly-settings' as const satisfies TSecretManagementScope;
56
+
57
+ /** Stable keys for values removed from serialized Cloudly settings. */
58
+ export const cloudlySystemSecretKeys = Object.freeze({
59
+ hetznerToken: 'HETZNER_TOKEN',
60
+ cloudflareToken: 'CLOUDFLARE_TOKEN',
61
+ backupExternalTargetCredentials: 'BACKUP_EXTERNAL_TARGET_CREDENTIALS',
62
+ dcrouterGatewayApiToken: 'DCROUTER_GATEWAY_API_TOKEN',
63
+ baseosJoinToken: 'BASEOS_JOIN_TOKEN',
64
+ corebuildWorkerToken: 'COREBUILD_WORKER_TOKEN',
65
+ corebuildWorkers: 'COREBUILD_WORKERS',
66
+ awsAccessKey: 'AWS_ACCESS_KEY',
67
+ awsSecretKey: 'AWS_SECRET_KEY',
68
+ awsRegion: 'AWS_REGION',
69
+ digitalOceanToken: 'DIGITALOCEAN_TOKEN',
70
+ azureClientId: 'AZURE_CLIENT_ID',
71
+ azureClientSecret: 'AZURE_CLIENT_SECRET',
72
+ azureTenantId: 'AZURE_TENANT_ID',
73
+ azureSubscriptionId: 'AZURE_SUBSCRIPTION_ID',
74
+ googleCloudKey: 'GOOGLE_CLOUD_KEY',
75
+ googleCloudProjectId: 'GOOGLE_CLOUD_PROJECT_ID',
76
+ vultrApiKey: 'VULTR_API_KEY',
77
+ linodeToken: 'LINODE_TOKEN',
78
+ ovhApplicationKey: 'OVH_APPLICATION_KEY',
79
+ ovhApplicationSecret: 'OVH_APPLICATION_SECRET',
80
+ ovhConsumerKey: 'OVH_CONSUMER_KEY',
81
+ scalewayAccessKey: 'SCALEWAY_ACCESS_KEY',
82
+ scalewaySecretKey: 'SCALEWAY_SECRET_KEY',
83
+ scalewayOrganizationId: 'SCALEWAY_ORGANIZATION_ID',
84
+ } as const);
@@ -1,3 +1,5 @@
1
+ import type { TSecretManagementScope } from '../data/secret.js';
2
+
1
3
  /**
2
4
  * Backend-neutral storage vocabulary shared by App Store manifests, control
3
5
  * planes, and fulfillment adapters. Physical providers and runtime attachment
@@ -100,13 +102,13 @@ export type TStorageClassCapabilities =
100
102
  * addresses, mount options, principals, and credential values are private.
101
103
  */
102
104
  export interface IStorageCapabilityAdvertisement {
103
- schemaVersion: 1;
105
+ schemaVersion: 2;
104
106
  featureIds: string[];
105
107
  classes: TStorageClassCapabilities[];
106
108
  }
107
109
 
108
- export interface IObjectStorageEnvironmentDelivery {
109
- type: 'environment';
110
+ export interface IObjectStorageLauncherEnvironmentDelivery {
111
+ type: 'launcher-environment';
110
112
  /**
111
113
  * Explicit target keys prevent two named bindings from silently overwriting
112
114
  * each other. Every required field must have a distinct environment key.
@@ -121,8 +123,8 @@ export interface IObjectStorageEnvironmentDelivery {
121
123
  };
122
124
  }
123
125
 
124
- export interface IObjectStorageSecretFileDelivery {
125
- type: 'secretFile';
126
+ export interface IObjectStorageFileDelivery {
127
+ type: 'file';
126
128
  /** Canonical absolute path below /run/secrets/. */
127
129
  targetPath: string;
128
130
  /**
@@ -130,11 +132,14 @@ export interface IObjectStorageSecretFileDelivery {
130
132
  * secretAccessKey, and optional sessionToken fields.
131
133
  */
132
134
  format: 'servezone-object-storage-v1';
135
+ uid: number;
136
+ gid: number;
137
+ mode: 0o400 | 0o440;
133
138
  }
134
139
 
135
140
  export type TObjectStorageDelivery =
136
- | IObjectStorageEnvironmentDelivery
137
- | IObjectStorageSecretFileDelivery;
141
+ | IObjectStorageLauncherEnvironmentDelivery
142
+ | IObjectStorageFileDelivery;
138
143
 
139
144
  export type TResolvedStorageBindingStatus =
140
145
  | 'requested'
@@ -176,7 +181,7 @@ export interface IResolvedStorageCapacity {
176
181
  }
177
182
 
178
183
  export interface IResolvedStorageBindingBase {
179
- schemaVersion: 1;
184
+ schemaVersion: 2;
180
185
  /** Stable binding/allocation identity. */
181
186
  id: string;
182
187
  serviceId: string;
@@ -208,13 +213,6 @@ extends IResolvedStorageBindingBase {
208
213
  accessMode: TFilesystemStorageAccessMode;
209
214
  }
210
215
 
211
- export interface IStorageObjectCredentialsRef {
212
- secretBundleId: string;
213
- accessKeyIdKey: string;
214
- secretAccessKeyKey: string;
215
- sessionTokenKey?: string;
216
- }
217
-
218
216
  export interface IResolvedObjectStorageConnection {
219
217
  endpoint: string;
220
218
  bucket: string;
@@ -226,7 +224,8 @@ extends IResolvedStorageBindingBase {
226
224
  kind: 'objectStorage';
227
225
  accessMode: TObjectStorageAccessMode;
228
226
  connection: IResolvedObjectStorageConnection;
229
- credentials: IStorageObjectCredentialsRef;
227
+ /** Value-free service-owned Secret reconciliation scope. */
228
+ credentialManagementScope: Extract<TSecretManagementScope, `platform:${string}`>;
230
229
  delivery: TObjectStorageDelivery;
231
230
  versioning: boolean;
232
231
  retentionDays?: number;
@@ -24,7 +24,7 @@ const capabilities = {
24
24
  } as const;
25
25
 
26
26
  const delivery = {
27
- type: 'environment',
27
+ type: 'launcher-environment',
28
28
  keys: {
29
29
  endpoint: 'APP_S3_ENDPOINT',
30
30
  bucket: 'APP_S3_BUCKET',
@@ -34,14 +34,10 @@ const delivery = {
34
34
  },
35
35
  } as const;
36
36
 
37
- const credentials = {
38
- secretBundleId: 'service-storage',
39
- accessKeyIdKey: 'object.accessKeyId',
40
- secretAccessKeyKey: 'object.secretAccessKey',
41
- };
37
+ const credentialManagementScope = 'platform:object-storage-binding';
42
38
 
43
39
  const sourceBinding: TActiveObjectStorageBinding = {
44
- schemaVersion: 1,
40
+ schemaVersion: 2,
45
41
  id: 'binding-object',
46
42
  serviceId: 'service-app',
47
43
  requestId: 'object-data',
@@ -63,7 +59,7 @@ const sourceBinding: TActiveObjectStorageBinding = {
63
59
  bucket: 'source-bucket',
64
60
  region: 'local',
65
61
  },
66
- credentials,
62
+ credentialManagementScope,
67
63
  delivery,
68
64
  versioning: false,
69
65
  createdAt: 1_700_000_000_000,
@@ -96,12 +92,12 @@ const target = {
96
92
  accessMode: 'readWrite',
97
93
  delivery,
98
94
  },
99
- credentials,
95
+ credentialManagementScope,
100
96
  } as const;
101
97
 
102
98
  const preparationSnapshotPayload:
103
99
  TUnfencedObjectStorageBindingControlSnapshotDigestPayload = {
104
- schemaVersion: 1,
100
+ schemaVersion: 2,
105
101
  binding: sourceBinding,
106
102
  recordRevision: 12,
107
103
  capturedAt: 1_700_000_000_010,
@@ -110,11 +106,11 @@ TUnfencedObjectStorageBindingControlSnapshotDigestPayload = {
110
106
  const preparationSnapshot: IUnfencedObjectStorageBindingControlSnapshot = {
111
107
  ...preparationSnapshotPayload,
112
108
  snapshotDigest:
113
- '35870a0c3ca7f2ee70d0ae7f83109bec23a8ce59bf8efef1c94221a496210439',
109
+ 'ac8166a9888144d11dc7419f60be055eeb6f392ec41a254a9f9b2a7b3df1fba7',
114
110
  };
115
111
 
116
112
  const prepareRequest: IObjectStorageMigrationPrepareRequest = {
117
- schemaVersion: 1,
113
+ schemaVersion: 2,
118
114
  migrationId: 'migration-object-capacity',
119
115
  sourceControlSnapshot: preparationSnapshot,
120
116
  workloadGeneration: 8,
@@ -124,7 +120,7 @@ const prepareRequest: IObjectStorageMigrationPrepareRequest = {
124
120
  const candidateBinding: TStagedObjectStorageBinding = {
125
121
  ...sourceBinding,
126
122
  requestDigest:
127
- '2096dfa1f6db50d670cbb4d6436f38c2eec383435c99346e31d0d1a9e0b1beba',
123
+ '3f864862041002e25b790b3bc7afbe37c399a006f385e1def9f679a93d4fa173',
128
124
  generation: 4,
129
125
  observedGeneration: 3,
130
126
  status: 'provisioning',
@@ -144,98 +140,25 @@ const candidateBinding: TStagedObjectStorageBinding = {
144
140
  };
145
141
 
146
142
  export const storageMigrationCanonicalDigestGoldenVectors = deepFreezeValue({
147
- version: 1 as const,
143
+ version: 2 as const,
148
144
  targetRequest: {
149
145
  input: target.request,
150
- canonicalJson:
151
- '{"accessMode":"readWrite","capacity":{"limit":"1TiB","request":"500GiB"},' +
152
- '"delivery":{"keys":{"accessKeyId":"APP_S3_ACCESS_KEY","bucket":"APP_S3_BUCKET",' +
153
- '"endpoint":"APP_S3_ENDPOINT","region":"APP_S3_REGION",' +
154
- '"secretAccessKey":"APP_S3_SECRET_KEY"},"type":"environment"},' +
155
- '"id":"object-data","kind":"objectStorage","reclaimPolicy":"retain",' +
156
- '"storageClass":"backupCapacity"}',
157
- sha256:
158
- '2096dfa1f6db50d670cbb4d6436f38c2eec383435c99346e31d0d1a9e0b1beba',
146
+ canonicalJson: '{"accessMode":"readWrite","capacity":{"limit":"1TiB","request":"500GiB"},"delivery":{"keys":{"accessKeyId":"APP_S3_ACCESS_KEY","bucket":"APP_S3_BUCKET","endpoint":"APP_S3_ENDPOINT","region":"APP_S3_REGION","secretAccessKey":"APP_S3_SECRET_KEY"},"type":"launcher-environment"},"id":"object-data","kind":"objectStorage","reclaimPolicy":"retain","storageClass":"backupCapacity"}',
147
+ sha256: '3f864862041002e25b790b3bc7afbe37c399a006f385e1def9f679a93d4fa173',
159
148
  },
160
149
  preparationSnapshot: {
161
150
  input: preparationSnapshotPayload,
162
- canonicalJson:
163
- '{"binding":{"accessMode":"readWrite","capabilities":{"backup":true,' +
164
- '"durability":"persistent","encryptedInTransit":true,"hardQuota":true,' +
165
- '"performanceTier":"capacity","snapshots":"none","topology":"singleNode"},' +
166
- '"connection":{"bucket":"source-bucket","endpoint":"https://source.example.test",' +
167
- '"region":"local"},"createdAt":1700000000000,"credentials":' +
168
- '{"accessKeyIdKey":"object.accessKeyId","secretAccessKeyKey":"object.secretAccessKey",' +
169
- '"secretBundleId":"service-storage"},"delivery":{"keys":' +
170
- '{"accessKeyId":"APP_S3_ACCESS_KEY","bucket":"APP_S3_BUCKET",' +
171
- '"endpoint":"APP_S3_ENDPOINT","region":"APP_S3_REGION",' +
172
- '"secretAccessKey":"APP_S3_SECRET_KEY"},"type":"environment"},' +
173
- '"generation":3,"id":"binding-object","kind":"objectStorage",' +
174
- '"observedGeneration":3,"policy":{"classId":"source-object","revision":"1"},' +
175
- '"requestDigest":"1111111111111111111111111111111111111111111111111111111111111111",' +
176
- '"requestId":"object-data","resourceRef":"source-resource","schemaVersion":1,' +
177
- '"serviceId":"service-app","status":"ready","updatedAt":1700000000001,' +
178
- '"versioning":false},"capturedAt":1700000000010,"recordRevision":12,"schemaVersion":1}',
179
- sha256:
180
- '35870a0c3ca7f2ee70d0ae7f83109bec23a8ce59bf8efef1c94221a496210439',
151
+ canonicalJson: '{"binding":{"accessMode":"readWrite","capabilities":{"backup":true,"durability":"persistent","encryptedInTransit":true,"hardQuota":true,"performanceTier":"capacity","snapshots":"none","topology":"singleNode"},"connection":{"bucket":"source-bucket","endpoint":"https://source.example.test","region":"local"},"createdAt":1700000000000,"credentialManagementScope":"platform:object-storage-binding","delivery":{"keys":{"accessKeyId":"APP_S3_ACCESS_KEY","bucket":"APP_S3_BUCKET","endpoint":"APP_S3_ENDPOINT","region":"APP_S3_REGION","secretAccessKey":"APP_S3_SECRET_KEY"},"type":"launcher-environment"},"generation":3,"id":"binding-object","kind":"objectStorage","observedGeneration":3,"policy":{"classId":"source-object","revision":"1"},"requestDigest":"1111111111111111111111111111111111111111111111111111111111111111","requestId":"object-data","resourceRef":"source-resource","schemaVersion":2,"serviceId":"service-app","status":"ready","updatedAt":1700000000001,"versioning":false},"capturedAt":1700000000010,"recordRevision":12,"schemaVersion":2}',
152
+ sha256: 'ac8166a9888144d11dc7419f60be055eeb6f392ec41a254a9f9b2a7b3df1fba7',
181
153
  },
182
154
  prepareRequest: {
183
155
  input: prepareRequest,
184
- canonicalJson:
185
- '{"migrationId":"migration-object-capacity","schemaVersion":1,' +
186
- '"sourceControlSnapshot":{"binding":{"accessMode":"readWrite",' +
187
- '"capabilities":{"backup":true,"durability":"persistent",' +
188
- '"encryptedInTransit":true,"hardQuota":true,"performanceTier":"capacity",' +
189
- '"snapshots":"none","topology":"singleNode"},"connection":' +
190
- '{"bucket":"source-bucket","endpoint":"https://source.example.test","region":"local"},' +
191
- '"createdAt":1700000000000,"credentials":{"accessKeyIdKey":"object.accessKeyId",' +
192
- '"secretAccessKeyKey":"object.secretAccessKey","secretBundleId":"service-storage"},' +
193
- '"delivery":{"keys":{"accessKeyId":"APP_S3_ACCESS_KEY","bucket":"APP_S3_BUCKET",' +
194
- '"endpoint":"APP_S3_ENDPOINT","region":"APP_S3_REGION",' +
195
- '"secretAccessKey":"APP_S3_SECRET_KEY"},"type":"environment"},' +
196
- '"generation":3,"id":"binding-object","kind":"objectStorage",' +
197
- '"observedGeneration":3,"policy":{"classId":"source-object","revision":"1"},' +
198
- '"requestDigest":"1111111111111111111111111111111111111111111111111111111111111111",' +
199
- '"requestId":"object-data","resourceRef":"source-resource","schemaVersion":1,' +
200
- '"serviceId":"service-app","status":"ready","updatedAt":1700000000001,' +
201
- '"versioning":false},"capturedAt":1700000000010,"recordRevision":12,' +
202
- '"schemaVersion":1,"snapshotDigest":' +
203
- '"35870a0c3ca7f2ee70d0ae7f83109bec23a8ce59bf8efef1c94221a496210439"},' +
204
- '"target":{"credentials":{"accessKeyIdKey":"object.accessKeyId",' +
205
- '"secretAccessKeyKey":"object.secretAccessKey","secretBundleId":"service-storage"},' +
206
- '"policy":{"classId":"capacity-object","revision":"4"},"request":' +
207
- '{"accessMode":"readWrite","capacity":{"limit":"1TiB","request":"500GiB"},' +
208
- '"delivery":{"keys":{"accessKeyId":"APP_S3_ACCESS_KEY","bucket":"APP_S3_BUCKET",' +
209
- '"endpoint":"APP_S3_ENDPOINT","region":"APP_S3_REGION",' +
210
- '"secretAccessKey":"APP_S3_SECRET_KEY"},"type":"environment"},' +
211
- '"id":"object-data","kind":"objectStorage","reclaimPolicy":"retain",' +
212
- '"storageClass":"backupCapacity"},"storageClass":{"kind":"objectStorage",' +
213
- '"purpose":"backup","required":{"backup":true,"durability":"persistent",' +
214
- '"performanceTier":"capacity"}}},"workloadGeneration":8}',
215
- sha256:
216
- 'ecbb40ec9bfa20b9f4372eb0d00eaf79c3e84dd3132c5bde7e65ba3fec55e595',
156
+ canonicalJson: '{"migrationId":"migration-object-capacity","schemaVersion":2,"sourceControlSnapshot":{"binding":{"accessMode":"readWrite","capabilities":{"backup":true,"durability":"persistent","encryptedInTransit":true,"hardQuota":true,"performanceTier":"capacity","snapshots":"none","topology":"singleNode"},"connection":{"bucket":"source-bucket","endpoint":"https://source.example.test","region":"local"},"createdAt":1700000000000,"credentialManagementScope":"platform:object-storage-binding","delivery":{"keys":{"accessKeyId":"APP_S3_ACCESS_KEY","bucket":"APP_S3_BUCKET","endpoint":"APP_S3_ENDPOINT","region":"APP_S3_REGION","secretAccessKey":"APP_S3_SECRET_KEY"},"type":"launcher-environment"},"generation":3,"id":"binding-object","kind":"objectStorage","observedGeneration":3,"policy":{"classId":"source-object","revision":"1"},"requestDigest":"1111111111111111111111111111111111111111111111111111111111111111","requestId":"object-data","resourceRef":"source-resource","schemaVersion":2,"serviceId":"service-app","status":"ready","updatedAt":1700000000001,"versioning":false},"capturedAt":1700000000010,"recordRevision":12,"schemaVersion":2,"snapshotDigest":"ac8166a9888144d11dc7419f60be055eeb6f392ec41a254a9f9b2a7b3df1fba7"},"target":{"credentialManagementScope":"platform:object-storage-binding","policy":{"classId":"capacity-object","revision":"4"},"request":{"accessMode":"readWrite","capacity":{"limit":"1TiB","request":"500GiB"},"delivery":{"keys":{"accessKeyId":"APP_S3_ACCESS_KEY","bucket":"APP_S3_BUCKET","endpoint":"APP_S3_ENDPOINT","region":"APP_S3_REGION","secretAccessKey":"APP_S3_SECRET_KEY"},"type":"launcher-environment"},"id":"object-data","kind":"objectStorage","reclaimPolicy":"retain","storageClass":"backupCapacity"},"storageClass":{"kind":"objectStorage","purpose":"backup","required":{"backup":true,"durability":"persistent","performanceTier":"capacity"}}},"workloadGeneration":8}',
157
+ sha256: '7682ed6f8c8b64d4c677ea91c04e4261bfe5326a3fb905d5da093f51e4b2dbbe',
217
158
  },
218
159
  candidateBinding: {
219
160
  input: candidateBinding,
220
- canonicalJson:
221
- '{"accessMode":"readWrite","capabilities":{"backup":true,' +
222
- '"durability":"persistent","encryptedInTransit":true,"hardQuota":true,' +
223
- '"performanceTier":"capacity","snapshots":"none","topology":"singleNode"},' +
224
- '"capacity":{"granted":"500GiB","limit":"1TiB","requested":"500GiB"},' +
225
- '"connection":{"bucket":"destination-bucket",' +
226
- '"endpoint":"https://destination.example.test","region":"local"},' +
227
- '"createdAt":1700000000000,"credentials":{"accessKeyIdKey":"object.accessKeyId",' +
228
- '"secretAccessKeyKey":"object.secretAccessKey","secretBundleId":"service-storage"},' +
229
- '"delivery":{"keys":{"accessKeyId":"APP_S3_ACCESS_KEY","bucket":"APP_S3_BUCKET",' +
230
- '"endpoint":"APP_S3_ENDPOINT","region":"APP_S3_REGION",' +
231
- '"secretAccessKey":"APP_S3_SECRET_KEY"},"type":"environment"},' +
232
- '"generation":4,"id":"binding-object","kind":"objectStorage",' +
233
- '"observedGeneration":3,"policy":{"classId":"capacity-object","revision":"4"},' +
234
- '"requestDigest":"2096dfa1f6db50d670cbb4d6436f38c2eec383435c99346e31d0d1a9e0b1beba",' +
235
- '"requestId":"object-data","resourceRef":"destination-resource",' +
236
- '"schemaVersion":1,"serviceId":"service-app","status":"provisioning",' +
237
- '"updatedAt":1700000000020,"versioning":false}',
238
- sha256:
239
- 'b49017f41cd86626ccb05ffa5fb591994a5e20fad9856182b1a1d4c964c6177c',
161
+ canonicalJson: '{"accessMode":"readWrite","capabilities":{"backup":true,"durability":"persistent","encryptedInTransit":true,"hardQuota":true,"performanceTier":"capacity","snapshots":"none","topology":"singleNode"},"capacity":{"granted":"500GiB","limit":"1TiB","requested":"500GiB"},"connection":{"bucket":"destination-bucket","endpoint":"https://destination.example.test","region":"local"},"createdAt":1700000000000,"credentialManagementScope":"platform:object-storage-binding","delivery":{"keys":{"accessKeyId":"APP_S3_ACCESS_KEY","bucket":"APP_S3_BUCKET","endpoint":"APP_S3_ENDPOINT","region":"APP_S3_REGION","secretAccessKey":"APP_S3_SECRET_KEY"},"type":"launcher-environment"},"generation":4,"id":"binding-object","kind":"objectStorage","observedGeneration":3,"policy":{"classId":"capacity-object","revision":"4"},"requestDigest":"3f864862041002e25b790b3bc7afbe37c399a006f385e1def9f679a93d4fa173","requestId":"object-data","resourceRef":"destination-resource","schemaVersion":2,"serviceId":"service-app","status":"provisioning","updatedAt":1700000000020,"versioning":false}',
162
+ sha256: '6e5c954466b600f81d1f19dcdd7ef426be99dc12ae33103e4d0c238e0070de71',
240
163
  },
241
164
  });