diff --git a/.github/workflows/test-action.yml b/.github/workflows/test-action.yml index 709b3c2..134cc1f 100644 --- a/.github/workflows/test-action.yml +++ b/.github/workflows/test-action.yml @@ -25,7 +25,6 @@ jobs: id: test-action uses: ./ with: - sbom.enabled: false dependencies.enabled: true policies: copyleft, undeclared diff --git a/dist/index.js b/dist/index.js index e79821e..7e40a86 100644 --- a/dist/index.js +++ b/dist/index.js @@ -125795,12 +125795,10 @@ var __importStar = (this && this.__importStar) || function (mod) { }; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.run = void 0; -const result_service_1 = __nccwpck_require__(32414); const github_utils_1 = __nccwpck_require__(17889); const copyleft_policy_check_1 = __nccwpck_require__(34466); const report_service_1 = __nccwpck_require__(32467); const core = __importStar(__nccwpck_require__(42186)); -const exec = __importStar(__nccwpck_require__(71514)); const inputs = __importStar(__nccwpck_require__(483)); const outputs = __importStar(__nccwpck_require__(22698)); const scan_service_1 = __nccwpck_require__(87577); @@ -125816,17 +125814,16 @@ async function run() { const policies = [new copyleft_policy_check_1.CopyleftPolicyCheck()]; policies.forEach(async (policy) => policy.start()); // run scan - const { stdout, stderr } = await exec.getExecOutput((0, scan_service_1.commandBuilder)(), []); + const { scan, stdout } = await scan_service_1.scanService.scan(); await (0, scan_service_1.uploadResults)(); - const scannerResults = await (0, result_service_1.readResult)(inputs.OUTPUT_FILEPATH); // run policies - policies.forEach(async (policy) => await policy.run(scannerResults)); + policies.forEach(async (policy) => await policy.run(scan)); if ((0, github_utils_1.isPullRequest)()) { // create reports - const report = (0, report_service_1.generateSummary)(scannerResults); + const report = (0, report_service_1.generateSummary)(scan); (0, github_utils_1.createCommentOnPR)(report); } - await (0, report_service_1.generateJobSummary)(scannerResults); + await (0, report_service_1.generateJobSummary)(scan); // set outputs for other workflow steps to use core.setOutput(outputs.RESULT_FILEPATH, inputs.OUTPUT_FILEPATH); core.setOutput(outputs.STDOUT_SCAN_COMMAND, stdout); @@ -126205,24 +126202,65 @@ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.commandBuilder = exports.uploadResults = void 0; -const path_1 = __importDefault(__nccwpck_require__(71017)); -const input = __importStar(__nccwpck_require__(483)); +exports.scanService = exports.ScanService = exports.uploadResults = void 0; const artifact_1 = __nccwpck_require__(79450); +const exec = __importStar(__nccwpck_require__(71514)); +const inputs = __importStar(__nccwpck_require__(483)); +const fs_1 = __importDefault(__nccwpck_require__(57147)); +const core = __importStar(__nccwpck_require__(42186)); +const path = __importStar(__nccwpck_require__(71017)); const artifact = new artifact_1.DefaultArtifactClient(); async function uploadResults() { - await artifact.uploadArtifact(path_1.default.basename(input.OUTPUT_FILEPATH), [input.OUTPUT_FILEPATH], path_1.default.dirname(input.OUTPUT_FILEPATH)); + await artifact.uploadArtifact(path.basename(inputs.OUTPUT_FILEPATH), [inputs.OUTPUT_FILEPATH], path.dirname(inputs.OUTPUT_FILEPATH)); } exports.uploadResults = uploadResults; -function commandBuilder() { - return `docker run -v "${input.REPO_DIR}":"/scanoss" ghcr.io/scanoss/scanoss-py:v1.9.0 scan . - --output ${input.OUTPUT_FILEPATH} - ${input.DEPENDENCIES_ENABLED ? `--dependencies` : ''} - ${input.SBOM_ENABLED ? `--${input.SBOM_TYPE} ${input.SBOM_FILEPATH}` : ''} - ${input.API_URL ? `--apiurl ${input.API_URL}` : ''} - ${input.API_KEY ? `--key ${input.API_KEY}` : ''}`.replace(/\n/gm, ''); -} -exports.commandBuilder = commandBuilder; +class ScanService { + options; + constructor(options) { + this.options = options || { + sbomFilepath: inputs.SBOM_FILEPATH, + sbomType: inputs.SBOM_TYPE, + sbomEnabled: inputs.SBOM_ENABLED, + apiKey: inputs.API_KEY, + apiUrl: inputs.API_URL, + dependenciesEnabled: inputs.DEPENDENCIES_ENABLED, + outputFilepath: inputs.OUTPUT_FILEPATH, + inputFilepath: inputs.REPO_DIR + }; + } + async scan() { + const command = await this.buildCommand(); + const { stdout, stderr } = await exec.getExecOutput(command, []); + const scan = await this.parseResult(); + return { scan, stdout, stderr }; + } + async buildCommand() { + return `docker run -v "${this.options.inputFilepath}":"/scanoss" ghcr.io/scanoss/scanoss-py:v1.9.0 scan . + --output ${this.options.outputFilepath} + ${this.options.dependenciesEnabled ? `--dependencies` : ''} + ${await this.detectSbom()} + ${this.options.apiUrl ? `--apiurl ${this.options.apiUrl}` : ''} + ${this.options.apiKey ? `--key ${this.options.apiKey}` : ''}`.replace(/\n/gm, ' '); + } + async detectSbom() { + if (!this.options.sbomEnabled || !this.options.sbomFilepath) + return ''; + try { + await fs_1.default.promises.access(this.options.sbomFilepath, fs_1.default.constants.F_OK); + return `--${this.options.sbomType} ${this.options.sbomFilepath}`; + } + catch (error) { + core.warning('SBOM not found'); + return ''; + } + } + async parseResult() { + const content = await fs_1.default.promises.readFile(this.options.outputFilepath, 'utf-8'); + return JSON.parse(content); + } +} +exports.ScanService = ScanService; +exports.scanService = new ScanService(); /***/ }), diff --git a/results.json b/results.json deleted file mode 100644 index e69de29..0000000 diff --git a/src/main.ts b/src/main.ts index 4c73493..c8d1e75 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,13 +1,11 @@ -import { getLicenses, readResult } from './services/result.service'; import { createCommentOnPR, isPullRequest } from './utils/github.utils'; import { CopyleftPolicyCheck } from './policies/copyleft-policy-check'; import { generateJobSummary, generateSummary } from './services/report.service'; import * as core from '@actions/core'; -import * as exec from '@actions/exec'; import * as inputs from './app.input'; import * as outputs from './app.output'; -import { commandBuilder, uploadResults } from './services/scan.service'; +import { scanService, uploadResults } from './services/scan.service'; /** * The main function for the action. * @returns {Promise} Resolves when the action is complete. @@ -22,20 +20,19 @@ export async function run(): Promise { policies.forEach(async policy => policy.start()); // run scan - const { stdout, stderr } = await exec.getExecOutput(commandBuilder(), []); + const { scan, stdout } = await scanService.scan(); await uploadResults(); - const scannerResults = await readResult(inputs.OUTPUT_FILEPATH); // run policies - policies.forEach(async policy => await policy.run(scannerResults)); + policies.forEach(async policy => await policy.run(scan)); if (isPullRequest()) { // create reports - const report = generateSummary(scannerResults); + const report = generateSummary(scan); createCommentOnPR(report); } - await generateJobSummary(scannerResults); + await generateJobSummary(scan); // set outputs for other workflow steps to use core.setOutput(outputs.RESULT_FILEPATH, inputs.OUTPUT_FILEPATH); core.setOutput(outputs.STDOUT_SCAN_COMMAND, stdout); diff --git a/src/services/scan.service.ts b/src/services/scan.service.ts index 3f0c484..b339971 100644 --- a/src/services/scan.service.ts +++ b/src/services/scan.service.ts @@ -1,22 +1,81 @@ -import path from 'path'; -import * as input from '../app.input'; import { DefaultArtifactClient } from '@actions/artifact'; +import * as exec from '@actions/exec'; +import * as inputs from '../app.input'; +import { ScannerResults } from './result.interfaces'; +import fs from 'fs'; +import * as core from '@actions/core'; +import * as path from 'path'; const artifact = new DefaultArtifactClient(); export async function uploadResults(): Promise { await artifact.uploadArtifact( - path.basename(input.OUTPUT_FILEPATH), - [input.OUTPUT_FILEPATH], - path.dirname(input.OUTPUT_FILEPATH) + path.basename(inputs.OUTPUT_FILEPATH), + [inputs.OUTPUT_FILEPATH], + path.dirname(inputs.OUTPUT_FILEPATH) ); } -export function commandBuilder(): string { - return `docker run -v "${input.REPO_DIR}":"/scanoss" ghcr.io/scanoss/scanoss-py:v1.9.0 scan . - --output ${input.OUTPUT_FILEPATH} - ${input.DEPENDENCIES_ENABLED ? `--dependencies` : ''} - ${input.SBOM_ENABLED ? `--${input.SBOM_TYPE} ${input.SBOM_FILEPATH}` : ''} - ${input.API_URL ? `--apiurl ${input.API_URL}` : ''} - ${input.API_KEY ? `--key ${input.API_KEY}` : ''}`.replace(/\n/gm, ''); +export interface Options { + sbomType?: string; + sbomEnabled?: boolean; + sbomFilepath?: string; + + dependenciesEnabled?: boolean; + + apiKey?: string; + apiUrl?: string; + + outputFilepath: string; + inputFilepath: string; +} + +export class ScanService { + private options: Options; + constructor(options?: Options) { + this.options = options || { + sbomFilepath: inputs.SBOM_FILEPATH, + sbomType: inputs.SBOM_TYPE, + sbomEnabled: inputs.SBOM_ENABLED, + apiKey: inputs.API_KEY, + apiUrl: inputs.API_URL, + dependenciesEnabled: inputs.DEPENDENCIES_ENABLED, + outputFilepath: inputs.OUTPUT_FILEPATH, + inputFilepath: inputs.REPO_DIR + }; + } + async scan(): Promise<{ scan: ScannerResults; stdout: string; stderr: string }> { + const command = await this.buildCommand(); + const { stdout, stderr } = await exec.getExecOutput(command, []); + const scan = await this.parseResult(); + return { scan, stdout, stderr }; + } + + private async buildCommand(): Promise { + return `docker run -v "${this.options.inputFilepath}":"/scanoss" ghcr.io/scanoss/scanoss-py:v1.9.0 scan . + --output ${this.options.outputFilepath} + ${this.options.dependenciesEnabled ? `--dependencies` : ''} + ${await this.detectSbom()} + ${this.options.apiUrl ? `--apiurl ${this.options.apiUrl}` : ''} + ${this.options.apiKey ? `--key ${this.options.apiKey}` : ''}`.replace(/\n/gm, ' '); + } + + private async detectSbom(): Promise { + if (!this.options.sbomEnabled || !this.options.sbomFilepath) return ''; + + try { + await fs.promises.access(this.options.sbomFilepath, fs.constants.F_OK); + return `--${this.options.sbomType} ${this.options.sbomFilepath}`; + } catch (error) { + core.warning('SBOM not found'); + return ''; + } + } + + private async parseResult(): Promise { + const content = await fs.promises.readFile(this.options.outputFilepath, 'utf-8'); + return JSON.parse(content) as ScannerResults; + } } + +export const scanService = new ScanService();