Skip to content

Commit 787ea14

Browse files
authored
SP-3575_result-conversion
* Added automatic conversion to CycloneDx, SPDXLite and CSV
2 parents abb63f2 + cc1cb98 commit 787ea14

11 files changed

Lines changed: 167 additions & 13 deletions

CHANGELOG.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Changelog
2+
3+
All notable changes to this project will be documented in this file.
4+
5+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7+
8+
## [Unreleased]
9+
### Added
10+
- Changes...
11+
12+
## [1.1.0] - 2025-10-22
13+
### Added
14+
- Added raw results conversion to CycloneDX, SPDXLite and CSV
15+
### Changed
16+
- Upgraded scanoss-py version to v1.37.1
17+
18+
[1.1.0]: https://github.com/scanoss/ado-code-scan/compare/v1.0.3...v1.1.0

OVERVIEW.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ When the pipeline is manually triggered or runs on a schedule, the results are u
153153
| policiesHaltOnFailure | Halt check on policy failure. If set to false checks will not fail. | Optional | `true` |
154154
| apiUrl | SCANOSS API URL | Optional | `https://api.osskb.org/scan/direct` |
155155
| apiKey | SCANOSS API Key | Optional | - |
156-
| runtimeContainer | Runtime URL | Optional | `ghcr.io/scanoss/scanoss-py:v1.32.0` |
156+
| runtimeContainer | Runtime URL | Optional | `ghcr.io/scanoss/scanoss-py:v1.37.1` |
157157
| licensesCopyleftInclude | List of Copyleft licenses to append to the default list. Provide licenses as a comma-separated list. | Optional | - |
158158
| licensesCopyleftExclude | List of Copyleft licenses to remove from default list. Provide licenses as a comma-separated list. | Optional | - |
159159
| licensesCopyleftExplicit | Explicit list of Copyleft licenses to consider. Provide licenses as a comma-separated list. | Optional | - |

codescantask/app.input.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@ export const COPYLEFT_LICENSE_EXCLUDE = tl.getInput('licensesCopyleftExclude');
3131
export const COPYLEFT_LICENSE_EXPLICIT = tl.getInput('licensesCopyleftExplicit');
3232
export const API_KEY = tl.getInput('apiKey');
3333
export const API_URL = tl.getInput('apiUrl');
34-
export const OUTPUT_FILEPATH = tl.getInput('outputFilepath') || "results.json";
34+
export const OUTPUT_FILEPATH = tl.getInput('outputFilepath') || "scanoss-raw.json";
3535
export const REPO_DIR = tl.getVariable('Build.Repository.LocalPath') || ''; // Get repository path
3636
export const POLICIES_HALT_ON_FAILURE = tl.getInput('policiesHaltOnFailure') === 'true';
37-
export const RUNTIME_CONTAINER = tl.getInput('runtimeContainer') || "ghcr.io/scanoss/scanoss-py:v1.32.0";
37+
export const RUNTIME_CONTAINER = tl.getInput('runtimeContainer') || "ghcr.io/scanoss/scanoss-py:v1.37.1";
3838
export const SKIP_SNIPPETS = tl.getInput('skipSnippets') === 'true';
3939
export const SCAN_FILES = tl.getInput('scanFiles') === 'true';
4040
export const SCANOSS_SETTINGS = tl.getInput('scanossSettings') === 'true';

codescantask/app.output.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// SPDX-License-Identifier: MIT
2+
/*
3+
Copyright (c) 2025, SCANOSS
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in
13+
all copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
THE SOFTWARE.
22+
*/
23+
24+
export const CYCLONEDX_FILE_NAME = 'scanoss-cyclonedx.json';
25+
26+
export const SPDXLITE_FILE_NAME = 'scanoss-spdxlite.json';
27+
28+
export const CSV_FILE_NAME = 'scanoss-sbom.csv'

