|
1 | 1 | import * as core from '@actions/core'; |
2 | | -import fs from 'fs'; |
3 | | -import { generateSARIFReport } from './src/sarif'; |
4 | | -import { cliScannerName, cliScannerResult, cliScannerURL, executeScan, pullScanner, ScanExecutionResult, ScanMode } from './src/scanner'; |
5 | | -import { ActionInputs, defaultSecureEndpoint } from './src/action'; |
6 | | -import { generateSummary } from './src/summary'; |
7 | | -import { Report, FilterOptions, Severity } from './src/report'; |
8 | | - |
9 | | -function parseCsvList(str?: string): string[] { |
10 | | - if (!str) return []; |
11 | | - return str.split(",").map(s => s.trim()).filter(s => !!s); |
12 | | -} |
13 | | - |
14 | | -export class ExecutionError extends Error { |
15 | | - constructor(stdout: string, stderr: string) { |
16 | | - super("execution error\n\nstdout: " + stdout + "\n\nstderr: " + stderr); |
17 | | - } |
18 | | -} |
19 | | - |
20 | | -function writeReport(reportData: string) { |
21 | | - fs.writeFileSync("./report.json", reportData); |
22 | | - core.setOutput("scanReport", "./report.json"); |
23 | | -} |
24 | | - |
25 | | -export async function run() { |
26 | | - |
| 2 | +import { RunScanUseCase } from './src/application/use-cases/RunScanUseCase'; |
| 3 | +import { GitHubActionsInputProvider } from './src/infrastructure/github/GitHubActionsInputProvider'; |
| 4 | +import { SysdigCliScanner } from './src/infrastructure/sysdig/SysdigCliScanner'; |
| 5 | +import { SarifReportPresenter } from './src/infrastructure/github/SarifReportPresenter'; |
| 6 | +import { SummaryReportPresenter } from './src/infrastructure/github/SummaryReportPresenter'; |
| 7 | +import { IReportPresenter } from './src/application/ports/IReportPresenter'; |
| 8 | + |
| 9 | +async function run(): Promise<void> { |
27 | 10 | try { |
28 | | - let opts = ActionInputs.parseActionInputs(); |
29 | | - opts.printOptions(); |
30 | | - let scanFlags = opts.composeFlags(); |
| 11 | + const inputProvider = new GitHubActionsInputProvider(); |
| 12 | + const config = inputProvider.getInputs(); |
31 | 13 |
|
32 | | - let scanResult: ScanExecutionResult; |
33 | | - // Download CLI Scanner from 'cliScannerURL' |
34 | | - let retCode = await pullScanner(opts.cliScannerURL); |
35 | | - if (retCode == 0) { |
36 | | - // Execute Scanner |
37 | | - scanResult = await executeScan(scanFlags); |
38 | | - |
39 | | - retCode = scanResult.ReturnCode; |
40 | | - if (retCode == 0 || retCode == 1) { |
41 | | - // Transform Scan Results to other formats such as SARIF |
42 | | - if (opts.mode == ScanMode.vm) { |
43 | | - await processScanResult(scanResult, opts); |
44 | | - } |
45 | | - } else { |
46 | | - core.error("Terminating scan. Scanner couldn't be executed.") |
47 | | - } |
48 | | - } else { |
49 | | - core.error("Terminating scan. Scanner couldn't be pulled.") |
50 | | - } |
| 14 | + const scanner = new SysdigCliScanner(); |
51 | 15 |
|
52 | | - if (opts.stopOnFailedPolicyEval && retCode == 1) { |
53 | | - core.setFailed(`Stopping because Policy Evaluation was FAILED.`); |
54 | | - } else if (opts.standalone && retCode == 0) { |
55 | | - core.info("Policy Evaluation was OMITTED."); |
56 | | - } else if (retCode == 0) { |
57 | | - core.info("Policy Evaluation was PASSED."); |
58 | | - } else if (opts.stopOnProcessingError && retCode > 1) { |
59 | | - core.setFailed(`Stopping because the scanner terminated with an error.`); |
60 | | - } // else: Don't stop regardless the outcome. |
| 16 | + const presenters: IReportPresenter[] = [ |
| 17 | + new SarifReportPresenter(), |
| 18 | + ]; |
61 | 19 |
|
62 | | - } catch (error) { |
63 | | - if (core.getInput('stop-on-processing-error') == 'true') { |
64 | | - core.setFailed(`Unexpected error: ${error instanceof Error ? error.stack : String(error)}`); |
| 20 | + if (!config.skipSummary) { |
| 21 | + presenters.push(new SummaryReportPresenter()); |
65 | 22 | } |
66 | | - core.error(`Unexpected error: ${error instanceof Error ? error.stack : String(error)}`); |
67 | | - } |
68 | | -} |
69 | 23 |
|
70 | | -export async function processScanResult(result: ScanExecutionResult, opts: ActionInputs) { |
71 | | - writeReport(result.Output); |
72 | | - |
73 | | - let report: Report; |
74 | | - try { |
75 | | - report = JSON.parse(result.Output); |
76 | | - } catch (error) { |
77 | | - core.error("Error parsing analysis JSON report: " + error + ". Output was: " + result.Output); |
78 | | - throw new ExecutionError(result.Output, result.Error); |
79 | | - } |
80 | | - |
81 | | - if (report) { |
82 | | - const filters: FilterOptions = { |
83 | | - minSeverity: (opts.severityAtLeast && opts.severityAtLeast.toLowerCase() !== "any") |
84 | | - ? opts.severityAtLeast.toLowerCase() as Severity |
85 | | - : undefined, |
86 | | - packageTypes: parseCsvList(opts.packageTypes), |
87 | | - notPackageTypes: parseCsvList(opts.notPackageTypes), |
88 | | - excludeAccepted: opts.excludeAccepted, |
89 | | - }; |
90 | | - |
91 | | - core.info("Generating SARIF Report...") |
92 | | - generateSARIFReport(report, opts.groupByPackage, filters); |
93 | | - |
94 | | - if (!opts.skipSummary) { |
95 | | - core.info("Generating Summary...") |
96 | | - await generateSummary(opts, report, filters); |
| 24 | + const useCase = new RunScanUseCase(scanner, presenters, inputProvider); |
| 25 | + await useCase.execute(); |
| 26 | +} catch (error) { |
| 27 | + if (error instanceof Error) { |
| 28 | + core.setFailed(error.message); |
97 | 29 | } else { |
98 | | - core.info("Skipping Summary...") |
| 30 | + core.setFailed(`Unknown error: ${error}`); |
99 | 31 | } |
100 | 32 | } |
101 | 33 | } |
102 | 34 |
|
103 | | -export { |
104 | | - cliScannerURL, |
105 | | - defaultSecureEndpoint, |
106 | | - pullScanner, |
107 | | - cliScannerName, |
108 | | - executeScan, |
109 | | - cliScannerResult, |
110 | | -}; |
111 | | - |
112 | | -if (require.main === module) { |
113 | | - run(); |
114 | | -} |
| 35 | +run(); |
0 commit comments