@fabasoad/sarif-to-slack 0.1.0 → 0.2.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.
Files changed (44) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +1 -1
  2. package/.github/pull_request_template.md +3 -3
  3. package/.github/workflows/linting.yml +14 -0
  4. package/.github/workflows/release.yml +2 -0
  5. package/.github/workflows/unit-tests.yml +1 -0
  6. package/.pre-commit-config.yaml +2 -2
  7. package/CONTRIBUTING.md +1 -1
  8. package/Makefile +1 -1
  9. package/README.md +36 -5
  10. package/api-extractor.json +1 -1
  11. package/biome.json +15 -12
  12. package/dist/Logger.d.ts +2 -0
  13. package/dist/Logger.d.ts.map +1 -0
  14. package/dist/Logger.js +25 -0
  15. package/dist/Processors.d.ts +2 -0
  16. package/dist/Processors.d.ts.map +1 -0
  17. package/dist/Processors.js +91 -0
  18. package/dist/SarifToSlackService.d.ts +39 -0
  19. package/dist/SarifToSlackService.d.ts.map +1 -0
  20. package/dist/SarifToSlackService.js +95 -0
  21. package/dist/SlackMessageBuilder.d.ts +2 -0
  22. package/dist/SlackMessageBuilder.d.ts.map +1 -0
  23. package/dist/SlackMessageBuilder.js +145 -0
  24. package/dist/index.d.ts +45 -0
  25. package/dist/index.d.ts.map +1 -0
  26. package/dist/index.js +46 -0
  27. package/dist/sarif-to-slack.d.ts +28 -9
  28. package/dist/types.d.ts +104 -0
  29. package/dist/types.d.ts.map +1 -0
  30. package/dist/types.js +45 -0
  31. package/dist/version.d.ts +2 -0
  32. package/dist/version.d.ts.map +1 -0
  33. package/dist/version.js +4 -0
  34. package/etc/sarif-to-slack.api.md +19 -6
  35. package/jest.config.json +2 -2
  36. package/package.json +10 -5
  37. package/scripts/save-version.sh +6 -0
  38. package/src/Logger.ts +2 -0
  39. package/src/SarifToSlackService.ts +5 -3
  40. package/src/SlackMessageBuilder.ts +11 -9
  41. package/src/index.ts +7 -4
  42. package/src/types.ts +24 -6
  43. package/src/version.ts +3 -0
  44. package/tsconfig.json +27 -13
@@ -31,7 +31,7 @@ If applicable, add screenshots to help explain your problem.
31
31
  #### Technical information (please complete the following information)
32
32
 
33
33
  - OS: [e.g. Windows 10 Enterprise v.1909 (OS Build 18363.720)]
34
- - `sarif-to-slack-action` version [e.g. 0.1.0]
34
+ - `sarif-to-slack` version [e.g. 0.1.1]
35
35
 
36
36
  #### Additional context
37
37
 
@@ -4,12 +4,12 @@
4
4
 
5
5
  Please check if your PR fulfills the following requirements:
6
6
 