codescantask/index.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
import tl = require('azure-pipelines-task-lib/task');
2525
import { ScanService } from './services/scan.service';
26+
import { scanossService } from "./services/scanoss.service";
2627
import { policyManager } from './policies/policy.manager';
2728
async function run() {
2829
try {
@@ -31,6 +32,12 @@ async function run() {
3132
await scanService.scan();
3233
const policies = policyManager.getPolicies();
3334

35+
// Convert raw result to CycloneDX, SPDXLite and CSV
36+
const formats = ['cyclonedx', 'spdxlite', 'csv'];
37+
for (const format of formats) {
38+
await scanossService.reformatScanResults(format);
39+
}
40+
3441
// run policies
3542
for (const policy of policies) {
3643
await policy.run();

codescantask/package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

codescantask/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "azure-devops-integration",
3-
"version": "1.0.3",
3+
"version": "1.1.0",
44
"description": "",
55
"main": "index.js",
66
"scripts": {
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
// SPDX-License-Identifier: MIT
2+
/*
3+
Copyright (c) 2025, SCANOSS
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in
13+
all copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
THE SOFTWARE.
22+
*/
23+
24+
import * as tl from 'azure-pipelines-task-lib';
25+
import {EXECUTABLE, OUTPUT_FILEPATH, REPO_DIR, RUNTIME_CONTAINER} from "../app.input";
26+
import {CYCLONEDX_FILE_NAME, SPDXLITE_FILE_NAME, CSV_FILE_NAME} from "../app.output";
27+
import fs from 'fs';
28+
import path from "path";
29+
30+
export class ScanOssService {
31+
/**
32+
* Build scanoss-py conversion parameters */
33+
private buildReformatParameters(format: string, filename: string): string[] {
34+
return [
35+
'run',
36+
'-v',
37+
`${REPO_DIR}:/scanoss`,
38+
RUNTIME_CONTAINER,
39+
'convert',
40+
'--input',
41+
`./${OUTPUT_FILEPATH}`,
42+
'--format',
43+
`${format}`,
44+
'--output',
45+
`./${filename}`
46+
];
47+
}
48+
49+
/**
50+
* Reformats SCANOSS results using scanoss-py.
51+
* Currently always generates CycloneDX, SPDXLite and CSV files to be
52+
* uploaded as an artifact for other integrations.
53+
*/
54+
async reformatScanResults(format: string): Promise<Error | undefined> {
55+
try {
56+
console.log(`Converting SCANOSS results to ${format} format...`);
57+
const options = {
58+
failOnStdErr: false,
59+
ignoreReturnCode: false
60+
};
61+
const filename =
62+
format === 'cyclonedx'
63+
? CYCLONEDX_FILE_NAME
64+
: format === 'spdxlite'
65+
? SPDXLITE_FILE_NAME
66+
: format === 'csv'
67+
? CSV_FILE_NAME
68+
: undefined;
69+
if (!filename) {
70+
return new Error(`Unknown format: ${format}`);
71+
}
72+
const exitCode = await tl.execAsync(
73+
EXECUTABLE,
74+
this.buildReformatParameters(format, filename),
75+
options
76+
);
77+
if (exitCode !== 0) {
78+
return new Error(`Error converting scan results into ${format} format`);
79+
}
80+
// Check if reformatted file was actually created before trying to upload it
81+
try {
82+
const formatAbsolutePath = path.join(process.cwd(), filename)
83+
await fs.promises.access(formatAbsolutePath, fs.constants.F_OK);
84+
this.uploadToArtifacts(formatAbsolutePath);
85+
console.log(`Successfully converted results into ${format} format`);
86+
} catch (fileError) {
87+
// File doesn't exist - this can happen with empty repos
88+
console.log(`${format} conversion completed but no file generated (likely empty repository)`);
89+
}
90+
} catch (e: any) {
91+
tl.error(e.message);
92+
}
93+
}
94+
95+
private uploadToArtifacts(pathToFile: string) {
96+
const artifactName = 'scanoss';
97+
tl.command('artifact.upload', { artifactname: artifactName }, pathToFile);
98+
}
99+
}
100+
101+
export const scanossService = new ScanOssService();

codescantask/task.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
"author": "SCANOSS",
1010
"version": {
1111
"Major": 1,
12-
"Minor": 0,
13-
"Patch": 3
12+
"Minor": 1,
13+
"Patch": 0
1414
},
1515
"inputs": [
1616
{
@@ -81,15 +81,15 @@
8181
"name": "runtimeContainer",
8282
"type": "string",
8383
"label": "Runtime container",
84-
"defaultValue": "ghcr.io/scanoss/scanoss-py:v1.32.0",
84+
"defaultValue": "ghcr.io/scanoss/scanoss-py:v1.37.1",
8585
"required": false,
8686
"helpMarkDown": "Specify runtime container to perform the scan."
8787
},
8888
{
8989
"name": "outputFilepath",
9090
"type": "string",
9191
"label": "Output File Path",
92-
"defaultValue": "results.json",
92+
"defaultValue": "scanoss-raw.json",
9393
"required": false,
9494
"helpMarkDown": "Scan output file name."
9595
},
@@ -159,7 +159,7 @@
159159
}
160160
],
161161
"execution": {
162-
"Node16": {
162+
"Node20_1": {
163163
"target": "index.js"
164164
}
165165
}

vss-extension-dev.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"manifestVersion": 1,
33
"id": "scanoss-code-scan-dev",
44
"name": "SCANOSS Code Scan DEV",
5-
"version": "1.0.3",
5+
"version": "0.21.51",
66
"publisher": "SCANOSS",
77
"public": false,
88
"targets": [

0 commit comments

Comments
 (0)