@fabasoad/sarif-to-slack 0.2.0 → 0.2.1
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 +3 -1
- package/.github/workflows/send-sarif-to-slack.yml +214 -0
- package/.pre-commit-config.yaml +3 -3
- package/.tool-versions +1 -1
- package/Makefile +9 -2
- package/README.md +1 -1
- package/dist/Logger.js +15 -6
- package/dist/Processors.js +23 -22
- package/dist/SarifToSlackService.d.ts.map +1 -1
- package/dist/SarifToSlackService.js +5 -6
- package/dist/SlackMessageBuilder.js +46 -52
- package/dist/index.d.ts +6 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -3
- package/dist/model/SarifModelPerRun.d.ts +17 -0
- package/dist/model/SarifModelPerRun.d.ts.map +1 -0
- package/dist/model/SarifModelPerRun.js +84 -0
- package/dist/model/SarifModelPerSarif.d.ts +20 -0
- package/dist/model/SarifModelPerSarif.d.ts.map +1 -0
- package/dist/model/SarifModelPerSarif.js +97 -0
- package/dist/model/types.d.ts +17 -0
- package/dist/model/types.d.ts.map +1 -0
- package/dist/model/types.js +31 -0
- package/dist/sarif-to-slack.d.ts +96 -12
- package/dist/tsdoc-metadata.json +1 -1
- package/dist/types.d.ts +87 -11
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +66 -9
- package/dist/utils/SarifUtils.d.ts +5 -0
- package/dist/utils/SarifUtils.d.ts.map +1 -0
- package/dist/utils/SarifUtils.js +32 -0
- package/dist/utils/SortUtils.d.ts +5 -0
- package/dist/utils/SortUtils.d.ts.map +1 -0
- package/dist/utils/SortUtils.js +8 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/etc/sarif-to-slack.api.md +32 -7
- package/jest.config.json +4 -4
- package/package.json +9 -7
- package/src/Logger.ts +20 -17
- package/src/Processors.ts +22 -22
- package/src/SarifToSlackService.ts +5 -6
- package/src/SlackMessageBuilder.ts +78 -63
- package/src/index.ts +10 -2
- package/src/model/SarifModelPerRun.ts +114 -0
- package/src/model/SarifModelPerSarif.ts +116 -0
- package/src/model/types.ts +31 -0
- package/src/types.ts +91 -11
- package/src/utils/SarifUtils.ts +44 -0
- package/src/utils/SortUtils.ts +21 -0
- package/src/version.ts +1 -1
- package/test-data/sarif/codeql-csharp.sarif +1 -0
- package/test-data/sarif/codeql-go.sarif +1 -0
- package/test-data/sarif/codeql-python.sarif +1 -0
- package/test-data/sarif/codeql-ruby.sarif +1 -0
- package/test-data/sarif/codeql-typescript.sarif +1 -0
- package/test-data/sarif/grype-container.sarif +1774 -0
- package/test-data/sarif/runs-1-tools-1-results-0.sarif +18 -0
- package/test-data/sarif/runs-2-tools-1-results-0.sarif +30 -0
- package/test-data/sarif/runs-2-tools-1.sarif +656 -0
- package/test-data/sarif/runs-2-tools-2-results-0.sarif +44 -0
- package/test-data/sarif/runs-2-tools-2.sarif +686 -0
- package/test-data/sarif/runs-3-tools-2-results-0.sarif +48 -0
- package/test-data/sarif/runs-3-tools-2.sarif +278 -0
- package/test-data/sarif/snyk-composer.sarif +934 -0
- package/test-data/sarif/snyk-container.sarif +313 -0
- package/test-data/sarif/snyk-gomodules.sarif +388 -0
- package/test-data/sarif/snyk-gradle.sarif +274 -0
- package/test-data/sarif/snyk-hex.sarif +66 -0
- package/test-data/sarif/snyk-maven.sarif +274 -0
- package/test-data/sarif/snyk-npm.sarif +896 -0
- package/test-data/sarif/snyk-nuget.sarif +90 -0
- package/test-data/sarif/snyk-pip.sarif +66 -0
- package/test-data/sarif/snyk-pnpm.sarif +90 -0
- package/test-data/sarif/snyk-poetry.sarif +1952 -0
- package/test-data/sarif/snyk-rubygems.sarif +440 -0
- package/test-data/sarif/snyk-sbt.sarif +178 -0
- package/test-data/sarif/snyk-swift.sarif +112 -0
- package/test-data/sarif/snyk-yarn.sarif +2900 -0
- package/test-data/sarif/trivy-iac.sarif +134 -0
- package/test-data/sarif/wiz-container.sarif +30916 -0
- package/test-data/sarif/wiz-iac.sarif +558 -0
- package/tests/Processors.spec.ts +3 -3
- package/tests/integration/SendSarifToSlack.spec.ts +56 -0
|
@@ -42,10 +42,12 @@ jobs:
|
|
|
42
42
|
run: npm ci
|
|
43
43
|
|
|
44
44
|
- name: Bump version
|
|
45
|
+
env:
|
|
46
|
+
BUMP_STRATEGY: "${{ github.event.inputs.bump-strategy }}"
|
|
45
47
|
run: |
|
|
46
48
|
git config user.email "fabasoad@gmail.com"
|
|
47
49
|
git config user.name "fabasoad"
|
|
48
|
-
npm run version:${
|
|
50
|
+
npm run version:${BUMP_STRATEGY}
|
|
49
51
|
|
|
50
52
|
- name: Install jq
|
|
51
53
|
uses: dcarbone/install-jq-action@v3
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Send SARIF to Slack
|
|
3
|
+
|
|
4
|
+
on: # yamllint disable-line rule:truthy
|
|
5
|
+
workflow_dispatch:
|
|
6
|
+
inputs:
|
|
7
|
+
sarif:
|
|
8
|
+
description: SARIF to send
|
|
9
|
+
required: true
|
|
10
|
+
default: "Snyk Yarn (Error: 30, Warning: 16, Note: 3)"
|
|
11
|
+
type: choice
|
|
12
|
+
options:
|
|
13
|
+
- "CodeQL C# (Unknown: 1)"
|
|
14
|
+
- "CodeQL Go (Unknown: 1)"
|
|
15
|
+
- "CodeQL Python (Unknown: 1)"
|
|
16
|
+
- "CodeQL Ruby (Unknown: 4)"
|
|
17
|
+
- "CodeQL TypeScript (Unknown: 1)"
|
|
18
|
+
- "Grype Container (Error: 10, Warning: 20, Note: 9)"
|
|
19
|
+
- "Snyk Composer (Error: 15, Warning: 5)"
|
|
20
|
+
- "Snyk Container (Error: 1, Note: 3)"
|
|
21
|
+
- "Snyk Gomodules (Error: 4, Warning: 4)"
|
|
22
|
+
- "Snyk Gradle (Error: 3, Warning: 1)"
|
|
23
|
+
- "Snyk Hex (Error: 1)"
|
|
24
|
+
- "Snyk Maven (Error: 3, Warning: 1)"
|
|
25
|
+
- "Snyk NPM (Error: 6, Warning: 6, Note: 2)"
|
|
26
|
+
- "Snyk Nuget (Error: 1)"
|
|
27
|
+
- "Snyk Pip (Warning: 1)"
|
|
28
|
+
- "Snyk PNPM (Error: 1)"
|
|
29
|
+
- "Snyk Poetry (Error: 6, Warning: 21, Note: 2)"
|
|
30
|
+
- "Snyk Rubygems (Error: 1, Warning: 5)"
|
|
31
|
+
- "Snyk Sbt (Error: 2, Warning: 1)"
|
|
32
|
+
- "Snyk Swift (Warning: 2)"
|
|
33
|
+
- "Snyk Yarn (Error: 30, Warning: 16, Note: 3)"
|
|
34
|
+
- "Trivy IaC (Error: 1, Note: 1)"
|
|
35
|
+
- "Wiz Container (Error: 12, Warning: 369, Note: 191)"
|
|
36
|
+
- "Wiz IaC (Warning: 5, Note: 5)"
|
|
37
|
+
- "Runs: 1, Tools: 1, Results: 0"
|
|
38
|
+
- "Runs: 2, Tools: 1, Results > 0"
|
|
39
|
+
- "Runs: 2, Tools: 1, Results: 0"
|
|
40
|
+
- "Runs: 2, Tools: 2, Results > 0"
|
|
41
|
+
- "Runs: 2, Tools: 2, Results: 0"
|
|
42
|
+
- "Runs: 3, Tools: 2, Results > 0"
|
|
43
|
+
- "Runs: 3, Tools: 2, Results: 0"
|
|
44
|
+
- "All"
|
|
45
|
+
group-by:
|
|
46
|
+
description: "Group results by:"
|
|
47
|
+
required: false
|
|
48
|
+
default: "Tool name"
|
|
49
|
+
type: choice
|
|
50
|
+
options:
|
|
51
|
+
- "Tool name"
|
|
52
|
+
- "Run"
|
|
53
|
+
- "Total"
|
|
54
|
+
calculate-by:
|
|
55
|
+
description: "Calculate results by:"
|
|
56
|
+
required: false
|
|
57
|
+
default: "Level"
|
|
58
|
+
type: choice
|
|
59
|
+
options:
|
|
60
|
+
- "Level"
|
|
61
|
+
- "Severity"
|
|
62
|
+
log-level:
|
|
63
|
+
description: "Log level:"
|
|
64
|
+
required: false
|
|
65
|
+
default: info
|
|
66
|
+
type: choice
|
|
67
|
+
options:
|
|
68
|
+
- silly
|
|
69
|
+
- trace
|
|
70
|
+
- debug
|
|
71
|
+
- info
|
|
72
|
+
- warning
|
|
73
|
+
- error
|
|
74
|
+
- fatal
|
|
75
|
+
color:
|
|
76
|
+
description: "Slack message color (hex):"
|
|
77
|
+
required: false
|
|
78
|
+
default: "#ff0000"
|
|
79
|
+
type: string
|
|
80
|
+
username:
|
|
81
|
+
description: "Slack message username:"
|
|
82
|
+
required: false
|
|
83
|
+
type: string
|
|
84
|
+
header:
|
|
85
|
+
description: |
|
|
86
|
+
Header (leave empty for default value, set to "skip" to not include it,
|
|
87
|
+
or set to any string to use it as a header):
|
|
88
|
+
required: false
|
|
89
|
+
default: "skip"
|
|
90
|
+
type: string
|
|
91
|
+
footer:
|
|
92
|
+
description: |
|
|
93
|
+
Footer (leave empty for default value, set to "skip" to not include it,
|
|
94
|
+
or set to any string to use it as a footer):
|
|
95
|
+
required: false
|
|
96
|
+
type: string
|
|
97
|
+
actor:
|
|
98
|
+
description: |
|
|
99
|
+
Actor (leave empty for default value, set to "skip" to not include it,
|
|
100
|
+
or set to any string to use it as an actor):
|
|
101
|
+
required: false
|
|
102
|
+
default: "skip"
|
|
103
|
+
type: string
|
|
104
|
+
include-run:
|
|
105
|
+
description: Include run in the message.
|
|
106
|
+
required: false
|
|
107
|
+
default: true
|
|
108
|
+
type: boolean
|
|
109
|
+
|
|
110
|
+
defaults:
|
|
111
|
+
run:
|
|
112
|
+
shell: sh
|
|
113
|
+
|
|
114
|
+
jobs:
|
|
115
|
+
send-sarif:
|
|
116
|
+
name: ${{ inputs.sarif }}
|
|
117
|
+
timeout-minutes: 5
|
|
118
|
+
runs-on: ubuntu-latest
|
|
119
|
+
steps:
|
|
120
|
+
- name: Checkout ${{ github.repository }}
|
|
121
|
+
uses: actions/checkout@v4
|
|
122
|
+
- name: Determine SARIF file
|
|
123
|
+
id: sarif-file
|
|
124
|
+
env:
|
|
125
|
+
INPUT_SARIF: "${{ inputs.sarif }}"
|
|
126
|
+
run: |
|
|
127
|
+
if [ "${INPUT_SARIF}" = "CodeQL C# (Unknown: 1)" ]; then
|
|
128
|
+
value="codeql-csharp.sarif"
|
|
129
|
+
elif [ "${INPUT_SARIF}" = "CodeQL Go (Unknown: 1)" ]; then
|
|
130
|
+
value="codeql-go.sarif"
|
|
131
|
+
elif [ "${INPUT_SARIF}" = "CodeQL Python (Unknown: 1)" ]; then
|
|
132
|
+
value="codeql-python.sarif"
|
|
133
|
+
elif [ "${INPUT_SARIF}" = "CodeQL Ruby (Unknown: 4)" ]; then
|
|
134
|
+
value="codeql-ruby.sarif"
|
|
135
|
+
elif [ "${INPUT_SARIF}" = "CodeQL TypeScript (Unknown: 1)" ]; then
|
|
136
|
+
value="codeql-typescript.sarif"
|
|
137
|
+
elif [ "${INPUT_SARIF}" = "Grype Container (Error: 10, Warning: 20, Note: 9)" ]; then
|
|
138
|
+
value="grype-container.sarif"
|
|
139
|
+
elif [ "${INPUT_SARIF}" = "Snyk Composer (Error: 15, Warning: 5)" ]; then
|
|
140
|
+
value="snyk-composer.sarif"
|
|
141
|
+
elif [ "${INPUT_SARIF}" = "Snyk Container (Error: 1, Note: 3)" ]; then
|
|
142
|
+
value="snyk-container.sarif"
|
|
143
|
+
elif [ "${INPUT_SARIF}" = "Snyk Gomodules (Error: 4, Warning: 4)" ]; then
|
|
144
|
+
value="snyk-gomodules.sarif"
|
|
145
|
+
elif [ "${INPUT_SARIF}" = "Snyk Gradle (Error: 3, Warning: 1)" ]; then
|
|
146
|
+
value="snyk-gradle.sarif"
|
|
147
|
+
elif [ "${INPUT_SARIF}" = "Snyk Hex (Error: 1)" ]; then
|
|
148
|
+
value="snyk-hex.sarif"
|
|
149
|
+
elif [ "${INPUT_SARIF}" = "Snyk Maven (Error: 3, Warning: 1)" ]; then
|
|
150
|
+
value="snyk-maven.sarif"
|
|
151
|
+
elif [ "${INPUT_SARIF}" = "Snyk NPM (Error: 6, Warning: 6, Note: 2)" ]; then
|
|
152
|
+
value="snyk-npm.sarif"
|
|
153
|
+
elif [ "${INPUT_SARIF}" = "Snyk Nuget (Error: 1)" ]; then
|
|
154
|
+
value="snyk-nuget.sarif"
|
|
155
|
+
elif [ "${INPUT_SARIF}" = "Snyk Pip (Warning: 1)" ]; then
|
|
156
|
+
value="snyk-pip.sarif"
|
|
157
|
+
elif [ "${INPUT_SARIF}" = "Snyk PNPM (Error: 1)" ]; then
|
|
158
|
+
value="snyk-pnpm.sarif"
|
|
159
|
+
elif [ "${INPUT_SARIF}" = "Snyk Poetry (Error: 6, Warning: 21, Note: 2)" ]; then
|
|
160
|
+
value="snyk-poetry.sarif"
|
|
161
|
+
elif [ "${INPUT_SARIF}" = "Snyk Rubygems (Error: 1, Warning: 5)" ]; then
|
|
162
|
+
value="snyk-rubygems.sarif"
|
|
163
|
+
elif [ "${INPUT_SARIF}" = "Snyk Sbt (Error: 2, Warning: 1)" ]; then
|
|
164
|
+
value="snyk-sbt.sarif"
|
|
165
|
+
elif [ "${INPUT_SARIF}" = "Snyk Swift (Warning: 2)" ]; then
|
|
166
|
+
value="snyk-swift.sarif"
|
|
167
|
+
elif [ "${INPUT_SARIF}" = "Snyk Yarn (Error: 30, Warning: 16, Note: 3)" ]; then
|
|
168
|
+
value="snyk-yarn.sarif"
|
|
169
|
+
elif [ "${INPUT_SARIF}" = "Trivy IaC (Error: 1, Note: 1)" ]; then
|
|
170
|
+
value="trivy-iac.sarif"
|
|
171
|
+
elif [ "${INPUT_SARIF}" = "Wiz Container (Error: 12, Warning: 369, Note: 191)" ]; then
|
|
172
|
+
value="wiz-container.sarif"
|
|
173
|
+
elif [ "${INPUT_SARIF}" = "Wiz IaC (Warning: 5, Note: 5)" ]; then
|
|
174
|
+
value="wiz-iac.sarif"
|
|
175
|
+
elif [ "${INPUT_SARIF}" = "Runs: 1, Tools: 1, Results: 0" ]; then
|
|
176
|
+
value="runs-1-tools-1-results-0.sarif"
|
|
177
|
+
elif [ "${INPUT_SARIF}" = "Runs: 2, Tools: 1, Results > 0" ]; then
|
|
178
|
+
value="runs-2-tools-1.sarif"
|
|
179
|
+
elif [ "${INPUT_SARIF}" = "Runs: 2, Tools: 1, Results: 0" ]; then
|
|
180
|
+
value="runs-2-tools-1-results-0.sarif"
|
|
181
|
+
elif [ "${INPUT_SARIF}" = "Runs: 2, Tools: 2, Results > 0" ]; then
|
|
182
|
+
value="runs-2-tools-2.sarif"
|
|
183
|
+
elif [ "${INPUT_SARIF}" = "Runs: 2, Tools: 2, Results: 0" ]; then
|
|
184
|
+
value="runs-2-tools-2-results-0.sarif"
|
|
185
|
+
elif [ "${INPUT_SARIF}" = "Runs: 3, Tools: 2, Results > 0" ]; then
|
|
186
|
+
value="runs-3-tools-2.sarif"
|
|
187
|
+
elif [ "${INPUT_SARIF}" = "Runs: 3, Tools: 2, Results: 0" ]; then
|
|
188
|
+
value="runs-3-tools-2-results-0.sarif"
|
|
189
|
+
else
|
|
190
|
+
# All
|
|
191
|
+
value=""
|
|
192
|
+
fi
|
|
193
|
+
echo "value=${value}" >> "$GITHUB_OUTPUT"
|
|
194
|
+
- name: Setup node
|
|
195
|
+
uses: actions/setup-node@v4
|
|
196
|
+
with:
|
|
197
|
+
node-version-file: ".tool-versions"
|
|
198
|
+
- name: Install dependencies
|
|
199
|
+
run: npm ci
|
|
200
|
+
- name: Send message
|
|
201
|
+
env:
|
|
202
|
+
SARIF_TO_SLACK_WEBHOOK_URL: "${{ secrets.TMP_EUGENE_SLACK_WEBHOOK }}"
|
|
203
|
+
SARIF_TO_SLACK_USERNAME: "${{ inputs.username }}"
|
|
204
|
+
SARIF_TO_SLACK_ICON_URL: "https://cdn-icons-png.flaticon.com/512/9070/9070006.png"
|
|
205
|
+
SARIF_TO_SLACK_COLOR: "${{ inputs.color }}"
|
|
206
|
+
SARIF_TO_SLACK_SARIF_FILE_NAME: "${{ steps.sarif-file.outputs.value }}"
|
|
207
|
+
SARIF_TO_SLACK_LOG_LEVEL: "${{ inputs.log-level }}"
|
|
208
|
+
SARIF_TO_SLACK_HEADER: "${{ inputs.header }}"
|
|
209
|
+
SARIF_TO_SLACK_FOOTER: "${{ inputs.footer }}"
|
|
210
|
+
SARIF_TO_SLACK_ACTOR: "${{ inputs.actor }}"
|
|
211
|
+
SARIF_TO_SLACK_INCLUDE_RUN: "${{ inputs.include-run }}"
|
|
212
|
+
SARIF_TO_SLACK_GROUP_BY: "${{ inputs.group-by}}"
|
|
213
|
+
SARIF_TO_SLACK_CALCULATE_BY: "${{ inputs.calculate-by}}"
|
|
214
|
+
run: npm run test:integration
|
package/.pre-commit-config.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
default_install_hook_types: ["pre-commit", "pre-push"]
|
|
3
3
|
default_stages: ["pre-commit", "pre-push"]
|
|
4
|
-
exclude: ^(dist/.*|etc/.*|node_modules/.*|temp/.*)$
|
|
4
|
+
exclude: ^(dist/.*|etc/.*|node_modules/.*|temp/.*|test-data/.*)$
|
|
5
5
|
minimum_pre_commit_version: 4.0.0
|
|
6
6
|
repos:
|
|
7
7
|
- repo: local
|
|
@@ -40,7 +40,7 @@ repos:
|
|
|
40
40
|
hooks:
|
|
41
41
|
- id: detect-secrets
|
|
42
42
|
- repo: https://github.com/gitleaks/gitleaks
|
|
43
|
-
rev: v8.
|
|
43
|
+
rev: v8.28.0
|
|
44
44
|
hooks:
|
|
45
45
|
- id: gitleaks
|
|
46
46
|
- repo: https://github.com/fabasoad/pre-commit-snyk
|
|
@@ -60,7 +60,7 @@ repos:
|
|
|
60
60
|
- --hook-args=--log-level debug
|
|
61
61
|
stages: ["pre-push"]
|
|
62
62
|
- repo: https://github.com/google/osv-scanner
|
|
63
|
-
rev: v2.0
|
|
63
|
+
rev: v2.1.0
|
|
64
64
|
hooks:
|
|
65
65
|
- id: osv-scanner
|
|
66
66
|
args:
|
package/.tool-versions
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
nodejs 24.
|
|
1
|
+
nodejs 24.4.1
|
package/Makefile
CHANGED
|
@@ -26,10 +26,17 @@ reinstall:
|
|
|
26
26
|
lint:
|
|
27
27
|
@npm run lint
|
|
28
28
|
|
|
29
|
-
.PHONY: test
|
|
30
|
-
test:
|
|
29
|
+
.PHONY: test/integration
|
|
30
|
+
test/integration:
|
|
31
|
+
@npm run test:integration
|
|
32
|
+
|
|
33
|
+
.PHONY: test/unit
|
|
34
|
+
test/unit:
|
|
31
35
|
@npm run test
|
|
32
36
|
|
|
37
|
+
.PHONY: test
|
|
38
|
+
test: test/unit
|
|
39
|
+
|
|
33
40
|
.PHONY: npm/update
|
|
34
41
|
npm/update:
|
|
35
42
|
@npm update
|
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|

|
|
6
6
|

|
|
7
7
|

|
|
8
|
-
[](https://codecov.io/github/fabasoad/sarif-to-slack)
|
|
9
9
|
|
|
10
10
|
TypeScript library to send results of SARIF file to Slack webhook URL.
|
|
11
11
|
|
package/dist/Logger.js
CHANGED
|
@@ -5,21 +5,30 @@ import { LogLevel } from './types';
|
|
|
5
5
|
* @internal
|
|
6
6
|
*/
|
|
7
7
|
export default class Logger {
|
|
8
|
-
static
|
|
9
|
-
static
|
|
8
|
+
static DEFAULT_LOG_LEVEL = LogLevel.Info;
|
|
9
|
+
static DEFAULT_LOG_TEMPLATE = '[{{logLevelName}}] [{{name}}] {{dateIsoStr}} ';
|
|
10
|
+
static DEFAULT_LOG_COLORED = true;
|
|
11
|
+
static instance;
|
|
12
|
+
static initialize(opts) {
|
|
10
13
|
if (!Logger.instance) {
|
|
11
14
|
Logger.instance = new TSLogger({
|
|
12
|
-
|
|
15
|
+
name: '@fabasoad/sarif-to-slack',
|
|
16
|
+
minLevel: process.env.ACTIONS_STEP_DEBUG === 'true' ? LogLevel.Silly : (opts?.level ?? Logger.DEFAULT_LOG_LEVEL),
|
|
13
17
|
type: 'pretty',
|
|
14
18
|
prettyLogTimeZone: 'UTC',
|
|
19
|
+
prettyLogTemplate: opts?.template ?? Logger.DEFAULT_LOG_TEMPLATE,
|
|
20
|
+
stylePrettyLogs: opts?.colored ?? Logger.DEFAULT_LOG_COLORED,
|
|
15
21
|
});
|
|
16
22
|
}
|
|
17
23
|
}
|
|
24
|
+
static warn(...args) {
|
|
25
|
+
Logger.instance.warn(...args);
|
|
26
|
+
}
|
|
18
27
|
static info(...args) {
|
|
19
|
-
Logger.instance.info(args);
|
|
28
|
+
Logger.instance.info(...args);
|
|
20
29
|
}
|
|
21
30
|
static debug(...args) {
|
|
22
|
-
Logger.instance.debug(args);
|
|
31
|
+
Logger.instance.debug(...args);
|
|
23
32
|
}
|
|
24
33
|
}
|
|
25
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
34
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTG9nZ2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL0xvZ2dlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQVcsTUFBTSxJQUFJLFFBQVEsRUFBRSxNQUFNLE9BQU8sQ0FBQTtBQUNuRCxPQUFPLEVBQUUsUUFBUSxFQUFjLE1BQU0sU0FBUyxDQUFBO0FBRTlDOzs7R0FHRztBQUNILE1BQU0sQ0FBQyxPQUFPLE9BQU8sTUFBTTtJQUNqQixNQUFNLENBQUMsaUJBQWlCLEdBQWEsUUFBUSxDQUFDLElBQUksQ0FBQTtJQUNsRCxNQUFNLENBQUMsb0JBQW9CLEdBQVcsK0NBQStDLENBQUE7SUFDckYsTUFBTSxDQUFDLG1CQUFtQixHQUFZLElBQUksQ0FBQTtJQUUxQyxNQUFNLENBQUMsUUFBUSxDQUFtQjtJQUVuQyxNQUFNLENBQUMsVUFBVSxDQUFDLElBQWlCO1FBQ3hDLElBQUksQ0FBQyxNQUFNLENBQUMsUUFBUSxFQUFFLENBQUM7WUFDckIsTUFBTSxDQUFDLFFBQVEsR0FBRyxJQUFJLFFBQVEsQ0FBQztnQkFDN0IsSUFBSSxFQUFFLDBCQUEwQjtnQkFDaEMsUUFBUSxFQUFFLE9BQU8sQ0FBQyxHQUFHLENBQUMsa0JBQWtCLEtBQUssTUFBTSxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBRSxLQUFLLElBQUksTUFBTSxDQUFDLGlCQUFpQixDQUFDO2dCQUNoSCxJQUFJLEVBQUUsUUFBUTtnQkFDZCxpQkFBaUIsRUFBRSxLQUFLO2dCQUN4QixpQkFBaUIsRUFBRSxJQUFJLEVBQUUsUUFBUSxJQUFJLE1BQU0sQ0FBQyxvQkFBb0I7Z0JBQ2hFLGVBQWUsRUFBRSxJQUFJLEVBQUUsT0FBTyxJQUFJLE1BQU0sQ0FBQyxtQkFBbUI7YUFDN0QsQ0FBQyxDQUFBO1FBQ0osQ0FBQztJQUNILENBQUM7SUFFTSxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsSUFBZTtRQUNuQyxNQUFNLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxHQUFHLElBQUksQ0FBQyxDQUFBO0lBQy9CLENBQUM7SUFFTSxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsSUFBZTtRQUNuQyxNQUFNLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxHQUFHLElBQUksQ0FBQyxDQUFBO0lBQy9CLENBQUM7SUFFTSxNQUFNLENBQUMsS0FBSyxDQUFDLEdBQUcsSUFBZTtRQUNwQyxNQUFNLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxHQUFHLElBQUksQ0FBQyxDQUFBO0lBQ2hDLENBQUMifQ==
|
package/dist/Processors.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as fs from 'fs';
|
|
2
2
|
import * as path from 'path';
|
|
3
3
|
import Logger from './Logger';
|
|
4
|
+
import { LogLevel } from './types';
|
|
4
5
|
/**
|
|
5
6
|
* Processes a color string and converts it to a specific hex code if it matches
|
|
6
7
|
* a CI status identifier.
|
|
@@ -25,7 +26,7 @@ export function processColor(color) {
|
|
|
25
26
|
Logger.info(`Converting "${color}" to #808080`);
|
|
26
27
|
return '#808080';
|
|
27
28
|
default:
|
|
28
|
-
Logger.debug(`"${color}" color is not a CI status identifier. Returning as is
|
|
29
|
+
Logger.debug(`"${color}" color is not a CI status identifier. Returning as is.`);
|
|
29
30
|
return color;
|
|
30
31
|
}
|
|
31
32
|
}
|
|
@@ -37,27 +38,27 @@ export function processColor(color) {
|
|
|
37
38
|
* @internal
|
|
38
39
|
*/
|
|
39
40
|
export function processLogLevel(logLevel) {
|
|
40
|
-
if (
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
41
|
+
if (!logLevel) {
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
switch (logLevel.toLowerCase()) {
|
|
45
|
+
case 'silly':
|
|
46
|
+
return LogLevel.Silly;
|
|
47
|
+
case 'trace':
|
|
48
|
+
return LogLevel.Trace;
|
|
49
|
+
case 'debug':
|
|
50
|
+
return LogLevel.Debug;
|
|
51
|
+
case 'info':
|
|
52
|
+
return LogLevel.Info;
|
|
53
|
+
case 'warning':
|
|
54
|
+
return LogLevel.Warning;
|
|
55
|
+
case 'error':
|
|
56
|
+
return LogLevel.Error;
|
|
57
|
+
case 'fatal':
|
|
58
|
+
return LogLevel.Fatal;
|
|
59
|
+
default:
|
|
60
|
+
throw new Error(`Unknown log level: ${logLevel}`);
|
|
59
61
|
}
|
|
60
|
-
return logLevel;
|
|
61
62
|
}
|
|
62
63
|
/**
|
|
63
64
|
* Processes the SARIF path, which can be a file or a directory. If it's a
|
|
@@ -88,4 +89,4 @@ export function processSarifPath(sarifPath) {
|
|
|
88
89
|
}
|
|
89
90
|
throw new Error(`"sarif-path" is neither a file nor a directory: ${sarifPath}`);
|
|
90
91
|
}
|
|
91
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
92
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUHJvY2Vzc29ycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9Qcm9jZXNzb3JzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxFQUFFLE1BQU0sSUFBSSxDQUFBO0FBQ3hCLE9BQU8sS0FBSyxJQUFJLE1BQU0sTUFBTSxDQUFBO0FBQzVCLE9BQU8sTUFBTSxNQUFNLFVBQVUsQ0FBQTtBQUM3QixPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sU0FBUyxDQUFBO0FBRWxDOzs7Ozs7OztHQVFHO0FBQ0gsTUFBTSxVQUFVLFlBQVksQ0FBQyxLQUFjO0lBQ3pDLFFBQVEsS0FBSyxFQUFFLENBQUM7UUFDZCxLQUFLLFNBQVM7WUFDWixNQUFNLENBQUMsSUFBSSxDQUFDLGVBQWUsS0FBSyxjQUFjLENBQUMsQ0FBQTtZQUMvQyxPQUFPLFNBQVMsQ0FBQTtRQUNsQixLQUFLLFNBQVM7WUFDWixNQUFNLENBQUMsSUFBSSxDQUFDLGVBQWUsS0FBSyxjQUFjLENBQUMsQ0FBQTtZQUMvQyxPQUFPLFNBQVMsQ0FBQTtRQUNsQixLQUFLLFdBQVc7WUFDZCxNQUFNLENBQUMsSUFBSSxDQUFDLGVBQWUsS0FBSyxjQUFjLENBQUMsQ0FBQTtZQUMvQyxPQUFPLFNBQVMsQ0FBQTtRQUNsQixLQUFLLFNBQVM7WUFDWixNQUFNLENBQUMsSUFBSSxDQUFDLGVBQWUsS0FBSyxjQUFjLENBQUMsQ0FBQTtZQUMvQyxPQUFPLFNBQVMsQ0FBQTtRQUNsQjtZQUNFLE1BQU0sQ0FBQyxLQUFLLENBQUMsSUFBSSxLQUFLLHlEQUF5RCxDQUFDLENBQUE7WUFDaEYsT0FBTyxLQUFLLENBQUE7SUFDaEIsQ0FBQztBQUNILENBQUM7QUFFRDs7Ozs7O0dBTUc7QUFDSCxNQUFNLFVBQVUsZUFBZSxDQUFDLFFBQWlCO0lBQy9DLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztRQUNkLE9BQU8sU0FBUyxDQUFBO0lBQ2xCLENBQUM7SUFDRCxRQUFRLFFBQVEsQ0FBQyxXQUFXLEVBQUUsRUFBRSxDQUFDO1FBQy9CLEtBQUssT0FBTztZQUNWLE9BQU8sUUFBUSxDQUFDLEtBQUssQ0FBQTtRQUN2QixLQUFLLE9BQU87WUFDVixPQUFPLFFBQVEsQ0FBQyxLQUFLLENBQUE7UUFDdkIsS0FBSyxPQUFPO1lBQ1YsT0FBTyxRQUFRLENBQUMsS0FBSyxDQUFBO1FBQ3ZCLEtBQUssTUFBTTtZQUNULE9BQU8sUUFBUSxDQUFDLElBQUksQ0FBQTtRQUN0QixLQUFLLFNBQVM7WUFDWixPQUFPLFFBQVEsQ0FBQyxPQUFPLENBQUE7UUFDekIsS0FBSyxPQUFPO1lBQ1YsT0FBTyxRQUFRLENBQUMsS0FBSyxDQUFBO1FBQ3ZCLEtBQUssT0FBTztZQUNWLE9BQU8sUUFBUSxDQUFDLEtBQUssQ0FBQTtRQUN2QjtZQUNFLE1BQU0sSUFBSSxLQUFLLENBQUMsc0JBQXNCLFFBQVEsRUFBRSxDQUFDLENBQUE7SUFDckQsQ0FBQztBQUNILENBQUM7QUFFRDs7Ozs7Ozs7O0dBU0c7QUFDSCxNQUFNLFVBQVUsZ0JBQWdCLENBQUMsU0FBaUI7SUFDaEQsSUFBSSxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQztRQUM5QixNQUFNLElBQUksS0FBSyxDQUFDLGdDQUFnQyxTQUFTLEVBQUUsQ0FBQyxDQUFBO0lBQzlELENBQUM7SUFFRCxNQUFNLFVBQVUsR0FBYSxFQUFFLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQyxDQUFBO0lBRW5ELElBQUksVUFBVSxDQUFDLFdBQVcsRUFBRSxFQUFFLENBQUM7UUFDN0IsTUFBTSxDQUFDLElBQUksQ0FBQyxnQ0FBZ0MsU0FBUyxFQUFFLENBQUMsQ0FBQTtRQUN4RCxNQUFNLEtBQUssR0FBYSxFQUFFLENBQUMsV0FBVyxDQUFDLFNBQVMsQ0FBQyxDQUFBO1FBQ2pELE1BQU0sYUFBYSxHQUFhLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQyxJQUFZLEVBQUUsRUFBRSxDQUM1RCxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLFdBQVcsRUFBRSxLQUFLLFFBQVEsQ0FDOUMsQ0FBQTtRQUNELE1BQU0sQ0FBQyxJQUFJLENBQUMsU0FBUyxhQUFhLENBQUMsTUFBTSxtQkFBbUIsU0FBUyxZQUFZLENBQUMsQ0FBQTtRQUNsRixNQUFNLENBQUMsS0FBSyxDQUFDLHlCQUF5QixhQUFhLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQTtRQUNqRSxPQUFPLGFBQWEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFZLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLElBQUksQ0FBQyxDQUFDLENBQUE7SUFDeEUsQ0FBQztJQUVELElBQUksVUFBVSxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUM7UUFDeEIsTUFBTSxDQUFDLElBQUksQ0FBQywyQkFBMkIsU0FBUyxFQUFFLENBQUMsQ0FBQTtRQUNuRCxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUE7SUFDcEIsQ0FBQztJQUVELE1BQU0sSUFBSSxLQUFLLENBQUMsbURBQW1ELFNBQVMsRUFBRSxDQUFDLENBQUE7QUFDakYsQ0FBQyJ9
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SarifToSlackService.d.ts","sourceRoot":"","sources":["../src/SarifToSlackService.ts"],"names":[],"mappings":"AAIA,OAAO,EAEL,0BAA0B,EAC1B,YAAY,EACb,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"SarifToSlackService.d.ts","sourceRoot":"","sources":["../src/SarifToSlackService.ts"],"names":[],"mappings":"AAIA,OAAO,EAEL,0BAA0B,EAC1B,YAAY,EACb,MAAM,SAAS,CAAA;AAoChB;;;GAGG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA4B;IAE3D,OAAO;IAIP;;;;OAIG;IACH,IAAW,aAAa,IAAI,WAAW,CAAC,MAAM,EAAE,YAAY,CAAC,CAE5D;IAED;;;;;;OAMG;WACiB,MAAM,CAAC,IAAI,EAAE,0BAA0B,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAQ1F;;;;;OAKG;IACU,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAMrC;;;;;;OAMG;IACU,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAQpD"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { promises as fs } from 'fs';
|
|
2
2
|
import Logger from './Logger';
|
|
3
|
-
import { processColor,
|
|
3
|
+
import { processColor, processSarifPath } from './Processors';
|
|
4
4
|
import { SlackMessageBuilder } from './SlackMessageBuilder';
|
|
5
5
|
async function initialize(opts) {
|
|
6
6
|
const slackMessages = new Map();
|
|
@@ -14,7 +14,8 @@ async function initialize(opts) {
|
|
|
14
14
|
username: opts.username,
|
|
15
15
|
iconUrl: opts.iconUrl,
|
|
16
16
|
color: processColor(opts.color),
|
|
17
|
-
sarif: JSON.parse(jsonString)
|
|
17
|
+
sarif: JSON.parse(jsonString),
|
|
18
|
+
output: opts.output,
|
|
18
19
|
});
|
|
19
20
|
if (opts.header?.include) {
|
|
20
21
|
messageBuilder.withHeader(opts.header?.value);
|
|
@@ -57,9 +58,7 @@ export class SarifToSlackService {
|
|
|
57
58
|
* @public
|
|
58
59
|
*/
|
|
59
60
|
static async create(opts) {
|
|
60
|
-
Logger.initialize(
|
|
61
|
-
logLevel: processLogLevel(opts.logLevel)
|
|
62
|
-
});
|
|
61
|
+
Logger.initialize(opts.log);
|
|
63
62
|
const instance = new SarifToSlackService();
|
|
64
63
|
const map = await initialize(opts);
|
|
65
64
|
map.forEach((val, key) => instance._slackMessages.set(key, val));
|
|
@@ -92,4 +91,4 @@ export class SarifToSlackService {
|
|
|
92
91
|
Logger.info(`Message sent for ${sarifPath} file. Status:`, text);
|
|
93
92
|
}
|
|
94
93
|
}
|
|
95
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
94
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU2FyaWZUb1NsYWNrU2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9TYXJpZlRvU2xhY2tTZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxRQUFRLElBQUksRUFBRSxFQUFFLE1BQU0sSUFBSSxDQUFDO0FBQ3BDLE9BQU8sTUFBTSxNQUFNLFVBQVUsQ0FBQTtBQUM3QixPQUFPLEVBQUUsWUFBWSxFQUFFLGdCQUFnQixFQUFFLE1BQU0sY0FBYyxDQUFBO0FBQzdELE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLHVCQUF1QixDQUFBO0FBTzNELEtBQUssVUFBVSxVQUFVLENBQUMsSUFBZ0M7SUFDeEQsTUFBTSxhQUFhLEdBQUcsSUFBSSxHQUFHLEVBQXdCLENBQUM7SUFDdEQsTUFBTSxVQUFVLEdBQWEsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFBO0lBQzdELElBQUksVUFBVSxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUUsQ0FBQztRQUM1QixNQUFNLElBQUksS0FBSyxDQUFDLDhDQUE4QyxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUMsQ0FBQTtJQUNqRixDQUFDO0lBRUQsS0FBSyxNQUFNLFNBQVMsSUFBSSxVQUFVLEVBQUUsQ0FBQztRQUNuQyxNQUFNLFVBQVUsR0FBVyxNQUFNLEVBQUUsQ0FBQyxRQUFRLENBQUMsU0FBUyxFQUFFLE1BQU0sQ0FBQyxDQUFBO1FBRS9ELE1BQU0sY0FBYyxHQUFHLElBQUksbUJBQW1CLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRTtZQUM5RCxRQUFRLEVBQUUsSUFBSSxDQUFDLFFBQVE7WUFDdkIsT0FBTyxFQUFFLElBQUksQ0FBQyxPQUFPO1lBQ3JCLEtBQUssRUFBRSxZQUFZLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQztZQUMvQixLQUFLLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxVQUFVLENBQWE7WUFDekMsTUFBTSxFQUFFLElB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
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { IncomingWebhook } from '@slack/webhook';
|
|
2
|
-
import { FooterType } from './types';
|
|
2
|
+
import { CalculateResultsBy, FooterType, GroupResultsBy } from './types';
|
|
3
3
|
import { LIB_VERSION } from './version';
|
|
4
|
+
import { SarifModelPerSarif } from './model/SarifModelPerSarif';
|
|
4
5
|
/**
|
|
5
6
|
* Class for building and sending Slack messages based on SARIF logs.
|
|
6
7
|
* @internal
|
|
@@ -9,6 +10,8 @@ export class SlackMessageBuilder {
|
|
|
9
10
|
webhook;
|
|
10
11
|
gitHubServerUrl;
|
|
11
12
|
color;
|
|
13
|
+
sarifModelPerSarif;
|
|
14
|
+
output;
|
|
12
15
|
header;
|
|
13
16
|
footer;
|
|
14
17
|
actor;
|
|
@@ -19,9 +22,14 @@ export class SlackMessageBuilder {
|
|
|
19
22
|
username: opts.username || 'SARIF results',
|
|
20
23
|
icon_url: opts.iconUrl
|
|
21
24
|
});
|
|
25
|
+
this.gitHubServerUrl = process.env.GITHUB_SERVER_URL || 'https://github.com';
|
|
22
26
|
this.color = opts.color;
|
|
23
27
|
this.sarif = opts.sarif;
|
|
24
|
-
this.
|
|
28
|
+
this.sarifModelPerSarif = new SarifModelPerSarif(opts.sarif);
|
|
29
|
+
this.output = opts.output || {
|
|
30
|
+
groupBy: GroupResultsBy.ToolName,
|
|
31
|
+
calculateBy: CalculateResultsBy.Level
|
|
32
|
+
};
|
|
25
33
|
}
|
|
26
34
|
withHeader(header) {
|
|
27
35
|
this.header = {
|
|
@@ -41,8 +49,8 @@ export class SlackMessageBuilder {
|
|
|
41
49
|
withFooter(text, type) {
|
|
42
50
|
const repoName = 'fabasoad/sarif-to-slack';
|
|
43
51
|
const element = text
|
|
44
|
-
? { type: type || FooterType.
|
|
45
|
-
: { type: FooterType.
|
|
52
|
+
? { type: type || FooterType.PlainText, text }
|
|
53
|
+
: { type: FooterType.Markdown, text: `Generated by <${this.gitHubServerUrl}/${repoName}|@${repoName}@${LIB_VERSION}>` };
|
|
46
54
|
this.footer = {
|
|
47
55
|
type: 'context',
|
|
48
56
|
elements: [element],
|
|
@@ -85,61 +93,47 @@ export class SlackMessageBuilder {
|
|
|
85
93
|
}
|
|
86
94
|
text.push(runText);
|
|
87
95
|
}
|
|
88
|
-
return text.join('\n');
|
|
96
|
+
return text.join('\n\n');
|
|
89
97
|
}
|
|
90
|
-
|
|
91
|
-
const
|
|
92
|
-
for (const [
|
|
93
|
-
|
|
94
|
-
levelsText.push(`*${levelCapitalized}*: ${count}`);
|
|
98
|
+
composeSummaryWith(map, resultProcessor = (result) => result) {
|
|
99
|
+
const stats = new Array();
|
|
100
|
+
for (const [key, count] of map.entries()) {
|
|
101
|
+
stats.push(`*${key}*: ${count}`);
|
|
95
102
|
}
|
|
96
|
-
return
|
|
103
|
+
return resultProcessor(stats.length == 0 ? 'No issues found' : stats.join(', '));
|
|
97
104
|
}
|
|
98
105
|
composeSummary() {
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
106
|
+
const summaries = new Array();
|
|
107
|
+
switch (this.output.groupBy) {
|
|
108
|
+
case GroupResultsBy.ToolName: {
|
|
109
|
+
const dataGroupedByToolName = this.output.calculateBy === CalculateResultsBy.Level
|
|
110
|
+
? this.sarifModelPerSarif.groupByToolNameWithSecurityLevel()
|
|
111
|
+
: this.sarifModelPerSarif.groupByToolNameWithSecuritySeverity();
|
|
112
|
+
for (const [toolName, map] of dataGroupedByToolName.entries()) {
|
|
113
|
+
summaries.push(this.composeSummaryWith(map, (result) => `*${toolName}*\n${result}`));
|
|
114
|
+
}
|
|
115
|
+
break;
|
|
104
116
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
117
|
+
case GroupResultsBy.Run: {
|
|
118
|
+
const dataGroupedByRun = this.output.calculateBy === CalculateResultsBy.Level
|
|
119
|
+
? this.sarifModelPerSarif.groupByRunWithSecurityLevel()
|
|
120
|
+
: this.sarifModelPerSarif.groupByRunWithSecuritySeverity();
|
|
121
|
+
for (let i = 0; i < dataGroupedByRun.length; i++) {
|
|
122
|
+
const { data, toolName } = dataGroupedByRun[i];
|
|
123
|
+
summaries.push(this.composeSummaryWith(data, (result) => `_[Run ${i + 1}]_: *${toolName}*\n${result}`));
|
|
124
|
+
}
|
|
125
|
+
break;
|
|
110
126
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
tryGetLevel(run, result) {
|
|
119
|
-
if (result.level) {
|
|
120
|
-
return result.level;
|
|
121
|
-
}
|
|
122
|
-
const ruleData = {};
|
|
123
|
-
if (result.rule) {
|
|
124
|
-
if (result.rule?.index) {
|
|
125
|
-
ruleData.index = result.rule.index;
|
|
126
|
-
}
|
|
127
|
-
if (result.rule?.id) {
|
|
128
|
-
ruleData.id = result.rule.id;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
if (!ruleData.index && result.ruleIndex) {
|
|
132
|
-
ruleData.index = result.ruleIndex;
|
|
133
|
-
}
|
|
134
|
-
if (ruleData.index
|
|
135
|
-
&& run.tool.driver?.rules
|
|
136
|
-
&& ruleData.index < run.tool.driver.rules.length) {
|
|
137
|
-
const rule = run.tool.driver.rules[ruleData.index];
|
|
138
|
-
if (rule.properties && 'problem.severity' in rule.properties) {
|
|
139
|
-
return rule.properties['problem.severity'];
|
|
127
|
+
default: {
|
|
128
|
+
const dataTotal = this.output.calculateBy === CalculateResultsBy.Level
|
|
129
|
+
? this.sarifModelPerSarif.groupByTotalWithSecurityLevel()
|
|
130
|
+
: this.sarifModelPerSarif.groupByTotalWithSecuritySeverity();
|
|
131
|
+
const toolNames = this.sarifModelPerSarif.listToolNames();
|
|
132
|
+
summaries.push(this.composeSummaryWith(dataTotal, (result) => `*${Array.from(toolNames).join('*, *')}*\n${result}`));
|
|
133
|
+
break;
|
|
140
134
|
}
|
|
141
135
|
}
|
|
142
|
-
return '
|
|
136
|
+
return summaries.join('\n\n');
|
|
143
137
|
}
|
|
144
138
|
}
|
|
145
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
139
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU2xhY2tNZXNzYWdlQnVpbGRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9TbGFja01lc3NhZ2VCdWlsZGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUdBLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQTtBQUVoRCxPQUFPLEVBQ0wsa0JBQWtCLEVBQ2xCLFVBQVUsRUFDVixjQUFjLEVBSWYsTUFBTSxTQUFTLENBQUE7QUFDaEIsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLFdBQVcsQ0FBQTtBQUN2QyxPQUFPLEVBRUwsa0JBQWtCLEVBQ25CLE1BQU0sNEJBQTRCLENBQUM7QUFlcEM7OztHQUdHO0FBQ0gsTUFBTSxPQUFPLG1CQUFtQjtJQUNiLE9BQU8sQ0FBaUI7SUFDeEIsZUFBZSxDQUFRO0lBQ3ZCLEtBQUssQ0FBUztJQUNkLGtCQUFrQixDQUFvQjtJQUN0QyxNQUFNLENBQW9CO0lBQ25DLE1BQU0sQ0FBYztJQUVwQixNQUFNLENBQWU7SUFDckIsS0FBSyxDQUFTO0lBQ2QsS0FBSyxDQUFTO0lBRU4sS0FBSyxDQUFVO0lBRS9CLFlBQVksR0FBVyxFQUFFLElBQWdDO1FBQ3ZELElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxlQUFlLENBQUMsR0FBRyxFQUFFO1lBQ3RDLFFBQVEsRUFBRSxJQUFJLENBQUMsUUFBUSxJQUFJLGVBQWU7WUFDMUMsUUFBUSxFQUFFLElBQUksQ0FBQyxPQUFPO1NBQ3ZCLENBQUMsQ0FBQTtRQUNGLElBQUksQ0FBQyxlQUFlLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxpQkFBaUIsSUFBSSxvQkFBb0IsQ0FBQTtRQUM1RSxJQUFJLENBQUMsS0FBSyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUE7UUFDdkIsSUFBSSxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFBO1FBQ3ZCLElBQUksQ0FBQyxrQkFBa0IsR0FBRyxJQUFJLGtCQUFrQixDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQTtRQUM1RCxJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksQ0FBQyxNQUFNLElBQUk7WUFDM0IsT0FBTyxFQUFFLGNBQWMsQ0FBQyxRQUFRO1lBQ2hDLFdBQVcsRUFBRSxrQkFBa0IsQ0FBQyxLQUFLO1NBQ3RDLENBQUE7SUFDSCxDQUFDO0lBRUQsVUFBVSxDQUFDLE1BQWU7UUFDeEIsSUFBSSxDQUFDLE1BQU0sR0FBRztZQUNaLElBQUksRUFBRSxRQUFRO1lBQ2QsSUFBSSxFQUFFO2dCQUNKLElBQUksRUFBRSxZQUFZO2dCQUNsQixJQUFJLEVBQUUsTUFBTSxJQUFJLE9BQU8sQ0FBQyxHQUFHLENBQUMsaUJBQWlCLElBQUksZUFBZTthQUNqRTtTQUNGLENBQUE7SUFDSCxDQUFDO0lBRUQsU0FBUyxDQUFDLEtBQWM7UUFDdEIsSUFBSSxDQUFDLEtBQUssR0FBRyxLQUFLLElBQUksT0FBTyxDQUFDLEdBQUcsQ0FBQyxZQUFZLENBQUE7SUFDaEQsQ0FBQztJQUVELE9BQU87UUFDTCxJQUFJLENBQUMsS0FBSyxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsYUFBYSxDQUFBO0lBQ3hDLENBQUM7SUFFRCxVQUFVLENBQUMsSUFBYSxFQUFFLElBQWlCO1FBQ3pDLE1BQU0sUUFBUSxHQUFHLHlCQUF5QixDQUFBO1FBQzFDLE1BQU0sT0FBTyxHQUFlLElBQUk7WUFDOUIsQ0FBQyxDQUFDLEVBQUUsSUFBSSxFQUFFLElBQUksSUFBSSxVQUFVLENBQUMsU0FBUyxFQUFFLElBQUksRUFBRTtZQUM5QyxDQUFDLENBQUMsRUFBRSxJQUFJLEVBQUUsVUFBVSxDQUFDLFFBQVEsRUFBRSxJQUFJLEVBQUUsaUJBQWlCLElBQUksQ0FBQyxlQUFlLElBQUksUUFBUSxLQUFLLFFBQVEsSUFBSSxXQUFXLEdBQUcsRUFBRSxDQUFBO1FBQ3pILElBQUksQ0FBQyxNQUFNLEdBQUc7WUFDWixJQUFJLEVBQUUsU0FBUztZQUNmLFFBQVEsRUFBRSxDQUFDLE9BQU8sQ0FBQztTQUNwQixDQUFBO0lBQ0gsQ0FBQztJQUVELEtBQUssQ0FBQyxJQUFJO1FBQ1IsTUFBTSxNQUFNLEdBQWUsRUFBRSxDQUFBO1FBQzdCLElBQUksSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQ2hCLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFBO1FBQzFCLENBQUM7UUFDRCxNQUFNLENBQUMsSUFBSSxDQUFDO1lBQ1YsSUFBSSxFQUFFLFNBQVM7WUFDZixJQUFJLEVBQUU7Z0JBQ0osSUFBSSxFQUFFLFFBQVE7Z0JBQ2QsSUFBSSxFQUFFLElBQUksQ0FBQyxTQUFTLEVBQUU7YUFDdkI7U0FDRixDQUFDLENBQUE7UUFDRixJQUFJLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQztZQUNoQixNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQTtRQUMxQixDQUFDO1FBQ0QsTUFBTSxFQUFFLElBQUksRUFBRSxHQUFHLE1BQU0sSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUM7WUFDdkMsV0FBVyxFQUFFLENBQUMsRUFBRSxLQUFLLEVBQUUsSUFBSSxDQUFDLEtBQUssRUFBRSxNQUFNLEVBQUUsQ0FBQztTQUM3QyxDQUFDLENBQUE7UUFDRixPQUFPLElBQUksQ0FBQTtJQUNiLENBQUM7SUFFTyxTQUFTO1FBQ2YsTUFBTSxJQUFJLEdBQWEsRUFBRSxDQUFBO1FBQ3pCLElBQUksSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQ2YsTUFBTSxRQUFRLEdBQUcsR0FBRyxJQUFJLENBQUMsZUFBZSxJQUFJLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQTtZQUN4RCxJQUFJLENBQUMsSUFBSSxDQUFDLGtCQUFrQixRQUFRLElBQUksSUFBSSxDQUFDLEtBQUssSUFBSSxDQUFDLENBQUE7UUFDekQsQ0FBQztRQUNELElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDLENBQUE7UUFDaEMsSUFBSSxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDZixJQUFJLE9BQU8sR0FBVyxNQUFNLENBQUE7WUFDNUIsSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLGlCQUFpQixFQUFFLENBQUM7Z0JBQ2xDLE9BQU8sSUFBSSxJQUFJLElBQUksQ0FBQyxlQUFlLElBQUksT0FBTyxDQUFDLEdBQUcsQ0FBQyxpQkFBaUIsaUJBQWlCLElBQUksQ0FBQyxLQUFLLEtBQUssSUFBSSxDQUFDLEtBQUssR0FBRyxDQUFBO1lBQ25ILENBQUM7aUJBQU0sQ0FBQztnQkFDTixPQUFPLElBQUksSUFBSSxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUE7WUFDN0IsQ0FBQztZQUNELElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUE7UUFDcEIsQ0FBQztRQUNELE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQTtJQUMxQixDQUFDO0lBRU8sa0JBQWtCLENBQ3hCLEdBQTJELEVBQzNELGtCQUE4QyxDQUFDLE1BQWMsRUFBVSxFQUFFLENBQUMsTUFBTTtRQUVoRixNQUFNLEtBQUssR0FBRyxJQUFJLEtBQUssRUFBVSxDQUFBO1FBQ2pDLEtBQUssTUFBTSxDQUFDLEdBQUcsRUFBRSxLQUFLLENBQUMsSUFBSSxHQUFHLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQztZQUN6QyxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksR0FBRyxNQUFNLEtBQUssRUFBRSxDQUFDLENBQUE7UUFDbEMsQ0FBQztRQUNELE9BQU8sZUFBZSxDQUNwQixLQUFLLENBQUMsTUFBTSxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsaUJBQWlCLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQ3pELENBQUE7SUFDSCxDQUFDO0lBRU8sY0FBYztRQUNwQixNQUFNLFNBQVMsR0FBRyxJQUFJLEtBQUssRUFBVSxDQUFBO1FBQ3JDLFFBQVEsSUFBSSxDQUFDLE1BQU0sQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUM1QixLQUFLLGNBQWMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDO2dCQUM3QixNQUFNLHFCQUFxQixHQUN6QixJQUFJLENBQUMsTUFBTSxDQUFDLFdBQVcsS0FBSyxrQkFBa0IsQ0FBQyxLQUFLO29CQUNsRCxDQUFDLENBQUMsSUFBSSxDQUFDLGtCQUFrQixDQUFDLGdDQUFnQyxFQUFFO29CQUM1RCxDQUFDLENBQUMsSUFBSSxDQUFDLGtCQUFrQixDQUFDLG1DQUFtQyxFQUFFLENBQUE7Z0JBQ25FLEtBQUssTUFBTSxDQUFDLFFBQVEsRUFBRSxHQUFHLENBQUMsSUFBSSxxQkFBcUIsQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDO29CQUM5RCxTQUFTLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxrQkFBa0IsQ0FDcEMsR0FBRyxFQUNILENBQUMsTUFBYyxFQUFVLEVBQUUsQ0FBQyxJQUFJLFFBQVEsTUFBTSxNQUFNLEVBQUUsQ0FDdkQsQ0FBQyxDQUFBO2dCQUNKLENBQUM7Z0JBQ0QsTUFBSztZQUNQLENBQUM7WUFDRCxLQUFLLGNBQWMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO2dCQUN4QixNQUFNLGdCQUFnQixHQUNwQixJQUFJLENBQUMsTUFBTSxDQUFDLFdBQVcsS0FBSyxrQkFBa0IsQ0FBQyxLQUFLO29CQUNsRCxDQUFDLENBQUMsSUFBSSxDQUFDLGtCQUFrQixDQUFDLDJCQUEyQixFQUFFO29CQUN2RCxDQUFDLENBQUMsSUFBSSxDQUFDLGtCQUFrQixDQUFDLDhCQUE4QixFQUFFLENBQUE7Z0JBQzlELEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxnQkFBZ0IsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQztvQkFDakQsTUFBTSxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsR0FBRyxnQkFBZ0IsQ0FBQyxDQUFDLENBQUMsQ0FBQTtvQkFDOUMsU0FBUyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsa0JBQWtCLENBQ3BDLElBQUksRUFDSixDQUFDLE1BQWMsRUFBVSxFQUFFLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxRQUFRLFFBQVEsTUFBTSxNQUFNLEVBQUUsQ0FDekUsQ0FBQyxDQUFBO2dCQUNKLENBQUM7Z0JBQ0QsTUFBSztZQUNQLENBQUM7WUFDRCxPQUFPLENBQUMsQ0FBQyxDQUFDO2dCQUNSLE1BQU0sU0FBUyxHQUNiLElBQUksQ0FBQyxNQUFNLENBQUMsV0FBVyxLQUFLLGtCQUFrQixDQUFDLEtBQUs7b0JBQ2xELENBQUMsQ0FBQyxJQUFJLENBQUMsa0JBQWtCLENBQUMsNkJBQTZCLEVBQUU7b0JBQ3pELENBQUMsQ0FBQyxJQUFJLENBQUMsa0JBQWtCLENBQUMsZ0NBQWdDLEVBQUUsQ0FBQTtnQkFDaEUsTUFBTSxTQUFTLEdBQWdCLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxhQUFhLEVBQUUsQ0FBQTtnQkFDdEUsU0FBUyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsa0JBQWtCLENBQ3BDLFNBQVMsRUFDVCxDQUFDLE1BQWMsRUFBVSxFQUFFLENBQUMsSUFBSSxLQUFLLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxNQUFNLEVBQUUsQ0FDakYsQ0FBQyxDQUFBO2dCQUNGLE1BQUs7WUFDUCxDQUFDO1FBQ0gsQ0FBQztRQUNELE9BQU8sU0FBUyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQTtJQUMvQixDQUFDO0NBQ0YifQ==
|