Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add manifest content to sbom' metadata #142

Merged
merged 1 commit into from
Jun 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/analysis.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
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

export default { requestComponent, requestStack, validateToken }

Expand All @@ -17,7 +19,10 @@
* @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["source-manifest"]= ""
opts[rhdaOperationTypeHeader.toUpperCase().replaceAll("-","_")] = "stack-analysis"
let startTime = new Date()
let EndTime
Expand Down Expand Up @@ -69,7 +74,9 @@
* @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 @@ -2,7 +2,7 @@
import { execSync } from "node:child_process"
import fs from 'node:fs'
import os from "node:os";
import {EOL} from "os";

Check warning on line 5 in src/providers/golang_gomodules.js

View workflow job for this annotation

GitHub Actions / Lint and test project (18)

Imports should be sorted alphabetically

Check warning on line 5 in src/providers/golang_gomodules.js

View workflow job for this annotation

GitHub Actions / Lint and test project (latest)

Imports should be sorted alphabetically
import {getCustom, getCustomPath} from "../tools.js";
import path from 'node:path'
import Sbom from '../sbom.js'
Expand Down Expand Up @@ -332,7 +332,7 @@
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
Loading