7
- - [ ] I have read the [CONTRIBUTING](https://github.com/fabasoad/sarif-to-slack-action/blob/main/CONTRIBUTING.md)
7
+ - [ ] I have read the [CONTRIBUTING](https://github.com/fabasoad/sarif-to-slack/blob/main/CONTRIBUTING.md)
8
8
  doc.
9
9
  - [ ] Tests for the changes have been added (for bug fixes / features).
10
10
  - [ ] Docs have been reviewed and added / updated if needed (for bug fixes / features).
11
- - [ ] Build (`yarn run build`) was run locally and any changes were pushed.
12
- - [ ] Tests (`yarn test`) has passed locally and any fixes were made for failures.
11
+ - [ ] Build (`make build`) was run locally and any changes were pushed.
12
+ - [ ] Tests (`make test`) has passed locally and any fixes were made for failures.
13
13
 
14
14
  ## Pull request type
15
15
 
@@ -6,13 +6,27 @@ on: # yamllint disable-line rule:truthy
6
6
  push:
7
7
  branches:
8
8
  - main
9
+ workflow_dispatch:
10
+ inputs:
11
+ linter:
12
+ description: |
13
+ The linter to run. Supported values: `js-lint`, `pre-commit`.
14
+ required: false
15
+ default: all
16
+ type: choice
17
+ options:
18
+ - all
19
+ - js-lint
20
+ - pre-commit
9
21
 
10
22
  jobs:
11
23
  js-lint:
12
24
  name: JS Lint
25
+ if: ${{ (github.event.inputs.linter || 'all') == 'all' || github.event.inputs.linter == 'js-lint' }}
13
26
  uses: fabasoad/reusable-workflows/.github/workflows/wf-js-lint.yml@main
14
27
  pre-commit:
15
28
  name: Pre-commit
29
+ if: ${{ (github.event.inputs.linter || 'all') == 'all' || github.event.inputs.linter == 'pre-commit' }}
16
30
  uses: fabasoad/reusable-workflows/.github/workflows/wf-pre-commit.yml@main
17
31
  with:
18
32
  skip-hooks: "audit, build, lint, test"
@@ -28,6 +28,8 @@ jobs:
28
28
  steps:
29
29
  - name: Checkout ${{ github.repository }}
30
30
  uses: actions/checkout@v4
31
+ with:
32
+ token: "${{ secrets.GH_TOKEN }}"
31
33
 
32
34
  - name: Setup Node
33
35
  uses: actions/setup-node@v4
@@ -9,6 +9,7 @@ on: # yamllint disable-line rule:truthy
9
9
  - jest.config.json
10
10
  - package.json
11
11
  - src/**
12
+ - tests/**
12
13
  - tsconfig.json
13
14
  push:
14
15
  branches:
@@ -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/.*|lib/.*|node_modules/.*|temp/.*)$
4
+ exclude: ^(dist/.*|etc/.*|node_modules/.*|temp/.*)$
5
5
  minimum_pre_commit_version: 4.0.0
6
6
  repos:
7
7
  - repo: local
@@ -29,7 +29,7 @@ repos:
29
29
  stages: ["pre-push"]
30
30
  # Security
31
31
  - id: audit
32
- name: NPM audit
32
+ name: npm audit
33
33
  entry: make audit
34
34
  language: system
35
35
  pass_filenames: false
package/CONTRIBUTING.md CHANGED
@@ -33,7 +33,7 @@ In short, when you submit code changes, your submissions are understood to be
33
33
  under the same [MIT License](http://choosealicense.com/licenses/mit/) that covers
34
34
  the project. Feel free to contact the maintainers if that's a concern.
35
35
 
36
- ## Report bugs using [GitHub Issues](https://github.com/fabasoad/sarif-to-slack-action/issues)
36
+ ## Report bugs using [GitHub Issues](https://github.com/fabasoad/sarif-to-slack/issues)
37
37
 
38
38
  We use GitHub issues to track public bugs. Report a bug by opening a new issue.
39
39
  It's that easy!
package/Makefile CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  .PHONY: audit
4
4
  audit:
5
- @npm audit --all
5
+ @npm audit --audit-level moderate --package-lock-only --include dev
6
6
 
7
7
  .PHONY: build
8
8
  build:
package/README.md CHANGED
@@ -1,11 +1,11 @@
1
1
  # SARIF to Slack TypeScript Library
2
2
 
3
3
  [![Stand With Ukraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/badges/StandWithUkraine.svg)](https://stand-with-ukraine.pp.ua)
4
- ![Releases](https://img.shields.io/github/v/release/fabasoad/sarif-to-slack-action?include_prereleases)
5
- ![unit-tests](https://github.com/fabasoad/sarif-to-slack-action/actions/workflows/unit-tests.yml/badge.svg)
6
- ![security](https://github.com/fabasoad/sarif-to-slack-action/actions/workflows/security.yml/badge.svg)
7
- ![linting](https://github.com/fabasoad/sarif-to-slack-action/actions/workflows/linting.yml/badge.svg)
8
- [![codecov](https://codecov.io/gh/fabasoad/sarif-to-slack-action/branch/main/graph/badge.svg?token=908QOYME6H)](https://codecov.io/gh/fabasoad/sarif-to-slack-action)
4
+ ![Releases](https://img.shields.io/github/v/release/fabasoad/sarif-to-slack?include_prereleases)
5
+ ![unit-tests](https://github.com/fabasoad/sarif-to-slack/actions/workflows/unit-tests.yml/badge.svg)
6
+ ![security](https://github.com/fabasoad/sarif-to-slack/actions/workflows/security.yml/badge.svg)
7
+ ![linting](https://github.com/fabasoad/sarif-to-slack/actions/workflows/linting.yml/badge.svg)
8
+ [![codecov](https://codecov.io/gh/fabasoad/sarif-to-slack/branch/main/graph/badge.svg?token=I4FV5Q328I)](https://codecov.io/gh/fabasoad/sarif-to-slack)
9
9
 
10
10
  TypeScript library to send results of SARIF file to Slack webhook URL.
11
11
 
@@ -16,19 +16,50 @@ TypeScript library to send results of SARIF file to Slack webhook URL.
16
16
  * [Contents](#contents)
17
17
  * [How to use](#how-to-use)
18
18
  * [Sample](#sample)
19
+ * [References](#references)
19
20
  * [Contributions](#contributions)
20
21
  <!-- TOC -->
21
22
 
22
23
  ## How to use
23
24
 
24
25
  ```typescript
26
+ import { SarifToSlackService, FooterType } from '@fabasoad/sarif-to-slack';
25
27
 
28
+ const service = await SarifToSlackService.create({
29
+ webhookUrl: 'https://hooks.slack.com/services/your/webhook/url',
30
+ sarifPath: 'path/to/your/sarif/file.sarif',
31
+ logLevel: 'info',
32
+ username: 'SARIF Bot',
33
+ iconUrl: 'https://example.com/icon.png',
34
+ color: '#36a64f',
35
+ header: {
36
+ include: true,
37
+ value: 'SARIF Analysis Results',
38
+ },
39
+ footer: {
40
+ include: true,
41
+ type: FooterType.PLAIN_TEXT,
42
+ value: 'Generated by @fabasoad/sarif-to-slack',
43
+ },
44
+ actor: {
45
+ include: true,
46
+ value: 'fabasoad',
47
+ },
48
+ run: {
49
+ include: true,
50
+ },
51
+ });
52
+ await service.sendAll();
26
53
  ```
27
54
 
28
55
  ## Sample
29
56
 
30
57
  <img alt="Sample" src="sample.png" width="450"/>
31
58
 
59
+ ## References
60
+
61
+ * [API Report](./etc/sarif-to-slack.api.md)
62
+
32
63
  ## Contributions
33
64
 
34
65
  ![Alt](https://repobeats.axiom.co/api/embed/a0989b54292b5c9e03ce1dd4cb23f68072f88f46.svg "Repobeats analytics image")
@@ -45,7 +45,7 @@
45
45
  *
46
46
  * SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
47
47
  */
48
- "mainEntryPointFilePath": "<projectFolder>/lib/index.d.ts",
48
+ "mainEntryPointFilePath": "<projectFolder>/dist/index.d.ts",
49
49
 
50
50
  /**
51
51
  * A list of NPM package names whose exports should be treated as part of this package.
package/biome.json CHANGED
@@ -3,12 +3,12 @@
3
3
  "enabled": true,
4
4
  "rules": {
5
5
  "recommended": false,
6
- "a11y": { "noBlankTarget": "error" },
6
+ "a11y": "off",
7
7
  "complexity": {
8
+ "noAdjacentSpacesInRegex": "error",
9
+ "noArguments": "error",
8
10
  "noExtraBooleanCast": "error",
9
- "noMultipleSpacesInRegularExpressionLiterals": "error",
10
- "noUselessCatch": "error",
11
- "noWith": "error"
11
+ "noUselessCatch": "error"
12
12
  },
13
13
  "correctness": {
14
14
  "noChildrenProp": "error",
@@ -19,7 +19,7 @@
19
19
  "noGlobalObjectCalls": "error",
20
20
  "noInnerDeclarations": "error",
21
21
  "noInvalidConstructorSuper": "error",
22
- "noNewSymbol": "error",
22
+ "noInvalidBuiltinInstantiation": "error",
23
23
  "noNonoctalDecimalEscape": "error",
24
24
  "noPrecisionLoss": "error",
25
25
  "noSelfAssign": "error",
@@ -35,12 +35,14 @@
35
35
  "useIsNan": "error",
36
36
  "useJsxKeyInIterable": "error",
37
37
  "useValidForDirection": "error",
38
+ "useValidTypeof": "error",
38
39
  "useYield": "error"
39
40
  },
40
- "security": { "noDangerouslySetInnerHtml": "error" },
41
+ "security": {
42
+ "noBlankTarget": "error",
43
+ "noDangerouslySetInnerHtml": "error"
44
+ },
41
45
  "style": {
42
- "noArguments": "error",
43
- "noVar": "error",
44
46
  "useBlockStatements": "error",
45
47
  "useConst": "error",
46
48
  "useSingleVarDeclarator": "error"
@@ -67,15 +69,16 @@
67
69
  "noPrototypeBuiltins": "error",
68
70
  "noRedeclare": "error",
69
71
  "noShadowRestrictedNames": "error",
72
+ "noVar": "error",
73
+ "noWith": "error",
70
74
  "noUnsafeNegation": "error",
71
- "useGetterReturn": "error",
72
- "useValidTypeof": "error"
75
+ "useGetterReturn": "error"
73
76
  }
74
77
  },
75
- "ignore": ["dist/**"]
78
+ "includes": ["src/**", "tests/**"]
76
79
  },
77
80
  "javascript": {
78
81
  "globals": ["Atomics", "SharedArrayBuffer", "jest", "afterEach", "beforeAll", "beforeEach", "expect", "test", "describe"]
79
82
  },
80
- "overrides": [{ "include": ["**/*.spec.ts", "**/*.spec.tsx"] }]
83
+ "overrides": [{ "includes": ["**/*.spec.ts", "**/*.spec.tsx"] }]
81
84
  }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=Logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Logger.d.ts","sourceRoot":"","sources":["../src/Logger.ts"],"names":[],"mappings":""}
package/dist/Logger.js ADDED
@@ -0,0 +1,25 @@
1
+ import { Logger as TSLogger } from 'tslog';
2
+ import { LogLevel } from './types';
3
+ /**
4
+ * Logger class for managing logging operations.
5
+ * @internal
6
+ */
7
+ export default class Logger {
8
+ static instance = new TSLogger();
9
+ static initialize({ logLevel = LogLevel.Info }) {
10
+ if (!Logger.instance) {
11
+ Logger.instance = new TSLogger({
12
+ minLevel: process.env.ACTIONS_STEP_DEBUG === 'true' ? 0 : logLevel,
13
+ type: 'pretty',
14
+ prettyLogTimeZone: 'UTC',
15
+ });
16
+ }
17
+ }
18
+ static info(...args) {
19
+ Logger.instance.info(args);
20
+ }
21
+ static debug(...args) {
22
+ Logger.instance.debug(args);
23
+ }
24
+ }
25
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTG9nZ2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL0xvZ2dlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsTUFBTSxJQUFJLFFBQVEsRUFBVyxNQUFNLE9BQU8sQ0FBQTtBQUNuRCxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sU0FBUyxDQUFBO0FBVWxDOzs7R0FHRztBQUNILE1BQU0sQ0FBQyxPQUFPLE9BQU8sTUFBTTtJQUNqQixNQUFNLENBQUMsUUFBUSxHQUFzQixJQUFJLFFBQVEsRUFBRSxDQUFDO0lBRXJELE1BQU0sQ0FBQyxVQUFVLENBQUMsRUFBRSxRQUFRLEdBQUcsUUFBUSxDQUFDLElBQUksRUFBaUI7UUFDbEUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxRQUFRLEVBQUUsQ0FBQztZQUNyQixNQUFNLENBQUMsUUFBUSxHQUFHLElBQUksUUFBUSxDQUFDO2dCQUM3QixRQUFRLEVBQUUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxrQkFBa0IsS0FBSyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsUUFBUTtnQkFDbEUsSUFBSSxFQUFFLFFBQVE7Z0JBQ2QsaUJBQWlCLEVBQUUsS0FBSzthQUN6QixDQUFDLENBQUE7UUFDSixDQUFDO0lBQ0gsQ0FBQztJQUVNLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxJQUFjO1FBQ2xDLE1BQU0sQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFBO0lBQzVCLENBQUM7SUFFTSxNQUFNLENBQUMsS0FBSyxDQUFDLEdBQUcsSUFBYztRQUNuQyxNQUFNLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQTtJQUM3QixDQUFDIn0=
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=Processors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Processors.d.ts","sourceRoot":"","sources":["../src/Processors.ts"],"names":[],"mappings":""}
@@ -0,0 +1,91 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import Logger from './Logger';
4
+ /**
5
+ * Processes a color string and converts it to a specific hex code if it matches
6
+ * a CI status identifier.
7
+ * @param color - The color string to process, which can be a CI status identifier
8
+ * or a custom color.
9
+ * @returns The processed color as a hex string or undefined if the input is not
10
+ * a recognized CI status identifier.
11
+ * @internal
12
+ */
13
+ export function processColor(color) {
14
+ switch (color) {
15
+ case 'success':
16
+ Logger.info(`Converting "${color}" to #008000`);
17
+ return '#008000';
18
+ case 'failure':
19
+ Logger.info(`Converting "${color}" to #ff0000`);
20
+ return '#ff0000';
21
+ case 'cancelled':
22
+ Logger.info(`Converting "${color}" to #0047ab`);
23
+ return '#0047ab';
24
+ case 'skipped':
25
+ Logger.info(`Converting "${color}" to #808080`);
26
+ return '#808080';
27
+ default:
28
+ Logger.debug(`"${color}" color is not a CI status identifier. Returning as is...`);
29
+ return color;
30
+ }
31
+ }
32
+ /**
33
+ * Processes a log level string or number and converts it to a numeric log level.
34
+ * @param logLevel
35
+ * @returns The numeric log level corresponding to the input string or number.
36
+ * @throws Error If the input string does not match any known log level.
37
+ * @internal
38
+ */
39
+ export function processLogLevel(logLevel) {
40
+ if (typeof logLevel === 'string') {
41
+ switch (logLevel.toLowerCase()) {
42
+ case 'silly':
43
+ return 0;
44
+ case 'trace':
45
+ return 1;
46
+ case 'debug':
47
+ return 2;
48
+ case 'info':
49
+ return 3;
50
+ case 'warning':
51
+ return 4;
52
+ case 'error':
53
+ return 5;
54
+ case 'fatal':
55
+ return 6;
56
+ default:
57
+ throw new Error(`Unknown log level: ${logLevel}`);
58
+ }
59
+ }
60
+ return logLevel;
61
+ }
62
+ /**
63
+ * Processes the SARIF path, which can be a file or a directory. If it's a
64
+ * directory, it returns an array of paths to all `.sarif` files, otherwise it
65
+ * returns an array with a single path to the file.
66
+ * @param sarifPath - The path to the SARIF file or directory.
67
+ * @returns An array of strings representing the paths to the SARIF files.
68
+ * @throws Error If the path does not exist, or if it is neither a file nor a
69
+ * directory.
70
+ * @internal
71
+ */
72
+ export function processSarifPath(sarifPath) {
73
+ if (!fs.existsSync(sarifPath)) {
74
+ throw new Error(`"sarif-path" does not exist: ${sarifPath}`);
75
+ }
76
+ const sarifStats = fs.statSync(sarifPath);
77
+ if (sarifStats.isDirectory()) {
78
+ Logger.info(`"sarif-path" is a directory: ${sarifPath}`);
79
+ const files = fs.readdirSync(sarifPath);
80
+ const filteredFiles = files.filter((file) => path.extname(file).toLowerCase() === '.sarif');
81
+ Logger.info(`Found ${filteredFiles.length} SARIF files in ${sarifPath} directory`);
82
+ Logger.debug(`Filtered SARIF files: ${filteredFiles.join(', ')}`);
83
+ return filteredFiles.map((file) => path.join(sarifPath, file));
84
+ }
85
+ if (sarifStats.isFile()) {
86
+ Logger.info(`"sarif-path" is a file: ${sarifPath}`);
87
+ return [sarifPath];
88
+ }
89
+ throw new Error(`"sarif-path" is neither a file nor a directory: ${sarifPath}`);
90
+ }
91
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUHJvY2Vzc29ycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9Qcm9jZXNzb3JzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxFQUFFLE1BQU0sSUFBSSxDQUFBO0FBQ3hCLE9BQU8sS0FBSyxJQUFJLE1BQU0sTUFBTSxDQUFBO0FBQzVCLE9BQU8sTUFBTSxNQUFNLFVBQVUsQ0FBQTtBQUc3Qjs7Ozs7Ozs7R0FRRztBQUNILE1BQU0sVUFBVSxZQUFZLENBQUMsS0FBYztJQUN6QyxRQUFRLEtBQUssRUFBRSxDQUFDO1FBQ2QsS0FBSyxTQUFTO1lBQ1osTUFBTSxDQUFDLElBQUksQ0FBQyxlQUFlLEtBQUssY0FBYyxDQUFDLENBQUE7WUFDL0MsT0FBTyxTQUFTLENBQUE7UUFDbEIsS0FBSyxTQUFTO1lBQ1osTUFBTSxDQUFDLElBQUksQ0FBQyxlQUFlLEtBQUssY0FBYyxDQUFDLENBQUE7WUFDL0MsT0FBTyxTQUFTLENBQUE7UUFDbEIsS0FBSyxXQUFXO1lBQ2QsTUFBTSxDQUFDLElBQUksQ0FBQyxlQUFlLEtBQUssY0FBYyxDQUFDLENBQUE7WUFDL0MsT0FBTyxTQUFTLENBQUE7UUFDbEIsS0FBSyxTQUFTO1lBQ1osTUFBTSxDQUFDLElBQUksQ0FBQyxlQUFlLEtBQUssY0FBYyxDQUFDLENBQUE7WUFDL0MsT0FBTyxTQUFTLENBQUE7UUFDbEI7WUFDRSxNQUFNLENBQUMsS0FBSyxDQUFDLElBQUksS0FBSywyREFBMkQsQ0FBQyxDQUFBO1lBQ2xGLE9BQU8sS0FBSyxDQUFBO0lBQ2hCLENBQUM7QUFDSCxDQUFDO0FBRUQ7Ozs7OztHQU1HO0FBQ0gsTUFBTSxVQUFVLGVBQWUsQ0FBQyxRQUE0QjtJQUMxRCxJQUFJLE9BQU8sUUFBUSxLQUFLLFFBQVEsRUFBRSxDQUFDO1FBQ2pDLFFBQVEsUUFBUSxDQUFDLFdBQVcsRUFBRSxFQUFFLENBQUM7WUFDL0IsS0FBSyxPQUFPO2dCQUNWLE9BQU8sQ0FBQyxDQUFBO1lBQ1YsS0FBSyxPQUFPO2dCQUNWLE9BQU8sQ0FBQyxDQUFBO1lBQ1YsS0FBSyxPQUFPO2dCQUNWLE9BQU8sQ0FBQyxDQUFBO1lBQ1YsS0FBSyxNQUFNO2dCQUNULE9BQU8sQ0FBQyxDQUFBO1lBQ1YsS0FBSyxTQUFTO2dCQUNaLE9BQU8sQ0FBQyxDQUFBO1lBQ1YsS0FBSyxPQUFPO2dCQUNWLE9BQU8sQ0FBQyxDQUFBO1lBQ1YsS0FBSyxPQUFPO2dCQUNWLE9BQU8sQ0FBQyxDQUFBO1lBQ1Y7Z0JBQ0UsTUFBTSxJQUFJLEtBQUssQ0FBQyxzQkFBc0IsUUFBUSxFQUFFLENBQUMsQ0FBQTtRQUNyRCxDQUFDO0lBQ0gsQ0FBQztJQUNELE9BQU8sUUFBUSxDQUFBO0FBQ2pCLENBQUM7QUFFRDs7Ozs7Ozs7O0dBU0c7QUFDSCxNQUFNLFVBQVUsZ0JBQWdCLENBQUMsU0FBaUI7SUFDaEQsSUFBSSxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQztRQUM5QixNQUFNLElBQUksS0FBSyxDQUFDLGdDQUFnQyxTQUFTLEVBQUUsQ0FBQyxDQUFBO0lBQzlELENBQUM7SUFFRCxNQUFNLFVBQVUsR0FBYSxFQUFFLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQyxDQUFBO0lBRW5ELElBQUksVUFBVSxDQUFDLFdBQVcsRUFBRSxFQUFFLENBQUM7UUFDN0IsTUFBTSxDQUFDLElBQUksQ0FBQyxnQ0FBZ0MsU0FBUyxFQUFFLENBQUMsQ0FBQTtRQUN4RCxNQUFNLEtBQUssR0FBYSxFQUFFLENBQUMsV0FBVyxDQUFDLFNBQVMsQ0FBQyxDQUFBO1FBQ2pELE1BQU0sYUFBYSxHQUFhLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQyxJQUFZLEVBQUUsRUFBRSxDQUM1RCxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLFdBQVcsRUFBRSxLQUFLLFFBQVEsQ0FDOUMsQ0FBQTtRQUNELE1BQU0sQ0FBQyxJQUFJLENBQUMsU0FBUyxhQUFhLENBQUMsTUFBTSxtQkFBbUIsU0FBUyxZQUFZLENBQUMsQ0FBQTtRQUNsRixNQUFNLENBQUMsS0FBSyxDQUFDLHlCQUF5QixhQUFhLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQTtRQUNqRSxPQUFPLGFBQWEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFZLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLElBQUksQ0FBQyxDQUFDLENBQUE7SUFDeEUsQ0FBQztJQUVELElBQUksVUFBVSxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUM7UUFDeEIsTUFBTSxDQUFDLElBQUksQ0FBQywyQkFBMkIsU0FBUyxFQUFFLENBQUMsQ0FBQTtRQUNuRCxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUE7SUFDcEIsQ0FBQztJQUVELE1BQU0sSUFBSSxLQUFLLENBQUMsbURBQW1ELFNBQVMsRUFBRSxDQUFDLENBQUE7QUFDakYsQ0FBQyJ9
@@ -0,0 +1,39 @@
1
+ import { SarifToSlackServiceOptions, SlackMessage } from './types';
2
+ /**
3
+ * Service to convert SARIF files to Slack messages and send them.
4
+ * @public
5
+ */
6
+ export declare class SarifToSlackService {
7
+ private readonly _slackMessages;
8
+ private constructor();
9
+ /**
10
+ * Gets the Slack messages prepared for each SARIF file.
11
+ * @returns A read-only map where keys are SARIF file paths and values are SlackMessage instances.
12
+ * @public
13
+ */
14
+ get slackMessages(): ReadonlyMap<string, SlackMessage>;
15
+ /**
16
+ * Creates an instance of SarifToSlackService.
17
+ * @param opts - Options for the service, including webhook URL, SARIF path, and other configurations.
18
+ * @returns A promise that resolves to an instance of SarifToSlackService.
19
+ * @throws Error if no SARIF files are found at the provided path.
20
+ * @public
21
+ */
22
+ static create(opts: SarifToSlackServiceOptions): Promise<SarifToSlackService>;
23
+ /**
24
+ * Sends all prepared Slack messages.
25
+ * @returns A promise that resolves when all messages have been sent.
26
+ * @throws Error if a Slack message was not prepared for a SARIF path.
27
+ * @public
28
+ */
29
+ sendAll(): Promise<void>;
30
+ /**
31
+ * Sends a Slack message for a specific SARIF path.
32
+ * @param sarifPath - The path of the SARIF file for which the message should be sent.
33
+ * @returns A promise that resolves when the message has been sent.
34
+ * @throws Error if a Slack message was not prepared for the given SARIF path.
35
+ * @public
36
+ */
37
+ send(sarifPath: string): Promise<void>;
38
+ }
39
+ //# sourceMappingURL=SarifToSlackService.d.ts.map
@@ -0,0 +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;AAmChB;;;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;IAU1F;;;;;OAKG;IACU,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAMrC;;;;;;OAMG;IACU,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAQpD"}
@@ -0,0 +1,95 @@
1
+ import { promises as fs } from 'fs';
2
+ import Logger from './Logger';
3
+ import { processColor, processLogLevel, processSarifPath } from './Processors';
4
+ import { SlackMessageBuilder } from './SlackMessageBuilder';
5
+ async function initialize(opts) {
6
+ const slackMessages = new Map();
7
+ const sarifFiles = processSarifPath(opts.sarifPath);
8
+ if (sarifFiles.length === 0) {
9
+ throw new Error(`No SARIF files found at the provided path: ${opts.sarifPath}`);
10
+ }
11
+ for (const sarifFile of sarifFiles) {
12
+ const jsonString = await fs.readFile(sarifFile, 'utf8');
13
+ const messageBuilder = new SlackMessageBuilder(opts.webhookUrl, {
14
+ username: opts.username,
15
+ iconUrl: opts.iconUrl,
16
+ color: processColor(opts.color),
17
+ sarif: JSON.parse(jsonString)
18
+ });
19
+ if (opts.header?.include) {
20
+ messageBuilder.withHeader(opts.header?.value);
21
+ }
22
+ if (opts.footer?.include) {
23
+ messageBuilder.withFooter(opts.footer?.value, opts.footer?.type);
24
+ }
25
+ if (opts.actor?.include) {
26
+ messageBuilder.withActor(opts.actor?.value);
27
+ }
28
+ if (opts.run?.include) {
29
+ messageBuilder.withRun();
30
+ }
31
+ slackMessages.set(sarifFile, messageBuilder);
32
+ }
33
+ return slackMessages;
34
+ }
35
+ /**
36
+ * Service to convert SARIF files to Slack messages and send them.
37
+ * @public
38
+ */
39
+ export class SarifToSlackService {
40
+ _slackMessages;
41
+ constructor() {
42
+ this._slackMessages = new Map();
43
+ }
44
+ /**
45
+ * Gets the Slack messages prepared for each SARIF file.
46
+ * @returns A read-only map where keys are SARIF file paths and values are SlackMessage instances.
47
+ * @public
48
+ */
49
+ get slackMessages() {
50
+ return this._slackMessages;
51
+ }
52
+ /**
53
+ * Creates an instance of SarifToSlackService.
54
+ * @param opts - Options for the service, including webhook URL, SARIF path, and other configurations.
55
+ * @returns A promise that resolves to an instance of SarifToSlackService.
56
+ * @throws Error if no SARIF files are found at the provided path.
57
+ * @public
58
+ */
59
+ static async create(opts) {
60
+ Logger.initialize({
61
+ logLevel: processLogLevel(opts.logLevel)
62
+ });
63
+ const instance = new SarifToSlackService();
64
+ const map = await initialize(opts);
65
+ map.forEach((val, key) => instance._slackMessages.set(key, val));
66
+ return instance;
67
+ }
68
+ /**
69
+ * Sends all prepared Slack messages.
70
+ * @returns A promise that resolves when all messages have been sent.
71
+ * @throws Error if a Slack message was not prepared for a SARIF path.
72
+ * @public
73
+ */
74
+ async sendAll() {
75
+ for (const sarifPath of this._slackMessages.keys()) {
76
+ await this.send(sarifPath);
77
+ }
78
+ }
79
+ /**
80
+ * Sends a Slack message for a specific SARIF path.
81
+ * @param sarifPath - The path of the SARIF file for which the message should be sent.
82
+ * @returns A promise that resolves when the message has been sent.
83
+ * @throws Error if a Slack message was not prepared for the given SARIF path.
84
+ * @public
85
+ */
86
+ async send(sarifPath) {
87
+ const message = this._slackMessages.get(sarifPath);
88
+ if (!message) {
89
+ throw new Error(`Slack message was not prepared for SARIF path: ${sarifPath}.`);
90
+ }
91
+ const text = await message.send();
92
+ Logger.info(`Message sent for ${sarifPath} file. Status:`, text);
93
+ }
94
+ }
95
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU2FyaWZUb1NsYWNrU2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9TYXJpZlRvU2xhY2tTZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxRQUFRLElBQUksRUFBRSxFQUFFLE1BQU0sSUFBSSxDQUFDO0FBQ3BDLE9BQU8sTUFBTSxNQUFNLFVBQVUsQ0FBQTtBQUM3QixPQUFPLEVBQUUsWUFBWSxFQUFFLGVBQWUsRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLGNBQWMsQ0FBQTtBQUM5RSxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQTtBQU8zRCxLQUFLLFVBQVUsVUFBVSxDQUFDLElBQWdDO0lBQ3hELE1BQU0sYUFBYSxHQUFHLElBQUksR0FBRyxFQUF3QixDQUFDO0lBQ3RELE1BQU0sVUFBVSxHQUFhLGdCQUFnQixDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQTtJQUM3RCxJQUFJLFVBQVUsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7UUFDNUIsTUFBTSxJQUFJLEtBQUssQ0FBQyw4Q0FBOEMsSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDLENBQUE7SUFDakYsQ0FBQztJQUVELEtBQUssTUFBTSxTQUFTLElBQUksVUFBVSxFQUFFLENBQUM7UUFDbkMsTUFBTSxVQUFVLEdBQVcsTUFBTSxFQUFFLENBQUMsUUFBUSxDQUFDLFNBQVMsRUFBRSxNQUFNLENBQUMsQ0FBQTtRQUUvRCxNQUFNLGNBQWMsR0FBRyxJQUFJLG1CQUFtQixDQUFDLElBQUksQ0FBQyxVQUFVLEVBQUU7WUFDOUQsUUFBUSxFQUFFLElBQUksQ0FBQyxRQUFRO1lBQ3ZCLE9BQU8sRUFBRSxJQUFJLENBQUMsT0FBTztZQUNyQixLQUFLLEVBQUUsWUFBWSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUM7WUFDL0IsS0FBSyxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsVUFBVSxDQUFVO1NBQ3ZDLENB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
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=SlackMessageBuilder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SlackMessageBuilder.d.ts","sourceRoot":"","sources":["../src/SlackMessageBuilder.ts"],"names":[],"mappings":""}