@fabasoad/sarif-to-slack 1.3.4 → 1.4.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/.github/workflows/release.yml +1 -1
- package/.github/workflows/security.yml +1 -0
- package/.github/workflows/send-sarif-to-slack.yml +39 -15
- package/.pre-commit-config.yaml +4 -4
- package/.tool-versions +1 -1
- package/Makefile +1 -1
- package/README.md +8 -7
- package/api-extractor.json +2 -2
- package/dist/Logger.js +40 -30
- package/dist/SarifToSlackClient.d.ts +0 -1
- package/dist/SarifToSlackClient.d.ts.map +1 -1
- package/dist/SarifToSlackClient.js +11 -8
- package/dist/globalState.d.ts +2 -0
- package/dist/globalState.d.ts.map +1 -0
- package/dist/globalState.js +2 -0
- package/dist/index.cjs +118 -81
- package/dist/index.d.ts +529 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -2
- package/dist/model/Finding.js +7 -5
- package/dist/model/FindingArray.js +1 -1
- package/dist/model/SendIf.js +1 -1
- package/dist/model/SlackMessage.js +6 -6
- package/dist/model/color/Color.d.ts.map +1 -1
- package/dist/model/color/Color.js +1 -1
- package/dist/model/color/ColorIdentification.js +5 -5
- package/dist/model/color/ColorOptions.d.ts.map +1 -1
- package/dist/processors/CodeQLProcessor.js +1 -1
- package/dist/processors/CommonProcessor.js +1 -1
- package/dist/processors/ProcessorFactory.js +1 -1
- package/dist/processors/SnykProcessor.js +2 -1
- package/dist/representations/CompactGroupByRepresentation.js +1 -1
- package/dist/representations/CompactGroupByRunPerLevelRepresentation.js +1 -1
- package/dist/representations/CompactGroupByRunPerSeverityRepresentation.js +1 -1
- package/dist/representations/CompactGroupByRunRepresentation.js +1 -1
- package/dist/representations/CompactGroupBySarifPerLevelRepresentation.js +1 -1
- package/dist/representations/CompactGroupBySarifPerSeverityRepresentation.js +1 -1
- package/dist/representations/CompactGroupBySarifRepresentation.js +1 -1
- package/dist/representations/CompactGroupByToolNamePerLevelRepresentation.js +1 -1
- package/dist/representations/CompactGroupByToolNamePerSeverityRepresentation.js +1 -1
- package/dist/representations/CompactGroupByToolNameRepresentation.js +1 -1
- package/dist/representations/CompactTotalPerLevelRepresentation.js +1 -1
- package/dist/representations/CompactTotalPerSeverityRepresentation.js +1 -1
- package/dist/representations/CompactTotalRepresentation.js +1 -1
- package/dist/representations/Representation.js +1 -1
- package/dist/representations/RepresentationFactory.js +1 -1
- package/dist/representations/TableGroupByRunPerLevelRepresentation.d.ts.map +1 -1
- package/dist/representations/TableGroupByRunPerLevelRepresentation.js +1 -1
- package/dist/representations/TableGroupByRunPerSeverityRepresentation.d.ts.map +1 -1
- package/dist/representations/TableGroupByRunPerSeverityRepresentation.js +1 -1
- package/dist/representations/TableGroupByRunRepresentation.d.ts.map +1 -1
- package/dist/representations/TableGroupByRunRepresentation.js +1 -1
- package/dist/representations/TableGroupBySarifPerLevelRepresentation.d.ts.map +1 -1
- package/dist/representations/TableGroupBySarifPerLevelRepresentation.js +1 -1
- package/dist/representations/TableGroupBySarifPerSeverityRepresentation.d.ts.map +1 -1
- package/dist/representations/TableGroupBySarifPerSeverityRepresentation.js +1 -1
- package/dist/representations/TableGroupBySarifRepresentation.d.ts.map +1 -1
- package/dist/representations/TableGroupBySarifRepresentation.js +1 -1
- package/dist/representations/TableGroupByToolNamePerLevelRepresentation.d.ts.map +1 -1
- package/dist/representations/TableGroupByToolNamePerLevelRepresentation.js +1 -1
- package/dist/representations/TableGroupByToolNamePerSeverityRepresentation.d.ts.map +1 -1
- package/dist/representations/TableGroupByToolNamePerSeverityRepresentation.js +1 -1
- package/dist/representations/TableGroupByToolNameRepresentation.d.ts.map +1 -1
- package/dist/representations/TableGroupByToolNameRepresentation.js +1 -1
- package/dist/representations/TableGroupRepresentation.d.ts +0 -1
- package/dist/representations/TableGroupRepresentation.d.ts.map +1 -1
- package/dist/representations/TableGroupRepresentation.js +3 -3
- package/dist/representations/table/Cell.d.ts.map +1 -1
- package/dist/representations/table/Cell.js +1 -1
- package/dist/representations/table/Column.d.ts +0 -1
- package/dist/representations/table/Column.d.ts.map +1 -1
- package/dist/representations/table/Column.js +4 -3
- package/dist/representations/table/Row.d.ts +0 -1
- package/dist/representations/table/Row.d.ts.map +1 -1
- package/dist/representations/table/Row.js +3 -3
- package/dist/representations/table/Table.d.ts.map +1 -1
- package/dist/representations/table/Table.js +1 -1
- package/dist/system.js +5 -5
- package/dist/tsdoc-metadata.json +1 -1
- package/dist/types.d.ts +29 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +11 -1
- package/dist/utils/Comparators.js +1 -1
- package/dist/utils/ExtendedArray.js +1 -1
- package/dist/utils/FileUtils.js +2 -2
- package/dist/utils/SarifUtils.js +1 -1
- package/dist/utils/StringUtils.js +1 -1
- package/etc/sarif-to-slack.api.md +21 -1
- package/jest.config.json +4 -4
- package/package.json +10 -9
- package/src/Logger.ts +50 -34
- package/src/SarifToSlackClient.ts +73 -68
- package/src/globalState.ts +11 -0
- package/src/index.ts +23 -12
- package/src/model/Finding.ts +36 -35
- package/src/model/FindingArray.ts +5 -5
- package/src/model/SendIf.ts +25 -25
- package/src/model/SlackMessage.ts +49 -49
- package/src/model/color/Color.ts +7 -7
- package/src/model/color/ColorIdentification.ts +77 -77
- package/src/model/color/ColorOptions.ts +1 -1
- package/src/processors/CodeQLProcessor.ts +3 -3
- package/src/processors/CommonProcessor.ts +24 -24
- package/src/processors/ProcessorFactory.ts +9 -9
- package/src/processors/SnykProcessor.ts +3 -2
- package/src/representations/CompactGroupByRepresentation.ts +20 -20
- package/src/representations/CompactGroupByRunPerLevelRepresentation.ts +2 -2
- package/src/representations/CompactGroupByRunPerSeverityRepresentation.ts +2 -2
- package/src/representations/CompactGroupByRunRepresentation.ts +10 -10
- package/src/representations/CompactGroupBySarifPerLevelRepresentation.ts +2 -2
- package/src/representations/CompactGroupBySarifPerSeverityRepresentation.ts +2 -2
- package/src/representations/CompactGroupBySarifRepresentation.ts +11 -11
- package/src/representations/CompactGroupByToolNamePerLevelRepresentation.ts +2 -2
- package/src/representations/CompactGroupByToolNamePerSeverityRepresentation.ts +2 -2
- package/src/representations/CompactGroupByToolNameRepresentation.ts +10 -10
- package/src/representations/CompactTotalPerLevelRepresentation.ts +2 -2
- package/src/representations/CompactTotalPerSeverityRepresentation.ts +2 -2
- package/src/representations/CompactTotalRepresentation.ts +5 -5
- package/src/representations/Representation.ts +8 -8
- package/src/representations/RepresentationFactory.ts +32 -32
- package/src/representations/TableGroupByRunPerLevelRepresentation.ts +3 -3
- package/src/representations/TableGroupByRunPerSeverityRepresentation.ts +3 -3
- package/src/representations/TableGroupByRunRepresentation.ts +5 -5
- package/src/representations/TableGroupBySarifPerLevelRepresentation.ts +3 -3
- package/src/representations/TableGroupBySarifPerSeverityRepresentation.ts +3 -3
- package/src/representations/TableGroupBySarifRepresentation.ts +9 -9
- package/src/representations/TableGroupByToolNamePerLevelRepresentation.ts +3 -3
- package/src/representations/TableGroupByToolNamePerSeverityRepresentation.ts +3 -3
- package/src/representations/TableGroupByToolNameRepresentation.ts +4 -4
- package/src/representations/TableGroupRepresentation.ts +32 -32
- package/src/representations/table/Cell.ts +8 -8
- package/src/representations/table/Column.ts +13 -13
- package/src/representations/table/Row.ts +17 -17
- package/src/representations/table/Table.ts +21 -21
- package/src/system.ts +5 -5
- package/src/types.ts +43 -13
- package/src/utils/Comparators.ts +6 -6
- package/src/utils/ExtendedArray.ts +1 -1
- package/src/utils/FileUtils.ts +3 -3
- package/src/utils/SarifUtils.ts +6 -6
- package/src/utils/StringUtils.ts +3 -3
- package/tests/integration/SendSarifToSlack.spec.ts +73 -67
- package/tests/representations/CompactGroupByRunPerLevelRepresentation.spec.ts +121 -0
- package/tests/representations/CompactGroupByRunPerSeverityRepresentation.spec.ts +122 -0
- package/tests/representations/CompactGroupBySarifPerLevelRepresentation.spec.ts +132 -0
- package/tests/representations/CompactGroupBySarifPerSeverityRepresentation.spec.ts +133 -0
- package/tsconfig.json +3 -4
- package/dist/sarif-to-slack.d.ts +0 -562
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import type { AnyBlock } from '@slack/types'
|
|
2
|
-
import type { ContextBlock, HeaderBlock } from '@slack/types/dist/block-kit/blocks'
|
|
3
|
-
import type { TextObject } from '@slack/types/dist/block-kit/composition-objects'
|
|
4
|
-
import { IncomingWebhook } from '@slack/webhook'
|
|
5
|
-
import { FooterType } from '../types'
|
|
6
|
-
import type Representation from '../representations/Representation'
|
|
7
|
-
import { version } from '../metadata.json'
|
|
1
|
+
import type { AnyBlock } from '@slack/types';
|
|
2
|
+
import type { ContextBlock, HeaderBlock } from '@slack/types/dist/block-kit/blocks';
|
|
3
|
+
import type { TextObject } from '@slack/types/dist/block-kit/composition-objects';
|
|
4
|
+
import { IncomingWebhook } from '@slack/webhook';
|
|
5
|
+
import { FooterType } from '../types';
|
|
6
|
+
import type Representation from '../representations/Representation';
|
|
7
|
+
import { version } from '../metadata.json';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Options for the SlackMessageBuilder.
|
|
11
11
|
* @internal
|
|
12
12
|
*/
|
|
13
13
|
export type SlackMessageOptions = {
|
|
14
|
-
username?: string
|
|
15
|
-
iconUrl?: string
|
|
16
|
-
color?: string
|
|
14
|
+
username?: string,
|
|
15
|
+
iconUrl?: string,
|
|
16
|
+
color?: string,
|
|
17
17
|
representation: Representation,
|
|
18
18
|
}
|
|
19
19
|
|
|
@@ -39,7 +39,7 @@ export interface SlackMessage {
|
|
|
39
39
|
* @param opts An instance of {@link SlackMessageOptions} type.
|
|
40
40
|
*/
|
|
41
41
|
export function createSlackMessage(url: string, opts: SlackMessageOptions): SlackMessage {
|
|
42
|
-
return new SlackMessageImpl(url, opts)
|
|
42
|
+
return new SlackMessageImpl(url, opts);
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
/**
|
|
@@ -47,24 +47,24 @@ export function createSlackMessage(url: string, opts: SlackMessageOptions): Slac
|
|
|
47
47
|
* @internal
|
|
48
48
|
*/
|
|
49
49
|
class SlackMessageImpl implements SlackMessage {
|
|
50
|
-
private readonly _webhook: IncomingWebhook
|
|
51
|
-
private readonly _gitHubServerUrl: string
|
|
52
|
-
private readonly _color?: string
|
|
53
|
-
private readonly _representation: Representation
|
|
50
|
+
private readonly _webhook: IncomingWebhook;
|
|
51
|
+
private readonly _gitHubServerUrl: string;
|
|
52
|
+
private readonly _color?: string;
|
|
53
|
+
private readonly _representation: Representation;
|
|
54
54
|
|
|
55
|
-
private _header?: HeaderBlock
|
|
56
|
-
private _footer?: ContextBlock
|
|
57
|
-
private _actor?: string
|
|
58
|
-
private _runId?: string
|
|
55
|
+
private _header?: HeaderBlock;
|
|
56
|
+
private _footer?: ContextBlock;
|
|
57
|
+
private _actor?: string;
|
|
58
|
+
private _runId?: string;
|
|
59
59
|
|
|
60
60
|
constructor(url: string, opts: SlackMessageOptions) {
|
|
61
61
|
this._webhook = new IncomingWebhook(url, {
|
|
62
62
|
username: opts.username || 'SARIF results',
|
|
63
|
-
icon_url: opts.iconUrl
|
|
64
|
-
})
|
|
65
|
-
this._gitHubServerUrl = process.env.GITHUB_SERVER_URL || 'https://github.com'
|
|
66
|
-
this._color = opts.color
|
|
67
|
-
this._representation = opts.representation
|
|
63
|
+
icon_url: opts.iconUrl,
|
|
64
|
+
});
|
|
65
|
+
this._gitHubServerUrl = process.env.GITHUB_SERVER_URL || 'https://github.com';
|
|
66
|
+
this._color = opts.color;
|
|
67
|
+
this._representation = opts.representation;
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
withHeader(header?: string): void {
|
|
@@ -72,67 +72,67 @@ class SlackMessageImpl implements SlackMessage {
|
|
|
72
72
|
type: 'header',
|
|
73
73
|
text: {
|
|
74
74
|
type: 'plain_text',
|
|
75
|
-
text: header || process.env.GITHUB_REPOSITORY || 'SARIF results'
|
|
76
|
-
}
|
|
77
|
-
}
|
|
75
|
+
text: header || process.env.GITHUB_REPOSITORY || 'SARIF results',
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
withActor(actor?: string): void {
|
|
81
|
-
this._actor = actor || process.env.GITHUB_ACTOR
|
|
81
|
+
this._actor = actor || process.env.GITHUB_ACTOR;
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
withRun(): void {
|
|
85
|
-
this._runId = process.env.GITHUB_RUN_ID
|
|
85
|
+
this._runId = process.env.GITHUB_RUN_ID;
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
withFooter(text?: string, type?: FooterType): void {
|
|
89
|
-
const repoName = 'fabasoad/sarif-to-slack'
|
|
89
|
+
const repoName = 'fabasoad/sarif-to-slack';
|
|
90
90
|
const element: TextObject = text
|
|
91
91
|
? { type: type || FooterType.PlainText, text }
|
|
92
|
-
: { type: FooterType.Markdown, text: `Generated by <${this._gitHubServerUrl}/${repoName}|@${repoName}@${version}>` }
|
|
92
|
+
: { type: FooterType.Markdown, text: `Generated by <${this._gitHubServerUrl}/${repoName}|@${repoName}@${version}>` };
|
|
93
93
|
this._footer = {
|
|
94
94
|
type: 'context',
|
|
95
95
|
elements: [element],
|
|
96
|
-
}
|
|
96
|
+
};
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
async send(): Promise<string> {
|
|
100
|
-
const blocks: AnyBlock[] = []
|
|
100
|
+
const blocks: AnyBlock[] = [];
|
|
101
101
|
if (this._header) {
|
|
102
|
-
blocks.push(this._header)
|
|
102
|
+
blocks.push(this._header);
|
|
103
103
|
}
|
|
104
104
|
blocks.push({
|
|
105
105
|
type: 'section',
|
|
106
106
|
text: {
|
|
107
107
|
type: 'mrkdwn',
|
|
108
108
|
text: this.buildText(),
|
|
109
|
-
}
|
|
110
|
-
})
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
111
|
if (this._footer) {
|
|
112
|
-
blocks.push(this._footer)
|
|
112
|
+
blocks.push(this._footer);
|
|
113
113
|
}
|
|
114
114
|
const { text } = await this._webhook.send({
|
|
115
|
-
attachments: [{ color: this._color, blocks }]
|
|
116
|
-
})
|
|
117
|
-
return text
|
|
115
|
+
attachments: [{ color: this._color, blocks }],
|
|
116
|
+
});
|
|
117
|
+
return text;
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
private buildText(): string {
|
|
121
|
-
const text: string[] = []
|
|
121
|
+
const text: string[] = [];
|
|
122
122
|
if (this._actor) {
|
|
123
|
-
const actorUrl = `${this._gitHubServerUrl}/${this._actor}
|
|
124
|
-
text.push(`_Triggered by <${actorUrl}|${this._actor}>_`)
|
|
123
|
+
const actorUrl = `${this._gitHubServerUrl}/${this._actor}`;
|
|
124
|
+
text.push(`_Triggered by <${actorUrl}|${this._actor}>_`);
|
|
125
125
|
}
|
|
126
|
-
text.push(this._representation.compose())
|
|
126
|
+
text.push(this._representation.compose());
|
|
127
127
|
if (this._runId) {
|
|
128
|
-
let runText: string = 'Job '
|
|
128
|
+
let runText: string = 'Job ';
|
|
129
129
|
if (process.env.GITHUB_REPOSITORY) {
|
|
130
|
-
runText += `<${this._gitHubServerUrl}/${process.env.GITHUB_REPOSITORY}/actions/runs/${this._runId}|#${this._runId}
|
|
130
|
+
runText += `<${this._gitHubServerUrl}/${process.env.GITHUB_REPOSITORY}/actions/runs/${this._runId}|#${this._runId}>`;
|
|
131
131
|
} else {
|
|
132
|
-
runText += `#${this._runId}
|
|
132
|
+
runText += `#${this._runId}`;
|
|
133
133
|
}
|
|
134
|
-
text.push(runText)
|
|
134
|
+
text.push(runText);
|
|
135
135
|
}
|
|
136
|
-
return text.join('\n\n')
|
|
136
|
+
return text.join('\n\n');
|
|
137
137
|
}
|
|
138
138
|
}
|
package/src/model/color/Color.ts
CHANGED
|
@@ -7,11 +7,11 @@ export class Color {
|
|
|
7
7
|
* A valid string that represents a color in hex format.
|
|
8
8
|
* @public
|
|
9
9
|
*/
|
|
10
|
-
public readonly color: string
|
|
10
|
+
public readonly color: string;
|
|
11
11
|
|
|
12
12
|
private constructor(color: string) {
|
|
13
|
-
this.color = this.mapColor(color)
|
|
14
|
-
this.assertHexColor()
|
|
13
|
+
this.color = this.mapColor(color);
|
|
14
|
+
this.assertHexColor();
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
/**
|
|
@@ -25,15 +25,15 @@ export class Color {
|
|
|
25
25
|
* @public
|
|
26
26
|
*/
|
|
27
27
|
public static from(color: string | undefined): Color | undefined {
|
|
28
|
-
return color ? new Color(color) : undefined
|
|
28
|
+
return color ? new Color(color) : undefined;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
private assertHexColor(): void {
|
|
32
32
|
if (this.color) {
|
|
33
|
-
const hexColorRegex = /^#(?:[0-9A-Fa-f]{3}|[0-9A-Fa-f]{4}|[0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})
|
|
33
|
+
const hexColorRegex = /^#(?:[0-9A-Fa-f]{3}|[0-9A-Fa-f]{4}|[0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})$/;
|
|
34
34
|
|
|
35
35
|
if (!hexColorRegex.test(this.color)) {
|
|
36
|
-
throw new Error(`Invalid hex color: "${this.color}"`)
|
|
36
|
+
throw new Error(`Invalid hex color: "${this.color}"`);
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
}
|
|
@@ -45,6 +45,6 @@ export class Color {
|
|
|
45
45
|
['cancelled', '#0047ab'],
|
|
46
46
|
['skipped', '#808080'],
|
|
47
47
|
])
|
|
48
|
-
return map.get(from) ?? from
|
|
48
|
+
return map.get(from) ?? from;
|
|
49
49
|
}
|
|
50
50
|
}
|
|
@@ -1,39 +1,39 @@
|
|
|
1
|
-
import type Finding from '../Finding'
|
|
2
|
-
import type FindingArray from '../FindingArray'
|
|
3
|
-
import { SecurityLevel, SecuritySeverity } from '../../types'
|
|
4
|
-
import Logger from '../../Logger'
|
|
1
|
+
import type Finding from '../Finding';
|
|
2
|
+
import type FindingArray from '../FindingArray';
|
|
3
|
+
import { SecurityLevel, SecuritySeverity } from '../../types';
|
|
4
|
+
import Logger from '../../Logger';
|
|
5
5
|
import type {
|
|
6
6
|
ColorGroupByLevel,
|
|
7
7
|
ColorGroupBySeverity,
|
|
8
8
|
ColorGroupCommon,
|
|
9
|
-
ColorOptions
|
|
10
|
-
} from './ColorOptions'
|
|
9
|
+
ColorOptions,
|
|
10
|
+
} from './ColorOptions';
|
|
11
11
|
import type { Color } from './Color';
|
|
12
12
|
|
|
13
13
|
function logColorTaken(
|
|
14
14
|
logger: Logger,
|
|
15
15
|
color: Color | undefined,
|
|
16
|
-
prop: string
|
|
16
|
+
prop: string,
|
|
17
17
|
): void {
|
|
18
|
-
logger.debug(`Message has ${color?.color} color taken from '${prop}' property.`)
|
|
18
|
+
logger.debug(`Message has ${color?.color} color taken from '${prop}' property.`);
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
function logPropDefinedButNoFindings<K extends keyof Pick<Finding, 'level' | 'severity'>>(
|
|
22
22
|
logger: Logger,
|
|
23
23
|
key: K,
|
|
24
|
-
val: string
|
|
24
|
+
val: string,
|
|
25
25
|
): void {
|
|
26
|
-
const prop: string = key === 'level' ? 'byLevel' : 'bySeverity'
|
|
27
|
-
logger.trace(`'${prop}.${val}' property is defined but no findings with "${val}" ${key} is found. Continue color identification...`)
|
|
26
|
+
const prop: string = key === 'level' ? 'byLevel' : 'bySeverity';
|
|
27
|
+
logger.trace(`'${prop}.${val}' property is defined but no findings with "${val}" ${key} is found. Continue color identification...`);
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
function logPropIsNotDefined<K extends keyof Pick<Finding, 'level' | 'severity'>>(
|
|
31
31
|
logger: Logger,
|
|
32
32
|
key: K,
|
|
33
|
-
val: string
|
|
33
|
+
val: string,
|
|
34
34
|
): void {
|
|
35
|
-
const prop: string = key === 'level' ? 'byLevel' : 'bySeverity'
|
|
36
|
-
logger.trace(`'${prop}.${val}' property is not defined. Continue color identification...`)
|
|
35
|
+
const prop: string = key === 'level' ? 'byLevel' : 'bySeverity';
|
|
36
|
+
logger.trace(`'${prop}.${val}' property is not defined. Continue color identification...`);
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
function identifyColorCommon<K extends keyof Pick<Finding, 'level' | 'severity'>>(
|
|
@@ -41,119 +41,119 @@ function identifyColorCommon<K extends keyof Pick<Finding, 'level' | 'severity'>
|
|
|
41
41
|
prop: K,
|
|
42
42
|
none: Finding[K],
|
|
43
43
|
unknown: Finding[K],
|
|
44
|
-
color: ColorGroupCommon
|
|
44
|
+
color: ColorGroupCommon,
|
|
45
45
|
): string | undefined {
|
|
46
|
-
const logger = new Logger(
|
|
46
|
+
const logger = new Logger();
|
|
47
47
|
if (color.none) {
|
|
48
48
|
if (findings.findByProperty(prop, none) != null) {
|
|
49
|
-
logColorTaken(logger, color.none, `${prop === 'severity' ? 'bySeverity' : 'byLevel'}.none`)
|
|
50
|
-
return color.none.color
|
|
49
|
+
logColorTaken(logger, color.none, `${prop === 'severity' ? 'bySeverity' : 'byLevel'}.none`);
|
|
50
|
+
return color.none.color;
|
|
51
51
|
} else {
|
|
52
|
-
logPropDefinedButNoFindings(logger, prop, 'none')
|
|
52
|
+
logPropDefinedButNoFindings(logger, prop, 'none');
|
|
53
53
|
}
|
|
54
54
|
} else {
|
|
55
|
-
logPropIsNotDefined(logger, prop, 'none')
|
|
55
|
+
logPropIsNotDefined(logger, prop, 'none');
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
if (color.unknown) {
|
|
59
59
|
if (findings.findByProperty(prop, unknown) != null) {
|
|
60
|
-
logColorTaken(logger, color.unknown, `${prop === 'severity' ? 'bySeverity' : 'byLevel'}.unknown`)
|
|
61
|
-
return color.unknown.color
|
|
60
|
+
logColorTaken(logger, color.unknown, `${prop === 'severity' ? 'bySeverity' : 'byLevel'}.unknown`);
|
|
61
|
+
return color.unknown.color;
|
|
62
62
|
} else {
|
|
63
|
-
logPropDefinedButNoFindings(logger, prop, 'unknown')
|
|
63
|
+
logPropDefinedButNoFindings(logger, prop, 'unknown');
|
|
64
64
|
}
|
|
65
65
|
} else {
|
|
66
|
-
logPropIsNotDefined(logger, prop, 'unknown')
|
|
66
|
+
logPropIsNotDefined(logger, prop, 'unknown');
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
return undefined
|
|
69
|
+
return undefined;
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
function identifyColorBySeverity(findings: FindingArray, color: ColorGroupBySeverity): string | undefined {
|
|
73
|
-
const logger = new Logger(
|
|
73
|
+
const logger = new Logger();
|
|
74
74
|
if (color.critical) {
|
|
75
75
|
if (findings.findByProperty('severity', SecuritySeverity.Critical) != null) {
|
|
76
|
-
logColorTaken(logger, color.critical, 'bySeverity.critical')
|
|
77
|
-
return color.critical.color
|
|
76
|
+
logColorTaken(logger, color.critical, 'bySeverity.critical');
|
|
77
|
+
return color.critical.color;
|
|
78
78
|
} else {
|
|
79
|
-
logPropDefinedButNoFindings(logger, 'severity', 'critical')
|
|
79
|
+
logPropDefinedButNoFindings(logger, 'severity', 'critical');
|
|
80
80
|
}
|
|
81
81
|
} else {
|
|
82
|
-
logPropIsNotDefined(logger, 'severity', 'critical')
|
|
82
|
+
logPropIsNotDefined(logger, 'severity', 'critical');
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
if (color.high) {
|
|
86
86
|
if (findings.findByProperty('severity', SecuritySeverity.High) != null) {
|
|
87
|
-
logColorTaken(logger, color.high, 'bySeverity.high')
|
|
88
|
-
return color.high.color
|
|
87
|
+
logColorTaken(logger, color.high, 'bySeverity.high');
|
|
88
|
+
return color.high.color;
|
|
89
89
|
} else {
|
|
90
|
-
logPropDefinedButNoFindings(logger, 'severity', 'high')
|
|
90
|
+
logPropDefinedButNoFindings(logger, 'severity', 'high');
|
|
91
91
|
}
|
|
92
92
|
} else {
|
|
93
|
-
logPropIsNotDefined(logger, 'severity', 'high')
|
|
93
|
+
logPropIsNotDefined(logger, 'severity', 'high');
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
if (color.medium) {
|
|
97
97
|
if (findings.findByProperty('severity', SecuritySeverity.Medium) != null) {
|
|
98
|
-
logColorTaken(logger, color.medium, 'bySeverity.medium')
|
|
99
|
-
return color.medium.color
|
|
98
|
+
logColorTaken(logger, color.medium, 'bySeverity.medium');
|
|
99
|
+
return color.medium.color;
|
|
100
100
|
} else {
|
|
101
|
-
logPropDefinedButNoFindings(logger, 'severity', 'medium')
|
|
101
|
+
logPropDefinedButNoFindings(logger, 'severity', 'medium');
|
|
102
102
|
}
|
|
103
103
|
} else {
|
|
104
|
-
logPropIsNotDefined(logger, 'severity', 'medium')
|
|
104
|
+
logPropIsNotDefined(logger, 'severity', 'medium');
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
if (color.low) {
|
|
108
108
|
if (findings.findByProperty('severity', SecuritySeverity.Low) != null) {
|
|
109
|
-
logColorTaken(logger, color.low, 'bySeverity.low')
|
|
110
|
-
return color.low.color
|
|
109
|
+
logColorTaken(logger, color.low, 'bySeverity.low');
|
|
110
|
+
return color.low.color;
|
|
111
111
|
} else {
|
|
112
|
-
logPropDefinedButNoFindings(logger, 'severity', 'low')
|
|
112
|
+
logPropDefinedButNoFindings(logger, 'severity', 'low');
|
|
113
113
|
}
|
|
114
114
|
} else {
|
|
115
|
-
logPropIsNotDefined(logger, 'severity', 'low')
|
|
115
|
+
logPropIsNotDefined(logger, 'severity', 'low');
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
-
return identifyColorCommon(findings, 'severity', SecuritySeverity.None, SecuritySeverity.Unknown, color)
|
|
118
|
+
return identifyColorCommon(findings, 'severity', SecuritySeverity.None, SecuritySeverity.Unknown, color);
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
function identifyColorByLevel(findings: FindingArray, color: ColorGroupByLevel): string | undefined {
|
|
122
|
-
const logger = new Logger(
|
|
122
|
+
const logger = new Logger();
|
|
123
123
|
if (color.error) {
|
|
124
124
|
if (findings.findByProperty('level', SecurityLevel.Error) != null) {
|
|
125
|
-
logColorTaken(logger, color.error, 'byLevel.error')
|
|
126
|
-
return color.error.color
|
|
125
|
+
logColorTaken(logger, color.error, 'byLevel.error');
|
|
126
|
+
return color.error.color;
|
|
127
127
|
} else {
|
|
128
|
-
logPropDefinedButNoFindings(logger, 'level', 'error')
|
|
128
|
+
logPropDefinedButNoFindings(logger, 'level', 'error');
|
|
129
129
|
}
|
|
130
130
|
} else {
|
|
131
|
-
logPropIsNotDefined(logger, 'level', 'error')
|
|
131
|
+
logPropIsNotDefined(logger, 'level', 'error');
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
if (color.warning) {
|
|
135
135
|
if (findings.findByProperty('level', SecurityLevel.Warning) != null) {
|
|
136
|
-
logColorTaken(logger, color.warning, 'byLevel.warning')
|
|
137
|
-
return color.warning.color
|
|
136
|
+
logColorTaken(logger, color.warning, 'byLevel.warning');
|
|
137
|
+
return color.warning.color;
|
|
138
138
|
} else {
|
|
139
|
-
logPropDefinedButNoFindings(logger, 'level', 'warning')
|
|
139
|
+
logPropDefinedButNoFindings(logger, 'level', 'warning');
|
|
140
140
|
}
|
|
141
141
|
} else {
|
|
142
|
-
logPropIsNotDefined(logger, 'level', 'warning')
|
|
142
|
+
logPropIsNotDefined(logger, 'level', 'warning');
|
|
143
143
|
}
|
|
144
144
|
|
|
145
145
|
if (color.note != null) {
|
|
146
146
|
if (findings.findByProperty('level', SecurityLevel.Note) != null) {
|
|
147
|
-
logColorTaken(logger, color.note, 'byLevel.note')
|
|
148
|
-
return color.note.color
|
|
147
|
+
logColorTaken(logger, color.note, 'byLevel.note');
|
|
148
|
+
return color.note.color;
|
|
149
149
|
} else {
|
|
150
|
-
logPropDefinedButNoFindings(logger, 'level', 'note')
|
|
150
|
+
logPropDefinedButNoFindings(logger, 'level', 'note');
|
|
151
151
|
}
|
|
152
152
|
} else {
|
|
153
|
-
logPropIsNotDefined(logger, 'level', 'note')
|
|
153
|
+
logPropIsNotDefined(logger, 'level', 'note');
|
|
154
154
|
}
|
|
155
155
|
|
|
156
|
-
return identifyColorCommon(findings, 'level', SecurityLevel.None, SecurityLevel.Unknown, color)
|
|
156
|
+
return identifyColorCommon(findings, 'level', SecurityLevel.None, SecurityLevel.Unknown, color);
|
|
157
157
|
}
|
|
158
158
|
|
|
159
159
|
/**
|
|
@@ -165,50 +165,50 @@ function identifyColorByLevel(findings: FindingArray, color: ColorGroupByLevel):
|
|
|
165
165
|
* @internal
|
|
166
166
|
*/
|
|
167
167
|
export function identifyColor(findings: FindingArray, colorOpts?: ColorOptions): string | undefined {
|
|
168
|
-
const logger = new Logger(
|
|
168
|
+
const logger = new Logger();
|
|
169
169
|
if (!colorOpts) {
|
|
170
|
-
logger.debug('Message has no color as color options are not defined.')
|
|
171
|
-
return undefined
|
|
170
|
+
logger.debug('Message has no color as color options are not defined.');
|
|
171
|
+
return undefined;
|
|
172
172
|
}
|
|
173
|
-
logger.trace(`Identifying color for ${findings.length} findings and the following color options:`, JSON.stringify(colorOpts, null, 2))
|
|
173
|
+
logger.trace(`Identifying color for ${findings.length} findings and the following color options:`, JSON.stringify(colorOpts, null, 2));
|
|
174
174
|
|
|
175
175
|
if (colorOpts.bySeverity) {
|
|
176
|
-
const color: string | undefined = identifyColorBySeverity(findings, colorOpts.bySeverity)
|
|
176
|
+
const color: string | undefined = identifyColorBySeverity(findings, colorOpts.bySeverity);
|
|
177
177
|
if (color) {
|
|
178
|
-
return color
|
|
178
|
+
return color;
|
|
179
179
|
}
|
|
180
|
-
logger.trace('None of the properties in \'bySeverity\' group is applicable. Continue color identification...')
|
|
180
|
+
logger.trace('None of the properties in \'bySeverity\' group is applicable. Continue color identification...');
|
|
181
181
|
} else {
|
|
182
|
-
logger.trace('\'bySeverity\' group is not defined. Continue color identification...')
|
|
182
|
+
logger.trace('\'bySeverity\' group is not defined. Continue color identification...');
|
|
183
183
|
}
|
|
184
184
|
|
|
185
185
|
if (colorOpts.byLevel) {
|
|
186
|
-
const color: string | undefined = identifyColorByLevel(findings, colorOpts.byLevel)
|
|
186
|
+
const color: string | undefined = identifyColorByLevel(findings, colorOpts.byLevel);
|
|
187
187
|
if (color) {
|
|
188
|
-
return color
|
|
188
|
+
return color;
|
|
189
189
|
}
|
|
190
|
-
logger.trace('None of the properties in \'byLevel\' group is applicable. Continue color identification...')
|
|
190
|
+
logger.trace('None of the properties in \'byLevel\' group is applicable. Continue color identification...');
|
|
191
191
|
} else {
|
|
192
|
-
logger.trace('\'byLevel\' group is not defined. Continue color identification...')
|
|
192
|
+
logger.trace('\'byLevel\' group is not defined. Continue color identification...');
|
|
193
193
|
}
|
|
194
194
|
|
|
195
195
|
if (findings.length === 0) {
|
|
196
|
-
logger.trace('There are no findings in the provided SARIF file(s). Checking if color is defined in "empty" property...')
|
|
196
|
+
logger.trace('There are no findings in the provided SARIF file(s). Checking if color is defined in "empty" property...');
|
|
197
197
|
if (colorOpts.empty?.color) {
|
|
198
|
-
logColorTaken(logger, colorOpts.empty, 'empty')
|
|
199
|
-
return colorOpts.empty.color
|
|
198
|
+
logColorTaken(logger, colorOpts.empty, 'empty');
|
|
199
|
+
return colorOpts.empty.color;
|
|
200
200
|
} else {
|
|
201
|
-
logger.trace('"empty" color is not defined. Continue color identification...')
|
|
201
|
+
logger.trace('"empty" color is not defined. Continue color identification...');
|
|
202
202
|
}
|
|
203
203
|
} else {
|
|
204
|
-
logger.trace(`"empty" color is not taken into account because there are ${findings.length} findings in the provided SARIF file(s). Continue color identification...`)
|
|
204
|
+
logger.trace(`"empty" color is not taken into account because there are ${findings.length} findings in the provided SARIF file(s). Continue color identification...`);
|
|
205
205
|
}
|
|
206
206
|
|
|
207
207
|
if (colorOpts.default?.color) {
|
|
208
|
-
logColorTaken(logger, colorOpts.default, 'default')
|
|
208
|
+
logColorTaken(logger, colorOpts.default, 'default');
|
|
209
209
|
} else {
|
|
210
|
-
logger.debug('Message has no color as none of the defined color options is applicable.')
|
|
210
|
+
logger.debug('Message has no color as none of the defined color options is applicable.');
|
|
211
211
|
}
|
|
212
212
|
|
|
213
|
-
return colorOpts?.default?.color
|
|
213
|
+
return colorOpts?.default?.color;
|
|
214
214
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { CommonProcessor } from './CommonProcessor'
|
|
2
|
-
import type { Result } from 'sarif'
|
|
1
|
+
import { CommonProcessor } from './CommonProcessor';
|
|
2
|
+
import type { Result } from 'sarif';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* This class has extra logic for processing SARIF files produced by CodeQL tool.
|
|
@@ -14,6 +14,6 @@ export class CodeQLProcessor extends CommonProcessor {
|
|
|
14
14
|
* "problem.severity" property.
|
|
15
15
|
*/
|
|
16
16
|
public override tryFindLevel(): Result.level | undefined {
|
|
17
|
-
return super.tryFindLevel() ?? this.tryFindRuleProperty('problem.severity')
|
|
17
|
+
return super.tryFindLevel() ?? this.tryFindRuleProperty('problem.severity');
|
|
18
18
|
}
|
|
19
19
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { ReportingDescriptor, Result, Run, ToolComponent } from 'sarif'
|
|
2
|
-
import * as sarifUtils from '../utils/SarifUtils'
|
|
1
|
+
import type { ReportingDescriptor, Result, Run, ToolComponent } from 'sarif';
|
|
2
|
+
import * as sarifUtils from '../utils/SarifUtils';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* This class has logic of the SARIF file processing, such as finding rule,
|
|
@@ -11,8 +11,8 @@ import * as sarifUtils from '../utils/SarifUtils'
|
|
|
11
11
|
* @internal
|
|
12
12
|
*/
|
|
13
13
|
export class CommonProcessor {
|
|
14
|
-
protected readonly _run: Run
|
|
15
|
-
protected readonly _result: Result
|
|
14
|
+
protected readonly _run: Run;
|
|
15
|
+
protected readonly _result: Result;
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Creates an instance of {@link CommonProcessor} class.
|
|
@@ -20,28 +20,28 @@ export class CommonProcessor {
|
|
|
20
20
|
* @param result An instance of {@link Result} object.
|
|
21
21
|
*/
|
|
22
22
|
public constructor(run: Run, result: Result) {
|
|
23
|
-
this._run = run
|
|
24
|
-
this._result = result
|
|
23
|
+
this._run = run;
|
|
24
|
+
this._result = result;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
public tryFindCvssScore(): number | undefined {
|
|
28
|
-
return this.tryFindRuleProperty('security-severity')
|
|
28
|
+
return this.tryFindRuleProperty('security-severity');
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
public tryFindLevel(): Result.level | undefined {
|
|
32
|
-
return this._result.level ?? this.tryFindRule()?.defaultConfiguration?.level
|
|
32
|
+
return this._result.level ?? this.tryFindRule()?.defaultConfiguration?.level;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
public findToolComponentDriver(): ToolComponent {
|
|
36
|
-
return sarifUtils.findToolComponentDriver(this._run)
|
|
36
|
+
return sarifUtils.findToolComponentDriver(this._run);
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
public tryFindToolComponentExtension(): ToolComponent | undefined {
|
|
40
|
-
return sarifUtils.tryFindToolComponentExtension(this._run, this._result)
|
|
40
|
+
return sarifUtils.tryFindToolComponentExtension(this._run, this._result);
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
public findToolComponent(): ToolComponent {
|
|
44
|
-
return sarifUtils.findToolComponent(this._run, this._result)
|
|
44
|
+
return sarifUtils.findToolComponent(this._run, this._result);
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
/**
|
|
@@ -49,41 +49,41 @@ export class CommonProcessor {
|
|
|
49
49
|
* @internal
|
|
50
50
|
*/
|
|
51
51
|
public tryFindRule(): ReportingDescriptor | undefined {
|
|
52
|
-
const ruleData: { id?: string, index?: number } = {}
|
|
52
|
+
const ruleData: { id?: string, index?: number } = {};
|
|
53
53
|
|
|
54
54
|
if (this._result.rule) {
|
|
55
55
|
if (this._result.rule?.index != null) {
|
|
56
|
-
ruleData.index = this._result.rule.index
|
|
56
|
+
ruleData.index = this._result.rule.index;
|
|
57
57
|
}
|
|
58
58
|
if (this._result.rule?.id) {
|
|
59
|
-
ruleData.id = this._result.rule.id
|
|
59
|
+
ruleData.id = this._result.rule.id;
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
if (ruleData.index == null && this._result.ruleIndex != null) {
|
|
64
|
-
ruleData.index = this._result.ruleIndex
|
|
64
|
+
ruleData.index = this._result.ruleIndex;
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
if (!ruleData.id && this._result.ruleId) {
|
|
68
|
-
ruleData.id = this._result.ruleId
|
|
68
|
+
ruleData.id = this._result.ruleId;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
const tool: ToolComponent = this.findToolComponent()
|
|
71
|
+
const tool: ToolComponent = this.findToolComponent();
|
|
72
72
|
|
|
73
73
|
if (ruleData.index != null
|
|
74
74
|
&& tool?.rules
|
|
75
75
|
&& ruleData.index < tool.rules.length) {
|
|
76
|
-
return tool.rules[ruleData.index]
|
|
76
|
+
return tool.rules[ruleData.index];
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
// If failed to find rule by index then try to find by ruleId
|
|
80
80
|
if (ruleData.id && tool?.rules) {
|
|
81
81
|
return tool.rules.find(
|
|
82
|
-
(r: ReportingDescriptor): boolean => r.id === ruleData.id
|
|
83
|
-
)
|
|
82
|
+
(r: ReportingDescriptor): boolean => r.id === ruleData.id,
|
|
83
|
+
);
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
return undefined
|
|
86
|
+
return undefined;
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
/**
|
|
@@ -93,11 +93,11 @@ export class CommonProcessor {
|
|
|
93
93
|
* @protected
|
|
94
94
|
*/
|
|
95
95
|
protected tryFindRuleProperty<T>(propertyName: string): T | undefined {
|
|
96
|
-
const rule: ReportingDescriptor | undefined = this.tryFindRule()
|
|
96
|
+
const rule: ReportingDescriptor | undefined = this.tryFindRule();
|
|
97
97
|
if (rule?.properties && propertyName in rule.properties) {
|
|
98
|
-
return rule.properties[propertyName] as T
|
|
98
|
+
return rule.properties[propertyName] as T;
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
-
return undefined
|
|
101
|
+
return undefined;
|
|
102
102
|
}
|
|
103
103
|
}
|