@andrian.yablonskyy/thub-common 1.0.21 → 1.0.22
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/package.json +1 -1
- package/src/job-spec.schema.js +24 -1
- package/src/validate-job-spec.js +30 -1
package/package.json
CHANGED
package/src/job-spec.schema.js
CHANGED
|
@@ -18,6 +18,10 @@
|
|
|
18
18
|
const DOCKER_IMAGE_PATTERN =
|
|
19
19
|
'^[A-Za-z0-9][A-Za-z0-9.-]*(:[0-9]+)?(/[a-z0-9]+((\\.|_|__|-+)[a-z0-9]+)*)*(:[A-Za-z0-9_][A-Za-z0-9_.-]{0,127})?(@sha256:[a-f0-9]{64})?$',
|
|
20
20
|
|
|
21
|
+
// A git branch or tag name: no leading "-" or "/", no "..", no spaces or
|
|
22
|
+
// the characters git forbids (~^:?*[\), not ending in "/", ".lock" or ".".
|
|
23
|
+
GIT_REF_PATTERN = '^(?![-/])(?!.*\\.\\.)(?!.*//)(?!.*(/|\\.lock|\\.)$)[A-Za-z0-9._/+@-]+$',
|
|
24
|
+
|
|
21
25
|
// Matches the job spec shape documented in README.md §4.3.
|
|
22
26
|
// Deliberately has no field for shell commands: the Client only ever
|
|
23
27
|
// runs the fixed entry point from the downloaded test package — the
|
|
@@ -66,12 +70,31 @@ const DOCKER_IMAGE_PATTERN =
|
|
|
66
70
|
flashAddress: { type: 'string' }
|
|
67
71
|
}
|
|
68
72
|
},
|
|
73
|
+
// Where the tests come from — exactly one of `url` (an archive: tar in
|
|
74
|
+
// any compression, or zip) or `git` (a repository at a branch, tag or
|
|
75
|
+
// commit; default: its default branch) — and how they start: `command`
|
|
76
|
+
// (a shell command run in the sources, if the Client allows it:
|
|
77
|
+
// allowJobCommands), else the package's own run-tests.sh. Combinations
|
|
78
|
+
// are checked in validate-job-spec.js.
|
|
69
79
|
tests: {
|
|
70
80
|
type: 'object',
|
|
71
81
|
additionalProperties: false,
|
|
72
|
-
required: ['url'],
|
|
73
82
|
properties: {
|
|
74
83
|
url: { type: 'string', format: 'uri' },
|
|
84
|
+
git: {
|
|
85
|
+
type: 'object',
|
|
86
|
+
additionalProperties: false,
|
|
87
|
+
required: ['url'],
|
|
88
|
+
properties: {
|
|
89
|
+
url: { type: 'string', minLength: 1, maxLength: 2048 },
|
|
90
|
+
// Ref names as git allows them — never starting with "-",
|
|
91
|
+
// so none can be taken for a git option.
|
|
92
|
+
branch: { type: 'string', maxLength: 255, pattern: GIT_REF_PATTERN },
|
|
93
|
+
tag: { type: 'string', maxLength: 255, pattern: GIT_REF_PATTERN },
|
|
94
|
+
commit: { type: 'string', pattern: '^[0-9a-fA-F]{7,40}$' }
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
command: { type: 'string', minLength: 1, maxLength: 4096 },
|
|
75
98
|
suite: { type: 'string', default: 'default' },
|
|
76
99
|
args: { type: 'array', items: { type: 'string' }, default: [] }
|
|
77
100
|
}
|
package/src/validate-job-spec.js
CHANGED
|
@@ -29,10 +29,39 @@ function validateJobSpec(spec){
|
|
|
29
29
|
const clone = JSON.parse(JSON.stringify(spec ?? {})),
|
|
30
30
|
schemaValid = validateFn(clone),
|
|
31
31
|
errors = schemaValid ? [] : (validateFn.errors || []).map((e) => `${e.instancePath || '/'} ${e.message}`);
|
|
32
|
-
errors.push(...firmwareErrors(clone));
|
|
32
|
+
errors.push(...firmwareErrors(clone), ...testsErrors(clone));
|
|
33
33
|
return { valid: errors.length === 0, spec: clone, errors };
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
// Git transports a Client may fetch test sources over. Never `ext::` (runs
|
|
37
|
+
// a command), `file://` or a local path: the Client also sets
|
|
38
|
+
// GIT_ALLOW_PROTOCOL to the same list (downloader.js).
|
|
39
|
+
const GIT_URL = /^(?:(?:https?|ssh|git):\/\/[^\s]+|[A-Za-z0-9._-]+@[A-Za-z0-9.-]+:[^\s]+)$/;
|
|
40
|
+
|
|
41
|
+
// tests.url (archive) vs tests.git (repo + at most one of branch/tag/commit).
|
|
42
|
+
function testsErrors(spec){
|
|
43
|
+
const tests = spec.tests;
|
|
44
|
+
if (!tests || typeof tests !== 'object'){
|
|
45
|
+
return [];
|
|
46
|
+
}
|
|
47
|
+
if (tests.url && tests.git){
|
|
48
|
+
return ['/tests give either url (an archive) or git (a repository), not both'];
|
|
49
|
+
}
|
|
50
|
+
if (!tests.url && !tests.git){
|
|
51
|
+
return ['/tests needs url (an archive: tar/tar.gz/zip) or git (a repository)'];
|
|
52
|
+
}
|
|
53
|
+
if (tests.git){
|
|
54
|
+
if (!GIT_URL.test(tests.git.url || '')){
|
|
55
|
+
return ['/tests/git/url must be an https://, http://, ssh:// or git:// URL, or user@host:path'];
|
|
56
|
+
}
|
|
57
|
+
const refs = ['branch', 'tag', 'commit'].filter((k) => tests.git[k]);
|
|
58
|
+
if (refs.length > 1){
|
|
59
|
+
return [`/tests/git give at most one of branch, tag or commit (got ${refs.join(', ')})`];
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return [];
|
|
63
|
+
}
|
|
64
|
+
|
|
36
65
|
// firmware.url vs firmware.image — spelled out here rather than as schema
|
|
37
66
|
// oneOf/if-then, whose errors ("must match exactly one schema") say little.
|
|
38
67
|
function firmwareErrors(spec){
|