@fabasoad/sarif-to-slack 1.3.1 → 1.3.3
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/actionlint.yaml +9 -0
- package/.github/workflows/release.yml +19 -9
- 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 +603 -237
- 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 +8 -7
- 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 +10 -10
- 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 +20 -19
- 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 @@
|
|
|
1
|
+
{"version":3,"file":"StringUtils.d.ts","sourceRoot":"","sources":["../../src/utils/StringUtils.ts"],"names":[],"mappings":"AAAA,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAMvD"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export function randomAlphabetic(length) {
|
|
2
|
+
const alphabet = 'abcdefghijklmnopqrstuvwxyz';
|
|
3
|
+
return Array.from({ length }, () => alphabet[Math.floor(Math.random() * alphabet.length)]).join('');
|
|
4
|
+
}
|
|
5
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU3RyaW5nVXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdXRpbHMvU3RyaW5nVXRpbHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsTUFBTSxVQUFVLGdCQUFnQixDQUFDLE1BQWM7SUFDN0MsTUFBTSxRQUFRLEdBQUcsNEJBQTRCLENBQUE7SUFDN0MsT0FBTyxLQUFLLENBQUMsSUFBSSxDQUNmLEVBQUUsTUFBTSxFQUFFLEVBQ1YsR0FBVyxFQUFFLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxHQUFHLFFBQVEsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUNwRSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQTtBQUNaLENBQUMifQ==
|
|
@@ -60,24 +60,6 @@ export type IncludeAwareWithValueOptions = IncludeAwareOptions & {
|
|
|
60
60
|
value?: string;
|
|
61
61
|
};
|
|
62
62
|
|
|
63
|
-
// @public
|
|
64
|
-
export enum LogLevel {
|
|
65
|
-
Debug = 2,
|
|
66
|
-
Error = 5,
|
|
67
|
-
Fatal = 6,
|
|
68
|
-
Info = 3,
|
|
69
|
-
Silly = 0,
|
|
70
|
-
Trace = 1,
|
|
71
|
-
Warning = 4
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// @public
|
|
75
|
-
export type LogOptions = {
|
|
76
|
-
level?: LogLevel;
|
|
77
|
-
template?: string;
|
|
78
|
-
colored?: boolean;
|
|
79
|
-
};
|
|
80
|
-
|
|
81
63
|
// @public
|
|
82
64
|
export enum RepresentationType {
|
|
83
65
|
CompactGroupByRunPerLevel = 0,
|
|
@@ -87,7 +69,13 @@ export enum RepresentationType {
|
|
|
87
69
|
CompactGroupByToolNamePerLevel = 2,
|
|
88
70
|
CompactGroupByToolNamePerSeverity = 3,
|
|
89
71
|
CompactTotalPerLevel = 6,
|
|
90
|
-
CompactTotalPerSeverity = 7
|
|
72
|
+
CompactTotalPerSeverity = 7,
|
|
73
|
+
TableGroupByRunPerLevel = 8,
|
|
74
|
+
TableGroupByRunPerSeverity = 9,
|
|
75
|
+
TableGroupBySarifPerLevel = 12,
|
|
76
|
+
TableGroupBySarifPerSeverity = 13,
|
|
77
|
+
TableGroupByToolNamePerLevel = 10,
|
|
78
|
+
TableGroupByToolNamePerSeverity = 11
|
|
91
79
|
}
|
|
92
80
|
|
|
93
81
|
// @public
|
|
@@ -102,19 +90,16 @@ export type SarifOptions = {
|
|
|
102
90
|
|
|
103
91
|
// @public
|
|
104
92
|
export class SarifToSlackClient {
|
|
105
|
-
|
|
106
|
-
static create(opts: SarifToSlackClientOptions): Promise<SarifToSlackClient>;
|
|
93
|
+
static create(webhookUrl: string, opts: SarifToSlackClientOptions): Promise<SarifToSlackClient>;
|
|
107
94
|
send(): Promise<void>;
|
|
108
95
|
}
|
|
109
96
|
|
|
110
97
|
// @public
|
|
111
98
|
export type SarifToSlackClientOptions = {
|
|
112
|
-
webhookUrl: string;
|
|
113
99
|
sarif: SarifOptions;
|
|
114
100
|
username?: string;
|
|
115
101
|
iconUrl?: string;
|
|
116
102
|
color?: ColorOptions;
|
|
117
|
-
log?: LogOptions;
|
|
118
103
|
header?: IncludeAwareWithValueOptions;
|
|
119
104
|
footer?: FooterOptions;
|
|
120
105
|
actor?: IncludeAwareWithValueOptions;
|
|
@@ -151,17 +136,4 @@ export enum SendIf {
|
|
|
151
136
|
Some = 21
|
|
152
137
|
}
|
|
153
138
|
|
|
154
|
-
// @public
|
|
155
|
-
export interface SlackMessage {
|
|
156
|
-
send: () => Promise<string>;
|
|
157
|
-
// (undocumented)
|
|
158
|
-
withActor(actor?: string): void;
|
|
159
|
-
// (undocumented)
|
|
160
|
-
withFooter(text?: string, type?: FooterType): void;
|
|
161
|
-
// (undocumented)
|
|
162
|
-
withHeader(header?: string): void;
|
|
163
|
-
// (undocumented)
|
|
164
|
-
withRun(): void;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
139
|
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fabasoad/sarif-to-slack",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.3",
|
|
4
4
|
"description": "TypeScript library to send results of SARIF file to Slack webhook URL.",
|
|
5
5
|
"main": "dist/index.cjs",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -44,18 +44,18 @@
|
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"@slack/webhook": "7.0.6",
|
|
46
46
|
"@types/sarif": "2.1.7",
|
|
47
|
-
"tslog": "4.
|
|
47
|
+
"tslog": "4.10.2",
|
|
48
|
+
"zod": "4.1.12"
|
|
48
49
|
},
|
|
49
50
|
"devDependencies": {
|
|
50
|
-
"@biomejs/biome": "2.2.
|
|
51
|
-
"@microsoft/api-documenter": "7.26.
|
|
52
|
-
"@microsoft/api-extractor": "7.52.
|
|
51
|
+
"@biomejs/biome": "2.2.5",
|
|
52
|
+
"@microsoft/api-documenter": "7.26.36",
|
|
53
|
+
"@microsoft/api-extractor": "7.52.15",
|
|
53
54
|
"@types/jest": "30.0.0",
|
|
54
|
-
"
|
|
55
|
-
"jest": "30.0
|
|
56
|
-
"jest
|
|
57
|
-
"ts-jest": "29.4.1",
|
|
55
|
+
"jest": "30.2.0",
|
|
56
|
+
"jest-circus": "30.2.0",
|
|
57
|
+
"ts-jest": "29.4.4",
|
|
58
58
|
"tsup": "8.5.0",
|
|
59
|
-
"typescript": "5.9.
|
|
59
|
+
"typescript": "5.9.3"
|
|
60
60
|
}
|
|
61
61
|
}
|
package/src/Logger.ts
CHANGED
|
@@ -1,43 +1,81 @@
|
|
|
1
|
-
import { ILogObj, Logger as TSLogger } from 'tslog'
|
|
2
|
-
import {
|
|
1
|
+
import { type ILogObj, Logger as TSLogger } from 'tslog'
|
|
2
|
+
import { z, type ZodSafeParseResult } from 'zod';
|
|
3
|
+
import { isDebug } from './system';
|
|
4
|
+
|
|
5
|
+
const LogLevelItems = ['silly', 'trace', 'debug', 'info', 'warning', 'error', 'fatal'] as const;
|
|
6
|
+
type LogLevel = (typeof LogLevelItems)[number];
|
|
3
7
|
|
|
4
8
|
/**
|
|
5
9
|
* Logger class for managing logging operations.
|
|
6
10
|
* @internal
|
|
7
11
|
*/
|
|
8
12
|
export default class Logger {
|
|
9
|
-
private static
|
|
10
|
-
private static
|
|
11
|
-
private static
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
13
|
+
private static APP_NAME: string = '@fabasoad/sarif-to-slack';
|
|
14
|
+
private static DEFAULT_LOG_LEVEL: LogLevel = 'info';
|
|
15
|
+
private static DEFAULT_LOG_TEMPLATE: string = '[{{logLevelName}}] [{{name}}] {{dateIsoStr}} ';
|
|
16
|
+
private static DEFAULT_LOG_COLORED: boolean = true;
|
|
17
|
+
|
|
18
|
+
private readonly _instance: TSLogger<ILogObj>;
|
|
19
|
+
|
|
20
|
+
private isLogLevel(v: string): v is LogLevel {
|
|
21
|
+
return (LogLevelItems as ReadonlyArray<string>).includes(v);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
private getMinLevel(): number {
|
|
25
|
+
let result: LogLevel = Logger.DEFAULT_LOG_LEVEL;
|
|
26
|
+
|
|
27
|
+
if (isDebug()) {
|
|
28
|
+
result = 'silly';
|
|
29
|
+
} else {
|
|
30
|
+
const parseResult: ZodSafeParseResult<LogLevel> = z
|
|
31
|
+
.string()
|
|
32
|
+
.refine((v: string): boolean => this.isLogLevel(v))
|
|
33
|
+
.transform((v: string): LogLevel => v as LogLevel)
|
|
34
|
+
.safeParse(process.env.SARIF_TO_SLACK_LOG_LEVEL);
|
|
35
|
+
if (parseResult.success) {
|
|
36
|
+
result = parseResult.data;
|
|
37
|
+
}
|
|
25
38
|
}
|
|
39
|
+
|
|
40
|
+
return LogLevelItems.findIndex((v: LogLevel): boolean => v === result);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
private getLogTemplate(): string {
|
|
44
|
+
const result: ZodSafeParseResult<string> =
|
|
45
|
+
z.string().safeParse(process.env.SARIF_TO_SLACK_LOG_TEMPLATE);
|
|
46
|
+
return result.success ? result.data : Logger.DEFAULT_LOG_TEMPLATE;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
private getLogColored(): boolean {
|
|
50
|
+
const result: ZodSafeParseResult<boolean> =
|
|
51
|
+
z.stringbool().safeParse(process.env.SARIF_TO_SLACK_LOG_COLORED);
|
|
52
|
+
return result.success ? result.data : Logger.DEFAULT_LOG_COLORED;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
public constructor(memberName?: string) {
|
|
56
|
+
this._instance = new TSLogger({
|
|
57
|
+
name: `${Logger.APP_NAME}${memberName === undefined ? '' : `::${memberName}`}`,
|
|
58
|
+
minLevel: this.getMinLevel(),
|
|
59
|
+
type: 'pretty',
|
|
60
|
+
prettyLogTimeZone: 'UTC',
|
|
61
|
+
prettyLogTemplate: this.getLogTemplate(),
|
|
62
|
+
stylePrettyLogs: this.getLogColored(),
|
|
63
|
+
})
|
|
26
64
|
}
|
|
27
65
|
|
|
28
|
-
public
|
|
29
|
-
|
|
66
|
+
public info(...args: unknown[]): void {
|
|
67
|
+
this._instance.info(...args);
|
|
30
68
|
}
|
|
31
69
|
|
|
32
|
-
public
|
|
33
|
-
|
|
70
|
+
public warn(...args: unknown[]): void {
|
|
71
|
+
this._instance.warn(...args);
|
|
34
72
|
}
|
|
35
73
|
|
|
36
|
-
public
|
|
37
|
-
|
|
74
|
+
public trace(...args: unknown[]): void {
|
|
75
|
+
this._instance.trace(...args);
|
|
38
76
|
}
|
|
39
77
|
|
|
40
|
-
public
|
|
41
|
-
|
|
78
|
+
public debug(...args: unknown[]): void {
|
|
79
|
+
this._instance.debug(...args);
|
|
42
80
|
}
|
|
43
81
|
}
|
|
@@ -1,23 +1,22 @@
|
|
|
1
|
-
import { promises as fs } from 'fs'
|
|
2
|
-
import { Log } from 'sarif'
|
|
1
|
+
import { promises as fs } from 'node:fs'
|
|
2
|
+
import type { Log } from 'sarif'
|
|
3
3
|
import Logger from './Logger'
|
|
4
4
|
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
SarifToSlackClientOptions,
|
|
5
|
+
type RunData,
|
|
6
|
+
type SarifModel,
|
|
7
|
+
type SarifOptions,
|
|
8
|
+
type SarifToSlackClientOptions,
|
|
10
9
|
SecurityLevel,
|
|
11
10
|
SecuritySeverity
|
|
12
11
|
} from './types'
|
|
13
|
-
import
|
|
12
|
+
import { logMetadata } from './system'
|
|
14
13
|
import { extractListOfFiles } from './utils/FileUtils'
|
|
15
14
|
import { createRepresentation } from './representations/RepresentationFactory'
|
|
16
15
|
import { createFinding } from './model/Finding'
|
|
17
16
|
import { findToolComponent, findToolComponentDriver } from './utils/SarifUtils'
|
|
18
17
|
import { identifyColor } from './model/color/ColorIdentification'
|
|
19
18
|
import FindingArray from './model/FindingArray'
|
|
20
|
-
import { createSlackMessage, SlackMessage } from './model/SlackMessage'
|
|
19
|
+
import { createSlackMessage, type SlackMessage } from './model/SlackMessage'
|
|
21
20
|
import { SendIf, sendIfLogMessage } from './model/SendIf'
|
|
22
21
|
|
|
23
22
|
/**
|
|
@@ -25,29 +24,40 @@ import { SendIf, sendIfLogMessage } from './model/SendIf'
|
|
|
25
24
|
* @public
|
|
26
25
|
*/
|
|
27
26
|
export class SarifToSlackClient {
|
|
28
|
-
private
|
|
29
|
-
private
|
|
27
|
+
private readonly _logger = new Logger('SarifToSlackClient');
|
|
28
|
+
private _message?: SlackMessage;
|
|
29
|
+
private _sarifModel?: SarifModel;
|
|
30
30
|
|
|
31
|
-
private _sendIf: SendIf = SendIf.Always
|
|
31
|
+
private _sendIf: SendIf = SendIf.Always;
|
|
32
32
|
|
|
33
|
-
private constructor(
|
|
34
|
-
|
|
35
|
-
System.initialize()
|
|
33
|
+
private constructor() {
|
|
34
|
+
logMetadata();
|
|
36
35
|
}
|
|
37
36
|
|
|
38
37
|
private static *createRunIdGenerator(): Generator<number> {
|
|
39
|
-
let runId: number = 1
|
|
38
|
+
let runId: number = 1;
|
|
40
39
|
while (true) {
|
|
41
|
-
yield runId
|
|
40
|
+
yield runId++;
|
|
42
41
|
}
|
|
43
42
|
}
|
|
44
43
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
44
|
+
/**
|
|
45
|
+
* Creates an instance of {@link SarifToSlackClient} class. It already has all
|
|
46
|
+
* properties and fields initialized.
|
|
47
|
+
* @param webhookUrl - Slack webhook URL.
|
|
48
|
+
* @param opts - An instance of {@link SarifToSlackClientOptions} type.
|
|
49
|
+
*
|
|
50
|
+
* @see SarifToSlackClientOptions
|
|
51
|
+
*
|
|
52
|
+
* @public
|
|
53
|
+
*/
|
|
54
|
+
public static async create(webhookUrl: string, opts: SarifToSlackClientOptions): Promise<SarifToSlackClient> {
|
|
55
|
+
const instance = new SarifToSlackClient();
|
|
56
|
+
instance._logger.trace(opts);
|
|
57
|
+
instance._sendIf = opts.sendIf ?? instance._sendIf;
|
|
58
|
+
instance._sarifModel = await SarifToSlackClient.buildModel(opts.sarif);
|
|
59
|
+
instance._message = await SarifToSlackClient.initialize(webhookUrl, opts, instance._sarifModel);
|
|
60
|
+
return instance;
|
|
51
61
|
}
|
|
52
62
|
|
|
53
63
|
private static async buildModel(sarifOpts: SarifOptions): Promise<SarifModel> {
|
|
@@ -64,7 +74,7 @@ export class SarifToSlackClient {
|
|
|
64
74
|
|
|
65
75
|
for (const run of sarifLog.runs) {
|
|
66
76
|
const runId: IteratorResult<number> = runIdGenerator.next()
|
|
67
|
-
let runMetadata: RunData | undefined
|
|
77
|
+
let runMetadata: RunData | undefined
|
|
68
78
|
for (const result of run.results ?? []) {
|
|
69
79
|
runMetadata = {
|
|
70
80
|
id: runId.value,
|
|
@@ -85,16 +95,19 @@ export class SarifToSlackClient {
|
|
|
85
95
|
/**
|
|
86
96
|
* The main function to initialize a list of {@link SlackMessage} objects based
|
|
87
97
|
* on the given SARIF file(s).
|
|
88
|
-
* @param
|
|
98
|
+
* @param webhookUrl - Slack webhook URL.
|
|
89
99
|
* @param opts - An instance of {@link SarifToSlackClientOptions} object.
|
|
100
|
+
* @param sarifModel - An instance of SarifModel object.
|
|
90
101
|
* @returns A map where key is the SARIF file and value is an instance of
|
|
91
102
|
* {@link SlackMessage} object.
|
|
103
|
+
* @internal
|
|
92
104
|
*/
|
|
93
105
|
private static async initialize(
|
|
106
|
+
webhookUrl: string,
|
|
107
|
+
opts: SarifToSlackClientOptions,
|
|
94
108
|
sarifModel: SarifModel,
|
|
95
|
-
opts: Omit<SarifToSlackClientOptions, 'sarif' | 'log' | 'sendIf'>
|
|
96
109
|
): Promise<SlackMessage> {
|
|
97
|
-
const message: SlackMessage = createSlackMessage(
|
|
110
|
+
const message: SlackMessage = createSlackMessage(webhookUrl, {
|
|
98
111
|
username: opts.username,
|
|
99
112
|
iconUrl: opts.iconUrl,
|
|
100
113
|
color: identifyColor(sarifModel.findings, opts.color),
|
|
@@ -130,9 +143,9 @@ export class SarifToSlackClient {
|
|
|
130
143
|
throw new Error('Slack message was not prepared.')
|
|
131
144
|
}
|
|
132
145
|
const text: string = await this._message.send()
|
|
133
|
-
|
|
146
|
+
this._logger.info('Message sent. Status:', text)
|
|
134
147
|
} else {
|
|
135
|
-
|
|
148
|
+
this._logger.info(sendIfLogMessage(this._sendIf))
|
|
136
149
|
}
|
|
137
150
|
}
|
|
138
151
|
|
package/src/index.ts
CHANGED
|
@@ -12,7 +12,6 @@
|
|
|
12
12
|
* import {
|
|
13
13
|
* Color,
|
|
14
14
|
* FooterType,
|
|
15
|
-
* LogLevel,
|
|
16
15
|
* RepresentationType,
|
|
17
16
|
* SarifToSlackClient,
|
|
18
17
|
* SendIf
|
|
@@ -46,11 +45,6 @@
|
|
|
46
45
|
* recursive: true,
|
|
47
46
|
* extension: 'sarif',
|
|
48
47
|
* },
|
|
49
|
-
* log: {
|
|
50
|
-
* level: LogLevel.Info,
|
|
51
|
-
* template: '[{{logLevelName}}] [{{name}}] {{dateIsoStr}} ',
|
|
52
|
-
* colored: false,
|
|
53
|
-
* },
|
|
54
48
|
* header: {
|
|
55
49
|
* include: true,
|
|
56
50
|
* value: 'SARIF Analysis Results'
|
|
@@ -85,15 +79,12 @@ export {
|
|
|
85
79
|
ColorGroupBySeverity
|
|
86
80
|
} from './model/color/ColorOptions'
|
|
87
81
|
export { SendIf } from './model/SendIf'
|
|
88
|
-
export { SlackMessage } from './model/SlackMessage'
|
|
89
82
|
export { SarifToSlackClient } from './SarifToSlackClient'
|
|
90
83
|
export {
|
|
91
84
|
FooterOptions,
|
|
92
85
|
FooterType,
|
|
93
86
|
IncludeAwareOptions,
|
|
94
87
|
IncludeAwareWithValueOptions,
|
|
95
|
-
LogLevel,
|
|
96
|
-
LogOptions,
|
|
97
88
|
RepresentationType,
|
|
98
89
|
SarifFileExtension,
|
|
99
90
|
SarifOptions,
|
package/src/model/Finding.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ReportingDescriptor, Result } from 'sarif'
|
|
2
|
-
import { RunData, SecurityLevel, SecuritySeverity } from '../types'
|
|
2
|
+
import { type RunData, SecurityLevel, SecuritySeverity } from '../types'
|
|
3
3
|
import Logger from '../Logger'
|
|
4
|
-
import { CommonProcessor } from '../processors/CommonProcessor'
|
|
4
|
+
import type { CommonProcessor } from '../processors/CommonProcessor'
|
|
5
5
|
import { createProcessor } from '../processors/ProcessorFactory'
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -43,17 +43,18 @@ export function createFinding(opts: FindingOptions): Finding {
|
|
|
43
43
|
* @private
|
|
44
44
|
*/
|
|
45
45
|
class FindingImpl implements Finding {
|
|
46
|
-
private readonly
|
|
47
|
-
private readonly
|
|
48
|
-
private readonly
|
|
49
|
-
private readonly
|
|
50
|
-
private readonly
|
|
46
|
+
private readonly _logger = new Logger('FindingImpl');
|
|
47
|
+
private readonly _runMetadata: RunData;
|
|
48
|
+
private readonly _result: Result;
|
|
49
|
+
private readonly _sarifPath: string;
|
|
50
|
+
private readonly _rule?: ReportingDescriptor;
|
|
51
|
+
private readonly _processor: CommonProcessor;
|
|
51
52
|
|
|
52
|
-
private _cvssScoreCacheProcessed: boolean = false
|
|
53
|
-
private _cvssScoreCache: number | undefined = undefined
|
|
53
|
+
private _cvssScoreCacheProcessed: boolean = false;
|
|
54
|
+
private _cvssScoreCache: number | undefined = undefined;
|
|
54
55
|
|
|
55
|
-
private _levelCacheProcessed: boolean = false
|
|
56
|
-
private _levelCache: Result.level | undefined = undefined
|
|
56
|
+
private _levelCacheProcessed: boolean = false;
|
|
57
|
+
private _levelCache: Result.level | undefined = undefined;
|
|
57
58
|
|
|
58
59
|
constructor(opts: FindingOptions) {
|
|
59
60
|
this._processor = createProcessor(opts.runMetadata.run, opts.result)
|
|
@@ -98,7 +99,7 @@ class FindingImpl implements Finding {
|
|
|
98
99
|
}
|
|
99
100
|
|
|
100
101
|
if (this._levelCache === undefined) {
|
|
101
|
-
|
|
102
|
+
this._logger.debug(`Unknown level of ${this._rule?.id} rule`)
|
|
102
103
|
return SecurityLevel.Unknown
|
|
103
104
|
}
|
|
104
105
|
|
|
@@ -112,7 +113,7 @@ class FindingImpl implements Finding {
|
|
|
112
113
|
|
|
113
114
|
public get severity(): SecuritySeverity {
|
|
114
115
|
if (this.cvssScore == null || this.cvssScore < 0 || this.cvssScore > 10) {
|
|
115
|
-
|
|
116
|
+
this._logger.debug(`Unsupported CVSS score ${this.cvssScore} in ${this._rule?.id} rule`)
|
|
116
117
|
return SecuritySeverity.Unknown
|
|
117
118
|
}
|
|
118
119
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { AnyBlock } from '@slack/types'
|
|
2
|
-
import { ContextBlock, HeaderBlock } from '@slack/types/dist/block-kit/blocks'
|
|
3
|
-
import { TextObject } from '@slack/types/dist/block-kit/composition-objects'
|
|
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
4
|
import { IncomingWebhook } from '@slack/webhook'
|
|
5
5
|
import { FooterType } from '../types'
|
|
6
|
-
import Representation from '../representations/Representation'
|
|
6
|
+
import type Representation from '../representations/Representation'
|
|
7
7
|
import { version } from '../metadata.json'
|
|
8
8
|
|
|
9
9
|
/**
|
|
@@ -19,7 +19,7 @@ export type SlackMessageOptions = {
|
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* Interface for a Slack message that can be sent.
|
|
22
|
-
* @
|
|
22
|
+
* @internal
|
|
23
23
|
*/
|
|
24
24
|
export interface SlackMessage {
|
|
25
25
|
/**
|