-
Notifications
You must be signed in to change notification settings - Fork 123
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
New feature: Exempt vulnerabilities for single archives (digests) #319
Merged
Merged
Changes from 3 commits
Commits
Show all changes
36 commits
Select commit
Hold shift + click to select a range
d3c764d
Added new class BugExemption in order to exempt bugs for indiv libraries
henrikplate 150fda5
Moved BugExemption to shared; Added JUnit test
henrikplate 725a4a7
Updated JUnit test; Improved Html report
henrikplate 7f20355
Added license and copyright header to new Java sources
henrikplate 0720a27
Changed exemption format to vulas.report.exempt.<bugId>.<digest>.<sco…
henrikplate ec793f8
Introduced interface IExemption
henrikplate 6bf0033
Modified rest-backend, frontend-app
henrikplate af4263c
Included exempted scopes and bugs in Html report
henrikplate 142f0c7
Updated Json and Xml reports
henrikplate f3ff184
Display bug description and alt. bug description in Html report
henrikplate ae090b9
Added serializaton test for ExemptionScope
henrikplate 06d7ef1
Small correction of the Html report
henrikplate c133fe1
Resolved compile problems that resulted from the rebase on master
henrikplate 92dd29f
Changed bug exemption format to vulas.report.exemptBug.CVE-0000-1111.…
henrikplate f571026
Upated JUnit tests to reflect format change for bug exemptions
henrikplate e9e7a43
Differentiate exemption type during finding export
henrikplate 5949a9b
improved test to get App VulnerableDependencies
serenaponta c7b7124
fix infinite recursion
serenaponta 85de90b
Undo changes of checkbox labels in vuln view (historical and unconfir…
henrikplate fd41e3f
use backend.View
serenaponta ee6a6b1
Merge branch 'master' into exempt-vuln-digest
serenaponta bfe08a4
exemption img renamed
serenaponta 36454ad
added failing test
serenaponta ff1e29f
modify expected value in tests
serenaponta 5af8963
added handling of config keys from previous scans
serenaponta 363033d
fix copy/paste
serenaponta 2d4f66e
New format for bug exemptions, consider package URLs
henrikplate 3eb12b0
Merge branch 'exempt-vuln-digest' of github.com:SAP/vulnerability-ass…
henrikplate bd1e5de
Updated doc
henrikplate 20aed16
Updated exemption-related doc in Html template
henrikplate ddfd24d
Added checks for package URLs (supported types and required elements …
henrikplate 6e280b8
Fixed NPE when reading exemptions from Map; Added option to created A…
henrikplate 5d8d0dd
Added digest info to report console log (to facilitate digest exempti…
henrikplate c5dacf0
modified computation of affected flag for bug w/o cc
serenaponta 57ad6a7
Merge branch 'master' into exempt-vuln-digest
henrikplate d2c9621
Fixed compilation error that has been introduced with the resolution …
henrikplate File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,15 +19,15 @@ | |
*/ | ||
package com.sap.psr.vulas.shared.json.model; | ||
|
||
import java.util.Arrays; | ||
import java.util.Iterator; | ||
import java.util.Map; | ||
|
||
import org.apache.commons.configuration.Configuration; | ||
import org.apache.commons.logging.Log; | ||
import org.apache.commons.logging.LogFactory; | ||
|
||
import com.sap.psr.vulas.shared.util.StringUtil; | ||
import com.github.packageurl.MalformedPackageURLException; | ||
import com.github.packageurl.PackageURL; | ||
|
||
|
||
/** | ||
|
@@ -57,26 +57,26 @@ public class ExemptionBug implements IExemption { | |
private String bugId = null; | ||
|
||
/** The digest of a library or star (*), which means that the exemption applies to all libraries. */ | ||
private String digest = null; | ||
private String library = null; | ||
|
||
private String reason = null; | ||
|
||
/** | ||
* Creates a new exemption, whereby parameters equal to null will be interpreted as star (*). | ||
* | ||
* @param _bug_id | ||
* @param _digest | ||
* @param _library | ||
* @param _reason | ||
*/ | ||
public ExemptionBug(String _bug_id, String _digest, String _reason) { | ||
public ExemptionBug(String _bug_id, String _library, String _reason) { | ||
this.bugId = (_bug_id==null ? ALL : _bug_id); | ||
this.digest = (_digest==null ? ALL : _digest); | ||
this.library = (_library==null ? ALL : _library); | ||
this.reason = _reason; | ||
} | ||
|
||
public String getBugId() { return bugId; } | ||
|
||
public String getDigest() { return digest; } | ||
public String getLibrary() { return library; } | ||
|
||
@Override | ||
public String getReason() { return reason; } | ||
|
@@ -89,17 +89,31 @@ public boolean isExempted(VulnerableDependency _vd) { | |
// Archive | ||
if(is_exempted) { | ||
// All | ||
if(ALL.equals(this.digest)) { ; } | ||
if(ALL.equals(this.library)) { ; } | ||
|
||
// Digest | ||
else if(this.digest.startsWith("dig:")) { | ||
is_exempted = is_exempted && this.digest.substring(4).equals(_vd.getDep().getLib().getDigest()); | ||
// Package URL according to https://github.com/package-url/purl-spec | ||
else if(this.library.startsWith("pkg:") && _vd.getDep().getLib().getLibraryId()!=null) { | ||
try { | ||
final LibraryId libid = _vd.getDep().getLib().getLibraryId(); | ||
final PackageURL purl = new PackageURL(this.library); | ||
if(purl.getName()==null) { | ||
log.error("The package URL [" + this.library + "] does not contain a name"); | ||
} | ||
else { | ||
is_exempted = is_exempted && | ||
(purl.getNamespace()==null || libid.getMvnGroup().equals(purl.getNamespace())) && // No purl.namespace || purl.namespace==libid.mvnGroup | ||
libid.getArtifact().equals(purl.getName()) && | ||
(purl.getVersion()==null || libid.getVersion().equals(purl.getVersion())); // No purl.version || purl.version==libid.version | ||
} | ||
} catch (MalformedPackageURLException e) { | ||
log.error("Invalid package URL [" + this.library + "]: " + e.getMessage()); | ||
is_exempted = false; | ||
} | ||
} | ||
|
||
//TODO: Support purl format to exempt findings: https://github.com/package-url/purl-spec | ||
else if(this.digest.startsWith("pkg:")) { | ||
log.warn("Purl format not yet supported"); | ||
is_exempted = false; | ||
// Digest | ||
else { | ||
is_exempted = is_exempted && this.library.equals(_vd.getDep().getLib().getDigest()); | ||
} | ||
} | ||
|
||
|
@@ -117,17 +131,42 @@ public static ExemptionSet readFromConfiguration(Configuration _cfg) { | |
final ExemptionSet exempts = new ExemptionSet(); | ||
|
||
// New format | ||
Iterator<String> iter = _cfg.subset(CFG_PREFIX).getKeys(); | ||
final Iterator<String> iter = _cfg.getKeys(CFG_PREFIX); | ||
while(iter.hasNext()) { | ||
final String k = iter.next(); | ||
if(!k.equals("")) { | ||
if(k.endsWith("." + "reason")) { | ||
final String[] key_elements = k.split("\\."); | ||
final int l = key_elements.length; | ||
if(l<2) { | ||
log.error("Exemption with key [" + CFG_PREFIX + "." + k + "] has less than 2 elements"); | ||
if(key_elements.length == 5) { | ||
final String vuln = key_elements[3]; | ||
final String reason = _cfg.getString(CFG_PREFIX + "." + vuln + "." + "reason"); | ||
final String[] libs = _cfg.getStringArray(CFG_PREFIX + "." + vuln + "." + "libraries"); | ||
|
||
if(libs==null || libs.length==0) { | ||
exempts.add(new ExemptionBug(vuln, ExemptionBug.ALL, reason)); | ||
} | ||
else { | ||
for(String lib: libs) { | ||
if(lib.startsWith("pkg:")) { | ||
try { | ||
final PackageURL purl = new PackageURL(lib); | ||
if(purl.getName()==null) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is linked to the previous comment, why not requiring that also the namespace is not null? |
||
log.error("The package URL [" + lib + "] does not contain a name"); | ||
continue; | ||
} | ||
exempts.add(new ExemptionBug(vuln, lib, reason)); | ||
} catch(MalformedPackageURLException e) { | ||
log.error("Invalid package URL [" + lib + "]: " + e.getMessage()); | ||
continue; | ||
} | ||
} | ||
else { | ||
exempts.add(new ExemptionBug(vuln, lib, reason)); | ||
} | ||
} | ||
} | ||
} | ||
else { | ||
exempts.add(new ExemptionBug(StringUtil.join(Arrays.copyOfRange(key_elements, 0, l-1), "."), key_elements[l-1], _cfg.getString(CFG_PREFIX + "." + k))); | ||
log.error("Invalid exemption format [" + CFG_PREFIX + "." + k + "]"); | ||
} | ||
} | ||
} | ||
|
@@ -157,14 +196,38 @@ public static ExemptionSet readFromConfiguration(Map<String, String> _map) { | |
|
||
// New format | ||
for(String k: _map.keySet()) { | ||
if(k.startsWith((CFG_PREFIX) + ".")) { | ||
final String[] key_elements = k.substring(CFG_PREFIX.length() + 1).split("\\."); | ||
final int l = key_elements.length; | ||
if(l<2) { | ||
log.error("Exemption with key [" + k + "] has less than 2 elements"); | ||
if(k.startsWith((CFG_PREFIX) + ".") && k.endsWith("." + "reason")) { | ||
final String[] key_elements = k.split("\\."); | ||
if(key_elements.length == 5) { | ||
final String vuln = key_elements[3]; | ||
final String reason = _map.get(CFG_PREFIX + "." + vuln + "." + "reason"); | ||
final String[] libs = _map.get(CFG_PREFIX + "." + vuln + "." + "libraries").split(","); | ||
|
||
if(libs==null || libs.length==0) { | ||
exempts.add(new ExemptionBug(vuln, ExemptionBug.ALL, reason)); | ||
} | ||
else { | ||
for(String lib: libs) { | ||
if(lib.startsWith("pkg:")) { | ||
try { | ||
final PackageURL purl = new PackageURL(lib); | ||
if(purl.getName()==null) { | ||
log.error("The package URL [" + lib + "] does not contain a name"); | ||
continue; | ||
} | ||
exempts.add(new ExemptionBug(vuln, lib, reason)); | ||
} catch(MalformedPackageURLException e) { | ||
log.error("Invalid package URL [" + lib + "]: " + e.getMessage()); | ||
} | ||
} | ||
else { | ||
exempts.add(new ExemptionBug(vuln, lib, reason)); | ||
} | ||
} | ||
} | ||
} | ||
else { | ||
exempts.add(new ExemptionBug(StringUtil.join(Arrays.copyOfRange(key_elements, 0, l-1), "."), key_elements[l-1], _map.get(k))); | ||
log.error("Invalid exemption format: [" + CFG_PREFIX + "." + k + "]"); | ||
} | ||
} | ||
} | ||
|
@@ -204,15 +267,15 @@ public String toString() { | |
} | ||
|
||
public String toShortString() { | ||
return this.bugId + "." + this.digest; | ||
return this.bugId + "." + this.library; | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
final int prime = 31; | ||
int result = 1; | ||
result = prime * result + ((bugId == null) ? 0 : bugId.hashCode()); | ||
result = prime * result + ((digest == null) ? 0 : digest.hashCode()); | ||
result = prime * result + ((library == null) ? 0 : library.hashCode()); | ||
result = prime * result + ((reason == null) ? 0 : reason.hashCode()); | ||
return result; | ||
} | ||
|
@@ -231,10 +294,10 @@ public boolean equals(Object obj) { | |
return false; | ||
} else if (!bugId.equals(other.bugId)) | ||
return false; | ||
if (digest == null) { | ||
if (other.digest != null) | ||
if (library == null) { | ||
if (other.library != null) | ||
return false; | ||
} else if (!digest.equals(other.digest)) | ||
} else if (!library.equals(other.library)) | ||
return false; | ||
if (reason == null) { | ||
if (other.reason != null) | ||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why should we allow exemptions for library ids whose namespace (aka mvn group) is not specified?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Package URLs for Python packages will not have a namespace. Alternatively, we can consider the type, but such if-else conditions would not be nice either. Moreover, I do not know whether the prg. language can be easily determined at this point in time.