Skip to content

Commit

Permalink
fix(vulnerable-code): Fix search for Go package vulnerabilities
Browse files Browse the repository at this point in the history
For Go packages, both the namespace and name may contain path
segments separated by a "/" character. The purl specification
requires these "/" characters to be percent-encoded in the
namespace and name components of a purl.

The VulnerableCode bulk-search API is unable to handle these
percent-encoded "/" characters, resulting in no vulnerability
records being returned.

This bugfix decodes any percent-encoded "/" characters just
before making the VulnerableCode query to ensure proper
functionality.

Fixes oss-review-toolkit#9298

Signed-off-by: Wolfgang Klenk <[email protected]>
  • Loading branch information
wkl3nk committed Oct 17, 2024
1 parent 03b4ed9 commit df5821e
Showing 1 changed file with 18 additions and 6 deletions.
24 changes: 18 additions & 6 deletions plugins/advisors/vulnerable-code/src/main/kotlin/VulnerableCode.kt
Original file line number Diff line number Diff line change
Expand Up @@ -93,23 +93,35 @@ class VulnerableCode(override val descriptor: PluginDescriptor, config: Vulnerab
override suspend fun retrievePackageFindings(packages: Set<Package>): Map<Package, AdvisorResult> {
val startTime = Instant.now()

val purls = packages.mapNotNull { pkg -> pkg.purl.ifEmpty { null } }
val chunks = purls.chunked(BULK_REQUEST_SIZE)
// Workaround for #9298
// Create a list of pairs, where the first element is the purl without percent encoding
// and the second element is the original purl (with percent encoding).
val purlPairs = packages
.mapNotNull { pkg -> pkg.purl.ifEmpty { null } }
.map { it.replace("%2F", "/", ignoreCase = true) to it }

purlPairs.forEach(logger::info)

val chunks = purlPairs.chunked(BULK_REQUEST_SIZE)

val allVulnerabilities = mutableMapOf<String, List<VulnerableCodeService.Vulnerability>>()
val issues = mutableListOf<Issue>()

chunks.forEachIndexed { index, chunk ->
runCatching {
val chunkVulnerabilities = service.getPackageVulnerabilities(PackagesWrapper(chunk)).filter {
// Use list of purls without percent encoding for the request to VulnerableCode
val purlsWithoutPercentEncoding = chunk.map { it.first }
service.getPackageVulnerabilities(PackagesWrapper(purlsWithoutPercentEncoding)).filter {
it.affectedByVulnerabilities.isNotEmpty()
}.map {
val purlWithPercentEncoding = chunk.first { purlPair -> purlPair.first == it.purl }.second
allVulnerabilities += purlWithPercentEncoding to it.affectedByVulnerabilities
}

allVulnerabilities += chunkVulnerabilities.associate { it.purl to it.affectedByVulnerabilities }
}.onFailure {
// Create dummy entries for all packages in the chunk as the current data model does not allow to return
// issues that are not associated to any package.
allVulnerabilities += chunk.associateWith { emptyList() }
val allOriginalPurls = chunk.map { purlPair -> purlPair.second }
allVulnerabilities += allOriginalPurls.associateWith { emptyList() }

issues += Issue(source = descriptor.displayName, message = it.collectMessages())

Expand Down

0 comments on commit df5821e

Please sign in to comment.