@serve.zone/interfaces 22.0.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 (75) hide show
  1. package/changelog.md +12 -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/deploymentoperation.js +6 -20
  6. package/dist_ts/data/deploymentpreflight.d.ts +2 -6
  7. package/dist_ts/data/deploymentpreflight.js +1 -1
  8. package/dist_ts/data/hostedapp.d.ts +40 -14
  9. package/dist_ts/data/hostedapp.js +90 -1
  10. package/dist_ts/data/immutableimage.d.ts +30 -1
  11. package/dist_ts/data/immutableimage.js +103 -1
  12. package/dist_ts/data/index.d.ts +0 -2
  13. package/dist_ts/data/index.js +1 -3
  14. package/dist_ts/data/secret.d.ts +186 -13
  15. package/dist_ts/data/secret.js +543 -45
  16. package/dist_ts/data/service.d.ts +0 -39
  17. package/dist_ts/data/service.js +1 -77
  18. package/dist_ts/data/settings.d.ts +62 -43
  19. package/dist_ts/data/settings.js +34 -2
  20. package/dist_ts/platform/storage.d.ts +13 -14
  21. package/dist_ts/platform/storage.js +1 -1
  22. package/dist_ts/platform/storagemigration.d.ts +8 -8
  23. package/dist_ts/platform/storagemigration.golden.d.ts +2 -2
  24. package/dist_ts/platform/storagemigration.golden.js +19 -88
  25. package/dist_ts/platform/storagemigration.js +46 -58
  26. package/dist_ts/platform/types.d.ts +5 -19
  27. package/dist_ts/plugins.d.ts +2 -1
  28. package/dist_ts/plugins.js +3 -2
  29. package/dist_ts/requests/hostedapp.d.ts +12 -9
  30. package/dist_ts/requests/hostedapp.js +38 -1
  31. package/dist_ts/requests/index.d.ts +1 -3
  32. package/dist_ts/requests/index.js +2 -4
  33. package/dist_ts/requests/platform.d.ts +0 -1
  34. package/dist_ts/requests/secret.d.ts +23 -17
  35. package/dist_ts/requests/secret.js +161 -2
  36. package/dist_ts/requests/service.d.ts +0 -13
  37. package/dist_ts/requests/settings.d.ts +3 -3
  38. package/dist_ts/runtime.d.ts +78 -26
  39. package/dist_ts/runtime.js +219 -19
  40. package/package.json +2 -1
  41. package/readme.md +106 -28
  42. package/ts/00_commitinfo_data.ts +1 -1
  43. package/ts/appstore/types.ts +251 -25
  44. package/ts/data/deploymentoperation.ts +7 -31
  45. package/ts/data/deploymentpreflight.ts +2 -5
  46. package/ts/data/hostedapp.ts +144 -18
  47. package/ts/data/immutableimage.ts +150 -1
  48. package/ts/data/index.ts +0 -2
  49. package/ts/data/secret.ts +775 -53
  50. package/ts/data/service.ts +0 -118
  51. package/ts/data/settings.ts +70 -80
  52. package/ts/platform/storage.ts +15 -16
  53. package/ts/platform/storagemigration.golden.ts +18 -95
  54. package/ts/platform/storagemigration.ts +57 -87
  55. package/ts/platform/types.ts +6 -19
  56. package/ts/plugins.ts +2 -0
  57. package/ts/requests/hostedapp.ts +50 -9
  58. package/ts/requests/index.ts +0 -4
  59. package/ts/requests/platform.ts +0 -1
  60. package/ts/requests/secret.ts +204 -9
  61. package/ts/requests/service.ts +0 -16
  62. package/ts/requests/settings.ts +3 -3
  63. package/ts/runtime.ts +314 -41
  64. package/dist_ts/data/secretbundle.d.ts +0 -57
  65. package/dist_ts/data/secretbundle.js +0 -2
  66. package/dist_ts/data/secretgroup.d.ts +0 -52
  67. package/dist_ts/data/secretgroup.js +0 -2
  68. package/dist_ts/requests/secretbundle.d.ts +0 -75
  69. package/dist_ts/requests/secretbundle.js +0 -4
  70. package/dist_ts/requests/secretgroup.d.ts +0 -52
  71. package/dist_ts/requests/secretgroup.js +0 -4
  72. package/ts/data/secretbundle.ts +0 -65
  73. package/ts/data/secretgroup.ts +0 -58
  74. package/ts/requests/secretbundle.ts +0 -103
  75. package/ts/requests/secretgroup.ts +0 -74
