@fabasoad/sarif-to-slack 1.3.0 → 1.3.2
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/.gitattributes +1 -0
- package/.github/workflows/release.yml +3 -3
- package/.github/workflows/send-sarif-to-slack.yml +15 -12
- package/.pre-commit-config.yaml +2 -1
- package/.tool-versions +1 -1
- package/README.md +47 -12
- package/biome.json +5 -52
- package/dist/Logger.js +51 -22
- package/dist/SarifToSlackClient.d.ts +12 -10
- package/dist/SarifToSlackClient.d.ts.map +1 -1
- package/dist/SarifToSlackClient.js +28 -15
- package/dist/index.cjs +612 -244
- package/dist/index.d.ts +1 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -8
- package/dist/model/Finding.js +4 -3
- package/dist/model/SlackMessage.d.ts +0 -16
- package/dist/model/SlackMessage.d.ts.map +1 -1
- package/dist/model/color/ColorIdentification.js +50 -46
- package/dist/model/color/ColorOptions.d.ts +1 -1
- package/dist/model/color/ColorOptions.d.ts.map +1 -1
- package/dist/representations/CompactGroupByRepresentation.js +2 -2
- package/dist/representations/Representation.js +6 -2
- package/dist/representations/RepresentationFactory.js +19 -1
- package/dist/representations/TableGroupByRunPerLevelRepresentation.d.ts +6 -0
- package/dist/representations/TableGroupByRunPerLevelRepresentation.d.ts.map +1 -0
- package/dist/representations/TableGroupByRunPerLevelRepresentation.js +8 -0
- package/dist/representations/TableGroupByRunPerSeverityRepresentation.d.ts +6 -0
- package/dist/representations/TableGroupByRunPerSeverityRepresentation.d.ts.map +1 -0
- package/dist/representations/TableGroupByRunPerSeverityRepresentation.js +8 -0
- package/dist/representations/TableGroupByRunRepresentation.d.ts +7 -0
- package/dist/representations/TableGroupByRunRepresentation.d.ts.map +1 -0
- package/dist/representations/TableGroupByRunRepresentation.js +7 -0
- package/dist/representations/TableGroupBySarifPerLevelRepresentation.d.ts +6 -0
- package/dist/representations/TableGroupBySarifPerLevelRepresentation.d.ts.map +1 -0
- package/dist/representations/TableGroupBySarifPerLevelRepresentation.js +8 -0
- package/dist/representations/TableGroupBySarifPerSeverityRepresentation.d.ts +6 -0
- package/dist/representations/TableGroupBySarifPerSeverityRepresentation.d.ts.map +1 -0
- package/dist/representations/TableGroupBySarifPerSeverityRepresentation.js +8 -0
- package/dist/representations/TableGroupBySarifRepresentation.d.ts +9 -0
- package/dist/representations/TableGroupBySarifRepresentation.d.ts.map +1 -0
- package/dist/representations/TableGroupBySarifRepresentation.js +15 -0
- package/dist/representations/TableGroupByToolNamePerLevelRepresentation.d.ts +6 -0
- package/dist/representations/TableGroupByToolNamePerLevelRepresentation.d.ts.map +1 -0
- package/dist/representations/TableGroupByToolNamePerLevelRepresentation.js +8 -0
- package/dist/representations/TableGroupByToolNamePerSeverityRepresentation.d.ts +6 -0
- package/dist/representations/TableGroupByToolNamePerSeverityRepresentation.d.ts.map +1 -0
- package/dist/representations/TableGroupByToolNamePerSeverityRepresentation.js +8 -0
- package/dist/representations/TableGroupByToolNameRepresentation.d.ts +7 -0
- package/dist/representations/TableGroupByToolNameRepresentation.d.ts.map +1 -0
- package/dist/representations/TableGroupByToolNameRepresentation.js +7 -0
- package/dist/representations/TableGroupRepresentation.d.ts +16 -0
- package/dist/representations/TableGroupRepresentation.d.ts.map +1 -0
- package/dist/representations/TableGroupRepresentation.js +62 -0
- package/dist/representations/table/Cell.d.ts +10 -0
- package/dist/representations/table/Cell.d.ts.map +1 -0
- package/dist/representations/table/Cell.js +23 -0
- package/dist/representations/table/Column.d.ts +11 -0
- package/dist/representations/table/Column.d.ts.map +1 -0
- package/dist/representations/table/Column.js +31 -0
- package/dist/representations/table/Row.d.ts +15 -0
- package/dist/representations/table/Row.d.ts.map +1 -0
- package/dist/representations/table/Row.js +45 -0
- package/dist/representations/table/Table.d.ts +14 -0
- package/dist/representations/table/Table.d.ts.map +1 -0
- package/dist/representations/table/Table.js +66 -0
- package/dist/sarif-to-slack.d.ts +98 -88
- package/dist/system.d.ts +2 -0
- package/dist/system.d.ts.map +1 -0
- package/dist/system.js +24 -0
- package/dist/tsdoc-metadata.json +1 -1
- package/dist/types.d.ts +90 -56
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +89 -42
- package/dist/utils/FileUtils.js +23 -21
- package/dist/utils/StringUtils.d.ts +2 -0
- package/dist/utils/StringUtils.d.ts.map +1 -0
- package/dist/utils/StringUtils.js +5 -0
- package/etc/sarif-to-slack.api.md +8 -36
- package/package.json +11 -11
- package/src/Logger.ts +64 -26
- package/src/SarifToSlackClient.ts +42 -29
- package/src/index.ts +0 -9
- package/src/model/Finding.ts +14 -13
- package/src/model/FindingArray.ts +1 -1
- package/src/model/SlackMessage.ts +5 -5
- package/src/model/color/ColorIdentification.ts +66 -50
- package/src/model/color/ColorOptions.ts +1 -1
- package/src/processors/CodeQLProcessor.ts +1 -1
- package/src/representations/CompactGroupByRepresentation.ts +2 -2
- package/src/representations/CompactGroupByRunRepresentation.ts +2 -2
- package/src/representations/CompactGroupBySarifRepresentation.ts +2 -2
- package/src/representations/CompactGroupByToolNameRepresentation.ts +2 -2
- package/src/representations/CompactTotalRepresentation.ts +1 -1
- package/src/representations/Representation.ts +9 -4
- package/src/representations/RepresentationFactory.ts +26 -2
- package/src/representations/TableGroupByRunPerLevelRepresentation.ts +9 -0
- package/src/representations/TableGroupByRunPerSeverityRepresentation.ts +9 -0
- package/src/representations/TableGroupByRunRepresentation.ts +15 -0
- package/src/representations/TableGroupBySarifPerLevelRepresentation.ts +9 -0
- package/src/representations/TableGroupBySarifPerSeverityRepresentation.ts +9 -0
- package/src/representations/TableGroupBySarifRepresentation.ts +25 -0
- package/src/representations/TableGroupByToolNamePerLevelRepresentation.ts +10 -0
- package/src/representations/TableGroupByToolNamePerSeverityRepresentation.ts +10 -0
- package/src/representations/TableGroupByToolNameRepresentation.ts +15 -0
- package/src/representations/TableGroupRepresentation.ts +78 -0
- package/src/representations/table/Cell.ts +25 -0
- package/src/representations/table/Column.ts +39 -0
- package/src/representations/table/Row.ts +50 -0
- package/src/representations/table/Table.ts +93 -0
- package/src/system.ts +27 -0
- package/src/types.ts +98 -58
- package/src/utils/Comparators.ts +1 -1
- package/src/utils/FileUtils.ts +30 -27
- package/src/utils/StringUtils.ts +7 -0
- package/test-data/sarif/codeql-go.sarif +1 -1
- package/test-data/sarif/runs-1-extensions-1-results-0.sarif +2 -2
- package/test-data/sarif/snyk-hex.sarif +1 -1
- package/tests/integration/SendSarifToSlack.spec.ts +73 -83
- package/tests/representations/table/Table.spec.ts +174 -0
- package/dist/System.d.ts +0 -2
- package/dist/System.d.ts.map +0 -1
- package/dist/System.js +0 -15
- package/src/System.ts +0 -16
- /package/test-data/sarif/{tmp → multiple}/codeql-csharp.sarif +0 -0
- /package/test-data/sarif/{tmp → multiple}/grype-container.sarif +0 -0
- /package/test-data/sarif/{tmp → multiple}/runs-1-tools-1-results-0.sarif +0 -0
- /package/test-data/sarif/{tmp → multiple}/runs-2-tools-2.sarif +0 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type Cell from './Cell'
|
|
2
|
+
import Logger from '../../Logger'
|
|
3
|
+
|
|
4
|
+
export default class Column {
|
|
5
|
+
private readonly _logger: Logger = new Logger('Column');
|
|
6
|
+
private readonly _cells: Cell[];
|
|
7
|
+
|
|
8
|
+
public constructor(
|
|
9
|
+
public readonly header: string,
|
|
10
|
+
cellsCount: number,
|
|
11
|
+
) {
|
|
12
|
+
this._cells = new Array<Cell>(cellsCount)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
public get total(): number {
|
|
16
|
+
return this._cells
|
|
17
|
+
.reduce((sum: number, c: Cell): number => {
|
|
18
|
+
sum += Number(c.value)
|
|
19
|
+
return sum
|
|
20
|
+
}, 0)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
public get width(): number {
|
|
24
|
+
return Math.max(
|
|
25
|
+
...this._cells.map((c: Cell): number => c.getWidth()),
|
|
26
|
+
this.total.toString().length
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
public setCell(index: number, value: Cell): void {
|
|
31
|
+
if (index >= 0 && index < this._cells.length) {
|
|
32
|
+
this._cells[index] = value
|
|
33
|
+
const width: number = this.width
|
|
34
|
+
this._cells.forEach((c: Cell): void => c.setWidth(width))
|
|
35
|
+
} else {
|
|
36
|
+
this._logger.warn(`Cell index out of range. Requested index: ${index}. Cells count: ${this._cells.length}.`)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import Cell from './Cell'
|
|
2
|
+
import Logger from '../../Logger'
|
|
3
|
+
|
|
4
|
+
export default class Row {
|
|
5
|
+
private readonly _logger = new Logger('Row');
|
|
6
|
+
private readonly _cells: Cell[];
|
|
7
|
+
private _totalWidth: number;
|
|
8
|
+
|
|
9
|
+
public constructor(
|
|
10
|
+
private readonly _header: string,
|
|
11
|
+
public readonly headerWidth: number,
|
|
12
|
+
cellsCount: number,
|
|
13
|
+
) {
|
|
14
|
+
this._cells = Array.from({ length: cellsCount }, (): Cell => new Cell())
|
|
15
|
+
this._totalWidth = 1
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
public get total(): number {
|
|
19
|
+
return this._cells
|
|
20
|
+
.reduce((sum: number, c: Cell): number => {
|
|
21
|
+
sum += Number(c.value)
|
|
22
|
+
return sum
|
|
23
|
+
}, 0)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
public setCell(index: number, value: Cell): void {
|
|
27
|
+
if (index >= 0 && index < this._cells.length) {
|
|
28
|
+
this._cells[index] = value
|
|
29
|
+
} else {
|
|
30
|
+
this._logger.warn(`Setting cell failed. Reason: index out of range. Requested index: ${index}. Cells count: ${this._cells.length}.`)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
public get totalWidth(): number {
|
|
35
|
+
return this._totalWidth
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
public setTotalWidth(value: number): void {
|
|
39
|
+
this._totalWidth = value
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public toString(): string {
|
|
43
|
+
const result: string[] = []
|
|
44
|
+
result.push(`${this._header}${this.headerWidth > this._header.length ? ' '.repeat(this.headerWidth - this._header.length) : ''}`)
|
|
45
|
+
this._cells.map((c: Cell): string => c.toString()).forEach((v: string): number => result.push(v))
|
|
46
|
+
const totalStr: string = this.total.toString();
|
|
47
|
+
result.push(`${totalStr}${this._totalWidth > totalStr.length ? ' '.repeat(this._totalWidth - totalStr.length) : ''}`)
|
|
48
|
+
return `|${result.join('|')}|`
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import Column from './Column'
|
|
2
|
+
import Row from './Row'
|
|
3
|
+
import Cell from './Cell'
|
|
4
|
+
|
|
5
|
+
const HEADER_TOTAL: string = 'Total'
|
|
6
|
+
|
|
7
|
+
export type TableHeaders = {
|
|
8
|
+
main?: string,
|
|
9
|
+
rows: string[],
|
|
10
|
+
columns: string[],
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export default class Table {
|
|
14
|
+
private readonly header: string
|
|
15
|
+
private readonly columns: Column[]
|
|
16
|
+
private readonly rows: Row[]
|
|
17
|
+
|
|
18
|
+
public constructor(
|
|
19
|
+
headers: TableHeaders,
|
|
20
|
+
) {
|
|
21
|
+
this.header = headers.main ?? ''
|
|
22
|
+
this.columns = Array.from(
|
|
23
|
+
{ length: headers.columns.length },
|
|
24
|
+
(_: unknown, index: number): Column => new Column(headers.columns[index], headers.rows.length)
|
|
25
|
+
)
|
|
26
|
+
const headerWidth: number = Math.max(
|
|
27
|
+
this.header.length,
|
|
28
|
+
...headers.rows.map((v: string): number => v.length),
|
|
29
|
+
HEADER_TOTAL.length,
|
|
30
|
+
)
|
|
31
|
+
this.rows = Array.from(
|
|
32
|
+
{ length: headers.rows.length },
|
|
33
|
+
(_: unknown, index: number): Row => new Row(headers.rows[index], headerWidth, headers.columns.length)
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
public set(rowIndex: number, columnIndex: number, v: number): void {
|
|
38
|
+
if (rowIndex >= 0 && rowIndex < this.rows.length && columnIndex >= 0 && columnIndex < this.columns.length) {
|
|
39
|
+
const cell = new Cell(v)
|
|
40
|
+
cell.setWidth(this.columns[columnIndex].header.length)
|
|
41
|
+
this.columns[columnIndex].setCell(rowIndex, cell)
|
|
42
|
+
this.rows[rowIndex].setCell(columnIndex, cell)
|
|
43
|
+
// Update width of the last cell ("Total") of every row, so that it is shown
|
|
44
|
+
// correctly in string representation
|
|
45
|
+
const rowTotalWidth: number = Math.max(
|
|
46
|
+
// Based on the sum of all total values
|
|
47
|
+
this.rows.reduce((sum: number, r: Row): number => {
|
|
48
|
+
sum += r.total
|
|
49
|
+
return sum
|
|
50
|
+
}, 0).toString().length,
|
|
51
|
+
// Based on the width of "Total" header
|
|
52
|
+
HEADER_TOTAL.length,
|
|
53
|
+
)
|
|
54
|
+
this.rows.forEach((r: Row): void => r.setTotalWidth(rowTotalWidth))
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
public toString(): string {
|
|
59
|
+
const rowsStr: string[] = [];
|
|
60
|
+
if (this.rows.length > 0 && this.columns.length > 0) {
|
|
61
|
+
this.rows.forEach((row: Row): number => rowsStr.push(row.toString()));
|
|
62
|
+
|
|
63
|
+
const rowSeparator: string = rowsStr[0].replace(/[^|]/g, '-');
|
|
64
|
+
rowsStr.unshift(rowSeparator);
|
|
65
|
+
rowsStr.push(rowSeparator);
|
|
66
|
+
|
|
67
|
+
const rowTotal: string[] = [];
|
|
68
|
+
let sumTotal: number = 0;
|
|
69
|
+
for (const column of this.columns) {
|
|
70
|
+
const total: number = column.total;
|
|
71
|
+
rowTotal.push(`${total}${total.toString().length < column.width ? ' '.repeat(column.width - total.toString().length) : ''}`);
|
|
72
|
+
sumTotal += total;
|
|
73
|
+
}
|
|
74
|
+
const column1: string = `${HEADER_TOTAL}${this.rows[0].headerWidth > HEADER_TOTAL.length ? ' '.repeat(this.rows[0].headerWidth - HEADER_TOTAL.length) : ''}`;
|
|
75
|
+
const columnLast: string = `${sumTotal}${sumTotal.toString().length < HEADER_TOTAL.length ? ' '.repeat(HEADER_TOTAL.length - sumTotal.toString().length) : ''}`;
|
|
76
|
+
rowsStr.push(`|${column1}|${rowTotal.join('|')}|${columnLast}|`);
|
|
77
|
+
|
|
78
|
+
// Insert first row with titles and second row with separator
|
|
79
|
+
const rowTop: string[] = [
|
|
80
|
+
this.header + (this.header.length < this.rows[0].headerWidth ? ' '.repeat(this.rows[0].headerWidth - this.header.length) : ''),
|
|
81
|
+
this.columns
|
|
82
|
+
.map((c: Column): string => `${c.header}${c.header.length < c.width ? ' '.repeat(c.width - c.header.length) : ''}`)
|
|
83
|
+
.join('|'),
|
|
84
|
+
HEADER_TOTAL + (HEADER_TOTAL.length < this.rows[0].totalWidth ? ' '.repeat(this.rows[0].totalWidth - HEADER_TOTAL.length) : ''),
|
|
85
|
+
];
|
|
86
|
+
rowsStr.unshift(`|${rowTop.join('|')}|`);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return rowsStr
|
|
90
|
+
.join('\n')
|
|
91
|
+
.replace(/[|]/g, ' | ');
|
|
92
|
+
}
|
|
93
|
+
}
|
package/src/system.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { z, type ZodSafeParseResult } from 'zod';
|
|
2
|
+
import Logger from './Logger';
|
|
3
|
+
import { version, sha, buildAt } from './metadata.json';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Prints metadata information into the logs, such as library version, SHA and
|
|
7
|
+
* build time.
|
|
8
|
+
* @internal
|
|
9
|
+
*/
|
|
10
|
+
export function logMetadata(): void {
|
|
11
|
+
const logger = new Logger(logMetadata.name);
|
|
12
|
+
logger.info(`version: ${version}`);
|
|
13
|
+
logger.info(`sha: ${sha}`);
|
|
14
|
+
logger.info(`built at: ${buildAt}`);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Checks if it is running in GitHub Actions with debug mode enabled.
|
|
19
|
+
* @returns false if ACTIONS_STEP_DEBUG env var is falsy, otherwise returns true.
|
|
20
|
+
* @internal
|
|
21
|
+
*/
|
|
22
|
+
export function isDebug(): boolean {
|
|
23
|
+
const parseResult: ZodSafeParseResult<boolean> = z.stringbool().safeParse(
|
|
24
|
+
process.env.ACTIONS_STEP_DEBUG
|
|
25
|
+
);
|
|
26
|
+
return parseResult.success && parseResult.data;
|
|
27
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -1,48 +1,7 @@
|
|
|
1
|
-
import { Run } from 'sarif'
|
|
2
|
-
import { ColorOptions } from './model/color/ColorOptions'
|
|
3
|
-
import FindingArray from './model/FindingArray'
|
|
4
|
-
import { SendIf } from './model/SendIf'
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Enum representing log levels for the service.
|
|
8
|
-
* @public
|
|
9
|
-
*/
|
|
10
|
-
export enum LogLevel {
|
|
11
|
-
/**
|
|
12
|
-
* Represents the most verbose logging level, typically used for detailed
|
|
13
|
-
* debugging information.
|
|
14
|
-
*/
|
|
15
|
-
Silly = 0,
|
|
16
|
-
/**
|
|
17
|
-
* Represents a logging level for tracing the flow of the application.
|
|
18
|
-
*/
|
|
19
|
-
Trace = 1,
|
|
20
|
-
/**
|
|
21
|
-
* Represents a logging level for debugging information that is less verbose
|
|
22
|
-
* than silly.
|
|
23
|
-
*/
|
|
24
|
-
Debug = 2,
|
|
25
|
-
/**
|
|
26
|
-
* Represents a logging level for general informational messages that highlight
|
|
27
|
-
* the progress of the application.
|
|
28
|
-
*/
|
|
29
|
-
Info = 3,
|
|
30
|
-
/**
|
|
31
|
-
* Represents a logging level for potentially harmful situations that require
|
|
32
|
-
* attention.
|
|
33
|
-
*/
|
|
34
|
-
Warning = 4,
|
|
35
|
-
/**
|
|
36
|
-
* Represents a logging level for error conditions that do not require immediate
|
|
37
|
-
* action but should be noted.
|
|
38
|
-
*/
|
|
39
|
-
Error = 5,
|
|
40
|
-
/**
|
|
41
|
-
* Represents a logging level for critical errors that require immediate attention
|
|
42
|
-
* and may cause the application to terminate.
|
|
43
|
-
*/
|
|
44
|
-
Fatal = 6
|
|
45
|
-
}
|
|
1
|
+
import type { Run } from 'sarif'
|
|
2
|
+
import type { ColorOptions } from './model/color/ColorOptions'
|
|
3
|
+
import type FindingArray from './model/FindingArray'
|
|
4
|
+
import type { SendIf } from './model/SendIf'
|
|
46
5
|
|
|
47
6
|
/**
|
|
48
7
|
* Type representing properties that indicate whether to include certain information
|
|
@@ -174,19 +133,92 @@ export enum RepresentationType {
|
|
|
174
133
|
* ```
|
|
175
134
|
*/
|
|
176
135
|
CompactTotalPerSeverity = 7,
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* Options for logging.
|
|
181
|
-
* @public
|
|
182
|
-
*/
|
|
183
|
-
export type LogOptions = {
|
|
184
|
-
level?: LogLevel,
|
|
185
136
|
/**
|
|
186
|
-
*
|
|
137
|
+
* Table information about findings grouped by Run with the level representation.
|
|
138
|
+
* @example
|
|
139
|
+
* ```text
|
|
140
|
+
* | | Unknown | None | Note | Warning | Error | Total |
|
|
141
|
+
* | ----- | ------- | ---- | ---- | ------- | ----- | ----- |
|
|
142
|
+
* | 1 | 0 | 0 | 0 | 1 | 0 | 1 |
|
|
143
|
+
* | 2 | 0 | 0 | 9 | 20 | 10 | 39 |
|
|
144
|
+
* | 3 | 0 | 0 | 1 | 0 | 1 | 2 |
|
|
145
|
+
* | 4 | 0 | 0 | 5 | 5 | 0 | 10 |
|
|
146
|
+
* | ----- | ------- | ---- | ---- | ------- | ----- | ----- |
|
|
147
|
+
* | Total | 0 | 0 | 15 | 26 | 11 | 52 |
|
|
148
|
+
* ```
|
|
149
|
+
*/
|
|
150
|
+
TableGroupByRunPerLevel = 8,
|
|
151
|
+
/**
|
|
152
|
+
* Table information about findings grouped by Run with the severity representation.
|
|
153
|
+
* @example
|
|
154
|
+
* ```text
|
|
155
|
+
* | | Unknown | None | Low | Medium | High | Critical | Total |
|
|
156
|
+
* | ----- | ------- | ---- | --- | ------ | ---- | -------- | ----- |
|
|
157
|
+
* | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 1 |
|
|
158
|
+
* | 2 | 0 | 0 | 9 | 20 | 10 | 0 | 39 |
|
|
159
|
+
* | 3 | 0 | 0 | 1 | 0 | 1 | 0 | 2 |
|
|
160
|
+
* | 4 | 0 | 0 | 5 | 5 | 0 | 0 | 10 |
|
|
161
|
+
* | ----- | ------- | ---- | --- | ------ | ---- | -------- | ----- |
|
|
162
|
+
* | Total | 0 | 0 | 15 | 26 | 11 | 0 | 52 |
|
|
163
|
+
* ```
|
|
164
|
+
*/
|
|
165
|
+
TableGroupByRunPerSeverity = 9,
|
|
166
|
+
/**
|
|
167
|
+
* Table information about findings grouped by tool name with the level representation.
|
|
168
|
+
* @example
|
|
169
|
+
* ```text
|
|
170
|
+
* | | Unknown | None | Note | Warning | Error | Total |
|
|
171
|
+
* | ------ | ------- | ---- | ---- | ------- | ----- | ----- |
|
|
172
|
+
* | CodeQL | 0 | 0 | 0 | 1 | 0 | 1 |
|
|
173
|
+
* | grype | 0 | 0 | 9 | 20 | 10 | 39 |
|
|
174
|
+
* | Trivy | 0 | 0 | 1 | 0 | 1 | 2 |
|
|
175
|
+
* | WizCLI | 0 | 0 | 5 | 5 | 0 | 10 |
|
|
176
|
+
* | ------ | ------- | ---- | ---- | ------- | ----- | ----- |
|
|
177
|
+
* | Total | 0 | 0 | 15 | 26 | 11 | 52 |
|
|
178
|
+
* ```
|
|
187
179
|
*/
|
|
188
|
-
|
|
189
|
-
|
|
180
|
+
TableGroupByToolNamePerLevel = 10,
|
|
181
|
+
/**
|
|
182
|
+
* Table information about findings grouped by tool name with the severity representation.
|
|
183
|
+
* @example
|
|
184
|
+
* ```text
|
|
185
|
+
* | | Unknown | None | Low | Medium | High | Critical | Total |
|
|
186
|
+
* | ------ | ------- | ---- | --- | ------ | ---- | -------- | ----- |
|
|
187
|
+
* | CodeQL | 0 | 0 | 0 | 1 | 0 | 0 | 1 |
|
|
188
|
+
* | grype | 0 | 0 | 9 | 20 | 10 | 0 | 39 |
|
|
189
|
+
* | Trivy | 0 | 0 | 1 | 0 | 1 | 0 | 2 |
|
|
190
|
+
* | WizCLI | 0 | 0 | 5 | 5 | 0 | 0 | 10 |
|
|
191
|
+
* | ------ | ------- | ---- | --- | ------ | ---- | -------- | ----- |
|
|
192
|
+
* | Total | 0 | 0 | 15 | 26 | 11 | 0 | 52 |
|
|
193
|
+
* ```
|
|
194
|
+
*/
|
|
195
|
+
TableGroupByToolNamePerSeverity = 11,
|
|
196
|
+
/**
|
|
197
|
+
* Table information about findings grouped by SARIF file with the level representation.
|
|
198
|
+
* @example
|
|
199
|
+
* ```text
|
|
200
|
+
* | | Unknown | None | Note | Warning | Error | Total |
|
|
201
|
+
* | ----- | ------- | ---- | ---- | ------- | ----- | ----- |
|
|
202
|
+
* | 1 | 0 | 0 | 0 | 1 | 0 | 1 |
|
|
203
|
+
* | 2 | 0 | 0 | 9 | 20 | 10 | 39 |
|
|
204
|
+
* | ----- | ------- | ---- | ---- | ------- | ----- | ----- |
|
|
205
|
+
* | Total | 0 | 0 | 9 | 21 | 10 | 40 |
|
|
206
|
+
* ```
|
|
207
|
+
*/
|
|
208
|
+
TableGroupBySarifPerLevel = 12,
|
|
209
|
+
/**
|
|
210
|
+
* Table information about findings grouped by SARIF file with the severity representation.
|
|
211
|
+
* @example
|
|
212
|
+
* ```text
|
|
213
|
+
* | | Unknown | None | Low | Medium | High | Critical | Total |
|
|
214
|
+
* | ----- | ------- | ---- | --- | ------ | ---- | -------- | ----- |
|
|
215
|
+
* | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 1 |
|
|
216
|
+
* | 2 | 0 | 0 | 9 | 20 | 10 | 0 | 39 |
|
|
217
|
+
* | ----- | ------- | ---- | --- | ------ | ---- | -------- | ----- |
|
|
218
|
+
* | Total | 0 | 0 | 9 | 21 | 10 | 0 | 40 |
|
|
219
|
+
* ```
|
|
220
|
+
*/
|
|
221
|
+
TableGroupBySarifPerSeverity = 13,
|
|
190
222
|
}
|
|
191
223
|
|
|
192
224
|
/**
|
|
@@ -211,12 +243,10 @@ export type SarifOptions = {
|
|
|
211
243
|
* @public
|
|
212
244
|
*/
|
|
213
245
|
export type SarifToSlackClientOptions = {
|
|
214
|
-
webhookUrl: string,
|
|
215
246
|
sarif: SarifOptions,
|
|
216
247
|
username?: string,
|
|
217
248
|
iconUrl?: string,
|
|
218
249
|
color?: ColorOptions,
|
|
219
|
-
log?: LogOptions,
|
|
220
250
|
header?: IncludeAwareWithValueOptions,
|
|
221
251
|
footer?: FooterOptions,
|
|
222
252
|
actor?: IncludeAwareWithValueOptions,
|
|
@@ -241,6 +271,11 @@ export enum SecuritySeverity {
|
|
|
241
271
|
Critical = 5,
|
|
242
272
|
}
|
|
243
273
|
|
|
274
|
+
export const SecuritySeverityValues: string[] =
|
|
275
|
+
Object.values(SecuritySeverity).filter(
|
|
276
|
+
(v: string | SecuritySeverity): v is string => typeof v === 'string'
|
|
277
|
+
)
|
|
278
|
+
|
|
244
279
|
/**
|
|
245
280
|
* Enum of security level.
|
|
246
281
|
* @privateRemarks Order should remain unchanged. It is used in multiple places,
|
|
@@ -256,6 +291,11 @@ export enum SecurityLevel {
|
|
|
256
291
|
Error = 4,
|
|
257
292
|
}
|
|
258
293
|
|
|
294
|
+
export const SecurityLevelValues: string[] =
|
|
295
|
+
Object.values(SecurityLevel).filter(
|
|
296
|
+
(v: string | SecurityLevel): v is string => typeof v === 'string'
|
|
297
|
+
)
|
|
298
|
+
|
|
259
299
|
/**
|
|
260
300
|
* The data about run, such as {@link Run} itself, tool name of the run and ID
|
|
261
301
|
* which is manually generated and unique within a single execution.
|
package/src/utils/Comparators.ts
CHANGED
package/src/utils/FileUtils.ts
CHANGED
|
@@ -1,31 +1,35 @@
|
|
|
1
|
-
import fs from 'fs'
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
import Logger from '../Logger';
|
|
4
|
+
import type { SarifFileExtension, SarifOptions } from '../types';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Traverse directory recursively and returns list of files with the requested
|
|
8
8
|
* extension.
|
|
9
9
|
* @param dir A root directory. Starting point.
|
|
10
|
+
* @param recursive Whether to list files recursively or not.
|
|
10
11
|
* @param extension An instance of {@link SarifFileExtension} type.
|
|
11
12
|
* @param fileList Collected list of files.
|
|
12
13
|
* @private
|
|
13
14
|
*/
|
|
14
|
-
function
|
|
15
|
+
function listFiles(
|
|
15
16
|
dir: string,
|
|
17
|
+
recursive: boolean,
|
|
16
18
|
extension: SarifFileExtension,
|
|
17
19
|
fileList: string[] = []
|
|
18
20
|
): string[] {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
21
|
+
if (fs.statSync(dir).isDirectory()) {
|
|
22
|
+
const entries: string[] = fs.readdirSync(dir);
|
|
23
|
+
entries.forEach((entry: string): void => {
|
|
24
|
+
const fullPath: string = path.join(dir, entry);
|
|
25
|
+
if (recursive && fs.statSync(fullPath).isDirectory()) {
|
|
26
|
+
listFiles(fullPath, recursive, extension, fileList);
|
|
27
|
+
} else if (path.extname(fullPath).toLowerCase() === `.${extension}`) {
|
|
28
|
+
fileList.push(fullPath);
|
|
29
|
+
}
|
|
30
|
+
})
|
|
31
|
+
}
|
|
32
|
+
return fileList;
|
|
29
33
|
}
|
|
30
34
|
|
|
31
35
|
/**
|
|
@@ -35,26 +39,25 @@ function listFilesRecursively(
|
|
|
35
39
|
* @internal
|
|
36
40
|
*/
|
|
37
41
|
export function extractListOfFiles(opts: SarifOptions): string[] {
|
|
42
|
+
const logger = new Logger(extractListOfFiles.name);
|
|
38
43
|
if (!fs.existsSync(opts.path)) {
|
|
39
|
-
throw new Error(`Provided path does not exist: ${opts.path}`)
|
|
44
|
+
throw new Error(`Provided path does not exist: ${opts.path}`);
|
|
40
45
|
}
|
|
41
46
|
|
|
42
|
-
const stats: fs.Stats = fs.statSync(opts.path)
|
|
47
|
+
const stats: fs.Stats = fs.statSync(opts.path);
|
|
43
48
|
|
|
44
49
|
if (stats.isDirectory()) {
|
|
45
|
-
|
|
46
|
-
const files: string[] = opts.recursive
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
Logger.debug(`Found files: ${files.join(', ')}`)
|
|
51
|
-
return files
|
|
50
|
+
logger.info(`Provided path is a directory: ${opts.path}`);
|
|
51
|
+
const files: string[] = listFiles(opts.path, !!opts.recursive, opts.extension ?? 'sarif');
|
|
52
|
+
logger.info(`Found ${files.length} files in ${opts.path} directory with ${opts.extension} extension`);
|
|
53
|
+
logger.debug(`Found files: ${files.join(', ')}`);
|
|
54
|
+
return files;
|
|
52
55
|
}
|
|
53
56
|
|
|
54
57
|
if (stats.isFile()) {
|
|
55
|
-
|
|
56
|
-
return [opts.path]
|
|
58
|
+
logger.info(`Provided path is a file: ${opts.path}`);
|
|
59
|
+
return [opts.path];
|
|
57
60
|
}
|
|
58
61
|
|
|
59
|
-
throw new Error(`Provided path is neither a file nor a directory: ${opts.path}`)
|
|
62
|
+
throw new Error(`Provided path is neither a file nor a directory: ${opts.path}`);
|
|
60
63
|
}
|