@fnndsc/salsa 4.4.3 → 4.5.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.
@@ -0,0 +1,224 @@
1
+ /**
2
+ * @file Checking plugin descriptors before any CUBE sees them.
3
+ *
4
+ * Five rules, cheapest first, each failure naming the file and the rule:
5
+ *
6
+ * 1. the index's own JSON Schema (`schema/plugin.schema.json`), so the
7
+ * schema has one home and this check follows it without a release;
8
+ * 2. CUBE's administrative upload rules (ChRIS_ultron_backEnd
9
+ * `plugins/admin.py`): a JSON object, required descriptors, a dotted-number version,
10
+ * the upload's parameter types (`str|int|float|bool|path|unextpath`,
11
+ * not the read API's `string|integer|boolean`), an optional parameter
12
+ * carries a default and is never a path, a required one is exposed;
13
+ * 3. the file is named for the plugin (`<name>.json`);
14
+ * 4. no two names differ only in case;
15
+ * 5. every `dock_image` resolves anonymously on its registry, digests too.
16
+ *
17
+ * Rules 1–4 read nothing but the descriptors. Rule 5 asks registries, four
18
+ * at a time; a registry that cannot be reached is a failure, never a pass.
19
+ * A rule that was not run says so (`not checked, no schema`; `not checked,
20
+ * --offline`), so a clean report never hides an unchecked rule.
21
+ *
22
+ * Key components:
23
+ * - ValidateFinding: one failure, its file, rule and reason.
24
+ * - ValidateRuleState: whether a rule ran, and how many files it failed.
25
+ * - ValidateReport: the findings and the rules' states for an index.
26
+ * - DescriptorChecked: one descriptor, parsed, with its local findings.
27
+ * - descriptors_checkLocal: rules 1–4 over an index's descriptors.
28
+ * - pluginIndex_validate: all five rules over an index.
29
+ * - imageReference_parse / image_resolve: rule 5's registry lookup.
30
+ *
31
+ * Typical usage:
32
+ * ```ts
33
+ * const report: ValidateReport = await pluginIndex_validate(index, { offline: false });
34
+ * if (!report.ok) report.findings.forEach((f: ValidateFinding): void => console.log(f.file, f.message));
35
+ * ```
36
+ *
37
+ * Dependencies: `ajv` (draft 2020-12 build) for rule 1; `fetch` for rule 5.
38
+ *
39
+ * @module
40
+ */
41
+ import type { PluginIndex } from './plugin_index.js';
42
+ /** The rules, by number, as the report names them. */
43
+ export declare const VALIDATE_RULES: Readonly<Record<ValidateRuleNumber, string>>;
44
+ /** A rule's number. */
45
+ export type ValidateRuleNumber = 1 | 2 | 3 | 4 | 5;
46
+ /**
47
+ * One failure.
48
+ *
49
+ * @example
50
+ * ```ts
51
+ * const finding: ValidateFinding = { file: 'pl-x.json', rule: 3, message: "named 'pl-y'" };
52
+ * ```
53
+ */
54
+ export interface ValidateFinding {
55
+ /** The descriptor file. */
56
+ readonly file: string;
57
+ /** The rule it fails. */
58
+ readonly rule: ValidateRuleNumber;
59
+ /** Why, in a line. */
60
+ readonly message: string;
61
+ }
62
+ /**
63
+ * What one rule did.
64
+ *
65
+ * @example
66
+ * ```ts
67
+ * const state: ValidateRuleState = { rule: 5, title: 'images resolve', checked: false, note: '--offline', failed: 0 };
68
+ * ```
69
+ */
70
+ export interface ValidateRuleState {
71
+ /** The rule. */
72
+ readonly rule: ValidateRuleNumber;
73
+ /** Its title. */
74
+ readonly title: string;
75
+ /** Whether it ran. */
76
+ readonly checked: boolean;
77
+ /** Why it did not run, when it did not. */
78
+ readonly note?: string;
79
+ /** How many files it failed. */
80
+ readonly failed: number;
81
+ }
82
+ /**
83
+ * The report on an index.
84
+ *
85
+ * @example
86
+ * ```ts
87
+ * const report: ValidateReport = await pluginIndex_validate(index, { offline: true });
88
+ * report.ok;
89
+ * ```
90
+ */
91
+ export interface ValidateReport {
92
+ /** The index's short name. */
93
+ readonly label: string;
94
+ /** The commit read, when known. */
95
+ readonly commit: string | null;
96
+ /** How many descriptor files were read. */
97
+ readonly descriptors: number;
98
+ /** Every failure, by file then rule. */
99
+ readonly findings: ValidateFinding[];
100
+ /** Each rule's state, in order. */
101
+ readonly rules: ValidateRuleState[];
102
+ /** True when no rule that ran failed a file. */
103
+ readonly ok: boolean;
104
+ }
105
+ /**
106
+ * One descriptor, parsed, with what rules 1–4 found in it.
107
+ *
108
+ * @example
109
+ * ```ts
110
+ * const [checked] = descriptors_checkLocal(index).descriptors;
111
+ * checked.findings.length === 0;
112
+ * ```
113
+ */
114
+ export interface DescriptorChecked {
115
+ /** The file. */
116
+ readonly file: string;
117
+ /** The file's text. */
118
+ readonly text: string;
119
+ /** The parsed descriptor, or null when the file is not a JSON object. */
120
+ readonly data: Record<string, unknown> | null;
121
+ /** Rules 1–4's failures for this file. */
122
+ readonly findings: ValidateFinding[];
123
+ }
124
+ /**
125
+ * Rules 1–4 over an index.
126
+ *
127
+ * @example
128
+ * ```ts
129
+ * const local: LocalCheck = descriptors_checkLocal(index);
130
+ * local.schemaChecked;
131
+ * ```
132
+ */
133
+ export interface LocalCheck {
134
+ /** Each descriptor with its findings, in file order. */
135
+ readonly descriptors: DescriptorChecked[];
136
+ /** Whether rule 1 ran (the index carried a schema). */
137
+ readonly schemaChecked: boolean;
138
+ }
139
+ /**
140
+ * What rule 5 needs to know.
141
+ *
142
+ * @example
143
+ * ```ts
144
+ * const options: ValidateOptions = { offline: false };
145
+ * ```
146
+ */
147
+ export interface ValidateOptions {
148
+ /** Skip rule 5, saying so. */
149
+ readonly offline: boolean;
150
+ /** The fetch rule 5 uses; the global one by default. */
151
+ readonly fetcher?: typeof fetch;
152
+ }
153
+ /**
154
+ * A parsed image reference.
155
+ *
156
+ * @example
157
+ * ```ts
158
+ * imageReference_parse('fnndsc/pl-dircopy:2.1.1');
159
+ * // { registry: 'registry-1.docker.io', repository: 'fnndsc/pl-dircopy', reference: '2.1.1' }
160
+ * ```
161
+ */
162
+ export interface ImageReference {
163
+ /** The registry host to ask. */
164
+ readonly registry: string;
165
+ /** The repository path on it. */
166
+ readonly repository: string;
167
+ /** The digest when the reference pins one, else the tag. */
168
+ readonly reference: string;
169
+ }
170
+ /**
171
+ * Runs rules 1–4 over an index's descriptors.
172
+ *
173
+ * @param index - The index.
174
+ * @returns Each descriptor parsed, with its findings, and whether rule 1 ran.
175
+ * @throws {Error} When the index's schema does not compile.
176
+ *
177
+ * @example
178
+ * ```ts
179
+ * const local: LocalCheck = descriptors_checkLocal(index);
180
+ * local.descriptors.filter((d: DescriptorChecked): boolean => d.findings.length > 0);
181
+ * ```
182
+ */
183
+ export declare function descriptors_checkLocal(index: PluginIndex): LocalCheck;
184
+ /**
185
+ * Runs all five rules over an index.
186
+ *
187
+ * @param index - The index.
188
+ * @param options - Whether to skip rule 5, and the fetch it uses.
189
+ * @returns The report.
190
+ * @throws {Error} When the index's schema does not compile.
191
+ *
192
+ * @example
193
+ * ```ts
194
+ * const report: ValidateReport = await pluginIndex_validate(index, { offline: false });
195
+ * ```
196
+ */
197
+ export declare function pluginIndex_validate(index: PluginIndex, options: ValidateOptions): Promise<ValidateReport>;
198
+ /**
199
+ * Parses an image reference into what a registry lookup needs.
200
+ *
201
+ * @param image - The reference (`[registry/]repo[:tag][@sha256:…]`).
202
+ * @returns The registry host, repository and reference; null when unreadable.
203
+ *
204
+ * @example
205
+ * ```ts
206
+ * imageReference_parse('ghcr.io/fnndsc/pl-x:1.0@sha256:ab…'); // reference is the digest
207
+ * ```
208
+ */
209
+ export declare function imageReference_parse(image: string): ImageReference | null;
210
+ /**
211
+ * Asks an image's registry, anonymously, whether its manifest is there.
212
+ *
213
+ * Follows the registry's anonymous bearer-token challenge when it sends one.
214
+ *
215
+ * @param image - The image reference.
216
+ * @param fetcher - The fetch to use.
217
+ * @returns Null when the manifest resolves; else why not, in a few words.
218
+ *
219
+ * @example
220
+ * ```ts
221
+ * await image_resolve('docker.io/library/alpine:3.20', fetch); // null
222
+ * ```
223
+ */
224
+ export declare function image_resolve(image: string, fetcher: typeof fetch): Promise<string | null>;
@@ -0,0 +1,395 @@
1
+ "use strict";
2
+ /**
3
+ * @file Checking plugin descriptors before any CUBE sees them.
4
+ *
5
+ * Five rules, cheapest first, each failure naming the file and the rule:
6
+ *
7
+ * 1. the index's own JSON Schema (`schema/plugin.schema.json`), so the
8
+ * schema has one home and this check follows it without a release;
9
+ * 2. CUBE's administrative upload rules (ChRIS_ultron_backEnd
10
+ * `plugins/admin.py`): a JSON object, required descriptors, a dotted-number version,
11
+ * the upload's parameter types (`str|int|float|bool|path|unextpath`,
12
+ * not the read API's `string|integer|boolean`), an optional parameter
13
+ * carries a default and is never a path, a required one is exposed;
14
+ * 3. the file is named for the plugin (`<name>.json`);
15
+ * 4. no two names differ only in case;
16
+ * 5. every `dock_image` resolves anonymously on its registry, digests too.
17
+ *
18
+ * Rules 1–4 read nothing but the descriptors. Rule 5 asks registries, four
19
+ * at a time; a registry that cannot be reached is a failure, never a pass.
20
+ * A rule that was not run says so (`not checked, no schema`; `not checked,
21
+ * --offline`), so a clean report never hides an unchecked rule.
22
+ *
23
+ * Key components:
24
+ * - ValidateFinding: one failure, its file, rule and reason.
25
+ * - ValidateRuleState: whether a rule ran, and how many files it failed.
26
+ * - ValidateReport: the findings and the rules' states for an index.
27
+ * - DescriptorChecked: one descriptor, parsed, with its local findings.
28
+ * - descriptors_checkLocal: rules 1–4 over an index's descriptors.
29
+ * - pluginIndex_validate: all five rules over an index.
30
+ * - imageReference_parse / image_resolve: rule 5's registry lookup.
31
+ *
32
+ * Typical usage:
33
+ * ```ts
34
+ * const report: ValidateReport = await pluginIndex_validate(index, { offline: false });
35
+ * if (!report.ok) report.findings.forEach((f: ValidateFinding): void => console.log(f.file, f.message));
36
+ * ```
37
+ *
38
+ * Dependencies: `ajv` (draft 2020-12 build) for rule 1; `fetch` for rule 5.
39
+ *
40
+ * @module
41
+ */
42
+ var __importDefault = (this && this.__importDefault) || function (mod) {
43
+ return (mod && mod.__esModule) ? mod : { "default": mod };
44
+ };
45
+ Object.defineProperty(exports, "__esModule", { value: true });
46
+ exports.VALIDATE_RULES = void 0;
47
+ exports.descriptors_checkLocal = descriptors_checkLocal;
48
+ exports.pluginIndex_validate = pluginIndex_validate;
49
+ exports.imageReference_parse = imageReference_parse;
50
+ exports.image_resolve = image_resolve;
51
+ const _2020_1 = __importDefault(require("ajv/dist/2020"));
52
+ const pool_js_1 = require("./pool.js");
53
+ /** The rules, by number, as the report names them. */
54
+ exports.VALIDATE_RULES = {
55
+ 1: 'schema',
56
+ 2: "CUBE's upload rules",
57
+ 3: 'file name equals name',
58
+ 4: 'no names differ only in case',
59
+ 5: 'images resolve',
60
+ };
61
+ /** Descriptors CUBE's upload refuses a file without. */
62
+ const REQUIRED_DESCRIPTORS = ['name', 'version', 'dock_image', 'execshell', 'selfpath', 'selfexec', 'parameters'];
63
+ /** Parameter types CUBE's upload takes (its front-end spellings). */
64
+ const UPLOAD_PARAMETER_TYPES = ['str', 'int', 'float', 'bool', 'path', 'unextpath'];
65
+ /** Parameter types that may never be optional. */
66
+ const PATH_TYPES = ['path', 'unextpath'];
67
+ /** Docker Hub's registry, as image references name it and as it is reached. */
68
+ const DOCKER_HUB = { named: 'docker.io', host: 'registry-1.docker.io' };
69
+ /** Manifest media types a registry may answer a manifest lookup with. */
70
+ const MANIFEST_ACCEPT = [
71
+ 'application/vnd.oci.image.index.v1+json',
72
+ 'application/vnd.oci.image.manifest.v1+json',
73
+ 'application/vnd.docker.distribution.manifest.list.v2+json',
74
+ 'application/vnd.docker.distribution.manifest.v2+json',
75
+ ].join(', ');
76
+ /**
77
+ * Runs rules 1–4 over an index's descriptors.
78
+ *
79
+ * @param index - The index.
80
+ * @returns Each descriptor parsed, with its findings, and whether rule 1 ran.
81
+ * @throws {Error} When the index's schema does not compile.
82
+ *
83
+ * @example
84
+ * ```ts
85
+ * const local: LocalCheck = descriptors_checkLocal(index);
86
+ * local.descriptors.filter((d: DescriptorChecked): boolean => d.findings.length > 0);
87
+ * ```
88
+ */
89
+ function descriptors_checkLocal(index) {
90
+ const schemaValidate = index.schema === null ? null : schema_compile(index.schema);
91
+ const checked = index.descriptors.map((descriptor) => descriptor_checkAlone(descriptor, schemaValidate));
92
+ const byLower = new Map();
93
+ for (const entry of checked) {
94
+ const name = entry.data?.['name'];
95
+ if (typeof name !== 'string')
96
+ continue;
97
+ byLower.set(name.toLowerCase(), [...(byLower.get(name.toLowerCase()) ?? []), name]);
98
+ }
99
+ const descriptors = checked.map((entry) => {
100
+ const name = entry.data?.['name'];
101
+ if (typeof name !== 'string')
102
+ return entry;
103
+ const others = (byLower.get(name.toLowerCase()) ?? []).filter((other) => other !== name);
104
+ if (others.length === 0)
105
+ return entry;
106
+ return { ...entry, findings: [...entry.findings, { file: entry.file, rule: 4, message: `'${name}' differs only in case from ${others.map((o) => `'${o}'`).join(', ')}` }] };
107
+ });
108
+ return { descriptors, schemaChecked: schemaValidate !== null };
109
+ }
110
+ /**
111
+ * Runs all five rules over an index.
112
+ *
113
+ * @param index - The index.
114
+ * @param options - Whether to skip rule 5, and the fetch it uses.
115
+ * @returns The report.
116
+ * @throws {Error} When the index's schema does not compile.
117
+ *
118
+ * @example
119
+ * ```ts
120
+ * const report: ValidateReport = await pluginIndex_validate(index, { offline: false });
121
+ * ```
122
+ */
123
+ async function pluginIndex_validate(index, options) {
124
+ const local = descriptors_checkLocal(index);
125
+ const findings = local.descriptors.flatMap((entry) => entry.findings);
126
+ if (!options.offline) {
127
+ const fetcher = options.fetcher ?? fetch;
128
+ const images = local.descriptors.flatMap((entry) => {
129
+ const image = entry.data?.['dock_image'];
130
+ return typeof image === 'string' && image !== '' ? [{ file: entry.file, image }] : [];
131
+ });
132
+ const failures = await (0, pool_js_1.items_mapPooled)(images, pool_js_1.POOL_WIDTH, (item) => image_resolve(item.image, fetcher));
133
+ images.forEach((item, at) => {
134
+ const failure = failures[at];
135
+ if (failure)
136
+ findings.push({ file: item.file, rule: 5, message: `${item.image}: ${failure}` });
137
+ });
138
+ }
139
+ findings.sort((a, b) => a.file.localeCompare(b.file) || a.rule - b.rule);
140
+ const rules = [1, 2, 3, 4, 5].map((rule) => {
141
+ const failed = new Set(findings.filter((f) => f.rule === rule).map((f) => f.file)).size;
142
+ if (rule === 1 && !local.schemaChecked)
143
+ return { rule, title: exports.VALIDATE_RULES[rule], checked: false, note: 'no schema', failed };
144
+ if (rule === 5 && options.offline)
145
+ return { rule, title: exports.VALIDATE_RULES[rule], checked: false, note: '--offline', failed };
146
+ return { rule, title: exports.VALIDATE_RULES[rule], checked: true, failed };
147
+ });
148
+ return {
149
+ label: index.label,
150
+ commit: index.commit,
151
+ descriptors: index.descriptors.length,
152
+ findings,
153
+ rules,
154
+ ok: findings.length === 0,
155
+ };
156
+ }
157
+ /**
158
+ * Parses an image reference into what a registry lookup needs.
159
+ *
160
+ * @param image - The reference (`[registry/]repo[:tag][@sha256:…]`).
161
+ * @returns The registry host, repository and reference; null when unreadable.
162
+ *
163
+ * @example
164
+ * ```ts
165
+ * imageReference_parse('ghcr.io/fnndsc/pl-x:1.0@sha256:ab…'); // reference is the digest
166
+ * ```
167
+ */
168
+ function imageReference_parse(image) {
169
+ const at = image.indexOf('@');
170
+ const digest = at === -1 ? null : image.slice(at + 1);
171
+ const named = at === -1 ? image : image.slice(0, at);
172
+ const slash = named.indexOf('/');
173
+ const first = slash === -1 ? '' : named.slice(0, slash);
174
+ const hasRegistry = first.includes('.') || first.includes(':') || first === 'localhost';
175
+ const registryNamed = hasRegistry ? first : DOCKER_HUB.named;
176
+ let rest = hasRegistry ? named.slice(slash + 1) : named;
177
+ const colon = rest.lastIndexOf(':');
178
+ const tag = colon === -1 ? 'latest' : rest.slice(colon + 1);
179
+ if (colon !== -1)
180
+ rest = rest.slice(0, colon);
181
+ if (rest === '' || /\s/.test(image))
182
+ return null;
183
+ const registry = registryNamed === DOCKER_HUB.named ? DOCKER_HUB.host : registryNamed;
184
+ const repository = registry === DOCKER_HUB.host && !rest.includes('/') ? `library/${rest}` : rest;
185
+ return { registry, repository, reference: digest ?? tag };
186
+ }
187
+ /**
188
+ * Asks an image's registry, anonymously, whether its manifest is there.
189
+ *
190
+ * Follows the registry's anonymous bearer-token challenge when it sends one.
191
+ *
192
+ * @param image - The image reference.
193
+ * @param fetcher - The fetch to use.
194
+ * @returns Null when the manifest resolves; else why not, in a few words.
195
+ *
196
+ * @example
197
+ * ```ts
198
+ * await image_resolve('docker.io/library/alpine:3.20', fetch); // null
199
+ * ```
200
+ */
201
+ async function image_resolve(image, fetcher) {
202
+ const reference = imageReference_parse(image);
203
+ if (reference === null)
204
+ return 'not an image reference';
205
+ const url = `https://${reference.registry}/v2/${reference.repository}/manifests/${reference.reference}`;
206
+ try {
207
+ let response = await fetcher(url, { method: 'HEAD', headers: { Accept: MANIFEST_ACCEPT } });
208
+ if (response.status === 401) {
209
+ const token = await registryToken_get(response.headers.get('www-authenticate'), fetcher);
210
+ if (token === null)
211
+ return `${reference.registry} refuses anonymous reads`;
212
+ response = await fetcher(url, { method: 'HEAD', headers: { Accept: MANIFEST_ACCEPT, Authorization: `Bearer ${token}` } });
213
+ }
214
+ if (response.ok)
215
+ return null;
216
+ if (response.status === 404)
217
+ return `not found on ${reference.registry}`;
218
+ if (response.status === 401 || response.status === 403)
219
+ return `${reference.registry} refuses anonymous reads (HTTP ${response.status})`;
220
+ return `${reference.registry} answered HTTP ${response.status}`;
221
+ }
222
+ catch (error) {
223
+ return `${reference.registry} could not be reached (${error instanceof Error ? error.message : String(error)})`;
224
+ }
225
+ }
226
+ /**
227
+ * Gets an anonymous token from a registry's bearer challenge.
228
+ *
229
+ * @param challenge - The `WWW-Authenticate` header, when sent.
230
+ * @param fetcher - The fetch to use.
231
+ * @returns The token, or null when there is no bearer challenge or no token.
232
+ */
233
+ async function registryToken_get(challenge, fetcher) {
234
+ if (challenge === null || !/^bearer\s/i.test(challenge))
235
+ return null;
236
+ const fields = {};
237
+ for (const match of challenge.matchAll(/(\w+)="([^"]*)"/g)) {
238
+ if (match[1] !== undefined && match[2] !== undefined)
239
+ fields[match[1]] = match[2];
240
+ }
241
+ const realm = fields['realm'];
242
+ if (realm === undefined)
243
+ return null;
244
+ const query = new URLSearchParams();
245
+ if (fields['service'] !== undefined)
246
+ query.set('service', fields['service']);
247
+ if (fields['scope'] !== undefined)
248
+ query.set('scope', fields['scope']);
249
+ const response = await fetcher(`${realm}?${query.toString()}`);
250
+ if (!response.ok)
251
+ return null;
252
+ const body = (await response.json());
253
+ const token = body.token ?? body.access_token;
254
+ return typeof token === 'string' ? token : null;
255
+ }
256
+ /**
257
+ * Compiles the index's schema.
258
+ *
259
+ * @param schema - The parsed schema.
260
+ * @returns The validator.
261
+ * @throws {Error} When the schema does not compile.
262
+ */
263
+ function schema_compile(schema) {
264
+ // Strict mode refuses keywords it does not know; the schema belongs to the
265
+ // index and may grow annotations this check has no business refusing.
266
+ const ajv = new _2020_1.default({ allErrors: true, strict: false });
267
+ try {
268
+ return ajv.compile(schema);
269
+ }
270
+ catch (error) {
271
+ throw new Error(`the index's schema does not compile: ${error instanceof Error ? error.message : String(error)}`);
272
+ }
273
+ }
274
+ /**
275
+ * Runs rules 1–3 over one descriptor.
276
+ *
277
+ * @param descriptor - The file.
278
+ * @param schemaValidate - Rule 1's validator, or null when there is no schema.
279
+ * @returns The descriptor parsed, with its findings.
280
+ */
281
+ function descriptor_checkAlone(descriptor, schemaValidate) {
282
+ let parsed;
283
+ try {
284
+ parsed = JSON.parse(descriptor.text);
285
+ }
286
+ catch (error) {
287
+ const reason = error instanceof Error ? error.message : String(error);
288
+ return { file: descriptor.file, text: descriptor.text, data: null, findings: [{ file: descriptor.file, rule: 2, message: `not JSON: ${reason}` }] };
289
+ }
290
+ if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
291
+ return { file: descriptor.file, text: descriptor.text, data: null, findings: [{ file: descriptor.file, rule: 2, message: 'not a JSON object' }] };
292
+ }
293
+ const data = parsed;
294
+ const findings = [];
295
+ if (schemaValidate !== null && !schemaValidate(data)) {
296
+ for (const problem of schemaValidate.errors ?? []) {
297
+ findings.push({ file: descriptor.file, rule: 1, message: schemaError_render(problem) });
298
+ }
299
+ }
300
+ for (const message of uploadRules_check(data))
301
+ findings.push({ file: descriptor.file, rule: 2, message });
302
+ const name = data['name'];
303
+ if (typeof name === 'string' && descriptor.file !== `${name}.json`) {
304
+ findings.push({ file: descriptor.file, rule: 3, message: `names the plugin '${name}': the file should be ${name}.json` });
305
+ }
306
+ return { file: descriptor.file, text: descriptor.text, data, findings };
307
+ }
308
+ /**
309
+ * Renders one schema error as a line.
310
+ *
311
+ * @param problem - The ajv error.
312
+ * @returns `<where> <what>` (`/parameters/0 must have required property 'type'`).
313
+ */
314
+ function schemaError_render(problem) {
315
+ const where = problem.instancePath === '' ? 'the descriptor' : problem.instancePath;
316
+ const extra = problem.keyword === 'additionalProperties'
317
+ ? ` ('${String(problem.params.additionalProperty)}')`
318
+ : '';
319
+ return `${where} ${problem.message ?? 'is invalid'}${extra}`;
320
+ }
321
+ /**
322
+ * Checks CUBE's administrative upload rules (rule 2).
323
+ *
324
+ * @param data - The parsed descriptor.
325
+ * @returns One line per rule broken; empty when CUBE's upload would take it.
326
+ */
327
+ function uploadRules_check(data) {
328
+ const problems = [];
329
+ for (const required of REQUIRED_DESCRIPTORS) {
330
+ if (!(required in data))
331
+ problems.push(`descriptor ${required} is required`);
332
+ }
333
+ const version = data['version'];
334
+ if ('version' in data && (typeof version !== 'string' || !/^[0-9.]+$/.test(version))) {
335
+ problems.push(`version ${JSON.stringify(version)} is not a dotted number`);
336
+ }
337
+ for (const field of ['min_number_of_workers', 'max_number_of_workers']) {
338
+ if (field in data && data[field] !== '' && !integer_isAtLeast(data[field], 1))
339
+ problems.push(`${field} must be a positive integer`);
340
+ }
341
+ for (const field of ['min_gpu_limit', 'max_gpu_limit']) {
342
+ if (field in data && data[field] !== '' && !integer_isAtLeast(data[field], 0))
343
+ problems.push(`${field} must be a non-negative integer`);
344
+ }
345
+ const parameters = data['parameters'];
346
+ if ('parameters' in data && !Array.isArray(parameters))
347
+ problems.push('parameters must be a list');
348
+ if (Array.isArray(parameters)) {
349
+ parameters.forEach((parameter, at) => {
350
+ problems.push(...parameterRules_check(parameter, at));
351
+ });
352
+ }
353
+ return problems;
354
+ }
355
+ /**
356
+ * Checks one parameter against CUBE's upload rules.
357
+ *
358
+ * @param parameter - The parameter as declared.
359
+ * @param at - Its position, for the message.
360
+ * @returns One line per rule broken.
361
+ */
362
+ function parameterRules_check(parameter, at) {
363
+ if (parameter === null || typeof parameter !== 'object')
364
+ return [`parameter ${at} is not an object`];
365
+ const declared = parameter;
366
+ const label = typeof declared['name'] === 'string' ? `parameter '${declared['name']}'` : `parameter ${at}`;
367
+ const type = declared['type'];
368
+ if (type === undefined)
369
+ return [`${label}: type is required`];
370
+ if (typeof type !== 'string' || !UPLOAD_PARAMETER_TYPES.includes(type)) {
371
+ return [`${label}: type ${JSON.stringify(type)} is not one the upload takes (${UPLOAD_PARAMETER_TYPES.join('|')})`];
372
+ }
373
+ if (declared['optional'] === true) {
374
+ if (PATH_TYPES.includes(type))
375
+ return [`${label}: a ${type} parameter cannot be optional`];
376
+ if (declared['default'] === undefined || declared['default'] === null)
377
+ return [`${label}: an optional parameter needs a default`];
378
+ return [];
379
+ }
380
+ if (declared['ui_exposed'] === false)
381
+ return [`${label}: a required parameter must be exposed to the UI`];
382
+ return [];
383
+ }
384
+ /**
385
+ * Reports whether a value is an integer no smaller than a floor.
386
+ *
387
+ * @param value - The value.
388
+ * @param floor - The least integer allowed.
389
+ * @returns True for an integer (or an integer string) at or above the floor.
390
+ */
391
+ function integer_isAtLeast(value, floor) {
392
+ const number = typeof value === 'string' && /^-?\d+$/.test(value) ? Number(value) : typeof value === 'number' ? value : Number.NaN;
393
+ return Number.isInteger(number) && number >= floor;
394
+ }
395
+ //# sourceMappingURL=plugin_validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin_validate.js","sourceRoot":"","sources":["../../src/plugins/plugin_validate.ts"],"names":[],"mappings":"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"}