@red-hat-developer-hub/backstage-plugin-ai-skills-common 0.0.0-stage → 0.3.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 +27 -0
- package/README.md +126 -2
- package/dist/catalog-helpers.cjs.js +198 -0
- package/dist/catalog-helpers.cjs.js.map +1 -0
- package/dist/catalog-helpers.esm.js +190 -0
- package/dist/catalog-helpers.esm.js.map +1 -0
- package/dist/fixtures.cjs.js +269 -0
- package/dist/fixtures.cjs.js.map +1 -0
- package/dist/fixtures.esm.js +239 -0
- package/dist/fixtures.esm.js.map +1 -0
- package/dist/index.cjs.js +62 -0
- package/dist/index.cjs.js.map +1 -0
- package/dist/index.d.ts +764 -0
- package/dist/index.esm.js +6 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/rest-contract.cjs.js +8 -0
- package/dist/rest-contract.cjs.js.map +1 -0
- package/dist/rest-contract.esm.js +5 -0
- package/dist/rest-contract.esm.js.map +1 -0
- package/dist/snapshot.cjs.js +115 -0
- package/dist/snapshot.cjs.js.map +1 -0
- package/dist/snapshot.esm.js +110 -0
- package/dist/snapshot.esm.js.map +1 -0
- package/dist/validation.cjs.js +442 -0
- package/dist/validation.cjs.js.map +1 -0
- package/dist/validation.esm.js +432 -0
- package/dist/validation.esm.js.map +1 -0
- package/package.json +47 -3
|
@@ -0,0 +1,442 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const MAX_SNAPSHOT_RECORDS = 1e3;
|
|
4
|
+
const MAX_SNAPSHOT_BYTES = 5 * 1024 * 1024;
|
|
5
|
+
const SUPPORTED_SCHEMA_VERSION = "1";
|
|
6
|
+
const SHA256_DIGEST_RE = /^sha256:[0-9a-f]{64}$/;
|
|
7
|
+
const VALID_SOURCE_TYPES = /* @__PURE__ */ new Set([
|
|
8
|
+
"oci",
|
|
9
|
+
"npx"
|
|
10
|
+
]);
|
|
11
|
+
const VALID_STATUSES = /* @__PURE__ */ new Set([
|
|
12
|
+
"loading",
|
|
13
|
+
"ready",
|
|
14
|
+
"partial",
|
|
15
|
+
"failed"
|
|
16
|
+
]);
|
|
17
|
+
const ALLOWED_OCI_EXTENSION_KEYS = /* @__PURE__ */ new Set([
|
|
18
|
+
"namespace",
|
|
19
|
+
"prompt"
|
|
20
|
+
]);
|
|
21
|
+
const ALLOWED_NPX_EXTENSION_KEYS = /* @__PURE__ */ new Set(["type"]);
|
|
22
|
+
function isNonEmptyString(value) {
|
|
23
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
24
|
+
}
|
|
25
|
+
function isValidDigest(digest) {
|
|
26
|
+
return SHA256_DIGEST_RE.test(digest);
|
|
27
|
+
}
|
|
28
|
+
function isValidUtcTimestamp(value) {
|
|
29
|
+
if (!value.endsWith("Z") && !value.endsWith("+00:00")) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
const d = new Date(value);
|
|
33
|
+
return !Number.isNaN(d.getTime());
|
|
34
|
+
}
|
|
35
|
+
function validateAuthor(author, path, errors) {
|
|
36
|
+
if (typeof author !== "object" || author === null) {
|
|
37
|
+
errors.push(`${path}: must be an object`);
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
const a = author;
|
|
41
|
+
if (!isNonEmptyString(a.name)) {
|
|
42
|
+
errors.push(`${path}.name: must be a non-empty string`);
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
if (a.email !== void 0 && typeof a.email !== "string") {
|
|
46
|
+
errors.push(`${path}.email: must be a string when present`);
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
const validAuthorKeys = /* @__PURE__ */ new Set(["name", "email"]);
|
|
50
|
+
for (const key of Object.keys(a)) {
|
|
51
|
+
if (!validAuthorKeys.has(key)) {
|
|
52
|
+
errors.push(`${path}: unknown key '${key}'`);
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
function validateRequiredRecordFields(r, prefix, errors) {
|
|
59
|
+
if (!isNonEmptyString(r.key)) {
|
|
60
|
+
errors.push(`${prefix}.key: must be a non-empty string`);
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
if (!isNonEmptyString(r.name)) {
|
|
64
|
+
errors.push(`${prefix}.name: must be a non-empty string`);
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
if (!isNonEmptyString(r.sourceUri)) {
|
|
68
|
+
errors.push(`${prefix}.sourceUri: must be a non-empty string`);
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
if (!isNonEmptyString(r.digest)) {
|
|
72
|
+
errors.push(`${prefix}.digest: must be a non-empty string`);
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
if (!isValidDigest(r.digest)) {
|
|
76
|
+
errors.push(
|
|
77
|
+
`${prefix}.digest: must match sha256:<64 lowercase hex digits>`
|
|
78
|
+
);
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
function validateOptionalRecordFields(r, prefix, errors) {
|
|
84
|
+
const optionalStrings = [
|
|
85
|
+
"description",
|
|
86
|
+
"version",
|
|
87
|
+
"license",
|
|
88
|
+
"compatibility",
|
|
89
|
+
"owner",
|
|
90
|
+
"lifecycle"
|
|
91
|
+
];
|
|
92
|
+
for (const field of optionalStrings) {
|
|
93
|
+
if (r[field] !== void 0 && typeof r[field] !== "string") {
|
|
94
|
+
errors.push(`${prefix}.${field}: must be a string when present`);
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (!validateAuthorsField(r, prefix, errors)) {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
return validateTagsField(r, prefix, errors);
|
|
102
|
+
}
|
|
103
|
+
function validateAuthorsField(r, prefix, errors) {
|
|
104
|
+
if (r.authors === void 0) {
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
107
|
+
if (!Array.isArray(r.authors)) {
|
|
108
|
+
errors.push(`${prefix}.authors: must be an array when present`);
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
let allValid = true;
|
|
112
|
+
for (let i = 0; i < r.authors.length; i++) {
|
|
113
|
+
if (!validateAuthor(r.authors[i], `${prefix}.authors[${i}]`, errors)) {
|
|
114
|
+
allValid = false;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return allValid;
|
|
118
|
+
}
|
|
119
|
+
function validateTagsField(r, prefix, errors) {
|
|
120
|
+
if (r.tags === void 0) {
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
if (!Array.isArray(r.tags)) {
|
|
124
|
+
errors.push(`${prefix}.tags: must be an array when present`);
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
for (let i = 0; i < r.tags.length; i++) {
|
|
128
|
+
if (typeof r.tags[i] !== "string") {
|
|
129
|
+
errors.push(`${prefix}.tags[${i}]: must be a string`);
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
135
|
+
function validateBaseRecord(record, index, errors) {
|
|
136
|
+
const prefix = `skills[${index}]`;
|
|
137
|
+
if (typeof record !== "object" || record === null) {
|
|
138
|
+
errors.push(`${prefix}: must be an object`);
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
const r = record;
|
|
142
|
+
if (!validateRequiredRecordFields(r, prefix, errors)) {
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
return validateOptionalRecordFields(r, prefix, errors);
|
|
146
|
+
}
|
|
147
|
+
function validateOciContainerKeys(oci, prefix, errors) {
|
|
148
|
+
for (const key of Object.keys(oci)) {
|
|
149
|
+
if (!ALLOWED_OCI_EXTENSION_KEYS.has(key)) {
|
|
150
|
+
errors.push(`${prefix}.extensions.oci: unknown key '${key}'`);
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
if (oci[key] !== void 0 && typeof oci[key] !== "string") {
|
|
154
|
+
errors.push(
|
|
155
|
+
`${prefix}.extensions.oci.${key}: must be a string when present`
|
|
156
|
+
);
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return true;
|
|
161
|
+
}
|
|
162
|
+
function validateOciExtensions(record, index, errors) {
|
|
163
|
+
const prefix = `skills[${index}]`;
|
|
164
|
+
if (record.extensions === void 0) {
|
|
165
|
+
return true;
|
|
166
|
+
}
|
|
167
|
+
if (typeof record.extensions !== "object" || record.extensions === null) {
|
|
168
|
+
errors.push(`${prefix}.extensions: must be an object when present`);
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
const ext = record.extensions;
|
|
172
|
+
for (const key of Object.keys(ext)) {
|
|
173
|
+
if (key !== "oci") {
|
|
174
|
+
errors.push(
|
|
175
|
+
`${prefix}.extensions: unknown container '${key}'; only 'oci' is allowed for OCI source`
|
|
176
|
+
);
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
if (ext.oci === void 0) {
|
|
181
|
+
return true;
|
|
182
|
+
}
|
|
183
|
+
if (typeof ext.oci !== "object" || ext.oci === null) {
|
|
184
|
+
errors.push(`${prefix}.extensions.oci: must be an object when present`);
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
return validateOciContainerKeys(
|
|
188
|
+
ext.oci,
|
|
189
|
+
prefix,
|
|
190
|
+
errors
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
function validateNpxContainerKeys(npx, prefix, errors) {
|
|
194
|
+
for (const key of Object.keys(npx)) {
|
|
195
|
+
if (!ALLOWED_NPX_EXTENSION_KEYS.has(key)) {
|
|
196
|
+
errors.push(`${prefix}.extensions.npx: unknown key '${key}'`);
|
|
197
|
+
return false;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
if (npx.type !== void 0 && npx.type !== "skill-md") {
|
|
201
|
+
errors.push(
|
|
202
|
+
`${prefix}.extensions.npx.type: must be 'skill-md' when present`
|
|
203
|
+
);
|
|
204
|
+
return false;
|
|
205
|
+
}
|
|
206
|
+
return true;
|
|
207
|
+
}
|
|
208
|
+
function validateNpxExtensions(record, index, errors) {
|
|
209
|
+
const prefix = `skills[${index}]`;
|
|
210
|
+
if (record.extensions === void 0) {
|
|
211
|
+
return true;
|
|
212
|
+
}
|
|
213
|
+
if (typeof record.extensions !== "object" || record.extensions === null) {
|
|
214
|
+
errors.push(`${prefix}.extensions: must be an object when present`);
|
|
215
|
+
return false;
|
|
216
|
+
}
|
|
217
|
+
const ext = record.extensions;
|
|
218
|
+
for (const key of Object.keys(ext)) {
|
|
219
|
+
if (key !== "npx") {
|
|
220
|
+
errors.push(
|
|
221
|
+
`${prefix}.extensions: unknown container '${key}'; only 'npx' is allowed for npx source`
|
|
222
|
+
);
|
|
223
|
+
return false;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
if (ext.npx === void 0) {
|
|
227
|
+
return true;
|
|
228
|
+
}
|
|
229
|
+
if (typeof ext.npx !== "object" || ext.npx === null) {
|
|
230
|
+
errors.push(`${prefix}.extensions.npx: must be an object when present`);
|
|
231
|
+
return false;
|
|
232
|
+
}
|
|
233
|
+
return validateNpxContainerKeys(
|
|
234
|
+
ext.npx,
|
|
235
|
+
prefix,
|
|
236
|
+
errors
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
function validateRecordExtensions(record, index, sourceType, errors) {
|
|
240
|
+
if (sourceType === "oci") {
|
|
241
|
+
return validateOciExtensions(record, index, errors);
|
|
242
|
+
}
|
|
243
|
+
return validateNpxExtensions(record, index, errors);
|
|
244
|
+
}
|
|
245
|
+
function validateSnapshotShape(s, errors) {
|
|
246
|
+
if (s.schemaVersion !== SUPPORTED_SCHEMA_VERSION) {
|
|
247
|
+
errors.push(
|
|
248
|
+
`schemaVersion: must be '${SUPPORTED_SCHEMA_VERSION}', got '${String(
|
|
249
|
+
s.schemaVersion
|
|
250
|
+
)}'`
|
|
251
|
+
);
|
|
252
|
+
return null;
|
|
253
|
+
}
|
|
254
|
+
if (typeof s.source !== "object" || s.source === null) {
|
|
255
|
+
errors.push("source: must be an object");
|
|
256
|
+
return null;
|
|
257
|
+
}
|
|
258
|
+
const source = s.source;
|
|
259
|
+
if (!isNonEmptyString(source.id)) {
|
|
260
|
+
errors.push("source.id: must be a non-empty string");
|
|
261
|
+
}
|
|
262
|
+
if (!VALID_SOURCE_TYPES.has(source.type)) {
|
|
263
|
+
errors.push(
|
|
264
|
+
`source.type: must be one of 'oci', 'npx', got '${String(source.type)}'`
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
if (errors.length > 0) {
|
|
268
|
+
return null;
|
|
269
|
+
}
|
|
270
|
+
const sourceType = source.type;
|
|
271
|
+
if (!VALID_STATUSES.has(s.status)) {
|
|
272
|
+
errors.push(
|
|
273
|
+
`status: must be one of 'loading', 'ready', 'partial', 'failed', got '${String(
|
|
274
|
+
s.status
|
|
275
|
+
)}'`
|
|
276
|
+
);
|
|
277
|
+
return null;
|
|
278
|
+
}
|
|
279
|
+
const status = s.status;
|
|
280
|
+
if (!Array.isArray(s.skills)) {
|
|
281
|
+
errors.push("skills: must be an array");
|
|
282
|
+
return null;
|
|
283
|
+
}
|
|
284
|
+
if (!Array.isArray(s.failedSkillKeys)) {
|
|
285
|
+
errors.push("failedSkillKeys: must be an array");
|
|
286
|
+
return null;
|
|
287
|
+
}
|
|
288
|
+
return { sourceType, status };
|
|
289
|
+
}
|
|
290
|
+
function validateObservedAt(s, status, errors) {
|
|
291
|
+
if (status === "loading") {
|
|
292
|
+
if (s.observedAt !== null) {
|
|
293
|
+
errors.push("observedAt: must be null for loading status");
|
|
294
|
+
}
|
|
295
|
+
} else if (typeof s.observedAt !== "string") {
|
|
296
|
+
errors.push(
|
|
297
|
+
"observedAt: must be a UTC timestamp string for completed status"
|
|
298
|
+
);
|
|
299
|
+
} else if (!isValidUtcTimestamp(s.observedAt)) {
|
|
300
|
+
errors.push("observedAt: must be a valid UTC ISO 8601 timestamp");
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
function validateStatusInvariants(skills, failedSkillKeys, status, errors) {
|
|
304
|
+
if (status === "loading") {
|
|
305
|
+
if (skills.length > 0) {
|
|
306
|
+
errors.push("skills: must be empty for loading status");
|
|
307
|
+
}
|
|
308
|
+
if (failedSkillKeys.length > 0) {
|
|
309
|
+
errors.push("failedSkillKeys: must be empty for loading status");
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
if (status === "ready") {
|
|
313
|
+
if (failedSkillKeys.length > 0) {
|
|
314
|
+
errors.push("failedSkillKeys: must be empty for ready status");
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
if (status === "failed") {
|
|
318
|
+
if (skills.length > 0) {
|
|
319
|
+
errors.push("skills: must be empty for failed status");
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
function validateSnapshotRecords(skills, sourceType, errors) {
|
|
324
|
+
const skillKeys = /* @__PURE__ */ new Set();
|
|
325
|
+
for (let i = 0; i < skills.length; i++) {
|
|
326
|
+
const record = skills[i];
|
|
327
|
+
if (validateBaseRecord(record, i, errors)) {
|
|
328
|
+
const r = record;
|
|
329
|
+
if (skillKeys.has(r.key)) {
|
|
330
|
+
errors.push(`skills[${i}].key: duplicate key '${r.key}'`);
|
|
331
|
+
}
|
|
332
|
+
skillKeys.add(r.key);
|
|
333
|
+
}
|
|
334
|
+
if (typeof record === "object" && record !== null) {
|
|
335
|
+
validateRecordExtensions(
|
|
336
|
+
record,
|
|
337
|
+
i,
|
|
338
|
+
sourceType,
|
|
339
|
+
errors
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
return skillKeys;
|
|
344
|
+
}
|
|
345
|
+
function validateDisjointKeys(failedSkillKeys, skillKeys, errors) {
|
|
346
|
+
for (let i = 0; i < failedSkillKeys.length; i++) {
|
|
347
|
+
if (!isNonEmptyString(failedSkillKeys[i])) {
|
|
348
|
+
errors.push(`failedSkillKeys[${i}]: must be a non-empty string`);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
const failedKeys = /* @__PURE__ */ new Set();
|
|
352
|
+
for (const fk of failedSkillKeys) {
|
|
353
|
+
if (typeof fk === "string") {
|
|
354
|
+
if (failedKeys.has(fk)) {
|
|
355
|
+
errors.push(`failedSkillKeys: duplicate key '${fk}'`);
|
|
356
|
+
}
|
|
357
|
+
failedKeys.add(fk);
|
|
358
|
+
if (skillKeys.has(fk)) {
|
|
359
|
+
errors.push(`failedSkillKeys: key '${fk}' overlaps with skills`);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
function validateSnapshot(snapshot) {
|
|
365
|
+
const errors = [];
|
|
366
|
+
if (typeof snapshot !== "object" || snapshot === null) {
|
|
367
|
+
return { valid: false, errors: ["snapshot: must be an object"] };
|
|
368
|
+
}
|
|
369
|
+
const s = snapshot;
|
|
370
|
+
const shape = validateSnapshotShape(s, errors);
|
|
371
|
+
if (shape === null) {
|
|
372
|
+
return { valid: false, errors };
|
|
373
|
+
}
|
|
374
|
+
const { sourceType, status } = shape;
|
|
375
|
+
validateObservedAt(s, status, errors);
|
|
376
|
+
validateStatusInvariants(
|
|
377
|
+
s.skills,
|
|
378
|
+
s.failedSkillKeys,
|
|
379
|
+
status,
|
|
380
|
+
errors
|
|
381
|
+
);
|
|
382
|
+
const skillKeys = validateSnapshotRecords(
|
|
383
|
+
s.skills,
|
|
384
|
+
sourceType,
|
|
385
|
+
errors
|
|
386
|
+
);
|
|
387
|
+
validateDisjointKeys(s.failedSkillKeys, skillKeys, errors);
|
|
388
|
+
if (s.skills.length > MAX_SNAPSHOT_RECORDS) {
|
|
389
|
+
errors.push(
|
|
390
|
+
`skills: count ${s.skills.length} exceeds maximum ${MAX_SNAPSHOT_RECORDS}`
|
|
391
|
+
);
|
|
392
|
+
}
|
|
393
|
+
return { valid: errors.length === 0, errors };
|
|
394
|
+
}
|
|
395
|
+
function utf8ByteLength(str) {
|
|
396
|
+
if (typeof TextEncoder !== "undefined") {
|
|
397
|
+
return new TextEncoder().encode(str).byteLength;
|
|
398
|
+
}
|
|
399
|
+
return Buffer.byteLength(str, "utf8");
|
|
400
|
+
}
|
|
401
|
+
function validateSnapshotSize(snapshot) {
|
|
402
|
+
const errors = [];
|
|
403
|
+
const serialized = JSON.stringify(snapshot);
|
|
404
|
+
const byteLength = utf8ByteLength(serialized);
|
|
405
|
+
if (byteLength > MAX_SNAPSHOT_BYTES) {
|
|
406
|
+
errors.push(
|
|
407
|
+
`snapshot serialized size ${byteLength} bytes exceeds maximum ${MAX_SNAPSHOT_BYTES} bytes`
|
|
408
|
+
);
|
|
409
|
+
}
|
|
410
|
+
return { valid: errors.length === 0, errors };
|
|
411
|
+
}
|
|
412
|
+
function isOciSkillRecord(record, sourceType) {
|
|
413
|
+
if (sourceType !== "oci") {
|
|
414
|
+
return false;
|
|
415
|
+
}
|
|
416
|
+
if (!("extensions" in record) || record.extensions === void 0) {
|
|
417
|
+
return true;
|
|
418
|
+
}
|
|
419
|
+
const ext = record.extensions;
|
|
420
|
+
return ext !== void 0 && !("npx" in ext);
|
|
421
|
+
}
|
|
422
|
+
function isNpxSkillRecord(record, sourceType) {
|
|
423
|
+
if (sourceType !== "npx") {
|
|
424
|
+
return false;
|
|
425
|
+
}
|
|
426
|
+
if (!("extensions" in record) || record.extensions === void 0) {
|
|
427
|
+
return true;
|
|
428
|
+
}
|
|
429
|
+
const ext = record.extensions;
|
|
430
|
+
return ext !== void 0 && !("oci" in ext);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
exports.MAX_SNAPSHOT_BYTES = MAX_SNAPSHOT_BYTES;
|
|
434
|
+
exports.MAX_SNAPSHOT_RECORDS = MAX_SNAPSHOT_RECORDS;
|
|
435
|
+
exports.SUPPORTED_SCHEMA_VERSION = SUPPORTED_SCHEMA_VERSION;
|
|
436
|
+
exports.isNpxSkillRecord = isNpxSkillRecord;
|
|
437
|
+
exports.isOciSkillRecord = isOciSkillRecord;
|
|
438
|
+
exports.isValidDigest = isValidDigest;
|
|
439
|
+
exports.isValidUtcTimestamp = isValidUtcTimestamp;
|
|
440
|
+
exports.validateSnapshot = validateSnapshot;
|
|
441
|
+
exports.validateSnapshotSize = validateSnapshotSize;
|
|
442
|
+
//# sourceMappingURL=validation.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.cjs.js","sources":["../src/validation.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n NpxSkillRecord,\n OciSkillRecord,\n SkillAuthor,\n SkillRecord,\n SkillSnapshot,\n SkillSourceType,\n SnapshotStatus,\n} from './types';\n\n/**\n * Maximum number of records in a single snapshot (design D2).\n *\n * @public\n */\nexport const MAX_SNAPSHOT_RECORDS = 1_000;\n\n/**\n * Maximum serialized snapshot size in bytes (design D2: 5 MiB).\n *\n * @public\n */\nexport const MAX_SNAPSHOT_BYTES = 5 * 1024 * 1024;\n\n/**\n * Supported schema version.\n *\n * @public\n */\nexport const SUPPORTED_SCHEMA_VERSION = '1';\n\n/** Regex for valid SHA-256 digest: `sha256:` followed by 64 lowercase hex. */\nconst SHA256_DIGEST_RE = /^sha256:[0-9a-f]{64}$/;\n\n/** Valid source types. */\nconst VALID_SOURCE_TYPES: ReadonlySet<string> = new Set<SkillSourceType>([\n 'oci',\n 'npx',\n]);\n\n/** Valid snapshot statuses. */\nconst VALID_STATUSES: ReadonlySet<string> = new Set<SnapshotStatus>([\n 'loading',\n 'ready',\n 'partial',\n 'failed',\n]);\n\n/** Allowed OCI extension keys. */\nconst ALLOWED_OCI_EXTENSION_KEYS: ReadonlySet<string> = new Set([\n 'namespace',\n 'prompt',\n]);\n\n/** Allowed npx extension keys. */\nconst ALLOWED_NPX_EXTENSION_KEYS: ReadonlySet<string> = new Set(['type']);\n\n/**\n * Result of a validation operation.\n *\n * @public\n */\nexport interface ValidationResult {\n /** Whether the validated input passed all checks. */\n valid: boolean;\n /** Human-readable error messages for each failed check. */\n errors: string[];\n}\n\n/**\n * Returns true when the value is a non-empty string after trimming.\n */\nfunction isNonEmptyString(value: unknown): value is string {\n return typeof value === 'string' && value.trim().length > 0;\n}\n\n/**\n * Validates a SHA-256 digest string.\n *\n * @public\n */\nexport function isValidDigest(digest: string): boolean {\n return SHA256_DIGEST_RE.test(digest);\n}\n\n/**\n * Validates an ISO 8601 UTC date string. Accepts strings ending in `Z`\n * or `+00:00` that parse to a valid Date.\n *\n * @public\n */\nexport function isValidUtcTimestamp(value: string): boolean {\n if (!value.endsWith('Z') && !value.endsWith('+00:00')) {\n return false;\n }\n const d = new Date(value);\n return !Number.isNaN(d.getTime());\n}\n\n/**\n * Validates a single SkillAuthor entry.\n */\nfunction validateAuthor(\n author: unknown,\n path: string,\n errors: string[],\n): author is SkillAuthor {\n if (typeof author !== 'object' || author === null) {\n errors.push(`${path}: must be an object`);\n return false;\n }\n const a = author as Record<string, unknown>;\n if (!isNonEmptyString(a.name)) {\n errors.push(`${path}.name: must be a non-empty string`);\n return false;\n }\n if (a.email !== undefined && typeof a.email !== 'string') {\n errors.push(`${path}.email: must be a string when present`);\n return false;\n }\n // Reject unknown keys on author\n const validAuthorKeys = new Set(['name', 'email']);\n for (const key of Object.keys(a)) {\n if (!validAuthorKeys.has(key)) {\n errors.push(`${path}: unknown key '${key}'`);\n return false;\n }\n }\n return true;\n}\n\n/**\n * Validates the required fields of a SkillRecord (key, name, sourceUri, digest).\n */\nfunction validateRequiredRecordFields(\n r: Record<string, unknown>,\n prefix: string,\n errors: string[],\n): boolean {\n if (!isNonEmptyString(r.key)) {\n errors.push(`${prefix}.key: must be a non-empty string`);\n return false;\n }\n if (!isNonEmptyString(r.name)) {\n errors.push(`${prefix}.name: must be a non-empty string`);\n return false;\n }\n if (!isNonEmptyString(r.sourceUri)) {\n errors.push(`${prefix}.sourceUri: must be a non-empty string`);\n return false;\n }\n if (!isNonEmptyString(r.digest)) {\n errors.push(`${prefix}.digest: must be a non-empty string`);\n return false;\n }\n if (!isValidDigest(r.digest as string)) {\n errors.push(\n `${prefix}.digest: must match sha256:<64 lowercase hex digits>`,\n );\n return false;\n }\n return true;\n}\n\n/**\n * Validates optional string fields, authors array, and tags array on a record.\n */\nfunction validateOptionalRecordFields(\n r: Record<string, unknown>,\n prefix: string,\n errors: string[],\n): boolean {\n const optionalStrings = [\n 'description',\n 'version',\n 'license',\n 'compatibility',\n 'owner',\n 'lifecycle',\n ] as const;\n for (const field of optionalStrings) {\n if (r[field] !== undefined && typeof r[field] !== 'string') {\n errors.push(`${prefix}.${field}: must be a string when present`);\n return false;\n }\n }\n\n if (!validateAuthorsField(r, prefix, errors)) {\n return false;\n }\n\n return validateTagsField(r, prefix, errors);\n}\n\n/**\n * Validates the optional `authors` array field on a record.\n */\nfunction validateAuthorsField(\n r: Record<string, unknown>,\n prefix: string,\n errors: string[],\n): boolean {\n if (r.authors === undefined) {\n return true;\n }\n if (!Array.isArray(r.authors)) {\n errors.push(`${prefix}.authors: must be an array when present`);\n return false;\n }\n let allValid = true;\n for (let i = 0; i < r.authors.length; i++) {\n if (!validateAuthor(r.authors[i], `${prefix}.authors[${i}]`, errors)) {\n allValid = false;\n }\n }\n return allValid;\n}\n\n/**\n * Validates the optional `tags` array field on a record.\n */\nfunction validateTagsField(\n r: Record<string, unknown>,\n prefix: string,\n errors: string[],\n): boolean {\n if (r.tags === undefined) {\n return true;\n }\n if (!Array.isArray(r.tags)) {\n errors.push(`${prefix}.tags: must be an array when present`);\n return false;\n }\n for (let i = 0; i < r.tags.length; i++) {\n if (typeof r.tags[i] !== 'string') {\n errors.push(`${prefix}.tags[${i}]: must be a string`);\n return false;\n }\n }\n return true;\n}\n\n/**\n * Validates a base SkillRecord (common fields).\n */\nfunction validateBaseRecord(\n record: unknown,\n index: number,\n errors: string[],\n): record is SkillRecord {\n const prefix = `skills[${index}]`;\n if (typeof record !== 'object' || record === null) {\n errors.push(`${prefix}: must be an object`);\n return false;\n }\n const r = record as Record<string, unknown>;\n\n if (!validateRequiredRecordFields(r, prefix, errors)) {\n return false;\n }\n\n return validateOptionalRecordFields(r, prefix, errors);\n}\n\n/**\n * Validates keys within the OCI extension container.\n */\nfunction validateOciContainerKeys(\n oci: Record<string, unknown>,\n prefix: string,\n errors: string[],\n): boolean {\n for (const key of Object.keys(oci)) {\n if (!ALLOWED_OCI_EXTENSION_KEYS.has(key)) {\n errors.push(`${prefix}.extensions.oci: unknown key '${key}'`);\n return false;\n }\n if (oci[key] !== undefined && typeof oci[key] !== 'string') {\n errors.push(\n `${prefix}.extensions.oci.${key}: must be a string when present`,\n );\n return false;\n }\n }\n return true;\n}\n\n/**\n * Validates OCI-specific extension fields. Rejects unknown extension\n * containers and unknown keys within the `oci` container.\n */\nfunction validateOciExtensions(\n record: Record<string, unknown>,\n index: number,\n errors: string[],\n): boolean {\n const prefix = `skills[${index}]`;\n if (record.extensions === undefined) {\n return true;\n }\n if (typeof record.extensions !== 'object' || record.extensions === null) {\n errors.push(`${prefix}.extensions: must be an object when present`);\n return false;\n }\n const ext = record.extensions as Record<string, unknown>;\n\n // Only 'oci' container is allowed for OCI records\n for (const key of Object.keys(ext)) {\n if (key !== 'oci') {\n errors.push(\n `${prefix}.extensions: unknown container '${key}'; only 'oci' is allowed for OCI source`,\n );\n return false;\n }\n }\n\n if (ext.oci === undefined) {\n return true;\n }\n if (typeof ext.oci !== 'object' || ext.oci === null) {\n errors.push(`${prefix}.extensions.oci: must be an object when present`);\n return false;\n }\n return validateOciContainerKeys(\n ext.oci as Record<string, unknown>,\n prefix,\n errors,\n );\n}\n\n/**\n * Validates keys within the npx extension container.\n */\nfunction validateNpxContainerKeys(\n npx: Record<string, unknown>,\n prefix: string,\n errors: string[],\n): boolean {\n for (const key of Object.keys(npx)) {\n if (!ALLOWED_NPX_EXTENSION_KEYS.has(key)) {\n errors.push(`${prefix}.extensions.npx: unknown key '${key}'`);\n return false;\n }\n }\n if (npx.type !== undefined && npx.type !== 'skill-md') {\n errors.push(\n `${prefix}.extensions.npx.type: must be 'skill-md' when present`,\n );\n return false;\n }\n return true;\n}\n\n/**\n * Validates npx-specific extension fields. Rejects unknown extension\n * containers and unknown keys within the `npx` container.\n */\nfunction validateNpxExtensions(\n record: Record<string, unknown>,\n index: number,\n errors: string[],\n): boolean {\n const prefix = `skills[${index}]`;\n if (record.extensions === undefined) {\n return true;\n }\n if (typeof record.extensions !== 'object' || record.extensions === null) {\n errors.push(`${prefix}.extensions: must be an object when present`);\n return false;\n }\n const ext = record.extensions as Record<string, unknown>;\n\n // Only 'npx' container is allowed for npx records\n for (const key of Object.keys(ext)) {\n if (key !== 'npx') {\n errors.push(\n `${prefix}.extensions: unknown container '${key}'; only 'npx' is allowed for npx source`,\n );\n return false;\n }\n }\n\n if (ext.npx === undefined) {\n return true;\n }\n if (typeof ext.npx !== 'object' || ext.npx === null) {\n errors.push(`${prefix}.extensions.npx: must be an object when present`);\n return false;\n }\n return validateNpxContainerKeys(\n ext.npx as Record<string, unknown>,\n prefix,\n errors,\n );\n}\n\n/**\n * Validates source-discriminated records: OCI snapshots accept only\n * OCI extension containers; npx snapshots accept only npx extension\n * containers.\n */\nfunction validateRecordExtensions(\n record: Record<string, unknown>,\n index: number,\n sourceType: SkillSourceType,\n errors: string[],\n): boolean {\n if (sourceType === 'oci') {\n return validateOciExtensions(record, index, errors);\n }\n return validateNpxExtensions(record, index, errors);\n}\n\n/**\n * Validates the structural shape of a snapshot: schemaVersion, source,\n * status, and the presence of skills and failedSkillKeys arrays.\n *\n * Returns the parsed sourceType and status on success, or null on failure\n * (with errors pushed to the provided array).\n */\nfunction validateSnapshotShape(\n s: Record<string, unknown>,\n errors: string[],\n): { sourceType: SkillSourceType; status: SnapshotStatus } | null {\n // Schema version\n if (s.schemaVersion !== SUPPORTED_SCHEMA_VERSION) {\n errors.push(\n `schemaVersion: must be '${SUPPORTED_SCHEMA_VERSION}', got '${String(\n s.schemaVersion,\n )}'`,\n );\n return null;\n }\n\n // Source\n if (typeof s.source !== 'object' || s.source === null) {\n errors.push('source: must be an object');\n return null;\n }\n const source = s.source as Record<string, unknown>;\n if (!isNonEmptyString(source.id)) {\n errors.push('source.id: must be a non-empty string');\n }\n if (!VALID_SOURCE_TYPES.has(source.type as string)) {\n errors.push(\n `source.type: must be one of 'oci', 'npx', got '${String(source.type)}'`,\n );\n }\n\n // Early return if source is invalid — can't validate records\n if (errors.length > 0) {\n return null;\n }\n const sourceType = source.type as SkillSourceType;\n\n // Status\n if (!VALID_STATUSES.has(s.status as string)) {\n errors.push(\n `status: must be one of 'loading', 'ready', 'partial', 'failed', got '${String(\n s.status,\n )}'`,\n );\n return null;\n }\n const status = s.status as SnapshotStatus;\n\n // Arrays must be present\n if (!Array.isArray(s.skills)) {\n errors.push('skills: must be an array');\n return null;\n }\n if (!Array.isArray(s.failedSkillKeys)) {\n errors.push('failedSkillKeys: must be an array');\n return null;\n }\n\n return { sourceType, status };\n}\n\n/**\n * Validates the `observedAt` field based on the snapshot status.\n */\nfunction validateObservedAt(\n s: Record<string, unknown>,\n status: SnapshotStatus,\n errors: string[],\n): void {\n if (status === 'loading') {\n if (s.observedAt !== null) {\n errors.push('observedAt: must be null for loading status');\n }\n } else if (typeof s.observedAt !== 'string') {\n errors.push(\n 'observedAt: must be a UTC timestamp string for completed status',\n );\n } else if (!isValidUtcTimestamp(s.observedAt)) {\n errors.push('observedAt: must be a valid UTC ISO 8601 timestamp');\n }\n}\n\n/**\n * Validates status invariants per design D6.\n */\nfunction validateStatusInvariants(\n skills: unknown[],\n failedSkillKeys: unknown[],\n status: SnapshotStatus,\n errors: string[],\n): void {\n if (status === 'loading') {\n if (skills.length > 0) {\n errors.push('skills: must be empty for loading status');\n }\n if (failedSkillKeys.length > 0) {\n errors.push('failedSkillKeys: must be empty for loading status');\n }\n }\n if (status === 'ready') {\n if (failedSkillKeys.length > 0) {\n errors.push('failedSkillKeys: must be empty for ready status');\n }\n }\n if (status === 'failed') {\n if (skills.length > 0) {\n errors.push('skills: must be empty for failed status');\n }\n }\n}\n\n/**\n * Validates individual records and collects unique skill keys.\n */\nfunction validateSnapshotRecords(\n skills: unknown[],\n sourceType: SkillSourceType,\n errors: string[],\n): Set<string> {\n const skillKeys = new Set<string>();\n for (let i = 0; i < skills.length; i++) {\n const record = skills[i];\n if (validateBaseRecord(record, i, errors)) {\n const r = record as SkillRecord;\n if (skillKeys.has(r.key)) {\n errors.push(`skills[${i}].key: duplicate key '${r.key}'`);\n }\n skillKeys.add(r.key);\n }\n if (typeof record === 'object' && record !== null) {\n validateRecordExtensions(\n record as Record<string, unknown>,\n i,\n sourceType,\n errors,\n );\n }\n }\n return skillKeys;\n}\n\n/**\n * Validates failedSkillKeys entries and checks for disjointness\n * with successful skill keys.\n */\nfunction validateDisjointKeys(\n failedSkillKeys: unknown[],\n skillKeys: Set<string>,\n errors: string[],\n): void {\n for (let i = 0; i < failedSkillKeys.length; i++) {\n if (!isNonEmptyString(failedSkillKeys[i])) {\n errors.push(`failedSkillKeys[${i}]: must be a non-empty string`);\n }\n }\n\n const failedKeys = new Set<string>();\n for (const fk of failedSkillKeys) {\n if (typeof fk === 'string') {\n if (failedKeys.has(fk)) {\n errors.push(`failedSkillKeys: duplicate key '${fk}'`);\n }\n failedKeys.add(fk);\n if (skillKeys.has(fk)) {\n errors.push(`failedSkillKeys: key '${fk}' overlaps with skills`);\n }\n }\n }\n}\n\n/**\n * Validates a complete v1 SkillSnapshot.\n *\n * Checks:\n * - Schema version is supported\n * - Source identity is valid\n * - Status is valid\n * - Status invariants (loading/ready/partial/failed) per design D6\n * - Timestamp validity\n * - Record validation including source-discriminated extensions\n * - Unique record keys\n * - Disjoint successful/failed key sets\n * - Count and size bounds\n *\n * Does NOT check deterministic ordering — that is the producer's\n * responsibility enforced by {@link boundSnapshot}.\n *\n * @public\n */\nexport function validateSnapshot(snapshot: unknown): ValidationResult {\n const errors: string[] = [];\n\n if (typeof snapshot !== 'object' || snapshot === null) {\n return { valid: false, errors: ['snapshot: must be an object'] };\n }\n const s = snapshot as Record<string, unknown>;\n\n const shape = validateSnapshotShape(s, errors);\n if (shape === null) {\n return { valid: false, errors };\n }\n const { sourceType, status } = shape;\n\n validateObservedAt(s, status, errors);\n validateStatusInvariants(\n s.skills as unknown[],\n s.failedSkillKeys as unknown[],\n status,\n errors,\n );\n\n const skillKeys = validateSnapshotRecords(\n s.skills as unknown[],\n sourceType,\n errors,\n );\n\n validateDisjointKeys(s.failedSkillKeys as unknown[], skillKeys, errors);\n\n if ((s.skills as unknown[]).length > MAX_SNAPSHOT_RECORDS) {\n errors.push(\n `skills: count ${\n (s.skills as unknown[]).length\n } exceeds maximum ${MAX_SNAPSHOT_RECORDS}`,\n );\n }\n\n return { valid: errors.length === 0, errors };\n}\n\n/**\n * Returns the UTF-8 byte length of a string in a portable way.\n *\n * Uses `TextEncoder` when available (browsers, modern Node.js) and\n * falls back to `Buffer.byteLength` in Node-only environments (e.g.,\n * older Jest jsdom setups where `TextEncoder` is not global).\n */\nfunction utf8ByteLength(str: string): number {\n if (typeof TextEncoder !== 'undefined') {\n return new TextEncoder().encode(str).byteLength;\n }\n // Node.js fallback for environments where TextEncoder is not global\n return Buffer.byteLength(str, 'utf8');\n}\n\n/**\n * Validates the serialized byte size of a snapshot against the 5 MiB\n * limit. Call after `validateSnapshot` succeeds.\n *\n * @public\n */\nexport function validateSnapshotSize(\n snapshot: SkillSnapshot,\n): ValidationResult {\n const errors: string[] = [];\n const serialized = JSON.stringify(snapshot);\n const byteLength = utf8ByteLength(serialized);\n if (byteLength > MAX_SNAPSHOT_BYTES) {\n errors.push(\n `snapshot serialized size ${byteLength} bytes exceeds maximum ${MAX_SNAPSHOT_BYTES} bytes`,\n );\n }\n return { valid: errors.length === 0, errors };\n}\n\n/**\n * Type guard for OciSkillRecord.\n *\n * Requires the snapshot's `source.type` to disambiguate records that\n * have no `extensions` field — a bare record is only an OCI record\n * when the enclosing snapshot source is `'oci'`.\n *\n * @public\n */\nexport function isOciSkillRecord(\n record: SkillRecord,\n sourceType: SkillSourceType,\n): record is OciSkillRecord {\n if (sourceType !== 'oci') {\n return false;\n }\n if (!('extensions' in record) || record.extensions === undefined) {\n return true; // No extensions is valid for OCI\n }\n const ext = (record as OciSkillRecord).extensions;\n return ext !== undefined && !('npx' in ext);\n}\n\n/**\n * Type guard for NpxSkillRecord.\n *\n * Requires the snapshot's `source.type` to disambiguate records that\n * have no `extensions` field — a bare record is only an npx record\n * when the enclosing snapshot source is `'npx'`.\n *\n * @public\n */\nexport function isNpxSkillRecord(\n record: SkillRecord,\n sourceType: SkillSourceType,\n): record is NpxSkillRecord {\n if (sourceType !== 'npx') {\n return false;\n }\n if (!('extensions' in record) || record.extensions === undefined) {\n return true; // No extensions is valid for npx\n }\n const ext = (record as NpxSkillRecord).extensions;\n return ext !== undefined && !('oci' in ext);\n}\n"],"names":[],"mappings":"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"}
|