@fabasoad/sarif-to-slack 0.2.2 → 0.2.4
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/security.yml +1 -0
- package/.github/workflows/send-sarif-to-slack.yml +6 -0
- package/api-extractor.json +2 -2
- package/dist/index.cjs +643 -0
- package/dist/model/SarifModelPerRun.js +3 -3
- package/dist/sarif-to-slack.d.ts +278 -278
- package/dist/tsdoc-metadata.json +11 -11
- package/dist/utils/SarifUtils.js +29 -9
- package/dist/version.js +1 -1
- package/jest.config.json +1 -1
- package/package.json +4 -4
- package/scripts/build.sh +11 -0
- package/src/model/SarifModelPerRun.ts +5 -2
- package/src/utils/SarifUtils.ts +35 -10
- package/src/version.ts +1 -1
- package/test-data/sarif/runs-1-extensions-1-results-0.sarif +24 -0
- package/test-data/sarif/runs-1-extensions-1.sarif +79 -0
package/dist/utils/SarifUtils.js
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This function finds the respective tool for the given result.
|
|
3
|
+
* @param run An instance of {@link Run} object.
|
|
4
|
+
* @param result An instance of {@link Result} object.
|
|
5
|
+
* @internal
|
|
6
|
+
*/
|
|
7
|
+
export function findToolComponentByResult(run, result) {
|
|
8
|
+
let tool;
|
|
9
|
+
if (result?.rule?.toolComponent?.index != null) {
|
|
10
|
+
tool = run.tool.extensions?.[result.rule.toolComponent.index];
|
|
11
|
+
}
|
|
12
|
+
if (!tool) {
|
|
13
|
+
tool = run.tool.driver;
|
|
14
|
+
}
|
|
15
|
+
return tool;
|
|
16
|
+
}
|
|
1
17
|
/**
|
|
2
18
|
* This function tries to find the respective rule for the given result.
|
|
3
19
|
* @param run An instance of {@link Run} object.
|
|
@@ -7,24 +23,28 @@
|
|
|
7
23
|
export function findRuleByResult(run, result) {
|
|
8
24
|
const ruleData = {};
|
|
9
25
|
if (result.rule) {
|
|
10
|
-
if (result.rule?.index) {
|
|
26
|
+
if (result.rule?.index != null) {
|
|
11
27
|
ruleData.index = result.rule.index;
|
|
12
28
|
}
|
|
13
29
|
if (result.rule?.id) {
|
|
14
30
|
ruleData.id = result.rule.id;
|
|
15
31
|
}
|
|
16
32
|
}
|
|
17
|
-
if (
|
|
33
|
+
if (ruleData.index == null && result.ruleIndex != null) {
|
|
18
34
|
ruleData.index = result.ruleIndex;
|
|
19
35
|
}
|
|
20
|
-
if (ruleData.
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
36
|
+
if (!ruleData.id && result.ruleId) {
|
|
37
|
+
ruleData.id = result.ruleId;
|
|
38
|
+
}
|
|
39
|
+
const tool = findToolComponentByResult(run, result);
|
|
40
|
+
if (ruleData.index != null
|
|
41
|
+
&& tool?.rules
|
|
42
|
+
&& ruleData.index < tool.rules.length) {
|
|
43
|
+
return tool.rules[ruleData.index];
|
|
24
44
|
}
|
|
25
45
|
// If failed to find rule by index then try to find by ruleId
|
|
26
|
-
if (
|
|
27
|
-
return
|
|
46
|
+
if (ruleData.id && tool?.rules) {
|
|
47
|
+
return tool.rules.find((r) => r.id === ruleData.id);
|
|
28
48
|
}
|
|
29
49
|
return undefined;
|
|
30
50
|
}
|
|
@@ -43,4 +63,4 @@ export function tryGetRulePropertyByResult(run, result, propertyName) {
|
|
|
43
63
|
}
|
|
44
64
|
return undefined;
|
|
45
65
|
}
|
|
46
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
66
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU2FyaWZVdGlscy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy91dGlscy9TYXJpZlV0aWxzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUVBOzs7OztHQUtHO0FBQ0gsTUFBTSxVQUFVLHlCQUF5QixDQUFDLEdBQVEsRUFBRSxNQUFlO0lBQ2pFLElBQUksSUFBK0IsQ0FBQTtJQUNuQyxJQUFJLE1BQU0sRUFBRSxJQUFJLEVBQUUsYUFBYSxFQUFFLEtBQUssSUFBSSxJQUFJLEVBQUUsQ0FBQztRQUMvQyxJQUFJLEdBQUcsR0FBRyxDQUFDLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxLQUFLLENBQUMsQ0FBQTtJQUMvRCxDQUFDO0lBRUQsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ1YsSUFBSSxHQUFHLEdBQUcsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFBO0lBQ3hCLENBQUM7SUFFRCxPQUFPLElBQUksQ0FBQTtBQUNiLENBQUM7QUFFRDs7Ozs7R0FLRztBQUNILE1BQU0sVUFBVSxnQkFBZ0IsQ0FBQyxHQUFRLEVBQUUsTUFBYztJQUN2RCxNQUFNLFFBQVEsR0FBb0MsRUFBRSxDQUFBO0lBRXBELElBQUksTUFBTSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ2hCLElBQUksTUFBTSxDQUFDLElBQUksRUFBRSxLQUFLLElBQUksSUFBSSxFQUFFLENBQUM7WUFDL0IsUUFBUSxDQUFDLEtBQUssR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQTtRQUNwQyxDQUFDO1FBQ0QsSUFBSSxNQUFNLENBQUMsSUFBSSxFQUFFLEVBQUUsRUFBRSxDQUFDO1lBQ3BCLFFBQVEsQ0FBQyxFQUFFLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUE7UUFDOUIsQ0FBQztJQUNILENBQUM7SUFFRCxJQUFJLFFBQVEsQ0FBQyxLQUFLLElBQUksSUFBSSxJQUFJLE1BQU0sQ0FBQyxTQUFTLElBQUksSUFBSSxFQUFFLENBQUM7UUFDdkQsUUFBUSxDQUFDLEtBQUssR0FBRyxNQUFNLENBQUMsU0FBUyxDQUFBO0lBQ25DLENBQUM7SUFFRCxJQUFJLENBQUMsUUFBUSxDQUFDLEVBQUUsSUFBSSxNQUFNLENBQUMsTUFBTSxFQUFFLENBQUM7UUFDbEMsUUFBUSxDQUFDLEVBQUUsR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFBO0lBQzdCLENBQUM7SUFFRCxNQUFNLElBQUksR0FBa0IseUJBQXlCLENBQUMsR0FBRyxFQUFFLE1BQU0sQ0FBQyxDQUFBO0lBRWxFLElBQUksUUFBUSxDQUFDLEtBQUssSUFBSSxJQUFJO1dBQ3JCLElBQUksRUFBRSxLQUFLO1dBQ1gsUUFBUSxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sRUFBRSxDQUFDO1FBQ3hDLE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUE7SUFDbkMsQ0FBQztJQUVELDZEQUE2RDtJQUM3RCxJQUFJLFFBQVEsQ0FBQyxFQUFFLElBQUksSUFBSSxFQUFFLEtBQUssRUFBRSxDQUFDO1FBQy9CLE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQ3BCLENBQUMsQ0FBc0IsRUFBVyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxRQUFRLENBQUMsRUFBRSxDQUMxRCxDQUFBO0lBQ0gsQ0FBQztJQUVELE9BQU8sU0FBUyxDQUFBO0FBQ2xCLENBQUM7QUFRRDs7Ozs7OztHQU9HO0FBQ0gsTUFBTSxVQUFVLDBCQUEwQixDQUFJLEdBQVEsRUFBRSxNQUFjLEVBQUUsWUFBMEI7SUFDaEcsTUFBTSxJQUFJLEdBQW9DLGdCQUFnQixDQUFDLEdBQUcsRUFBRSxNQUFNLENBQUMsQ0FBQTtJQUMzRSxJQUFJLElBQUksSUFBSSxJQUFJLENBQUMsVUFBVSxJQUFJLFlBQVksSUFBSSxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7UUFDL0QsT0FBTyxJQUFJLENBQUMsVUFBVSxDQUFDLFlBQVksQ0FBTSxDQUFBO0lBQzNDLENBQUM7SUFFRCxPQUFPLFNBQVMsQ0FBQTtBQUNsQixDQUFDIn0=
|
package/dist/version.js
CHANGED
|
@@ -7,5 +7,5 @@
|
|
|
7
7
|
*
|
|
8
8
|
* @internal
|
|
9
9
|
*/
|
|
10
|
-
export const LIB_VERSION = '0.2.
|
|
10
|
+
export const LIB_VERSION = '0.2.4';
|
|
11
11
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmVyc2lvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy92ZXJzaW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7OztHQVFHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sV0FBVyxHQUFHLE9BQU8sQ0FBQSJ9
|
package/jest.config.json
CHANGED
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fabasoad/sarif-to-slack",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"description": "TypeScript library to send results of SARIF file to Slack webhook URL.",
|
|
5
|
-
"main": "dist/index.
|
|
5
|
+
"main": "dist/index.cjs",
|
|
6
6
|
"module": "dist/index.js",
|
|
7
7
|
"typings": "dist/index.d.ts",
|
|
8
8
|
"private": false,
|
|
@@ -12,9 +12,8 @@
|
|
|
12
12
|
"test:integration": "jest --config=jest.config.json --testNamePattern=integration",
|
|
13
13
|
"clean": "rm -rf coverage && rm -rf temp",
|
|
14
14
|
"clean:unsafe": "rm -f package-lock.json && rm -rf node_modules && rm -rf dist && rm -rf lib",
|
|
15
|
-
"tsc": "tsc",
|
|
16
15
|
"prebuild": "./scripts/save-version.sh",
|
|
17
|
-
"build": "
|
|
16
|
+
"build": "./scripts/build.sh",
|
|
18
17
|
"prepublishOnly": "npm run build",
|
|
19
18
|
"preinstall": "./scripts/save-version.sh",
|
|
20
19
|
"version:patch": "npm version patch --commit-hooks --git-tag-version --message 'chore: bump to version %s'",
|
|
@@ -56,6 +55,7 @@
|
|
|
56
55
|
"jest": "30.0.5",
|
|
57
56
|
"jest-circus": "30.0.5",
|
|
58
57
|
"ts-jest": "29.4.0",
|
|
58
|
+
"tsup": "8.5.0",
|
|
59
59
|
"typescript": "5.8.3"
|
|
60
60
|
}
|
|
61
61
|
}
|
package/scripts/build.sh
ADDED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import type { Result, Run } from 'sarif';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
findToolComponentByResult,
|
|
4
|
+
tryGetRulePropertyByResult
|
|
5
|
+
} from '../utils/SarifUtils'
|
|
3
6
|
import { SecurityLevel, SecuritySeverity } from './types'
|
|
4
7
|
import Logger from '../Logger'
|
|
5
8
|
import { Map as ImmutableMap } from 'immutable'
|
|
@@ -21,7 +24,7 @@ export class SarifModelPerRun {
|
|
|
21
24
|
private readonly _securityLevelMap: ImmutableMap<SecurityLevel, number>
|
|
22
25
|
|
|
23
26
|
constructor(run: Run) {
|
|
24
|
-
this.toolName = run.
|
|
27
|
+
this.toolName = findToolComponentByResult(run, run.results?.[0]).name
|
|
25
28
|
|
|
26
29
|
this._securitySeverityMap = ImmutableMap<SecuritySeverity, number>().asMutable()
|
|
27
30
|
this._securityLevelMap = ImmutableMap<SecurityLevel, number>().asMutable()
|
package/src/utils/SarifUtils.ts
CHANGED
|
@@ -1,4 +1,23 @@
|
|
|
1
|
-
import type { ReportingDescriptor, Result, Run } from "sarif";
|
|
1
|
+
import type { ReportingDescriptor, Result, Run, ToolComponent } from "sarif";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* This function finds the respective tool for the given result.
|
|
5
|
+
* @param run An instance of {@link Run} object.
|
|
6
|
+
* @param result An instance of {@link Result} object.
|
|
7
|
+
* @internal
|
|
8
|
+
*/
|
|
9
|
+
export function findToolComponentByResult(run: Run, result?: Result): ToolComponent {
|
|
10
|
+
let tool: ToolComponent | undefined
|
|
11
|
+
if (result?.rule?.toolComponent?.index != null) {
|
|
12
|
+
tool = run.tool.extensions?.[result.rule.toolComponent.index]
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (!tool) {
|
|
16
|
+
tool = run.tool.driver
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return tool
|
|
20
|
+
}
|
|
2
21
|
|
|
3
22
|
/**
|
|
4
23
|
* This function tries to find the respective rule for the given result.
|
|
@@ -10,7 +29,7 @@ export function findRuleByResult(run: Run, result: Result): ReportingDescriptor
|
|
|
10
29
|
const ruleData: { id?: string, index?: number } = {}
|
|
11
30
|
|
|
12
31
|
if (result.rule) {
|
|
13
|
-
if (result.rule?.index) {
|
|
32
|
+
if (result.rule?.index != null) {
|
|
14
33
|
ruleData.index = result.rule.index
|
|
15
34
|
}
|
|
16
35
|
if (result.rule?.id) {
|
|
@@ -18,20 +37,26 @@ export function findRuleByResult(run: Run, result: Result): ReportingDescriptor
|
|
|
18
37
|
}
|
|
19
38
|
}
|
|
20
39
|
|
|
21
|
-
if (
|
|
40
|
+
if (ruleData.index == null && result.ruleIndex != null) {
|
|
22
41
|
ruleData.index = result.ruleIndex
|
|
23
42
|
}
|
|
24
43
|
|
|
25
|
-
if (ruleData.
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
44
|
+
if (!ruleData.id && result.ruleId) {
|
|
45
|
+
ruleData.id = result.ruleId
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const tool: ToolComponent = findToolComponentByResult(run, result)
|
|
49
|
+
|
|
50
|
+
if (ruleData.index != null
|
|
51
|
+
&& tool?.rules
|
|
52
|
+
&& ruleData.index < tool.rules.length) {
|
|
53
|
+
return tool.rules[ruleData.index]
|
|
29
54
|
}
|
|
30
55
|
|
|
31
56
|
// If failed to find rule by index then try to find by ruleId
|
|
32
|
-
if (
|
|
33
|
-
return
|
|
34
|
-
(r: ReportingDescriptor): boolean => r.id ===
|
|
57
|
+
if (ruleData.id && tool?.rules) {
|
|
58
|
+
return tool.rules.find(
|
|
59
|
+
(r: ReportingDescriptor): boolean => r.id === ruleData.id
|
|
35
60
|
)
|
|
36
61
|
}
|
|
37
62
|
|
package/src/version.ts
CHANGED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json",
|
|
3
|
+
"version": "2.1.0",
|
|
4
|
+
"runs": [
|
|
5
|
+
{
|
|
6
|
+
"tool": {
|
|
7
|
+
"driver": {
|
|
8
|
+
"language": "en-US",
|
|
9
|
+
"name": "Snyk Open Source"
|
|
10
|
+
},
|
|
11
|
+
"extensions": [
|
|
12
|
+
{
|
|
13
|
+
"name": "Snyk Open Source Extension",
|
|
14
|
+
"properties": {
|
|
15
|
+
"artifactsScanned": 6
|
|
16
|
+
},
|
|
17
|
+
"rules": []
|
|
18
|
+
}
|
|
19
|
+
]
|
|
20
|
+
},
|
|
21
|
+
"results": []
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json",
|
|
3
|
+
"version": "2.1.0",
|
|
4
|
+
"runs": [
|
|
5
|
+
{
|
|
6
|
+
"tool": {
|
|
7
|
+
"driver": {
|
|
8
|
+
"language": "en-US",
|
|
9
|
+
"name": "Snyk Open Source"
|
|
10
|
+
},
|
|
11
|
+
"extensions": [
|
|
12
|
+
{
|
|
13
|
+
"name": "Snyk Open Source Extension",
|
|
14
|
+
"properties": {
|
|
15
|
+
"artifactsScanned": 6
|
|
16
|
+
},
|
|
17
|
+
"rules": [
|
|
18
|
+
{
|
|
19
|
+
"id": "SNYK-HEX-PAGINATOR-1086684",
|
|
20
|
+
"shortDescription": {
|
|
21
|
+
"text": "Critical severity - Remote Code Execution (RCE) vulnerability in paginator"
|
|
22
|
+
},
|
|
23
|
+
"fullDescription": {
|
|
24
|
+
"text": "(CVE-2020-15150) paginator@0.6.0"
|
|
25
|
+
},
|
|
26
|
+
"help": {
|
|
27
|
+
"text": "",
|
|
28
|
+
"markdown": "* Package Manager: hex\n* Vulnerable module: paginator\n* Introduced through: carafe@0.1.0 and paginator@0.6.0\n### Detailed paths\n* _Introduced through_: carafe@0.1.0 › paginator@0.6.0\n# Overview\n[paginator](https://hex.pm/packages/paginator) is a package that enables cursor-based pagination for Elixir Ecto.\n\nAffected versions of this package are vulnerable to Remote Code Execution (RCE) via `paginate()` function when untrusted input is passed from a remote user.\r\n\r\n# PoC\r\n```\r\ndefp rce_start_xcalc() do\r\n exploit = fn _, _ -> System.cmd(\"xcalc\", []); {:cont, []} end\r\n payload =\r\n exploit\r\n |> :erlang.term_to_binary()\r\n |> Base.url_encode64()\r\nend\r\n```\n# Remediation\nUpgrade `paginator` to version 1.0.0 or higher.\n# References\n- [GitHub PR](https://github.com/duffelhq/paginator/commit/bf45e92602e517c75aea0465efc35cd661d9ebf8)\n- [Research Blog Post](https://www.alphabot.com/security/blog/2020/elixir/Remote-code-execution-vulnerability-in-Elixir-based-Paginator-project.html)\n"
|
|
29
|
+
},
|
|
30
|
+
"properties": {
|
|
31
|
+
"tags": [
|
|
32
|
+
"security",
|
|
33
|
+
"CWE-94",
|
|
34
|
+
"hex"
|
|
35
|
+
],
|
|
36
|
+
"cvssv3_baseScore": 9.8,
|
|
37
|
+
"security-severity": "9.8"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
]
|
|
41
|
+
}
|
|
42
|
+
]
|
|
43
|
+
},
|
|
44
|
+
"results": [
|
|
45
|
+
{
|
|
46
|
+
"rule": {
|
|
47
|
+
"id": "SNYK-HEX-PAGINATOR-1086684",
|
|
48
|
+
"index": 0,
|
|
49
|
+
"toolComponent": {
|
|
50
|
+
"index": 0
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
"ruleId": "SNYK-HEX-PAGINATOR-1086684",
|
|
54
|
+
"level": "error",
|
|
55
|
+
"message": {
|
|
56
|
+
"text": "This file introduces a vulnerable paginator package with a critical severity vulnerability."
|
|
57
|
+
},
|
|
58
|
+
"locations": [
|
|
59
|
+
{
|
|
60
|
+
"physicalLocation": {
|
|
61
|
+
"artifactLocation": {
|
|
62
|
+
"uri": "mix.exs"
|
|
63
|
+
},
|
|
64
|
+
"region": {
|
|
65
|
+
"startLine": 1
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
"logicalLocations": [
|
|
69
|
+
{
|
|
70
|
+
"fullyQualifiedName": "paginator@0.6.0"
|
|
71
|
+
}
|
|
72
|
+
]
|
|
73
|
+
}
|
|
74
|
+
]
|
|
75
|
+
}
|
|
76
|
+
]
|
|
77
|
+
}
|
|
78
|
+
]
|
|
79
|
+
}
|