Skip to content

Commit

Permalink
feat: add manifest content to sbom' metadata
Browse files Browse the repository at this point in the history
Signed-off-by: Zvi Grinberg <zgrinber@redhat.com>
  • Loading branch information
zvigrinberg committed Jun 13, 2024
1 parent b4328d0 commit 9108631
Show file tree
Hide file tree
Showing 10 changed files with 83 additions and 59 deletions.
9 changes: 8 additions & 1 deletion src/analysis.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import fs from "node:fs";
import path from "node:path";
import {EOL} from "os";

Check warning on line 3 in src/analysis.js

View workflow job for this annotation

GitHub Actions / Lint and test project (18)

Imports should be sorted alphabetically

Check warning on line 3 in src/analysis.js

View workflow job for this annotation

GitHub Actions / Lint and test project (latest)

Imports should be sorted alphabetically
import {RegexNotToBeLogged, getCustom} from "./tools.js";

Check warning on line 4 in src/analysis.js

View workflow job for this annotation

GitHub Actions / Lint and test project (18)

Expected 'multiple' syntax before 'single' syntax

Check warning on line 4 in src/analysis.js

View workflow job for this annotation

GitHub Actions / Lint and test project (latest)

Expected 'multiple' syntax before 'single' syntax

Expand All @@ -17,8 +19,11 @@ const rhdaOperationTypeHeader = "rhda-operation-type"
* @returns {Promise<string|import('../generated/backend/AnalysisReport').AnalysisReport>}
*/
async function requestStack(provider, manifest, url, html = false, opts = {}) {
opts["source-manifest"] = Buffer.from(fs.readFileSync(manifest).toString()).toString('base64')
opts["manifest-type"] = path.parse(manifest).base
let provided = provider.provideStack(manifest, opts) // throws error if content providing failed
opts[rhdaOperationTypeHeader.toUpperCase().replaceAll("-","_")] = "stack-analysis"
opts["source-manifest"]= ""
opts[rhdaOperationTypeHeader.toUpperCase().replaceAll("-","_")] = "stack-analysis"

Check failure on line 26 in src/analysis.js

View workflow job for this annotation

GitHub Actions / Lint and test project (18)

Expected indentation of 1 tab but found 2

Check failure on line 26 in src/analysis.js

View workflow job for this annotation

GitHub Actions / Lint and test project (latest)

Expected indentation of 1 tab but found 2
let startTime = new Date()
let EndTime
if (process.env["EXHORT_DEBUG"] === "true") {
Expand Down Expand Up @@ -69,7 +74,9 @@ async function requestStack(provider, manifest, url, html = false, opts = {}) {
* @returns {Promise<import('../generated/backend/AnalysisReport').AnalysisReport>}
*/
async function requestComponent(provider, data, url, opts = {}, path = '') {
opts["source-manifest"]= Buffer.from(data).toString('base64')
let provided = provider.provideComponent(data, opts,path) // throws error if content providing failed
opts["source-manifest"]= ""
opts[rhdaOperationTypeHeader.toUpperCase().replaceAll("-","_")] = "component-analysis"
if (process.env["EXHORT_DEBUG"] === "true") {
console.log("Starting time of sending component analysis request to exhort server= " + new Date())
Expand Down
24 changes: 20 additions & 4 deletions src/cyclone_dx_sbom.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export default class CycloneDxSbom {
rootComponent
components
dependencies
sourceManifestForAuditTrail

constructor() {
this.dependencies = new Array()
Expand Down Expand Up @@ -117,17 +118,20 @@ export default class CycloneDxSbom {
return this
}

/**
* @return String CycloneDx Sbom json object in a string format
/** @param {{}} opts - various options, settings and configuration of application.
* @return String CycloneDx Sbom json object in a string format
*/
getAsJsonString() {
getAsJsonString(opts) {
let manifestType = opts["manifest-type"]
this.setSourceManifest(opts["source-manifest"])
this.sbomObject = {
"bomFormat": "CycloneDX",
"specVersion": "1.4",
"version": 1,
"metadata": {
"timestamp": new Date(),
"component": this.rootComponent
"component": this.rootComponent,
"properties": new Array()
},
"components": this.components,
"dependencies": this.dependencies
Expand All @@ -136,6 +140,14 @@ export default class CycloneDxSbom {
{
delete this.sbomObject.metadata.component
}
if(this.sourceManifestForAuditTrail !== undefined && manifestType !== undefined) {
this.sbomObject.metadata.properties.push({"name" : "rhda:manifest:content" , "value" : this.sourceManifestForAuditTrail})
this.sbomObject.metadata.properties.push({"name" : "rhda:manifest:filename" , "value" : manifestType})
}
else {
delete this.sbomObject.metadata.properties
}

if (process.env["EXHORT_DEBUG"] === "true") {
console.log("SBOM Generated for manifest, to be sent to exhort service:" + EOL + JSON.stringify(this.sbomObject, null, 4))
}
Expand Down Expand Up @@ -252,4 +264,8 @@ export default class CycloneDxSbom {
this.dependencies.splice(depIndex, 1)
this.rootComponent = undefined
}

setSourceManifest(manifestData) {
this.sourceManifestForAuditTrail = manifestData
}
}
1 change: 1 addition & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ async function stackAnalysis(manifest, html = false, opts = {}) {
*/
async function componentAnalysis(manifestType, data, opts = {}, path = '') {
theUrl = selectExhortBackend(opts)
opts["manifest-type"] = manifestType
let provider = match(manifestType, availableProviders) // throws error if no matching provider
return await analysis.requestComponent(provider, data, theUrl, opts,path) // throws error request sending failed
}
Expand Down
2 changes: 1 addition & 1 deletion src/providers/golang_gomodules.js
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ function getSBOM(manifest, opts = {}, includeTransitive) {
enforceRemovingIgnoredDepsInCaseOfAutomaticVersionUpdate(ignoredDeps,sbom)
}

return sbom.getAsJsonString()
return sbom.getAsJsonString(opts)
}


Expand Down
8 changes: 4 additions & 4 deletions src/providers/java_gradle.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ export default class Java_gradle extends Base_java {
if (process.env["EXHORT_DEBUG"] === "true") {
console.log("Dependency tree that will be used as input for creating the BOM =>" + EOL + EOL + content)
}
let sbom = this.#buildSbomFileFromTextFormat(content, properties, "runtimeClasspath", manifest)
let sbom = this.#buildSbomFileFromTextFormat(content, properties, "runtimeClasspath", manifest,opts)
return sbom
}

Expand Down Expand Up @@ -204,7 +204,7 @@ export default class Java_gradle extends Base_java {
}
}

let sbom = this.#buildSbomFileFromTextFormat(content, properties, configName, manifestPath)
let sbom = this.#buildSbomFileFromTextFormat(content, properties, configName, manifestPath, opts)
return sbom

}
Expand Down Expand Up @@ -251,7 +251,7 @@ export default class Java_gradle extends Base_java {
* @param configName {string} - the configuration name of dependencies to include in sbom.
* @return {string} return sbom json string of the build.gradle manifest file
*/
#buildSbomFileFromTextFormat(content, properties, configName, manifestPath) {
#buildSbomFileFromTextFormat(content, properties, configName, manifestPath, opts = {}) {
let sbom = new Sbom();
let root = `${properties.group}:${properties[ROOT_PROJECT_KEY_NAME].match(/Root project '(.+)'/)[1]}:jar:${properties.version}`
let rootPurl = this.parseDep(root)
Expand All @@ -272,7 +272,7 @@ export default class Java_gradle extends Base_java {
}
this.parseDependencyTree(root + ":compile", 0, arrayForSbom, sbom)
let ignoredDeps = this.#getIgnoredDeps(manifestPath)
return sbom.filterIgnoredDepsIncludingVersion(ignoredDeps).getAsJsonString();
return sbom.filterIgnoredDepsIncludingVersion(ignoredDeps).getAsJsonString(opts);
}

/**
Expand Down
8 changes: 4 additions & 4 deletions src/providers/java_maven.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ export default class Java_maven extends Base_java {
if (process.env["EXHORT_DEBUG"] === "true") {
console.log("Dependency tree that will be used as input for creating the BOM =>" + EOL + EOL + content.toString())
}
let sbom = this.createSbomFileFromTextFormat(content.toString(), ignoredDeps);
let sbom = this.createSbomFileFromTextFormat(content.toString(), ignoredDeps,opts);
// delete temp file and directory
fs.rmSync(tmpDir, {recursive: true, force: true})
// return dependency graph as string
Expand All @@ -110,15 +110,15 @@ export default class Java_maven extends Base_java {
* @param {[String]} ignoredDeps List of ignored dependencies to be omitted from sbom
* @return {String} formatted sbom Json String with all dependencies
*/
createSbomFileFromTextFormat(textGraphList, ignoredDeps) {
createSbomFileFromTextFormat(textGraphList, ignoredDeps, opts) {
let lines = textGraphList.split(EOL);
// get root component
let root = lines[0];
let rootPurl = this.parseDep(root);
let sbom = new Sbom();
sbom.addRoot(rootPurl);
this.parseDependencyTree(root, 0, lines.slice(1), sbom);
return sbom.filterIgnoredDepsIncludingVersion(ignoredDeps).getAsJsonString();
return sbom.filterIgnoredDepsIncludingVersion(ignoredDeps).getAsJsonString(opts);
}

/**
Expand Down Expand Up @@ -174,7 +174,7 @@ export default class Java_maven extends Base_java {
}

// return dependencies list
return sbom.getAsJsonString()
return sbom.getAsJsonString(opts)
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/providers/javascript_npm.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ function getSBOM(manifest, opts = {}, includeTransitive) {
let ignoredDeps = Array.from(packageJsonObject.exhortignore);
sbom.filterIgnoredDeps(ignoredDeps)
}
return sbom.getAsJsonString()
return sbom.getAsJsonString(opts)
}


Expand Down
5 changes: 2 additions & 3 deletions src/providers/python_pip.js
Original file line number Diff line number Diff line change
Expand Up @@ -218,8 +218,7 @@ function createSbomStackAnalysis(manifest, opts = {}) {
handleIgnoredDependencies(requirementTxtContent,sbom,opts)
// In python there is no root component, then we must remove the dummy root we added, so the sbom json will be accepted by exhort backend
// sbom.removeRootComponent()
return sbom.getAsJsonString()

return sbom.getAsJsonString(opts)


}
Expand Down Expand Up @@ -248,7 +247,7 @@ function getSbomForComponentAnalysis(data, opts = {}) {
handleIgnoredDependencies(data,sbom,opts)
// In python there is no root component, then we must remove the dummy root we added, so the sbom json will be accepted by exhort backend
// sbom.removeRootComponent()
return sbom.getAsJsonString()
return sbom.getAsJsonString(opts)
}


Expand Down
5 changes: 3 additions & 2 deletions src/sbom.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,14 @@ export default class Sbom {
/**
* @return String sbom json in a string format
*/
getAsJsonString(){
getAsJsonString(opts = {}){
if (process.env["EXHORT_DEBUG"] === "true") {
this.#endTime = new Date()
console.log("Ending time to create sbom = " + this.#endTime)
let time = (this.#endTime - this.#startTime) / 1000
console.log("Total time in seconds to create sbom = " + time)
}
return this.sbomModel.getAsJsonString()
return this.sbomModel.getAsJsonString(opts)
}

/**
Expand Down Expand Up @@ -92,6 +92,7 @@ export default class Sbom {
{
return this.sbomModel.removeRootComponent()
}

}


Expand Down
78 changes: 39 additions & 39 deletions test/it/end-to-end.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,42 +137,42 @@ suite('Integration Tests', () => {
});
}).beforeAll(() => process.env["EXHORT_DEV_MODE"] = "true");

// suite('Integration Tests - Developer Test End to End', () => {
// let opts = {
// EXHORT_DEV_MODE: "true",
//
// }
//
// test(`Stack Analysis json`, async () => {
// process.env["EXHORT_DEBUG"]= "true"
// process.env["EXHORT_DEV_MODE"]= "true"
// // process.env["EXHORT_GO_PATH"]= "/home/zgrinber/test-go/go/bin/go"
// // process.env["RHDA_TOKEN"] = "34JKLDS-4234809-66666666666"
// // process.env["RHDA_SOURCE"] = "Zvika Client"
// // let result = await index.stackAnalysis("/tmp/rajan-0410/go.mod", false, opts);
// let opts = {
// MATCH_MANIFEST_VERSIONS: 'false',
// EXHORT_DEV_MODE: 'true',
// // EXHORT_OSS_INDEX_TOKEN: '2bb579b7894f13f180f0ebb591be7c8febbcf699',
// EXHORT_OSS_INDEX_USER: 'zgrinber@redhat.com',
// EXHORT_GO_MVS_LOGIC_ENABLED: 'true'
// }
// process.env["EXHORT_PYTHON_VIRTUAL_ENV"] = "true"
// process.env["EXHORT_PYTHON_INSTALL_BEST_EFFORTS"] = "true"
// process.env["MATCH_MANIFEST_VERSIONS"] = "false"
// // let pomPath = `/tmp/070324/package.json`
// let pomPath = `/tmp/170324/requirements.txt`
// // let pomPath = `/home/zgrinber/git/tracing-demos-and-examples/tracing-parent/pom.xml`
// let providedDataForStack;
// // providedDataForStack = await index.componentAnalysis("requirements.txt", fs.readFileSync(pomPath).toString(),{},pomPath);
// providedDataForStack = await index.stackAnalysis(pomPath);
// // console.log(JSON.stringify(providedDataForStack,null , 4))
// // fs.writeFileSync(`/tmp/301123/report.html`,providedDataForStack)
//
// // expect(providedDataForStack.summary.dependencies.scanned).greaterThan(0)
// }).timeout(15000);
//
//
//
//
// });
suite('Integration Tests - Developer Test End to End', () => {
let opts = {

Check failure on line 141 in test/it/end-to-end.js

View workflow job for this annotation

GitHub Actions / Lint and test project (18)

Expected indentation of 1 tab but found 0

Check failure on line 141 in test/it/end-to-end.js

View workflow job for this annotation

GitHub Actions / Lint and test project (18)

'opts' is assigned a value but never used

Check failure on line 141 in test/it/end-to-end.js

View workflow job for this annotation

GitHub Actions / Lint and test project (latest)

Expected indentation of 1 tab but found 0

Check failure on line 141 in test/it/end-to-end.js

View workflow job for this annotation

GitHub Actions / Lint and test project (latest)

'opts' is assigned a value but never used
EXHORT_DEV_MODE: "true",

Check failure on line 142 in test/it/end-to-end.js

View workflow job for this annotation

GitHub Actions / Lint and test project (18)

Expected indentation of 2 tabs but found 1

Check failure on line 142 in test/it/end-to-end.js

View workflow job for this annotation

GitHub Actions / Lint and test project (latest)

Expected indentation of 2 tabs but found 1

}

Check failure on line 144 in test/it/end-to-end.js

View workflow job for this annotation

GitHub Actions / Lint and test project (18)

Expected indentation of 1 tab but found 0

Check failure on line 144 in test/it/end-to-end.js

View workflow job for this annotation

GitHub Actions / Lint and test project (latest)

Expected indentation of 1 tab but found 0

test(`Stack Analysis json`, async () => {
process.env["EXHORT_DEBUG"]= "true"
process.env["EXHORT_DEV_MODE"]= "true"
process.env["EXHORT_GO_PATH"]= "/tmp/go-test/go/bin/go"
// process.env["RHDA_TOKEN"] = "34JKLDS-4234809-66666666666"
// process.env["RHDA_SOURCE"] = "Zvika Client"
// let result = await index.stackAnalysis("/tmp/rajan-0410/go.mod", false, opts);
let opts = {

Check failure on line 153 in test/it/end-to-end.js

View workflow job for this annotation

GitHub Actions / Lint and test project (18)

'opts' is assigned a value but never used

Check failure on line 153 in test/it/end-to-end.js

View workflow job for this annotation

GitHub Actions / Lint and test project (latest)

'opts' is assigned a value but never used
MATCH_MANIFEST_VERSIONS: 'false',
EXHORT_DEV_MODE: 'true',
// EXHORT_OSS_INDEX_TOKEN: '2bb579b7894f13f180f0ebb591be7c8febbcf699',
EXHORT_OSS_INDEX_USER: 'zgrinber@redhat.com',
EXHORT_GO_MVS_LOGIC_ENABLED: 'true'
}
// process.env["EXHORT_PYTHON_VIRTUAL_ENV"] = "true"
// process.env["EXHORT_PYTHON_INSTALL_BEST_EFFORTS"] = "true"
process.env["MATCH_MANIFEST_VERSIONS"] = "false"
// let pomPath = `/tmp/070324/package.json`
let pomPath = `/home/zgrinber/git/exhort-javascript-api/test/it/test_manifests/pip/requirements.txt`
// let pomPath = `/home/zgrinber/git/tracing-demos-and-examples/tracing-parent/pom.xml`
let providedDataForStack;
providedDataForStack = await index.componentAnalysis("requirements.txt", fs.readFileSync(pomPath).toString(),{},pomPath);

Check failure on line 167 in test/it/end-to-end.js

View workflow job for this annotation

GitHub Actions / Lint and test project (18)

'providedDataForStack' is assigned a value but never used

Check failure on line 167 in test/it/end-to-end.js

View workflow job for this annotation

GitHub Actions / Lint and test project (latest)

'providedDataForStack' is assigned a value but never used
// providedDataForStack = await index.stackAnalysis(pomPath);
// console.log(JSON.stringify(providedDataForStack,null , 4))
// fs.writeFileSync(`/tmp/301123/report.html`,providedDataForStack)

// expect(providedDataForStack.summary.dependencies.scanned).greaterThan(0)
}).timeout(15000);




});

0 comments on commit 9108631

Please sign in to comment.