From b9081a42feb554127e229c7cae08f1225f3fa8f5 Mon Sep 17 00:00:00 2001 From: Agustin Isasmendi Date: Wed, 24 Jan 2024 19:58:40 +0100 Subject: [PATCH] SCP-65 SBOM Ingestion --- .github/workflows/test-action.yml | 2 + action.yml | 13 ++++- dist/index.js | 90 +++++++++++++++++++++++++++---- scanoss-ignore.json | 7 +++ src/input.ts | 29 ++++++++++ src/main.ts | 4 +- vue.js | 56 +++++++++++++++++++ 7 files changed, 189 insertions(+), 12 deletions(-) create mode 100644 scanoss-ignore.json create mode 100644 src/input.ts create mode 100644 vue.js diff --git a/.github/workflows/test-action.yml b/.github/workflows/test-action.yml index 9d80735..ab60862 100644 --- a/.github/workflows/test-action.yml +++ b/.github/workflows/test-action.yml @@ -22,6 +22,8 @@ jobs: - name: Test Local Action id: test-action uses: ./ +# with: +# sbom-ignore: './scanoss-ignore.json' - name: Print output command run: echo "${{ steps.test-action.outputs.output-command }}" diff --git a/action.yml b/action.yml index d814f74..46d70ee 100644 --- a/action.yml +++ b/action.yml @@ -9,8 +9,17 @@ branding: # Define your inputs here. inputs: - scanner-parameters: - description: 'Parameters to run a scan' + sbom-identify: + description: 'Scan and identify components in SBOM file' + required: false + sbom-ignore: + description: 'Ignore components specified in the SBOM file' + required: false + api-key: + description: 'SCANOSS API Key token (optional - not required for default OSSKB URL)' + required: false + api-url: + description: 'SCANOSS API URL (optional - default: https://osskb.org/api/scan/direct)' required: false # Define your outputs here. diff --git a/dist/index.js b/dist/index.js index aff839a..172029b 100644 --- a/dist/index.js +++ b/dist/index.js @@ -3951,6 +3951,62 @@ function version(uuid) { var _default = version; exports["default"] = _default; +/***/ }), + +/***/ 747: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { + +"use strict"; + +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.commandParametersBuilder = exports.getInputs = void 0; +const core = __importStar(__nccwpck_require__(186)); +function getInputs() { + return { + sbomIdentify: core.getInput('sbom-identify'), + sbomIgnore: core.getInput('sbom-ignore'), + apiKey: core.getInput('api-key'), + apiUrl: core.getInput('api-url') + }; +} +exports.getInputs = getInputs; +function commandParametersBuilder(ap) { + return ap.sbomIdentify + ? `--identify ${ap.sbomIdentify}` + : '' + ap.sbomIgnore + ? `--ignore ${ap.sbomIgnore}` + : '' + ap.apiUrl + ? `--apiurl ${ap.apiUrl}` + : '' + ap.apiKey + ? `--key ${ap.apiKey}` + : ''; +} +exports.commandParametersBuilder = commandParametersBuilder; + + /***/ }), /***/ 399: @@ -3986,6 +4042,8 @@ exports.run = void 0; const core = __importStar(__nccwpck_require__(186)); const exec = __importStar(__nccwpck_require__(514)); const result_service_1 = __nccwpck_require__(414); +const input_1 = __nccwpck_require__(747); +const input_2 = __nccwpck_require__(747); /** * The main function for the action. * @returns {Promise} Resolves when the action is complete. @@ -4006,7 +4064,7 @@ async function run() { }; options.silent = true; // run scan - await exec.exec(`docker run -v "${repoDir}":"/scanoss" ghcr.io/scanoss/scanoss-py:v1.9.0 scan . --output ${outputPath}`, [], options); + await exec.exec(`docker run -v "${repoDir}":"/scanoss" ghcr.io/scanoss/scanoss-py:v1.9.0 scan . --output ${outputPath} ${(0, input_1.commandParametersBuilder)((0, input_2.getInputs)())}`, [], options); const scannerResults = await (0, result_service_1.readResult)(outputPath); const licenses = (0, result_service_1.getLicenses)(scannerResults); core.setOutput('licenses', licenses.toString()); @@ -4081,25 +4139,39 @@ async function readResult(filepath) { } exports.readResult = readResult; function getLicenses(results) { - const licenses = new Set(); + const licenses = new Array(); for (const component of Object.values(results)) { for (const c of component) { + if (c.id === result_interfaces_1.ComponentID.FILE || c.id === result_interfaces_1.ComponentID.SNIPPET) { + for (const l of c.licenses) { + licenses.push({ + spdxid: l.name, + copyleft: !l.copyleft ? null : l.copyleft === 'yes' ? true : false, + url: l?.url ? l.url : null + }); + } + } if (c.id === result_interfaces_1.ComponentID.DEPENDENCY) { const dependencies = c.dependencies; for (const d of dependencies) { for (const l of d.licenses) { - licenses.add(l.spdx_id); + if (!l.spdx_id) + continue; + licenses.push({ spdxid: l.spdx_id, copyleft: null, url: null }); } } } - if (c.id === result_interfaces_1.ComponentID.FILE || c.id === result_interfaces_1.ComponentID.SNIPPET) { - for (const l of c.licenses) { - licenses.add(l.name); - } - } } } - return Array.from(licenses); + const seenSpdxIds = new Set(); + const uniqueLicenses = licenses.filter(license => { + if (!seenSpdxIds.has(license.spdxid)) { + seenSpdxIds.add(license.spdxid); + return true; + } + return false; + }); + return uniqueLicenses; } exports.getLicenses = getLicenses; diff --git a/scanoss-ignore.json b/scanoss-ignore.json new file mode 100644 index 0000000..9edc209 --- /dev/null +++ b/scanoss-ignore.json @@ -0,0 +1,7 @@ +{ + "components": [ + { + "purl": "pkg:github/zhang14725804/notebook" + } + ] +} diff --git a/src/input.ts b/src/input.ts new file mode 100644 index 0000000..f996460 --- /dev/null +++ b/src/input.ts @@ -0,0 +1,29 @@ +import * as core from '@actions/core' + +export interface ActionParameters { + sbomIdentify: string + sbomIgnore: string + apiKey: string + apiUrl: string +} + +export function getInputs(): ActionParameters { + return { + sbomIdentify: core.getInput('sbom-identify'), + sbomIgnore: core.getInput('sbom-ignore'), + apiKey: core.getInput('api-key'), + apiUrl: core.getInput('api-url') + } +} + +export function commandParametersBuilder(ap: ActionParameters): string { + return ap.sbomIdentify + ? `--identify ${ap.sbomIdentify}` + : '' + ap.sbomIgnore + ? `--ignore ${ap.sbomIgnore}` + : '' + ap.apiUrl + ? `--apiurl ${ap.apiUrl}` + : '' + ap.apiKey + ? `--key ${ap.apiKey}` + : '' +} diff --git a/src/main.ts b/src/main.ts index cf78508..fb19efd 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,6 +1,8 @@ import * as core from '@actions/core' import * as exec from '@actions/exec' import { getLicenses, readResult } from './services/result.service' +import { commandParametersBuilder } from './input' +import { getInputs } from './input' /** * The main function for the action. @@ -25,7 +27,7 @@ export async function run(): Promise { // run scan await exec.exec( - `docker run -v "${repoDir}":"/scanoss" ghcr.io/scanoss/scanoss-py:v1.9.0 scan . --output ${outputPath}`, + `docker run -v "${repoDir}":"/scanoss" ghcr.io/scanoss/scanoss-py:v1.9.0 scan . --output ${outputPath} ${commandParametersBuilder(getInputs())}`, [], options ) diff --git a/vue.js b/vue.js new file mode 100644 index 0000000..f4443c5 --- /dev/null +++ b/vue.js @@ -0,0 +1,56 @@ + + + + + \ No newline at end of file