@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.
- package/changelog.md +12 -0
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/appstore/types.d.ts +31 -16
- package/dist_ts/appstore/types.js +208 -11
- package/dist_ts/data/deploymentoperation.js +6 -20
- package/dist_ts/data/deploymentpreflight.d.ts +2 -6
- package/dist_ts/data/deploymentpreflight.js +1 -1
- package/dist_ts/data/hostedapp.d.ts +40 -14
- package/dist_ts/data/hostedapp.js +90 -1
- package/dist_ts/data/immutableimage.d.ts +30 -1
- package/dist_ts/data/immutableimage.js +103 -1
- package/dist_ts/data/index.d.ts +0 -2
- package/dist_ts/data/index.js +1 -3
- package/dist_ts/data/secret.d.ts +186 -13
- package/dist_ts/data/secret.js +543 -45
- package/dist_ts/data/service.d.ts +0 -39
- package/dist_ts/data/service.js +1 -77
- package/dist_ts/data/settings.d.ts +62 -43
- package/dist_ts/data/settings.js +34 -2
- package/dist_ts/platform/storage.d.ts +13 -14
- package/dist_ts/platform/storage.js +1 -1
- package/dist_ts/platform/storagemigration.d.ts +8 -8
- package/dist_ts/platform/storagemigration.golden.d.ts +2 -2
- package/dist_ts/platform/storagemigration.golden.js +19 -88
- package/dist_ts/platform/storagemigration.js +46 -58
- package/dist_ts/platform/types.d.ts +5 -19
- package/dist_ts/plugins.d.ts +2 -1
- package/dist_ts/plugins.js +3 -2
- package/dist_ts/requests/hostedapp.d.ts +12 -9
- package/dist_ts/requests/hostedapp.js +38 -1
- package/dist_ts/requests/index.d.ts +1 -3
- package/dist_ts/requests/index.js +2 -4
- package/dist_ts/requests/platform.d.ts +0 -1
- package/dist_ts/requests/secret.d.ts +23 -17
- package/dist_ts/requests/secret.js +161 -2
- package/dist_ts/requests/service.d.ts +0 -13
- package/dist_ts/requests/settings.d.ts +3 -3
- package/dist_ts/runtime.d.ts +78 -26
- package/dist_ts/runtime.js +219 -19
- package/package.json +2 -1
- package/readme.md +106 -28
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/appstore/types.ts +251 -25
- package/ts/data/deploymentoperation.ts +7 -31
- package/ts/data/deploymentpreflight.ts +2 -5
- package/ts/data/hostedapp.ts +144 -18
- package/ts/data/immutableimage.ts +150 -1
- package/ts/data/index.ts +0 -2
- package/ts/data/secret.ts +775 -53
- package/ts/data/service.ts +0 -118
- package/ts/data/settings.ts +70 -80
- package/ts/platform/storage.ts +15 -16
- package/ts/platform/storagemigration.golden.ts +18 -95
- package/ts/platform/storagemigration.ts +57 -87
- package/ts/platform/types.ts +6 -19
- package/ts/plugins.ts +2 -0
- package/ts/requests/hostedapp.ts +50 -9
- package/ts/requests/index.ts +0 -4
- package/ts/requests/platform.ts +0 -1
- package/ts/requests/secret.ts +204 -9
- package/ts/requests/service.ts +0 -16
- package/ts/requests/settings.ts +3 -3
- package/ts/runtime.ts +314 -41
- package/dist_ts/data/secretbundle.d.ts +0 -57
- package/dist_ts/data/secretbundle.js +0 -2
- package/dist_ts/data/secretgroup.d.ts +0 -52
- package/dist_ts/data/secretgroup.js +0 -2
- package/dist_ts/requests/secretbundle.d.ts +0 -75
- package/dist_ts/requests/secretbundle.js +0 -4
- package/dist_ts/requests/secretgroup.d.ts +0 -52
- package/dist_ts/requests/secretgroup.js +0 -4
- package/ts/data/secretbundle.ts +0 -65
- package/ts/data/secretgroup.ts +0 -58
- package/ts/requests/secretbundle.ts +0 -103
- package/ts/requests/secretgroup.ts +0 -74
package/dist_ts/runtime.d.ts
CHANGED
|
@@ -1,41 +1,93 @@
|
|
|
1
|
-
import
|
|
2
|
-
import type { IIdentityCredential, IResolvedSecretManifest, TSha256Digest } from './data/index.js';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
* and is intentionally unreachable from the universal/browser-facing barrel.
|
|
6
|
-
*/
|
|
7
|
-
export interface IResolvedSecretMaterialValue {
|
|
1
|
+
import * as plugins from './plugins.js';
|
|
2
|
+
import type { IIdentityCredential, IResolvedSecretManifest, TSha256Digest, TSecretRecipientMetadata } from './data/index.js';
|
|
3
|
+
import { validateSecretRecipientMetadata } from './data/secret.js';
|
|
4
|
+
export interface ISealedResolvedSecretMaterialEntry {
|
|
8
5
|
secretVersionId: string;
|
|
9
|
-
|
|
6
|
+
envelope: plugins.smartcrypto.IX25519EnvelopeV1;
|
|
10
7
|
}
|
|
11
|
-
|
|
8
|
+
/** Runtime-only material. No plaintext value is represented in this DTO. */
|
|
9
|
+
export interface ISealedResolvedSecretMaterial {
|
|
12
10
|
schemaVersion: 1;
|
|
13
|
-
/** Full value-free manifest
|
|
11
|
+
/** Full schema-v2 value-free manifest used for digest and rollout verification. */
|
|
14
12
|
manifest: IResolvedSecretManifest;
|
|
15
|
-
/**
|
|
16
|
-
|
|
13
|
+
/** Sorted exact coverage of the manifest's pinned versions. */
|
|
14
|
+
entries: ISealedResolvedSecretMaterialEntry[];
|
|
15
|
+
}
|
|
16
|
+
export interface ISecretMaterialRequestFence {
|
|
17
|
+
serviceId: string;
|
|
18
|
+
imageRolloutId: string;
|
|
19
|
+
imageRolloutGeneration: number;
|
|
20
|
+
requestedImageDigest: TSha256Digest;
|
|
21
|
+
secretRolloutId: string;
|
|
22
|
+
secretRolloutGeneration: number;
|
|
23
|
+
manifestId: string;
|
|
24
|
+
manifestDigest: TSha256Digest;
|
|
25
|
+
expectedRecipientKeyId: string;
|
|
26
|
+
}
|
|
27
|
+
/** Request fence plus trusted local scope derived from the verified cluster identity. */
|
|
28
|
+
export interface ISecretMaterialExpectation extends ISecretMaterialRequestFence {
|
|
29
|
+
organizationId: string;
|
|
30
|
+
clusterId: string;
|
|
17
31
|
}
|
|
18
32
|
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*/
|
|
23
|
-
export declare const verifyResolvedSecretMaterial: (materialArg: unknown) => Promise<boolean>;
|
|
24
|
-
/**
|
|
25
|
-
* Cluster and organization are derived from the verified JWT. A caller cannot
|
|
26
|
-
* select either scope through request fields.
|
|
33
|
+
* Parses every envelope with SmartCrypto, verifies its bound context digest,
|
|
34
|
+
* and checks sorted exact version coverage. It never receives a private key
|
|
35
|
+
* and never decrypts material.
|
|
27
36
|
*/
|
|
37
|
+
export declare const verifySealedResolvedSecretMaterial: (materialArg: unknown, expectedArg: ISecretMaterialExpectation) => Promise<boolean>;
|
|
38
|
+
/** Organization and cluster are derived exclusively from the verified cluster JWT. */
|
|
28
39
|
export interface IReq_GetResolvedSecretMaterial extends plugins.typedrequestInterfaces.implementsTR<plugins.typedrequestInterfaces.ITypedRequest, IReq_GetResolvedSecretMaterial> {
|
|
29
40
|
method: 'getResolvedSecretMaterial';
|
|
41
|
+
request: ISecretMaterialRequestFence & {
|
|
42
|
+
identity: IIdentityCredential;
|
|
43
|
+
};
|
|
44
|
+
response: {
|
|
45
|
+
material: ISealedResolvedSecretMaterial;
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
export interface ISecretRecipientEnrollmentChallengeV1 {
|
|
49
|
+
schemaVersion: 1;
|
|
50
|
+
enrollmentId: string;
|
|
51
|
+
clusterId: string;
|
|
52
|
+
recipientKeyId: string;
|
|
53
|
+
publicKey: string;
|
|
54
|
+
generation: number;
|
|
55
|
+
expiresAt: number;
|
|
56
|
+
/** Sealed random 32-byte challenge; plaintext is never persisted or returned. */
|
|
57
|
+
envelope: plugins.smartcrypto.IX25519EnvelopeV1;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Cluster scope is derived from the JWT. The server persists only a one-time
|
|
61
|
+
* challenge hash plus expiry and consumes it with generation CAS; reuse,
|
|
62
|
+
* expiry, mismatch, and replay are rejected. Private keys and challenge
|
|
63
|
+
* plaintext have no persistence DTO.
|
|
64
|
+
*/
|
|
65
|
+
export interface IReq_BeginSecretRecipientEnrollment extends plugins.typedrequestInterfaces.implementsTR<plugins.typedrequestInterfaces.ITypedRequest, IReq_BeginSecretRecipientEnrollment> {
|
|
66
|
+
method: 'beginSecretRecipientEnrollment';
|
|
67
|
+
request: {
|
|
68
|
+
identity: IIdentityCredential;
|
|
69
|
+
proposedRecipientKeyId: string;
|
|
70
|
+
proposedPublicKey: string;
|
|
71
|
+
expectedGeneration: number;
|
|
72
|
+
};
|
|
73
|
+
response: {
|
|
74
|
+
challenge: ISecretRecipientEnrollmentChallengeV1;
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
export interface IReq_CompleteSecretRecipientEnrollment extends plugins.typedrequestInterfaces.implementsTR<plugins.typedrequestInterfaces.ITypedRequest, IReq_CompleteSecretRecipientEnrollment> {
|
|
78
|
+
method: 'completeSecretRecipientEnrollment';
|
|
30
79
|
request: {
|
|
31
80
|
identity: IIdentityCredential;
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
manifestDigest: TSha256Digest;
|
|
81
|
+
enrollmentId: string;
|
|
82
|
+
expectedGeneration: number;
|
|
83
|
+
/** Canonical unpadded base64url response containing exactly 32 bytes. */
|
|
84
|
+
response: string;
|
|
37
85
|
};
|
|
38
86
|
response: {
|
|
39
|
-
|
|
87
|
+
recipient: TSecretRecipientMetadata;
|
|
40
88
|
};
|
|
41
89
|
}
|
|
90
|
+
export declare const validateBeginSecretRecipientEnrollmentRequest: (requestArg: unknown) => string[];
|
|
91
|
+
export declare const validateSecretRecipientEnrollmentChallenge: (challengeArg: unknown) => Promise<string[]>;
|
|
92
|
+
export declare const validateCompleteSecretRecipientEnrollmentRequest: (requestArg: unknown) => string[];
|
|
93
|
+
export { validateSecretRecipientMetadata };
|
package/dist_ts/runtime.js
CHANGED
|
@@ -1,33 +1,233 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as plugins from './plugins.js';
|
|
2
|
+
import { createResolvedSecretMaterialEnvelopeContext, createSecretRecipientEnrollmentChallengeContext, validateResolvedSecretManifest, validateSecretRecipientMetadata, verifySecretEnvelopeContext, verifyResolvedSecretManifestDigest, } from './data/secret.js';
|
|
2
3
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Parses every envelope with SmartCrypto, verifies its bound context digest,
|
|
5
|
+
* and checks sorted exact version coverage. It never receives a private key
|
|
6
|
+
* and never decrypts material.
|
|
6
7
|
*/
|
|
7
|
-
export const
|
|
8
|
+
export const verifySealedResolvedSecretMaterial = async (materialArg, expectedArg) => {
|
|
8
9
|
if (!materialArg || typeof materialArg !== 'object' || Array.isArray(materialArg))
|
|
9
10
|
return false;
|
|
10
11
|
const material = materialArg;
|
|
11
|
-
if (
|
|
12
|
+
if (JSON.stringify(Object.keys(material).sort()) !== JSON.stringify([
|
|
13
|
+
'entries',
|
|
14
|
+
'manifest',
|
|
15
|
+
'schemaVersion',
|
|
16
|
+
])) {
|
|
12
17
|
return false;
|
|
13
|
-
|
|
18
|
+
}
|
|
19
|
+
if (material.schemaVersion !== 1 || !material.manifest || !Array.isArray(material.entries)) {
|
|
14
20
|
return false;
|
|
15
|
-
|
|
21
|
+
}
|
|
22
|
+
if (validateResolvedSecretManifest(material.manifest).length > 0
|
|
23
|
+
|| !await verifyResolvedSecretManifestDigest(material.manifest)) {
|
|
16
24
|
return false;
|
|
17
|
-
|
|
25
|
+
}
|
|
26
|
+
if (material.manifest.organizationId !== expectedArg.organizationId
|
|
27
|
+
|| material.manifest.clusterId !== expectedArg.clusterId
|
|
28
|
+
|| material.manifest.serviceId !== expectedArg.serviceId
|
|
29
|
+
|| material.manifest.imageRolloutId !== expectedArg.imageRolloutId
|
|
30
|
+
|| material.manifest.imageRolloutGeneration !== expectedArg.imageRolloutGeneration
|
|
31
|
+
|| material.manifest.requestedImageDigest !== expectedArg.requestedImageDigest
|
|
32
|
+
|| material.manifest.secretRolloutId !== expectedArg.secretRolloutId
|
|
33
|
+
|| material.manifest.secretRolloutGeneration !== expectedArg.secretRolloutGeneration
|
|
34
|
+
|| material.manifest.id !== expectedArg.manifestId
|
|
35
|
+
|| material.manifest.digest !== expectedArg.manifestDigest) {
|
|
18
36
|
return false;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
&& typeof valueArg.value === 'string')))
|
|
37
|
+
}
|
|
38
|
+
if (material.entries.length > 256
|
|
39
|
+
|| material.entries.length !== material.manifest.entries.length) {
|
|
23
40
|
return false;
|
|
41
|
+
}
|
|
24
42
|
const expectedVersionIds = material.manifest.entries
|
|
25
43
|
.map((entryArg) => entryArg.secretVersionId)
|
|
26
44
|
.sort();
|
|
27
|
-
const actualVersionIds = material.
|
|
28
|
-
|
|
29
|
-
.
|
|
30
|
-
|
|
31
|
-
|
|
45
|
+
const actualVersionIds = material.entries.map((entryArg) => entryArg.secretVersionId);
|
|
46
|
+
if (new Set(actualVersionIds).size !== actualVersionIds.length
|
|
47
|
+
|| JSON.stringify(actualVersionIds) !== JSON.stringify(expectedVersionIds)) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
const manifestEntriesByVersion = new Map(material.manifest.entries.map((entryArg) => [
|
|
51
|
+
entryArg.secretVersionId,
|
|
52
|
+
entryArg,
|
|
53
|
+
]));
|
|
54
|
+
for (const entry of material.entries) {
|
|
55
|
+
if (!entry || typeof entry !== 'object' || typeof entry.secretVersionId !== 'string')
|
|
56
|
+
return false;
|
|
57
|
+
if (JSON.stringify(Object.keys(entry).sort()) !== JSON.stringify([
|
|
58
|
+
'envelope',
|
|
59
|
+
'secretVersionId',
|
|
60
|
+
])) {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
const manifestEntry = manifestEntriesByVersion.get(entry.secretVersionId);
|
|
64
|
+
if (!manifestEntry)
|
|
65
|
+
return false;
|
|
66
|
+
let envelope;
|
|
67
|
+
try {
|
|
68
|
+
envelope = plugins.smartcrypto.parseX25519Envelope(entry.envelope);
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
if (envelope.recipientKeyId !== expectedArg.expectedRecipientKeyId)
|
|
74
|
+
return false;
|
|
75
|
+
const context = createResolvedSecretMaterialEnvelopeContext({
|
|
76
|
+
recipientKeyId: expectedArg.expectedRecipientKeyId,
|
|
77
|
+
organizationId: material.manifest.organizationId,
|
|
78
|
+
clusterId: material.manifest.clusterId,
|
|
79
|
+
serviceId: material.manifest.serviceId,
|
|
80
|
+
imageRolloutId: material.manifest.imageRolloutId,
|
|
81
|
+
imageRolloutGeneration: material.manifest.imageRolloutGeneration,
|
|
82
|
+
requestedImageDigest: material.manifest.requestedImageDigest,
|
|
83
|
+
secretRolloutId: material.manifest.secretRolloutId,
|
|
84
|
+
secretRolloutGeneration: material.manifest.secretRolloutGeneration,
|
|
85
|
+
manifestId: material.manifest.id,
|
|
86
|
+
manifestDigest: material.manifest.digest,
|
|
87
|
+
secretId: manifestEntry.secretId,
|
|
88
|
+
secretVersionId: manifestEntry.secretVersionId,
|
|
89
|
+
});
|
|
90
|
+
if (!await verifySecretEnvelopeContext(envelope, context))
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
return true;
|
|
94
|
+
};
|
|
95
|
+
const canonicalIdentifierRegex = /^[A-Za-z0-9][A-Za-z0-9:._-]{0,199}$/;
|
|
96
|
+
const raw32ByteBase64UrlRegex = /^[A-Za-z0-9_-]{42}[AEIMQUYcgkosw048]$/;
|
|
97
|
+
export const validateBeginSecretRecipientEnrollmentRequest = (requestArg) => {
|
|
98
|
+
if (!requestArg || typeof requestArg !== 'object' || Array.isArray(requestArg)) {
|
|
99
|
+
return ['enrollment request must be an object'];
|
|
100
|
+
}
|
|
101
|
+
const request = requestArg;
|
|
102
|
+
const errors = [];
|
|
103
|
+
if (JSON.stringify(Object.keys(request).sort()) !== JSON.stringify([
|
|
104
|
+
'expectedGeneration',
|
|
105
|
+
'identity',
|
|
106
|
+
'proposedPublicKey',
|
|
107
|
+
'proposedRecipientKeyId',
|
|
108
|
+
])) {
|
|
109
|
+
errors.push('enrollment request must use its exact schema');
|
|
110
|
+
}
|
|
111
|
+
if (!request.identity || typeof request.identity !== 'object'
|
|
112
|
+
|| typeof request.identity.jwt !== 'string') {
|
|
113
|
+
errors.push('enrollment identity must be a JWT credential');
|
|
114
|
+
}
|
|
115
|
+
if (typeof request.proposedRecipientKeyId !== 'string'
|
|
116
|
+
|| !canonicalIdentifierRegex.test(request.proposedRecipientKeyId)) {
|
|
117
|
+
errors.push('proposed recipient key id must be canonical');
|
|
118
|
+
}
|
|
119
|
+
if (typeof request.proposedPublicKey !== 'string'
|
|
120
|
+
|| !raw32ByteBase64UrlRegex.test(request.proposedPublicKey)) {
|
|
121
|
+
errors.push('proposed public key must be canonical base64url raw X25519 material');
|
|
122
|
+
}
|
|
123
|
+
if (!Number.isSafeInteger(request.expectedGeneration)
|
|
124
|
+
|| request.expectedGeneration < 0) {
|
|
125
|
+
errors.push('expected generation must be a non-negative integer');
|
|
126
|
+
}
|
|
127
|
+
if ('clusterId' in request || 'organizationId' in request) {
|
|
128
|
+
errors.push('enrollment request must not select cluster or organization scope');
|
|
129
|
+
}
|
|
130
|
+
return errors;
|
|
131
|
+
};
|
|
132
|
+
export const validateSecretRecipientEnrollmentChallenge = async (challengeArg) => {
|
|
133
|
+
if (!challengeArg || typeof challengeArg !== 'object' || Array.isArray(challengeArg)) {
|
|
134
|
+
return ['enrollment challenge must be an object'];
|
|
135
|
+
}
|
|
136
|
+
const challenge = challengeArg;
|
|
137
|
+
const errors = [];
|
|
138
|
+
if (JSON.stringify(Object.keys(challenge).sort()) !== JSON.stringify([
|
|
139
|
+
'clusterId',
|
|
140
|
+
'enrollmentId',
|
|
141
|
+
'envelope',
|
|
142
|
+
'expiresAt',
|
|
143
|
+
'generation',
|
|
144
|
+
'publicKey',
|
|
145
|
+
'recipientKeyId',
|
|
146
|
+
'schemaVersion',
|
|
147
|
+
])) {
|
|
148
|
+
errors.push('enrollment challenge must use its exact schema');
|
|
149
|
+
}
|
|
150
|
+
for (const field of ['enrollmentId', 'clusterId', 'recipientKeyId']) {
|
|
151
|
+
if (typeof challenge[field] !== 'string'
|
|
152
|
+
|| !canonicalIdentifierRegex.test(challenge[field])) {
|
|
153
|
+
errors.push(`enrollment challenge ${field} must be canonical`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
if (challenge.schemaVersion !== 1)
|
|
157
|
+
errors.push('enrollment challenge schemaVersion must be 1');
|
|
158
|
+
if (typeof challenge.publicKey !== 'string'
|
|
159
|
+
|| !raw32ByteBase64UrlRegex.test(challenge.publicKey)) {
|
|
160
|
+
errors.push('enrollment challenge public key must be canonical');
|
|
161
|
+
}
|
|
162
|
+
if (!Number.isSafeInteger(challenge.generation) || challenge.generation < 1) {
|
|
163
|
+
errors.push('enrollment challenge generation must be positive');
|
|
164
|
+
}
|
|
165
|
+
if (!Number.isSafeInteger(challenge.expiresAt) || challenge.expiresAt < 1) {
|
|
166
|
+
errors.push('enrollment challenge expiry must be positive');
|
|
167
|
+
}
|
|
168
|
+
let envelope;
|
|
169
|
+
try {
|
|
170
|
+
envelope = plugins.smartcrypto.parseX25519Envelope(challenge.envelope);
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
errors.push('enrollment challenge envelope must be strict');
|
|
174
|
+
}
|
|
175
|
+
if (envelope) {
|
|
176
|
+
if (envelope.recipientKeyId !== challenge.recipientKeyId) {
|
|
177
|
+
errors.push('enrollment challenge recipient does not match');
|
|
178
|
+
}
|
|
179
|
+
if (!raw32ByteBase64UrlRegex.test(envelope.ciphertext)) {
|
|
180
|
+
errors.push('enrollment challenge ciphertext must contain exactly 32 bytes');
|
|
181
|
+
}
|
|
182
|
+
if (errors.length === 0) {
|
|
183
|
+
const context = createSecretRecipientEnrollmentChallengeContext({
|
|
184
|
+
enrollmentId: challenge.enrollmentId,
|
|
185
|
+
clusterId: challenge.clusterId,
|
|
186
|
+
recipientKeyId: challenge.recipientKeyId,
|
|
187
|
+
publicKey: challenge.publicKey,
|
|
188
|
+
generation: challenge.generation,
|
|
189
|
+
expiresAt: challenge.expiresAt,
|
|
190
|
+
});
|
|
191
|
+
if (!await verifySecretEnvelopeContext(envelope, context)) {
|
|
192
|
+
errors.push('enrollment challenge context does not match');
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return errors;
|
|
197
|
+
};
|
|
198
|
+
export const validateCompleteSecretRecipientEnrollmentRequest = (requestArg) => {
|
|
199
|
+
if (!requestArg || typeof requestArg !== 'object' || Array.isArray(requestArg)) {
|
|
200
|
+
return ['enrollment completion must be an object'];
|
|
201
|
+
}
|
|
202
|
+
const request = requestArg;
|
|
203
|
+
const errors = [];
|
|
204
|
+
if (JSON.stringify(Object.keys(request).sort()) !== JSON.stringify([
|
|
205
|
+
'enrollmentId',
|
|
206
|
+
'expectedGeneration',
|
|
207
|
+
'identity',
|
|
208
|
+
'response',
|
|
209
|
+
])) {
|
|
210
|
+
errors.push('enrollment completion must use its exact schema');
|
|
211
|
+
}
|
|
212
|
+
if (!request.identity || typeof request.identity !== 'object'
|
|
213
|
+
|| typeof request.identity.jwt !== 'string') {
|
|
214
|
+
errors.push('enrollment identity must be a JWT credential');
|
|
215
|
+
}
|
|
216
|
+
if (typeof request.enrollmentId !== 'string'
|
|
217
|
+
|| !canonicalIdentifierRegex.test(request.enrollmentId)) {
|
|
218
|
+
errors.push('enrollment id must be canonical');
|
|
219
|
+
}
|
|
220
|
+
if (!Number.isSafeInteger(request.expectedGeneration)
|
|
221
|
+
|| request.expectedGeneration < 0) {
|
|
222
|
+
errors.push('expected generation must be a non-negative integer');
|
|
223
|
+
}
|
|
224
|
+
if (typeof request.response !== 'string' || !raw32ByteBase64UrlRegex.test(request.response)) {
|
|
225
|
+
errors.push('enrollment response must be canonical base64url containing exactly 32 bytes');
|
|
226
|
+
}
|
|
227
|
+
if ('clusterId' in request || 'organizationId' in request) {
|
|
228
|
+
errors.push('enrollment completion must not select cluster or organization scope');
|
|
229
|
+
}
|
|
230
|
+
return errors;
|
|
32
231
|
};
|
|
33
|
-
|
|
232
|
+
export { validateSecretRecipientMetadata };
|
|
233
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVudGltZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3J1bnRpbWUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxjQUFjLENBQUM7QUFPeEMsT0FBTyxFQUNMLDJDQUEyQyxFQUMzQywrQ0FBK0MsRUFDL0MsOEJBQThCLEVBQzlCLCtCQUErQixFQUMvQiwyQkFBMkIsRUFDM0Isa0NBQWtDLEdBQ25DLE1BQU0sa0JBQWtCLENBQUM7QUFtQzFCOzs7O0dBSUc7QUFDSCxNQUFNLENBQUMsTUFBTSxrQ0FBa0MsR0FBRyxLQUFLLEVBQ3JELFdBQW9CLEVBQ3BCLFdBQXVDLEVBQ3JCLEVBQUU7SUFDcEIsSUFBSSxDQUFDLFdBQVcsSUFBSSxPQUFPLFdBQVcsS0FBSyxRQUFRLElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxXQUFXLENBQUM7UUFBRSxPQUFPLEtBQUssQ0FBQztJQUNoRyxNQUFNLFFBQVEsR0FBRyxXQUFxRCxDQUFDO0lBQ3ZFLElBQUksSUFBSSxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDLEtBQUssSUFBSSxDQUFDLFNBQVMsQ0FBQztRQUNsRSxTQUFTO1FBQ1QsVUFBVTtRQUNWLGVBQWU7S0FDaEIsQ0FBQyxFQUFFLENBQUM7UUFDSCxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFDRCxJQUFJLFFBQVEsQ0FBQyxhQUFhLEtBQUssQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLFFBQVEsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7UUFDM0YsT0FBTyxLQUFLLENBQUM7SUFDZixDQUFDO0lBQ0QsSUFBSSw4QkFBOEIsQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLENBQUMsTUFBTSxHQUFHLENBQUM7V0FDM0QsQ0FBQyxNQUFNLGtDQUFrQyxDQUFDLFFB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
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@serve.zone/interfaces",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "23.0.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Shared TypeScript interfaces and TypedRequest contracts for the serve.zone ecosystem.",
|
|
6
6
|
"exports": {
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
"license": "MIT",
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"@api.global/typedrequest-interfaces": "^4.0.0",
|
|
21
|
+
"@push.rocks/smartcrypto": "^2.2.0",
|
|
21
22
|
"@push.rocks/smartlog-interfaces": "^3.0.2",
|
|
22
23
|
"@tsclass/tsclass": "^9.5.1"
|
|
23
24
|
},
|
package/readme.md
CHANGED
|
@@ -30,6 +30,43 @@ import { appstore, data, platform, platformservice, requests } from '@serve.zone
|
|
|
30
30
|
|
|
31
31
|
This package intentionally has no service implementation logic. It is a stable vocabulary for services that need to agree on payload shape, method names, and response types.
|
|
32
32
|
|
|
33
|
+
## Secrets v23 Pre-Cutover Contract
|
|
34
|
+
|
|
35
|
+
Version 23 removes the old grouped/bundled secret DTOs and plaintext runtime
|
|
36
|
+
material API. Secret values enter Cloudly only as strict SmartCrypto X25519
|
|
37
|
+
envelopes or an explicit bounded server-generation request. Coreflow receives a
|
|
38
|
+
full digest-verified schema-v2 manifest plus one sealed envelope per pinned
|
|
39
|
+
SecretVersion through the Node-only runtime export.
|
|
40
|
+
|
|
41
|
+
This is a contract release before consumer cutover. It does **not** claim that
|
|
42
|
+
clean-v2 migration, backup verification, historical secret erasure, or storage
|
|
43
|
+
cleanup has completed. Those operations remain separately gated and must be
|
|
44
|
+
proven by their owning services before destructive cleanup.
|
|
45
|
+
|
|
46
|
+
Breaking removals include:
|
|
47
|
+
|
|
48
|
+
- The SecretGroup and SecretBundle data/request modules and request namespaces.
|
|
49
|
+
- `getServiceSecretBundlesAsFlatObject` and every service/preflight field tied
|
|
50
|
+
to bundled flattening or aggregate runtime files.
|
|
51
|
+
- Plaintext resolved runtime values, generic platform config/credential maps,
|
|
52
|
+
credential-bearing Cloudly settings, and serialized object-storage
|
|
53
|
+
credential references.
|
|
54
|
+
- Hosted-app control-token identities and credential-bearing bootstrap actions.
|
|
55
|
+
|
|
56
|
+
Primary v23 additions include:
|
|
57
|
+
|
|
58
|
+
- `TSecretValueInput`, `TSecretIngressRecipient`, the
|
|
59
|
+
`requests.secret.IReq_GetSecretIngressRecipient` contract with method
|
|
60
|
+
`getSecretIngressRecipient`, and fixed-order create/rotate/App Store context
|
|
61
|
+
builders.
|
|
62
|
+
- Schema-v2 `IResolvedSecretManifest` contracts, stable Docker resource naming,
|
|
63
|
+
WorkloadInit map/wrapper helpers, and `ISealedResolvedSecretMaterial` under
|
|
64
|
+
`@serve.zone/interfaces/runtime`.
|
|
65
|
+
- Two-step Coreflow X25519 recipient enrollment and exact recipient lifecycle
|
|
66
|
+
validators.
|
|
67
|
+
- Mandatory `IImmutableContainerInvocationV1` evidence on immutable image
|
|
68
|
+
deployment plans.
|
|
69
|
+
|
|
33
70
|
## Portable Storage Contracts
|
|
34
71
|
|
|
35
72
|
App Store templates can declare logical, template-local `storageClasses` and
|
|
@@ -82,18 +119,21 @@ const storageConfig: appstore.IAppStoreVersionConfig = {
|
|
|
82
119
|
capacity: { request: '100GiB', limit: '1TiB' },
|
|
83
120
|
reclaimPolicy: 'retain',
|
|
84
121
|
delivery: {
|
|
85
|
-
type: '
|
|
122
|
+
type: 'file',
|
|
86
123
|
targetPath: '/run/secrets/backup-archive.json',
|
|
87
124
|
format: 'servezone-object-storage-v1',
|
|
125
|
+
uid: 1000,
|
|
126
|
+
gid: 1000,
|
|
127
|
+
mode: 0o400,
|
|
88
128
|
},
|
|
89
129
|
protection: { versioning: 'required', retentionDays: 30 },
|
|
90
130
|
},
|
|
91
131
|
],
|
|
92
132
|
requiresFeatures: [
|
|
93
|
-
appstore.appStoreStorageFeatureIds.
|
|
133
|
+
appstore.appStoreStorageFeatureIds.bindingsV2,
|
|
94
134
|
appstore.appStoreStorageFeatureIds.filesystemV1,
|
|
95
|
-
appstore.appStoreStorageFeatureIds.
|
|
96
|
-
appstore.appStoreStorageFeatureIds.
|
|
135
|
+
appstore.appStoreStorageFeatureIds.objectStorageV2,
|
|
136
|
+
appstore.appStoreStorageFeatureIds.objectStorageFileV2,
|
|
97
137
|
],
|
|
98
138
|
};
|
|
99
139
|
```
|
|
@@ -104,13 +144,15 @@ express requirements and preferences only; Onebox and Cloudly map them to
|
|
|
104
144
|
operator policy independently.
|
|
105
145
|
|
|
106
146
|
An app may declare multiple `objectStorage` requests. Each request resolves to
|
|
107
|
-
its own endpoint, bucket, and credential
|
|
108
|
-
an explicit key map and
|
|
147
|
+
its own endpoint, bucket, and value-free credential management scope. Launcher
|
|
148
|
+
environment delivery uses an explicit key map and file delivery uses one
|
|
149
|
+
managed JSON Secret at a unique target path, so two
|
|
109
150
|
bindings cannot share credential destinations accidentally.
|
|
110
151
|
|
|
111
152
|
`platform.storage` contains separate capability advertisements and resolved
|
|
112
153
|
binding/status contracts. Resolved object-storage bindings expose connection
|
|
113
|
-
metadata plus credential
|
|
154
|
+
metadata plus a service-owned credential management scope and delivery policy,
|
|
155
|
+
never credential references or values. Filesystem
|
|
114
156
|
bindings expose the container mount and access mode, never a host path.
|
|
115
157
|
|
|
116
158
|
Portable manifests and resolved bindings intentionally have no fields for
|
|
@@ -310,14 +352,15 @@ Common data contracts include:
|
|
|
310
352
|
- `IDomain`, `IDnsEntry`, and traffic contracts for routing and DNS management.
|
|
311
353
|
- Traffic and gateway route contracts including `ICoretrafficPortRouteConfig`, routing `portRoutes`, and `IGatewayClientRoute` client-owned route views. Gateway route intent supports optional match `domains`, `transport`, and `remoteIngress`, plus explicit route `priority` and `managedRouteKind`. Ownership can combine `hostname` with `routeRef` so a normal route and a path-specific managed route for the same hostname reconcile independently.
|
|
312
354
|
- Value-free `ISecretMetadata`, `ISecretVersionMetadata`, and `ISecretSetMetadata`
|
|
313
|
-
contracts for operator views, plus exact-version
|
|
314
|
-
contracts for cluster delivery. Manifest helpers
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
355
|
+
contracts for operator views, plus schema-v2 exact-version
|
|
356
|
+
`IResolvedSecretManifest` contracts for cluster delivery. Manifest helpers
|
|
357
|
+
bind immutable image rollout and invocation evidence, enforce canonical
|
|
358
|
+
digests and globally unique launcher/file targets, and track per-cluster
|
|
359
|
+
desired/applied/previous-accepted rollout state. Platform-provider and system
|
|
360
|
+
owners are valid metadata owners but are rejected from workload manifests.
|
|
319
361
|
`listSecrets` exposes the dedicated `targetSecretsRevision` CAS fence;
|
|
320
|
-
|
|
362
|
+
every create, rotate, and lifecycle mutation consumes and returns that
|
|
363
|
+
aggregate owner fence, while
|
|
321
364
|
`setServiceSecretSetAttachments` returns the independent
|
|
322
365
|
`secretConfigurationRevision`. Generic service writes own neither revision.
|
|
323
366
|
- Mail gateway contracts for domain authorities, address bindings, WorkApp bindings, managed SMTP/API credentials, spool items, delivery journals, and inbound/outbound message payloads.
|
|
@@ -368,7 +411,7 @@ const config: appstore.IAppStoreVersionConfig = {
|
|
|
368
411
|
};
|
|
369
412
|
```
|
|
370
413
|
|
|
371
|
-
`redirectPath` is a canonical callback path on the app's HTTPS origin. Registration validation also requires that canonical app origin explicitly and rejects cross-origin, normalized, query-bearing, fragment-bearing, or duplicate callback URLs. The five environment values are environment-key names, not credentials embedded in the manifest. A host injects the generated client secret through
|
|
414
|
+
`redirectPath` is a canonical callback path on the app's HTTPS origin. Registration validation also requires that canonical app origin explicitly and rejects cross-origin, normalized, query-bearing, fragment-bearing, or duplicate callback URLs. The five environment values are environment-key names, not credentials embedded in the manifest. A host injects the generated client secret through launcher environment delivery and injects the other registration values only while OIDC is enabled.
|
|
372
415
|
|
|
373
416
|
`data.IHostedAppRoleAssignment` binds a stable user subject to an immutable `appInstanceId`. That same app instance is the OIDC `client_id`, the ID-token `aud`, and the `servezone_app_instance_id` claim. Tokens include only the assigned roles for that audience; `preferred_username` is display metadata and must not be treated as identity authority.
|
|
374
417
|
|
|
@@ -380,6 +423,16 @@ Validate untrusted manifests, registrations, and claims with:
|
|
|
380
423
|
- `appstore.validateAppStorePlatformOidcCapability`
|
|
381
424
|
- `appstore.validateAppStoreVersionPlatformOidc`
|
|
382
425
|
|
|
426
|
+
Hosted lifecycle RPCs accept only `IIdentityCredential`. After JWT
|
|
427
|
+
verification, handlers validate `IHostedAppMachineClaims` and derive the exact
|
|
428
|
+
app instance and service from `servezone_app_instance_id` and
|
|
429
|
+
`servezone_service_id`; callers cannot submit those selectors. Bootstrap
|
|
430
|
+
actions are either a canonical same-origin `setupRoute` path or a nonsecret
|
|
431
|
+
`message`. Control tokens, usernames, passwords, and token URLs are not part of
|
|
432
|
+
the lifecycle contract. Each server action carries a CAS revision; completion
|
|
433
|
+
requires its exact ID, current revision, and `ready` status so a delayed request
|
|
434
|
+
cannot complete a replacement action.
|
|
435
|
+
|
|
383
436
|
## TypedRequest Contracts
|
|
384
437
|
|
|
385
438
|
Use `requests` when registering handlers with `@api.global/typedrequest` or when creating typed requests through a TypedSocket client.
|
|
@@ -619,8 +672,6 @@ Request groups are exported by product area:
|
|
|
619
672
|
- `requests.platform`
|
|
620
673
|
- `requests.routing`
|
|
621
674
|
- `requests.secret`
|
|
622
|
-
- `requests.secretbundle`
|
|
623
|
-
- `requests.secretgroup`
|
|
624
675
|
- `requests.server`
|
|
625
676
|
- `requests.service`
|
|
626
677
|
- `requests.settings`
|
|
@@ -630,28 +681,53 @@ Request groups are exported by product area:
|
|
|
630
681
|
- `requests.webpush`
|
|
631
682
|
|
|
632
683
|
Secret material response contracts are not exported from the universal
|
|
633
|
-
browser-facing entrypoint.
|
|
684
|
+
browser-facing entrypoint.
|
|
685
|
+
|
|
686
|
+
The root entrypoint does use `@push.rocks/smartcrypto` to parse and validate
|
|
687
|
+
strict ingress envelopes. Browser consumers that import the root contract can
|
|
688
|
+
therefore include SmartCrypto and its browser-compatible crypto dependencies in
|
|
689
|
+
their bundle. This package never opens private keys; sealed runtime material
|
|
690
|
+
contracts remain isolated to the Node-only `/runtime` subpath.
|
|
691
|
+
|
|
692
|
+
Node runtimes import the isolated subpath:
|
|
634
693
|
|
|
635
694
|
```typescript
|
|
636
695
|
import {
|
|
637
|
-
|
|
696
|
+
verifySealedResolvedSecretMaterial,
|
|
638
697
|
} from '@serve.zone/interfaces/runtime';
|
|
639
698
|
import type {
|
|
640
699
|
IReq_GetResolvedSecretMaterial,
|
|
641
|
-
|
|
700
|
+
ISecretMaterialExpectation,
|
|
701
|
+
ISealedResolvedSecretMaterial,
|
|
642
702
|
} from '@serve.zone/interfaces/runtime';
|
|
643
703
|
|
|
644
|
-
async function acceptMaterial(
|
|
645
|
-
|
|
704
|
+
async function acceptMaterial(
|
|
705
|
+
material: ISealedResolvedSecretMaterial,
|
|
706
|
+
expectation: ISecretMaterialExpectation,
|
|
707
|
+
) {
|
|
708
|
+
if (!await verifySealedResolvedSecretMaterial(material, expectation)) {
|
|
646
709
|
throw new Error('secret material does not match its immutable manifest');
|
|
647
710
|
}
|
|
648
711
|
}
|
|
649
712
|
```
|
|
650
713
|
|
|
651
|
-
Runtime material is shaped as `{ manifest,
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
714
|
+
Runtime material is shaped as `{ schemaVersion: 1, manifest, entries }`, where
|
|
715
|
+
each entry contains only `secretVersionId` and a strict X25519 envelope. The
|
|
716
|
+
helper verifies the canonical schema-v2 manifest digest, envelope context
|
|
717
|
+
digests, active recipient key, sorted exact one-to-one version coverage, every
|
|
718
|
+
request fence, and the trusted local organization/cluster expectation. It never
|
|
719
|
+
decrypts. Organization and cluster are derived from the verified cluster JWT
|
|
720
|
+
and cannot be selected by request fields.
|
|
721
|
+
|
|
722
|
+
Launcher environment delivery uses stable `szsv-<base32-sha256>` Docker
|
|
723
|
+
resource names and `/run/serve.zone/secrets/<resource>` source paths. The
|
|
724
|
+
nonsecret map is written to `/run/serve.zone/workloadinit-map-v1.json` with mode
|
|
725
|
+
0444. Runtime assets under `/opt/serve.zone/runtime-assets` are read-only, and
|
|
726
|
+
the wrapper executes
|
|
727
|
+
`workloadinit run --map /run/serve.zone/workloadinit-map-v1.json -- <argv...>`
|
|
728
|
+
without a shell, symlink, or aggregate value file. Resources and maps remain
|
|
729
|
+
retained while any desired, applied, or previous-accepted manifest references
|
|
730
|
+
them and are deleted only after Docker confirms rollout or service removal.
|
|
655
731
|
|
|
656
732
|
## Platform Contracts
|
|
657
733
|
|
|
@@ -675,7 +751,9 @@ Available platform modules:
|
|
|
675
751
|
- `platform.ai`, `platform.database`, `platform.objectstorage`, `platform.logging`, `platform.backup`, and `platform.sip` for infrastructure and application capabilities.
|
|
676
752
|
- `platform.storage` for provider-neutral storage classes, requests, capabilities, and resolved bindings.
|
|
677
753
|
- `platform.storagemigration` for fenced object-storage migration intent, status, consumer acknowledgements, canonical digests, and strict normalizers.
|
|
678
|
-
- `platform.types`
|
|
754
|
+
- `platform.types` provider and binding metadata is value-free. Provider-specific
|
|
755
|
+
operational config stays adapter-internal, while public DTOs expose typed
|
|
756
|
+
endpoints and optional credential management scopes only.
|
|
679
757
|
|
|
680
758
|
## Legacy Platformservice Contracts
|
|
681
759
|
|
|
@@ -714,7 +792,7 @@ pnpm test
|
|
|
714
792
|
pnpm run buildDocs
|
|
715
793
|
```
|
|
716
794
|
|
|
717
|
-
The package is authored as ESM TypeScript and built with `tsbuild tsfolders
|
|
795
|
+
The package is authored as ESM TypeScript and built with `tsbuild tsfolders`.
|
|
718
796
|
|
|
719
797
|
## License and Legal Information
|
|
720
798
|
|