@serve.zone/interfaces 32.48.0 → 32.49.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 +47 -0
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/appstore/catalog.d.ts +300 -0
- package/dist_ts/appstore/catalog.js +544 -0
- package/dist_ts/appstore/index.d.ts +2 -0
- package/dist_ts/appstore/index.js +3 -1
- package/dist_ts/appstore/types.d.ts +9 -0
- package/dist_ts/appstore/types.js +1 -1
- package/dist_ts/appstore/versionconfig.d.ts +21 -0
- package/dist_ts/appstore/versionconfig.js +685 -0
- package/dist_ts/private/keylist.d.ts +5 -0
- package/dist_ts/private/keylist.js +2 -0
- package/dist_ts/requests/appstore.d.ts +30 -1
- package/dist_ts/runtime.appstorecatalog.d.ts +46 -0
- package/dist_ts/runtime.appstorecatalog.js +142 -0
- package/dist_ts/runtime.d.ts +1 -0
- package/dist_ts/runtime.js +2 -1
- package/package.json +1 -1
- package/readme.md +57 -0
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/appstore/catalog.ts +851 -0
- package/ts/appstore/index.ts +2 -0
- package/ts/appstore/types.ts +9 -0
- package/ts/appstore/versionconfig.ts +803 -0
- package/ts/private/keylist.ts +6 -0
- package/ts/requests/appstore.ts +38 -0
- package/ts/runtime.appstorecatalog.ts +195 -0
- package/ts/runtime.ts +1 -0
|
@@ -0,0 +1,544 @@
|
|
|
1
|
+
import { getDigestFromPinnedImageReference, isSha256Digest } from '../data/immutableimage.js';
|
|
2
|
+
import { canonicalizeStrictJson, compareWireTokens, createCanonicalJsonSha256Hex, } from '../private/canonicaljson.js';
|
|
3
|
+
import { hasExactKeys, readDataElements, readDataProperties } from '../private/dataproperties.js';
|
|
4
|
+
import { validateAppStoreVersionConfig } from './versionconfig.js';
|
|
5
|
+
/**
|
|
6
|
+
* The contract identity, digest domains and bounds every catalog producer and consumer shares.
|
|
7
|
+
*
|
|
8
|
+
* `major` changes when a catalog written against it cannot be read by a consumer of the previous
|
|
9
|
+
* major. `minor` changes when catalog-level structure is added; a consumer reads every catalog of
|
|
10
|
+
* its own major whose minor is not newer than its own, and refuses the rest as
|
|
11
|
+
* `contractUnsupported`. New version-config capabilities do not need a minor: they are gated per
|
|
12
|
+
* version through `requiresFeatures` (see `IAppStoreVersionConfig.requiresFeatures`).
|
|
13
|
+
*/
|
|
14
|
+
export const appStoreCatalogContract = Object.freeze({
|
|
15
|
+
id: 'serve.zone/appstore-catalog',
|
|
16
|
+
major: 1,
|
|
17
|
+
minor: 0,
|
|
18
|
+
digestAlgorithm: 'sha256',
|
|
19
|
+
signatureAlgorithm: 'ed25519',
|
|
20
|
+
configDigestDomain: 'serve.zone/appstore-catalog/version-config',
|
|
21
|
+
catalogDigestDomain: 'serve.zone/appstore-catalog/catalog',
|
|
22
|
+
signatureDomain: 'serve.zone/appstore-catalog/signature',
|
|
23
|
+
signingKeyIdDomain: 'serve.zone/appstore-catalog/signing-key',
|
|
24
|
+
maximumApps: 1024,
|
|
25
|
+
maximumVersionsPerApp: 1024,
|
|
26
|
+
maximumSignatures: 8,
|
|
27
|
+
maximumTags: 32,
|
|
28
|
+
maximumLinks: 32,
|
|
29
|
+
maximumConfigListEntries: 256,
|
|
30
|
+
maximumRequiredFeatures: 64,
|
|
31
|
+
});
|
|
32
|
+
const versionConfigKeyList = [
|
|
33
|
+
'image',
|
|
34
|
+
'port',
|
|
35
|
+
'containerArgs',
|
|
36
|
+
'targetPorts',
|
|
37
|
+
'domains',
|
|
38
|
+
'publicPortMappings',
|
|
39
|
+
'envVars',
|
|
40
|
+
'volumes',
|
|
41
|
+
'storageClasses',
|
|
42
|
+
'storageRequests',
|
|
43
|
+
'publishedPorts',
|
|
44
|
+
'platformRequirements',
|
|
45
|
+
'platformOidc',
|
|
46
|
+
'minOneboxVersion',
|
|
47
|
+
'minCloudlyVersion',
|
|
48
|
+
'changelog',
|
|
49
|
+
'breaking',
|
|
50
|
+
'requiresManualReview',
|
|
51
|
+
'migrationRequired',
|
|
52
|
+
'backupBeforeUpgrade',
|
|
53
|
+
'requiresFeatures',
|
|
54
|
+
'healthCheck',
|
|
55
|
+
];
|
|
56
|
+
/** Every member a catalog version config may carry; any other member is refused. */
|
|
57
|
+
export const appStoreCatalogVersionConfigKeys = Object.freeze(versionConfigKeyList);
|
|
58
|
+
const withdrawalReasonMaximumLength = 512;
|
|
59
|
+
const semverPattern = /^(0|[1-9][0-9]{0,14})\.(0|[1-9][0-9]{0,14})\.(0|[1-9][0-9]{0,14})$/;
|
|
60
|
+
const versionTokenPattern = /^[A-Za-z0-9][A-Za-z0-9._+-]{0,127}$/;
|
|
61
|
+
const appIdPattern = /^[a-z0-9][a-z0-9-]{0,62}$/;
|
|
62
|
+
const iconNamePattern = /^[a-z0-9][a-z0-9-]{0,63}$/;
|
|
63
|
+
const tagPattern = /^[a-z0-9][a-z0-9.-]{0,63}$/;
|
|
64
|
+
const linkLabelPattern = /^[A-Za-z][A-Za-z0-9 _-]{0,63}$/;
|
|
65
|
+
const featureIdPattern = /^(?=.{1,128}$)[a-z][a-z0-9-]*(?:\.[a-z][a-z0-9-]*)*$/;
|
|
66
|
+
const sourceRevisionPattern = /^(?:[0-9a-f]{40}|[0-9a-f]{64})$/;
|
|
67
|
+
const publicKeyPattern = /^[0-9a-f]{64}$/;
|
|
68
|
+
const signaturePattern = /^[0-9a-f]{128}$/;
|
|
69
|
+
const controlCharacterPattern = /[\u0000-\u001f\u007f]/;
|
|
70
|
+
const multilineControlCharacterPattern = /[\u0000-\u0008\u000b-\u001f\u007f]/;
|
|
71
|
+
const isNonNegativeSafeInteger = (valueArg) => typeof valueArg === 'number' && Number.isSafeInteger(valueArg) && valueArg >= 0;
|
|
72
|
+
const isPort = (valueArg) => typeof valueArg === 'number' && Number.isSafeInteger(valueArg) && valueArg >= 1 && valueArg <= 65535;
|
|
73
|
+
const isLine = (valueArg, maximumLengthArg) => typeof valueArg === 'string'
|
|
74
|
+
&& valueArg.length > 0
|
|
75
|
+
&& valueArg.length <= maximumLengthArg
|
|
76
|
+
&& valueArg.trim() === valueArg
|
|
77
|
+
&& !controlCharacterPattern.test(valueArg);
|
|
78
|
+
const isText = (valueArg, maximumLengthArg) => typeof valueArg === 'string'
|
|
79
|
+
&& valueArg.length > 0
|
|
80
|
+
&& valueArg.length <= maximumLengthArg
|
|
81
|
+
&& !multilineControlCharacterPattern.test(valueArg);
|
|
82
|
+
const isHttpsUrl = (valueArg) => {
|
|
83
|
+
if (typeof valueArg !== 'string' || valueArg.length > 2048)
|
|
84
|
+
return false;
|
|
85
|
+
try {
|
|
86
|
+
const url = new URL(valueArg);
|
|
87
|
+
return url.protocol === 'https:' && url.username === '' && url.password === '';
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
const isCanonicalTimestamp = (valueArg) => {
|
|
94
|
+
if (typeof valueArg !== 'string')
|
|
95
|
+
return false;
|
|
96
|
+
const time = Date.parse(valueArg);
|
|
97
|
+
return Number.isFinite(time) && new Date(time).toISOString() === valueArg;
|
|
98
|
+
};
|
|
99
|
+
const compareSemver = (leftArg, rightArg) => {
|
|
100
|
+
const left = leftArg.split('.').map(Number);
|
|
101
|
+
const right = rightArg.split('.').map(Number);
|
|
102
|
+
for (let index = 0; index < 3; index++) {
|
|
103
|
+
if (left[index] !== right[index])
|
|
104
|
+
return left[index] < right[index] ? -1 : 1;
|
|
105
|
+
}
|
|
106
|
+
return 0;
|
|
107
|
+
};
|
|
108
|
+
/** True when a value is a canonical feature-id list: valid ids, strictly increasing. */
|
|
109
|
+
const isCanonicalFeatureIdList = (valueArg) => {
|
|
110
|
+
const entries = readDataElements(valueArg, appStoreCatalogContract.maximumRequiredFeatures);
|
|
111
|
+
if (entries === null)
|
|
112
|
+
return false;
|
|
113
|
+
let previous = null;
|
|
114
|
+
for (const entry of entries) {
|
|
115
|
+
if (typeof entry !== 'string' || !featureIdPattern.test(entry))
|
|
116
|
+
return false;
|
|
117
|
+
if (previous !== null && compareWireTokens(previous, entry) >= 0)
|
|
118
|
+
return false;
|
|
119
|
+
previous = entry;
|
|
120
|
+
}
|
|
121
|
+
return true;
|
|
122
|
+
};
|
|
123
|
+
/**
|
|
124
|
+
* The feature ids a version config requires that the consumer does not fulfil.
|
|
125
|
+
*
|
|
126
|
+
* Empty when the version is installable by this consumer. A malformed `requiresFeatures` is a
|
|
127
|
+
* schema error that `validateAppStoreCatalog` reports; here it yields no missing ids.
|
|
128
|
+
*/
|
|
129
|
+
export const getAppStoreCatalogMissingFeatureIds = (configArg, supportedFeatureIdsArg) => {
|
|
130
|
+
const config = readDataProperties(configArg);
|
|
131
|
+
if (config === null || !isCanonicalFeatureIdList(config.requiresFeatures))
|
|
132
|
+
return [];
|
|
133
|
+
const supported = new Set(supportedFeatureIdsArg);
|
|
134
|
+
return config.requiresFeatures.filter((featureIdArg) => !supported.has(featureIdArg));
|
|
135
|
+
};
|
|
136
|
+
/**
|
|
137
|
+
* Whether a catalog is written against a contract this consumer reads.
|
|
138
|
+
*
|
|
139
|
+
* `null` when it is. A malformed or absent `contract` member is `schemaInvalid`; a well-formed
|
|
140
|
+
* identity naming another id, another major or a newer minor is `contractUnsupported`.
|
|
141
|
+
*/
|
|
142
|
+
export const judgeAppStoreCatalogContract = (catalogArg) => {
|
|
143
|
+
const catalog = readDataProperties(catalogArg);
|
|
144
|
+
const identity = catalog === null ? null : readDataProperties(catalog.contract);
|
|
145
|
+
if (identity === null || !hasExactKeys(identity, ['id', 'major', 'minor'])
|
|
146
|
+
|| typeof identity.id !== 'string'
|
|
147
|
+
|| !isNonNegativeSafeInteger(identity.major) || !isNonNegativeSafeInteger(identity.minor)) {
|
|
148
|
+
return {
|
|
149
|
+
reason: 'schemaInvalid',
|
|
150
|
+
message: 'catalog.contract must be exactly { id, major, minor } with non-negative integers',
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
const supported = `${appStoreCatalogContract.id} ${appStoreCatalogContract.major}.${appStoreCatalogContract.minor}`;
|
|
154
|
+
if (identity.id !== appStoreCatalogContract.id
|
|
155
|
+
|| identity.major !== appStoreCatalogContract.major
|
|
156
|
+
|| identity.minor > appStoreCatalogContract.minor) {
|
|
157
|
+
return {
|
|
158
|
+
reason: 'contractUnsupported',
|
|
159
|
+
message: `catalog contract ${identity.id} ${identity.major}.${identity.minor} is not readable by this consumer (reads ${supported})`,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
return null;
|
|
163
|
+
};
|
|
164
|
+
const validateHealthCheck = (valueArg, labelArg, errorsArg) => {
|
|
165
|
+
const healthCheck = readDataProperties(valueArg);
|
|
166
|
+
if (healthCheck === null || !hasExactKeys(healthCheck, [], ['path', 'port', 'expectedStatus'])) {
|
|
167
|
+
errorsArg.push(`${labelArg} must be an object with only path, port and expectedStatus`);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
if (healthCheck.path !== undefined
|
|
171
|
+
&& (!isLine(healthCheck.path, 2048) || !healthCheck.path.startsWith('/'))) {
|
|
172
|
+
errorsArg.push(`${labelArg}.path must be an absolute request path`);
|
|
173
|
+
}
|
|
174
|
+
if (healthCheck.port !== undefined && !isPort(healthCheck.port)) {
|
|
175
|
+
errorsArg.push(`${labelArg}.port must be a port number`);
|
|
176
|
+
}
|
|
177
|
+
if (healthCheck.expectedStatus !== undefined
|
|
178
|
+
&& !(isNonNegativeSafeInteger(healthCheck.expectedStatus)
|
|
179
|
+
&& healthCheck.expectedStatus >= 100 && healthCheck.expectedStatus <= 599)) {
|
|
180
|
+
errorsArg.push(`${labelArg}.expectedStatus must be an HTTP status code`);
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
/**
|
|
184
|
+
* The contract's judgement of one version config: the catalog member set, image pinning, the
|
|
185
|
+
* gates and upgrade flags, and every member rule `validateAppStoreVersionConfig` applies.
|
|
186
|
+
*/
|
|
187
|
+
const validateCatalogVersionConfig = (configArg, labelArg, errorsArg) => {
|
|
188
|
+
if (!hasExactKeys(configArg, ['image'], appStoreCatalogVersionConfigKeys)) {
|
|
189
|
+
const unknown = Object.keys(configArg)
|
|
190
|
+
.filter((keyArg) => !appStoreCatalogVersionConfigKeys.some((knownArg) => knownArg === keyArg));
|
|
191
|
+
errorsArg.push(unknown.length > 0
|
|
192
|
+
? `${labelArg} has unknown field(s) ${unknown.sort().join(', ')}`
|
|
193
|
+
: `${labelArg}.image is required`);
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
if (typeof configArg.image !== 'string' || getDigestFromPinnedImageReference(configArg.image) === undefined) {
|
|
197
|
+
errorsArg.push(`${labelArg}.image must be a digest-pinned image reference (name@sha256:...)`);
|
|
198
|
+
}
|
|
199
|
+
for (const key of ['minOneboxVersion', 'minCloudlyVersion']) {
|
|
200
|
+
const value = configArg[key];
|
|
201
|
+
if (value !== undefined && (typeof value !== 'string' || !semverPattern.test(value))) {
|
|
202
|
+
errorsArg.push(`${labelArg}.${key} must be MAJOR.MINOR.PATCH`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
if (configArg.changelog !== undefined && !isText(configArg.changelog, 65536)) {
|
|
206
|
+
errorsArg.push(`${labelArg}.changelog must be bounded text`);
|
|
207
|
+
}
|
|
208
|
+
for (const key of ['breaking', 'requiresManualReview', 'migrationRequired', 'backupBeforeUpgrade']) {
|
|
209
|
+
if (configArg[key] !== undefined && typeof configArg[key] !== 'boolean') {
|
|
210
|
+
errorsArg.push(`${labelArg}.${key} must be a boolean`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
if (configArg.healthCheck !== undefined) {
|
|
214
|
+
validateHealthCheck(configArg.healthCheck, `${labelArg}.healthCheck`, errorsArg);
|
|
215
|
+
}
|
|
216
|
+
errorsArg.push(...validateAppStoreVersionConfig(configArg, labelArg));
|
|
217
|
+
};
|
|
218
|
+
const validateAppInfo = (valueArg, labelArg, errorsArg) => {
|
|
219
|
+
const info = readDataProperties(valueArg);
|
|
220
|
+
if (info === null
|
|
221
|
+
|| !hasExactKeys(info, ['id', 'name', 'description', 'category'], ['iconName', 'iconUrl', 'tags', 'maintainer', 'links'])) {
|
|
222
|
+
errorsArg.push(`${labelArg} must be exactly { id, name, description, category } plus optional iconName, iconUrl, tags, maintainer, links`);
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
const id = typeof info.id === 'string' && appIdPattern.test(info.id) ? info.id : null;
|
|
226
|
+
if (id === null)
|
|
227
|
+
errorsArg.push(`${labelArg}.id must be a lower-case app id`);
|
|
228
|
+
if (!isLine(info.name, 128))
|
|
229
|
+
errorsArg.push(`${labelArg}.name must be a single line`);
|
|
230
|
+
if (!isText(info.description, 4096))
|
|
231
|
+
errorsArg.push(`${labelArg}.description must be bounded text`);
|
|
232
|
+
if (!isLine(info.category, 64))
|
|
233
|
+
errorsArg.push(`${labelArg}.category must be a single line`);
|
|
234
|
+
if (info.iconName !== undefined && !(typeof info.iconName === 'string' && iconNamePattern.test(info.iconName))) {
|
|
235
|
+
errorsArg.push(`${labelArg}.iconName must be a lower-case icon name`);
|
|
236
|
+
}
|
|
237
|
+
if (info.iconUrl !== undefined && !isHttpsUrl(info.iconUrl)) {
|
|
238
|
+
errorsArg.push(`${labelArg}.iconUrl must be an https URL`);
|
|
239
|
+
}
|
|
240
|
+
if (info.maintainer !== undefined && !isLine(info.maintainer, 128)) {
|
|
241
|
+
errorsArg.push(`${labelArg}.maintainer must be a single line`);
|
|
242
|
+
}
|
|
243
|
+
if (info.tags !== undefined) {
|
|
244
|
+
const tags = readDataElements(info.tags, appStoreCatalogContract.maximumTags);
|
|
245
|
+
if (tags === null
|
|
246
|
+
|| tags.some((tagArg) => typeof tagArg !== 'string' || !tagPattern.test(tagArg))
|
|
247
|
+
|| new Set(tags).size !== tags.length) {
|
|
248
|
+
errorsArg.push(`${labelArg}.tags must be a bounded list of unique lower-case tags`);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
if (info.links !== undefined) {
|
|
252
|
+
const links = readDataProperties(info.links);
|
|
253
|
+
if (links === null
|
|
254
|
+
|| Object.keys(links).length > appStoreCatalogContract.maximumLinks
|
|
255
|
+
|| Object.entries(links).some(([labelKeyArg, urlArg]) => !linkLabelPattern.test(labelKeyArg) || !isHttpsUrl(urlArg))) {
|
|
256
|
+
errorsArg.push(`${labelArg}.links must map short labels to https URLs`);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return id;
|
|
260
|
+
};
|
|
261
|
+
const validateWithdrawal = (valueArg, labelArg, publishedAtArg, errorsArg) => {
|
|
262
|
+
const withdrawal = readDataProperties(valueArg);
|
|
263
|
+
if (withdrawal === null || !hasExactKeys(withdrawal, ['at', 'reason'])) {
|
|
264
|
+
errorsArg.push(`${labelArg} must be exactly { at, reason }`);
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
if (!isCanonicalTimestamp(withdrawal.at)) {
|
|
268
|
+
errorsArg.push(`${labelArg}.at must be a canonical UTC timestamp`);
|
|
269
|
+
}
|
|
270
|
+
else if (publishedAtArg !== null && Date.parse(withdrawal.at) > Date.parse(publishedAtArg)) {
|
|
271
|
+
errorsArg.push(`${labelArg}.at must not be later than catalog.publishedAt`);
|
|
272
|
+
}
|
|
273
|
+
if (!isLine(withdrawal.reason, withdrawalReasonMaximumLength)) {
|
|
274
|
+
errorsArg.push(`${labelArg}.reason must be a single line`);
|
|
275
|
+
}
|
|
276
|
+
};
|
|
277
|
+
const validateCatalogApp = (valueArg, labelArg, supportedFeatureIdsArg, publishedAtArg, errorsArg) => {
|
|
278
|
+
const app = readDataProperties(valueArg);
|
|
279
|
+
if (app === null || !hasExactKeys(app, ['info', 'latestVersion', 'versions'], ['upgradeStrategy'])) {
|
|
280
|
+
errorsArg.push(`${labelArg} must be exactly { info, latestVersion, versions } plus optional upgradeStrategy`);
|
|
281
|
+
return null;
|
|
282
|
+
}
|
|
283
|
+
const id = validateAppInfo(app.info, `${labelArg}.info`, errorsArg);
|
|
284
|
+
const strategy = app.upgradeStrategy ?? 'semver';
|
|
285
|
+
if (strategy !== 'semver' && strategy !== 'branch') {
|
|
286
|
+
errorsArg.push(`${labelArg}.upgradeStrategy must be semver or branch`);
|
|
287
|
+
return id;
|
|
288
|
+
}
|
|
289
|
+
const versionPattern = strategy === 'semver' ? semverPattern : versionTokenPattern;
|
|
290
|
+
const entries = readDataElements(app.versions, appStoreCatalogContract.maximumVersionsPerApp);
|
|
291
|
+
if (entries === null || entries.length === 0) {
|
|
292
|
+
errorsArg.push(`${labelArg}.versions must be a non-empty bounded array`);
|
|
293
|
+
return id;
|
|
294
|
+
}
|
|
295
|
+
const versions = [];
|
|
296
|
+
const withdrawnVersions = new Set();
|
|
297
|
+
entries.forEach((entryArg, indexArg) => {
|
|
298
|
+
const versionLabel = `${labelArg}.versions[${indexArg}]`;
|
|
299
|
+
const entry = readDataProperties(entryArg);
|
|
300
|
+
if (entry === null || !hasExactKeys(entry, ['version', 'config', 'configDigest'], ['withdrawn'])) {
|
|
301
|
+
errorsArg.push(`${versionLabel} must be exactly { version, config, configDigest } plus optional withdrawn`);
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
if (typeof entry.version !== 'string' || !versionPattern.test(entry.version)) {
|
|
305
|
+
errorsArg.push(`${versionLabel}.version must be ${strategy === 'semver' ? 'MAJOR.MINOR.PATCH' : 'a version token'}`);
|
|
306
|
+
}
|
|
307
|
+
else if (versions.includes(entry.version)) {
|
|
308
|
+
errorsArg.push(`${versionLabel}.version '${entry.version}' is listed twice`);
|
|
309
|
+
}
|
|
310
|
+
else {
|
|
311
|
+
versions.push(entry.version);
|
|
312
|
+
if (entry.withdrawn !== undefined)
|
|
313
|
+
withdrawnVersions.add(entry.version);
|
|
314
|
+
}
|
|
315
|
+
if (entry.withdrawn !== undefined) {
|
|
316
|
+
validateWithdrawal(entry.withdrawn, `${versionLabel}.withdrawn`, publishedAtArg, errorsArg);
|
|
317
|
+
}
|
|
318
|
+
if (typeof entry.configDigest !== 'string' || !isSha256Digest(entry.configDigest)) {
|
|
319
|
+
errorsArg.push(`${versionLabel}.configDigest must be a canonical sha256 digest`);
|
|
320
|
+
}
|
|
321
|
+
const config = readDataProperties(entry.config);
|
|
322
|
+
if (config === null) {
|
|
323
|
+
errorsArg.push(`${versionLabel}.config must be an object`);
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
if (config.requiresFeatures !== undefined && !isCanonicalFeatureIdList(config.requiresFeatures)) {
|
|
327
|
+
errorsArg.push(`${versionLabel}.config.requiresFeatures must be a strictly increasing list of feature ids`);
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
const missing = isCanonicalFeatureIdList(config.requiresFeatures)
|
|
331
|
+
? config.requiresFeatures.filter((featureIdArg) => !supportedFeatureIdsArg.has(featureIdArg))
|
|
332
|
+
: [];
|
|
333
|
+
// A version gated on a feature this consumer lacks may use members this consumer does not
|
|
334
|
+
// know. It stays listed, is never installed here, and its config is not interpreted.
|
|
335
|
+
if (missing.length === 0)
|
|
336
|
+
validateCatalogVersionConfig(config, `${versionLabel}.config`, errorsArg);
|
|
337
|
+
});
|
|
338
|
+
// While any version is installable, latestVersion names one of those; a fully withdrawn app
|
|
339
|
+
// still names a listed version.
|
|
340
|
+
const availableVersions = versions.filter((versionArg) => !withdrawnVersions.has(versionArg));
|
|
341
|
+
const latestCandidates = availableVersions.length > 0 ? availableVersions : versions;
|
|
342
|
+
const latestVersion = typeof app.latestVersion === 'string' ? app.latestVersion : null;
|
|
343
|
+
if (latestVersion === null || !versions.includes(latestVersion)) {
|
|
344
|
+
errorsArg.push(`${labelArg}.latestVersion must name a listed version`);
|
|
345
|
+
}
|
|
346
|
+
else if (!latestCandidates.includes(latestVersion)) {
|
|
347
|
+
errorsArg.push(`${labelArg}.latestVersion must not name a withdrawn version while another is not withdrawn`);
|
|
348
|
+
}
|
|
349
|
+
else if (strategy === 'semver'
|
|
350
|
+
&& latestCandidates.some((versionArg) => compareSemver(versionArg, latestVersion) > 0)) {
|
|
351
|
+
errorsArg.push(`${labelArg}.latestVersion must be the highest listed version that is not withdrawn`);
|
|
352
|
+
}
|
|
353
|
+
return id;
|
|
354
|
+
};
|
|
355
|
+
/**
|
|
356
|
+
* Every reason a value is not a catalog this consumer can read; empty when it is.
|
|
357
|
+
*
|
|
358
|
+
* Exact keys at every level: a member this contract does not define is refused, because a
|
|
359
|
+
* consumer that silently ignored it could not be trusted to honour it. The one exception is the
|
|
360
|
+
* config of a version whose `requiresFeatures` names a feature the consumer does not fulfil.
|
|
361
|
+
*/
|
|
362
|
+
export const validateAppStoreCatalog = (catalogArg, optionsArg) => {
|
|
363
|
+
const catalog = readDataProperties(catalogArg);
|
|
364
|
+
if (catalog === null
|
|
365
|
+
|| !hasExactKeys(catalog, ['contract', 'revision', 'publishedAt', 'sourceRevision', 'apps'])) {
|
|
366
|
+
return ['catalog must be exactly { contract, revision, publishedAt, sourceRevision, apps }'];
|
|
367
|
+
}
|
|
368
|
+
const errors = [];
|
|
369
|
+
const contractRefusal = judgeAppStoreCatalogContract(catalog);
|
|
370
|
+
if (contractRefusal !== null)
|
|
371
|
+
errors.push(contractRefusal.message);
|
|
372
|
+
if (!isNonNegativeSafeInteger(catalog.revision) || catalog.revision < 1) {
|
|
373
|
+
errors.push('catalog.revision must be a positive integer');
|
|
374
|
+
}
|
|
375
|
+
if (!isCanonicalTimestamp(catalog.publishedAt)) {
|
|
376
|
+
errors.push('catalog.publishedAt must be a canonical UTC timestamp');
|
|
377
|
+
}
|
|
378
|
+
if (typeof catalog.sourceRevision !== 'string' || !sourceRevisionPattern.test(catalog.sourceRevision)) {
|
|
379
|
+
errors.push('catalog.sourceRevision must be a lower-case hex commit id');
|
|
380
|
+
}
|
|
381
|
+
const apps = readDataElements(catalog.apps, appStoreCatalogContract.maximumApps);
|
|
382
|
+
if (apps === null) {
|
|
383
|
+
errors.push('catalog.apps must be a bounded array');
|
|
384
|
+
return errors;
|
|
385
|
+
}
|
|
386
|
+
const supportedFeatureIds = new Set(optionsArg.supportedFeatureIds);
|
|
387
|
+
const publishedAt = isCanonicalTimestamp(catalog.publishedAt) ? catalog.publishedAt : null;
|
|
388
|
+
const ids = [];
|
|
389
|
+
apps.forEach((appArg, indexArg) => {
|
|
390
|
+
const id = validateCatalogApp(appArg, `catalog.apps[${indexArg}]`, supportedFeatureIds, publishedAt, errors);
|
|
391
|
+
if (id === null)
|
|
392
|
+
return;
|
|
393
|
+
if (ids.includes(id))
|
|
394
|
+
errors.push(`catalog.apps[${indexArg}].info.id '${id}' is listed twice`);
|
|
395
|
+
else
|
|
396
|
+
ids.push(id);
|
|
397
|
+
});
|
|
398
|
+
return errors;
|
|
399
|
+
};
|
|
400
|
+
/** The envelope's own members; the catalog inside is judged by `validateAppStoreCatalog`. */
|
|
401
|
+
export const validateAppStoreCatalogEnvelopeShape = (envelopeArg) => {
|
|
402
|
+
const envelope = readDataProperties(envelopeArg);
|
|
403
|
+
if (envelope === null || !hasExactKeys(envelope, ['catalog', 'catalogDigest', 'signatures'])) {
|
|
404
|
+
return ['envelope must be exactly { catalog, catalogDigest, signatures }'];
|
|
405
|
+
}
|
|
406
|
+
const errors = [];
|
|
407
|
+
if (readDataProperties(envelope.catalog) === null)
|
|
408
|
+
errors.push('envelope.catalog must be an object');
|
|
409
|
+
if (typeof envelope.catalogDigest !== 'string' || !isSha256Digest(envelope.catalogDigest)) {
|
|
410
|
+
errors.push('envelope.catalogDigest must be a canonical sha256 digest');
|
|
411
|
+
}
|
|
412
|
+
const signatures = readDataElements(envelope.signatures, appStoreCatalogContract.maximumSignatures);
|
|
413
|
+
if (signatures === null || signatures.length === 0) {
|
|
414
|
+
errors.push(`envelope.signatures must hold 1 to ${appStoreCatalogContract.maximumSignatures} signatures`);
|
|
415
|
+
return errors;
|
|
416
|
+
}
|
|
417
|
+
const keyIds = [];
|
|
418
|
+
signatures.forEach((signatureArg, indexArg) => {
|
|
419
|
+
const signature = readDataProperties(signatureArg);
|
|
420
|
+
if (signature === null || !hasExactKeys(signature, ['keyId', 'signature'])
|
|
421
|
+
|| typeof signature.keyId !== 'string' || !isSha256Digest(signature.keyId)
|
|
422
|
+
|| typeof signature.signature !== 'string' || !signaturePattern.test(signature.signature)) {
|
|
423
|
+
errors.push(`envelope.signatures[${indexArg}] must be { keyId: sha256 digest, signature: 128 lower-case hex }`);
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
if (keyIds.includes(signature.keyId))
|
|
427
|
+
errors.push(`envelope.signatures[${indexArg}].keyId is listed twice`);
|
|
428
|
+
else
|
|
429
|
+
keyIds.push(signature.keyId);
|
|
430
|
+
});
|
|
431
|
+
return errors;
|
|
432
|
+
};
|
|
433
|
+
/** Every reason a value is not an envelope whose catalog this consumer can read. */
|
|
434
|
+
export const validateAppStoreCatalogEnvelope = (envelopeArg, optionsArg) => {
|
|
435
|
+
const shapeErrors = validateAppStoreCatalogEnvelopeShape(envelopeArg);
|
|
436
|
+
if (shapeErrors.length > 0)
|
|
437
|
+
return shapeErrors;
|
|
438
|
+
const envelope = readDataProperties(envelopeArg);
|
|
439
|
+
return envelope === null
|
|
440
|
+
? ['envelope must be an object']
|
|
441
|
+
: validateAppStoreCatalog(envelope.catalog, optionsArg);
|
|
442
|
+
};
|
|
443
|
+
/** Narrows a value `validateAppStoreCatalogEnvelope` accepts. */
|
|
444
|
+
export const isAppStoreCatalogEnvelope = (envelopeArg, optionsArg) => validateAppStoreCatalogEnvelope(envelopeArg, optionsArg).length === 0;
|
|
445
|
+
const failDigestInput = (reasonArg) => {
|
|
446
|
+
throw new Error(`App Store catalog digest input rejected: ${reasonArg}`);
|
|
447
|
+
};
|
|
448
|
+
/**
|
|
449
|
+
* SHA-256 over the strict canonical JSON of a domain-separated value: object keys in UTF-16 code
|
|
450
|
+
* unit order, no whitespace, safe integers only. A value canonical JSON cannot represent — a
|
|
451
|
+
* fractional number, an accessor, a cycle — throws.
|
|
452
|
+
*/
|
|
453
|
+
const computeDomainDigest = async (valueArg) => {
|
|
454
|
+
const hex = await createCanonicalJsonSha256Hex(canonicalizeStrictJson(valueArg, failDigestInput), failDigestInput);
|
|
455
|
+
return `sha256:${hex}`;
|
|
456
|
+
};
|
|
457
|
+
/** The digest a catalog version entry carries as `configDigest`. */
|
|
458
|
+
export const computeAppStoreCatalogConfigDigest = (configArg) => computeDomainDigest({ domain: appStoreCatalogContract.configDigestDomain, config: configArg });
|
|
459
|
+
/** The digest an envelope carries as `catalogDigest`. */
|
|
460
|
+
export const computeAppStoreCatalogDigest = (catalogArg) => computeDomainDigest({ domain: appStoreCatalogContract.catalogDigestDomain, catalog: catalogArg });
|
|
461
|
+
/** The key id of a raw Ed25519 public key (32 bytes, lower-case hex). */
|
|
462
|
+
export const computeAppStoreCatalogSigningKeyId = async (publicKeyArg) => {
|
|
463
|
+
if (!publicKeyPattern.test(publicKeyArg)) {
|
|
464
|
+
throw new Error('App Store catalog signing key must be 32 bytes of lower-case hex');
|
|
465
|
+
}
|
|
466
|
+
return computeDomainDigest({ domain: appStoreCatalogContract.signingKeyIdDomain, publicKey: publicKeyArg });
|
|
467
|
+
};
|
|
468
|
+
/** The exact bytes a catalog signature covers. */
|
|
469
|
+
export const createAppStoreCatalogSignaturePayload = (catalogDigestArg) => {
|
|
470
|
+
if (!isSha256Digest(catalogDigestArg)) {
|
|
471
|
+
throw new Error('App Store catalog digest must be a canonical sha256 digest');
|
|
472
|
+
}
|
|
473
|
+
return new TextEncoder().encode(canonicalizeStrictJson({ domain: appStoreCatalogContract.signatureDomain, catalogDigest: catalogDigestArg }, failDigestInput));
|
|
474
|
+
};
|
|
475
|
+
/**
|
|
476
|
+
* The first version entry whose `configDigest` does not match its config, or `null`.
|
|
477
|
+
*
|
|
478
|
+
* Judge the catalog with `validateAppStoreCatalog` first; an entry it would refuse is skipped.
|
|
479
|
+
*/
|
|
480
|
+
export const findAppStoreCatalogConfigDigestMismatch = async (catalogArg) => {
|
|
481
|
+
for (const app of catalogArg.apps) {
|
|
482
|
+
for (const version of app.versions) {
|
|
483
|
+
if (await computeAppStoreCatalogConfigDigest(version.config) !== version.configDigest) {
|
|
484
|
+
return `${app.info.id}@${version.version} configDigest does not match its config`;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
return null;
|
|
489
|
+
};
|
|
490
|
+
/**
|
|
491
|
+
* Whether a consumer may install a listed version, or upgrade a service to it; `null` when it may.
|
|
492
|
+
* A withdrawn version and a version requiring a feature the consumer does not fulfil stay listed
|
|
493
|
+
* and are refused here, and nowhere else is a second answer needed.
|
|
494
|
+
*/
|
|
495
|
+
export const judgeAppStoreCatalogInstallTarget = (versionArg, supportedFeatureIdsArg) => {
|
|
496
|
+
if (versionArg.withdrawn !== undefined)
|
|
497
|
+
return { reason: 'versionWithdrawn', withdrawal: versionArg.withdrawn };
|
|
498
|
+
const missingFeatureIds = getAppStoreCatalogMissingFeatureIds(versionArg.config, supportedFeatureIdsArg);
|
|
499
|
+
return missingFeatureIds.length > 0 ? { reason: 'featuresUnsupported', missingFeatureIds } : null;
|
|
500
|
+
};
|
|
501
|
+
const sameWithdrawal = (leftArg, rightArg) => leftArg?.at === rightArg?.at && leftArg?.reason === rightArg?.reason;
|
|
502
|
+
/**
|
|
503
|
+
* Whether a verified candidate may replace the active verified catalog.
|
|
504
|
+
*
|
|
505
|
+
* The same digest is `unchanged`. Otherwise the revision must be greater, and the candidate must
|
|
506
|
+
* keep the active catalog's full history: every `app@version` it lists stays listed
|
|
507
|
+
* (`publishedVersionRemoved`) with its `configDigest` (`publishedVersionMutated`), and every
|
|
508
|
+
* withdrawal stays exactly as published (`publishedWithdrawalChanged`). A candidate may add apps
|
|
509
|
+
* and versions and withdraw versions; it cannot remove, rewrite or reinstate one.
|
|
510
|
+
*/
|
|
511
|
+
export const judgeAppStoreCatalogSuccession = (activeArg, candidateArg) => {
|
|
512
|
+
if (activeArg === null)
|
|
513
|
+
return { outcome: 'activate' };
|
|
514
|
+
if (activeArg.catalogDigest === candidateArg.catalogDigest)
|
|
515
|
+
return { outcome: 'unchanged' };
|
|
516
|
+
const refuse = (reasonArg, messageArg) => ({ outcome: 'refused', refusal: { reason: reasonArg, message: messageArg } });
|
|
517
|
+
if (candidateArg.catalog.revision <= activeArg.catalog.revision) {
|
|
518
|
+
return refuse('revisionRegressed', `catalog revision ${candidateArg.catalog.revision} is not greater than active revision ${activeArg.catalog.revision}`);
|
|
519
|
+
}
|
|
520
|
+
const candidateVersions = new Map();
|
|
521
|
+
for (const app of candidateArg.catalog.apps) {
|
|
522
|
+
for (const version of app.versions)
|
|
523
|
+
candidateVersions.set(`${app.info.id}@${version.version}`, version);
|
|
524
|
+
}
|
|
525
|
+
for (const app of activeArg.catalog.apps) {
|
|
526
|
+
for (const published of app.versions) {
|
|
527
|
+
const key = `${app.info.id}@${published.version}`;
|
|
528
|
+
const candidate = candidateVersions.get(key);
|
|
529
|
+
if (candidate === undefined) {
|
|
530
|
+
return refuse('publishedVersionRemoved', `${key} was published and is no longer listed`);
|
|
531
|
+
}
|
|
532
|
+
if (candidate.configDigest !== published.configDigest) {
|
|
533
|
+
return refuse('publishedVersionMutated', `${key} was published with ${published.configDigest} and now carries ${candidate.configDigest}`);
|
|
534
|
+
}
|
|
535
|
+
if (published.withdrawn !== undefined && !sameWithdrawal(published.withdrawn, candidate.withdrawn)) {
|
|
536
|
+
return refuse('publishedWithdrawalChanged', candidate.withdrawn === undefined
|
|
537
|
+
? `${key} was withdrawn and a withdrawal is final`
|
|
538
|
+
: `${key} was withdrawn at ${published.withdrawn.at} and its withdrawal record changed`);
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
return { outcome: 'activate' };
|
|
543
|
+
};
|
|
544
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2F0YWxvZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL2FwcHN0b3JlL2NhdGFsb2cudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBYUEsT0FBTyxFQUFFLGlDQUFpQyxFQUFFLGNBQWMsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQzlGLE9BQU8sRUFDTCxzQkFBc0IsRUFDdEIsaUJBQWlCLEVBQ2pCLDRCQUE0QixHQUM3QixNQUFNLDZCQUE2QixDQUFDO0FBQ3JDLE9BQU8sRUFBRSxZQUFZLEVBQUUsZ0JBQWdCLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUVsRyxPQUFPLEVBQUUsNkJBQTZCLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQU9uRTs7Ozs7Ozs7R0FRRztBQUNILE1BQU0sQ0FBQyxNQUFNLHVCQUF1QixHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUM7SUFDbkQsRUFBRSxFQUFFLDZCQUE2QjtJQUNqQyxLQUFLLEVBQUUsQ0FBQztJQUNSLEtBQUssRUFBRSxDQUFDO0lBQ1IsZUFBZSxFQUFFLFFBQVE7SUFDekIsa0JBQWtCLEVBQUUsU0FBUztJQUM3QixrQkFBa0IsRUFBRSw0Q0FBNEM7SUFDaEUsbUJBQW1CLEVBQUUscUNBQXFDO0lBQzFELGVBQWUsRUFBRSx1Q0FBdUM7SUFDeEQsa0JBQWtCLEVBQUUseUNBQXlDO0lBQzdELFdBQVcsRUFBRSxJQUFJO0lBQ2pCLHFCQUFxQixFQUFFLElBQUk7SUFDM0IsaUJBQWlCLEVBQUUsQ0FBQztJQUNwQixXQUFXLEVBQUUsRUFBRTtJQUNmLFlBQVksRUFBRSxFQUFFO0lBQ2hCLHdCQUF3QixFQUFFLEdBQUc7SUFDN0IsdUJBQXVCLEVBQUUsRUFBRTtDQUNuQixDQUFDLENBQUM7QUFzQlosTUFBTSxvQkFBb0IsR0FBRztJQUMzQixPQUFPO0lBQ1AsTUFBTTtJQUNOLGVBQWU7SUFDZixhQUFhO0lBQ2IsU0FBUztJQUNULG9CQUFvQjtJQUNwQixTQUFTO0lBQ1Qs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
|
|
@@ -1,2 +1,4 @@
|
|
|
1
1
|
export * from './types.js';
|
|
2
|
-
|
|
2
|
+
export * from './versionconfig.js';
|
|
3
|
+
export * from './catalog.js';
|
|
4
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9hcHBzdG9yZS9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxjQUFjLFlBQVksQ0FBQztBQUMzQixjQUFjLG9CQUFvQixDQUFDO0FBQ25DLGNBQWMsY0FBYyxDQUFDIn0=
|
|
@@ -244,6 +244,15 @@ export interface IAppStoreVersionConfig {
|
|
|
244
244
|
requiresManualReview?: boolean;
|
|
245
245
|
migrationRequired?: boolean;
|
|
246
246
|
backupBeforeUpgrade?: boolean;
|
|
247
|
+
/**
|
|
248
|
+
* Feature ids this version needs from the consumer that installs it, as a strictly increasing
|
|
249
|
+
* list (e.g. `appStoreStorageFeatureIds` values). A consumer advertises the ids it fulfils; a
|
|
250
|
+
* version naming any other id stays listed in the catalog but is refused for install and
|
|
251
|
+
* upgrade by that consumer ("requires a newer Onebox/Cloudly"), and its config is not
|
|
252
|
+
* interpreted there. A version that uses a member introduced after the catalog contract's
|
|
253
|
+
* current minor must name the feature id that introduced it, so older consumers keep loading
|
|
254
|
+
* the rest of the catalog.
|
|
255
|
+
*/
|
|
247
256
|
requiresFeatures?: string[];
|
|
248
257
|
healthCheck?: {
|
|
249
258
|
path?: string;
|