@@ -67,7 +67,31 @@ export interface ICoreflowRuntimeCapabilities {
67
67
  /** Coreflow can answer the versioned, node-scoped Corestore inventory probe. */
68
68
  corestoreInventoryVersion?: 1;
69
69
  /** Coreflow can consume exact, cluster-scoped resolved secret manifests. */
70
- secretManifestVersion?: 1;
70
+ secretManifestVersion: 2;
71
+ sealedSecretMaterialVersion: 1;
72
+ secretRecipientEnrollmentVersion: 1;
73
+ workloadInitEnvironmentVersion: 1;
74
+ }
75
+
76
+ export type TImmutableContainerPlatform = 'linux/amd64' | 'linux/arm64';
77
+
78
+ export interface IImmutableContainerInvocationPlatformEvidenceV1 {
79
+ platform: TImmutableContainerPlatform;
80
+ platformManifestDigest: TSha256Digest;
81
+ imageConfigDigest: TSha256Digest;
82
+ /** Effective non-empty OCI argv after applying the deployment containerArgs. */
83
+ effectiveArgv: string[];
84
+ }
85
+
86
+ export interface IImmutableContainerInvocationV1 {
87
+ schemaVersion: 1;
88
+ /** Sorted, unique, non-empty and limited to the authoritative platform union. */
89
+ targetPlatforms: TImmutableContainerPlatform[];
90
+ /** The one effective argv shared by every target platform. */
91
+ argv: string[];
92
+ /** Sorted exact one-to-one platform evidence. */
93
+ evidence: IImmutableContainerInvocationPlatformEvidenceV1[];
94
+ digest: TSha256Digest;
71
95
  }
72
96
 
73
97
  /**
@@ -221,6 +245,8 @@ export interface IImmutableImageDeploymentPlan {
221
245
  requestedDigest: TSha256Digest;
222
246
  digestPinnedImageReference: string;
223
247
  manifestMediaType: TOciManifestMediaType;
248
+ /** Mandatory immutable command/config evidence for every target platform. */
249
+ containerInvocation: IImmutableContainerInvocationV1;
224
250
  createdAt: number;
225
251
  mode: TImmutableImageRolloutMode;
226
252
  /** Full pre-adoption service configuration fence, required only for adoption. */
