-
Notifications
You must be signed in to change notification settings - Fork 54
/
validation.ts
91 lines (81 loc) · 2.9 KB
/
validation.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
import fs from 'fs'
import type {ErrorObject} from 'ajv'
import Ajv from 'ajv'
import addFormats from 'ajv-formats'
import sarifJsonSchema from './json-schema/sarif-schema-2.1.0.json'
/**
* Validate the SARIF file against the SARIF schema.
*
* @param sarifReportPath - the path of the SARIF file
*/
export const validateSarif = (sarifReportPath: string) => {
const ajv = new Ajv({allErrors: true})
addFormats(ajv)
const sarifJsonSchemaValidate = ajv.compile(sarifJsonSchema)
try {
const sarifReportContent = JSON.parse(String(fs.readFileSync(sarifReportPath)))
const valid = sarifJsonSchemaValidate(sarifReportContent)
if (!valid) {
const errors = sarifJsonSchemaValidate.errors || []
const errorMessages = errors.map((error: ErrorObject) => {
return `${error.instancePath}: ${error.message}`
})
return errorMessages.join('\n')
}
} catch (error) {
return error.message
}
return undefined
}
/**
* Functions that looks for errors specific to how Datadog processes SARIF file. This way, we
* show the error directly to the user instead of uploading a file we cannot process in our backend.
*
* The function returns a list of errors to show. The return value is empty if there is no error.
*
* @param filePath - the path of the SARIF file.
*/
export const checkForError = (filePath: string): string[] => {
const report: any = JSON.parse(String(fs.readFileSync(filePath)))
const res: string[] = []
if ('runs' in report) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
for (const run of report['runs']) {
const rules: string[] = []
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
if ('tool' in run && 'driver' in run['tool'] && 'rules' in run['tool']['driver']) {
for (const rule of run['tool']['driver']['rules']) {
if ('id' in rule) {
rules.push(rule['id'])
}
}
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
if ('tool' in run && 'extensions' in run['tool']) {
for (const extension of run['tool']['extensions']) {
if ('rules' in extension) {
for (const rule of extension['rules']) {
if ('id' in rule) {
rules.push(rule['id'])
}
}
}
}
}
if ('results' in run) {
for (const result of run['results']) {
if (!('ruleId' in result)) {
res.push('a result should have a ruleId')
continue
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-assignment
const ruleId: string = result['ruleId']
if (rules.indexOf(ruleId) === -1) {
res.push(`result references rule ${ruleId} but rule not found in the tool section`)
}
}
}
}
}
return res
}