@@ -324,6 +350,122 @@ export interface IImageRolloutStatus {
324
350
 
325
351
  const sha256DigestRegex = /^sha256:[a-f0-9]{64}$/;
326
352
 
353
+ const immutableContainerPlatforms = new Set<TImmutableContainerPlatform>([
354
+ 'linux/amd64',
355
+ 'linux/arm64',
356
+ ]);
357
+
358
+ const validateImmutableArgv = (argvArg: unknown): argvArg is string[] => (
359
+ Array.isArray(argvArg)
360
+ && argvArg.length > 0
361
+ && argvArg.length <= 128
362
+ && argvArg.every((argumentArg) => typeof argumentArg === 'string'
363
+ && argumentArg.length > 0
364
+ && !/[\u0000-\u001f\u007f]/.test(argumentArg)
365
+ && new TextEncoder().encode(argumentArg).byteLength <= 4096)
366
+ );
367
+
368
+ export const createImmutableContainerInvocationDigestInput = (
369
+ invocationArg: Omit<IImmutableContainerInvocationV1, 'digest'> | IImmutableContainerInvocationV1,
370
+ ): string => JSON.stringify({
371
+ schemaVersion: invocationArg.schemaVersion,
372
+ targetPlatforms: invocationArg.targetPlatforms,
373
+ argv: invocationArg.argv,
374
+ evidence: invocationArg.evidence.map((entryArg) => ({
375
+ platform: entryArg.platform,
376
+ platformManifestDigest: entryArg.platformManifestDigest,
377
+ imageConfigDigest: entryArg.imageConfigDigest,
378
+ effectiveArgv: entryArg.effectiveArgv,
379
+ })),
380
+ });
381
+
382
+ export const computeImmutableContainerInvocationDigest = async (
383
+ invocationArg: Omit<IImmutableContainerInvocationV1, 'digest'> | IImmutableContainerInvocationV1,
384
+ ): Promise<TSha256Digest> => {
385
+ const input = new TextEncoder().encode(createImmutableContainerInvocationDigestInput(invocationArg));
386
+ const digest = new Uint8Array(await globalThis.crypto.subtle.digest(
387
+ 'SHA-256',
388
+ input.buffer as ArrayBuffer,
389
+ ));
390
+ return `sha256:${[...digest]
391
+ .map((byteArg) => byteArg.toString(16).padStart(2, '0'))
392
+ .join('')}` as TSha256Digest;
393
+ };
394
+
395
+ export const verifyImmutableContainerInvocationDigest = async (
396
+ invocationArg: IImmutableContainerInvocationV1,
397
+ ): Promise<boolean> => invocationArg.digest
398
+ === await computeImmutableContainerInvocationDigest(invocationArg);
399
+
400
+ export const validateImmutableContainerInvocation = (
401
+ invocationArg: unknown,
402
+ ): string[] => {
403
+ if (!invocationArg || typeof invocationArg !== 'object' || Array.isArray(invocationArg)) {
404
+ return ['containerInvocation must be an object'];
405
+ }
406
+ const invocation = invocationArg as Record<string, unknown>;
407
+ const errors: string[] = [];
408
+ if (JSON.stringify(Object.keys(invocation).sort()) !== JSON.stringify([
409
+ 'argv',
410
+ 'digest',
411
+ 'evidence',
412
+ 'schemaVersion',
413
+ 'targetPlatforms',
414
+ ])) {
415
+ errors.push('containerInvocation must use its exact schema');
416
+ }
417
+ if (invocation.schemaVersion !== 1) errors.push('containerInvocation schemaVersion must be 1');
418
+ const platforms = Array.isArray(invocation.targetPlatforms)
419
+ ? invocation.targetPlatforms
420
+ : [];
421
+ if (platforms.length === 0
422
+ || platforms.some((platformArg) => typeof platformArg !== 'string'
423
+ || !immutableContainerPlatforms.has(platformArg as TImmutableContainerPlatform))
424
+ || new Set(platforms).size !== platforms.length
425
+ || JSON.stringify(platforms) !== JSON.stringify([...platforms].sort())) {
426
+ errors.push('containerInvocation targetPlatforms must be sorted unique supported platforms');
427
+ }
428
+ if (!validateImmutableArgv(invocation.argv)) {
429
+ errors.push('containerInvocation argv must be a non-empty canonical argument vector');
430
+ }
431
+ const evidence = Array.isArray(invocation.evidence) ? invocation.evidence : [];
432
+ const evidencePlatforms: unknown[] = [];
433
+ for (const [index, entryArg] of evidence.entries()) {
434
+ if (!entryArg || typeof entryArg !== 'object' || Array.isArray(entryArg)) {
435
+ errors.push(`containerInvocation evidence[${index}] must be an object`);
436
+ continue;
437
+ }
438
+ const entry = entryArg as Record<string, unknown>;
439
+ if (JSON.stringify(Object.keys(entry).sort()) !== JSON.stringify([
440
+ 'effectiveArgv',
441
+ 'imageConfigDigest',
442
+ 'platform',
443
+ 'platformManifestDigest',
444
+ ])) {
445
+ errors.push(`containerInvocation evidence[${index}] must use its exact schema`);
446
+ }
447
+ evidencePlatforms.push(entry.platform);
448
+ if (!immutableContainerPlatforms.has(entry.platform as TImmutableContainerPlatform)) {
449
+ errors.push(`containerInvocation evidence[${index}].platform is unsupported`);
450
+ }
451
+ if (!isSha256Digest(entry.platformManifestDigest as string)
452
+ || !isSha256Digest(entry.imageConfigDigest as string)) {
453
+ errors.push(`containerInvocation evidence[${index}] digests must be canonical`);
454
+ }
455
+ if (!validateImmutableArgv(entry.effectiveArgv)
456
+ || JSON.stringify(entry.effectiveArgv) !== JSON.stringify(invocation.argv)) {
457
+ errors.push(`containerInvocation evidence[${index}] effective argv must match`);
458
+ }
459
+ }
460
+ if (JSON.stringify(evidencePlatforms) !== JSON.stringify(platforms)) {
461
+ errors.push('containerInvocation evidence must exactly cover targetPlatforms in order');
462
+ }
463
+ if (typeof invocation.digest !== 'string' || !isSha256Digest(invocation.digest)) {
464
+ errors.push('containerInvocation digest must be canonical');
465
+ }
466
+ return errors;
467
+ };
468
+
327
469
  export const normalizeSha256Digest = (digest: unknown): TSha256Digest | undefined => {
328
470
  if (typeof digest !== 'string') return undefined;
329
471
  const normalizedDigest = digest.trim().toLowerCase();
@@ -396,6 +538,7 @@ export const validateImmutableImageDeploymentPlan = (
396
538
  ].includes(planArg.manifestMediaType)) {
397
539
  errors.push('immutable rollout root must be an OCI image index');
398
540
  }
541
+ errors.push(...validateImmutableContainerInvocation(planArg.containerInvocation));
399
542
  let expectedReference: string | undefined;
400
543
  try {
401
544
  expectedReference = buildDigestPinnedImageReference(
@@ -443,6 +586,12 @@ export const validateImmutableImageDeploymentPlan = (
443
586
  return errors;
444
587
  };
445
588
 
589
+ /** Coreflow uses this async verifier before resolving or opening secret material. */
590
+ export const verifyImmutableImageDeploymentPlan = async (
591
+ planArg: IImmutableImageDeploymentPlan,
592
+ ): Promise<boolean> => validateImmutableImageDeploymentPlan(planArg).length === 0
593
+ && await verifyImmutableContainerInvocationDigest(planArg.containerInvocation);
594
+
446
595
  export const validateImageRolloutStatus = (statusArg: IImageRolloutStatus): string[] => {
447
596
  const errors: string[] = [];
448
597
  if (!isImmutableIdentifier(statusArg.rolloutId)) {
package/ts/data/index.ts CHANGED
@@ -22,8 +22,6 @@ export * from './isolatedrestore.golden.js';
22
22
  export * from './mail.js';
23
23
  export * from './registry.js';
24
24
  export * from './secret.js';
25
- export * from './secretbundle.js';
26
- export * from './secretgroup.js';
27
25
  export * from './baremetal.js';
28
26
  export * from './baseos.js';
29
27
  export * from './backup.js';