Skip to content

Commit 8ba30e4

Browse files
committed
feat(scanoss): Map ScanOSS snippets to the ScanSummary
This commits maps the snippets in a ScanOSS response using the newly-created snippet data model. Please note that the snippet's license in the test data file has been manipulated to be a license not present in the other identifications of this file. This allows to demonstrate that license findings and snippet findings are disjoint in ORT, even if they are returned together by ScanOSS. Signed-off-by: Nicolas Nobelis <[email protected]>
1 parent 73b8617 commit 8ba30e4

File tree

4 files changed

+564
-10
lines changed

4 files changed

+564
-10
lines changed

scanner/src/main/kotlin/scanners/scanoss/ScanOssResultParser.kt

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,17 @@ import java.io.File
2323
import java.time.Instant
2424

2525
import org.ossreviewtoolkit.clients.scanoss.FullScanResponse
26+
import org.ossreviewtoolkit.clients.scanoss.model.IdentificationType
2627
import org.ossreviewtoolkit.clients.scanoss.model.ScanResponse
2728
import org.ossreviewtoolkit.model.CopyrightFinding
2829
import org.ossreviewtoolkit.model.LicenseFinding
30+
import org.ossreviewtoolkit.model.RepositoryProvenance
2931
import org.ossreviewtoolkit.model.ScanSummary
3032
import org.ossreviewtoolkit.model.TextLocation
33+
import org.ossreviewtoolkit.model.VcsInfo
34+
import org.ossreviewtoolkit.model.VcsType
35+
import org.ossreviewtoolkit.model.utils.Snippet
36+
import org.ossreviewtoolkit.model.utils.SnippetFinding
3137
import org.ossreviewtoolkit.utils.spdx.SpdxConstants
3238
import org.ossreviewtoolkit.utils.spdx.SpdxExpression
3339
import org.ossreviewtoolkit.utils.spdx.calculatePackageVerificationCode
@@ -64,11 +70,25 @@ internal fun generateSummary(
6470
): ScanSummary {
6571
val licenseFindings = mutableListOf<LicenseFinding>()
6672
val copyrightFindings = mutableListOf<CopyrightFinding>()
73+
val snippetFindings = mutableSetOf<SnippetFinding>()
6774

6875
result.forEach { (_, scanResponses) ->
6976
scanResponses.forEach { scanResponse ->
70-
licenseFindings += getLicenseFindings(scanResponse, detectedLicenseMapping)
71-
copyrightFindings += getCopyrightFindings(scanResponse)
77+
if (scanResponse.id == IdentificationType.FILE) {
78+
licenseFindings += getLicenseFindings(scanResponse, detectedLicenseMapping)
79+
copyrightFindings += getCopyrightFindings(scanResponse)
80+
}
81+
82+
if (scanResponse.id == IdentificationType.SNIPPET) {
83+
val file = requireNotNull(scanResponse.file)
84+
val lines = requireNotNull(scanResponse.lines)
85+
val sourceLocation = convertLines(file, lines)
86+
val snippets = getSnippets(scanResponse)
87+
88+
snippets.forEach {
89+
snippetFindings += SnippetFinding(sourceLocation, it)
90+
}
91+
}
7292
}
7393
}
7494

@@ -78,6 +98,7 @@ internal fun generateSummary(
7898
packageVerificationCode = verificationCode,
7999
licenseFindings = licenseFindings.toSortedSet(),
80100
copyrightFindings = copyrightFindings.toSortedSet(),
101+
snippetFindings = snippetFindings.toSortedSet(),
81102
issues = emptyList()
82103
)
83104
}
@@ -131,3 +152,46 @@ private fun getCopyrightFindings(scanResponse: ScanResponse): List<CopyrightFind
131152
)
132153
}
133154
}
155+
156+
/**
157+
* Get the snippet findings from the given [scanResponse]. If a snippet returned by ScanOSS contains several Purls,
158+
* several snippets are created in ORT each containing a single Purl.
159+
*/
160+
private fun getSnippets(scanResponse: ScanResponse): Set<Snippet> {
161+
val matched = requireNotNull(scanResponse.matched)
162+
val fileUrl = requireNotNull(scanResponse.fileUrl)
163+
val ossLines = requireNotNull(scanResponse.ossLines)
164+
val url = requireNotNull(scanResponse.url)
165+
val purls = requireNotNull(scanResponse.purl)
166+
167+
val licenses = scanResponse.licenses.map { license ->
168+
SpdxExpression.parse(license.name)
169+
}.toSet()
170+
171+
val score = matched.substringBeforeLast("%").toFloat()
172+
val snippetLocation = convertLines(fileUrl, ossLines)
173+
// TODO: No resolved revision is available. Should a ArtifactProvenance be created instead ?
174+
val snippetProvenance = RepositoryProvenance(VcsInfo(VcsType.UNKNOWN, url, ""), ".")
175+
176+
return purls.map {
177+
Snippet(
178+
score,
179+
snippetLocation,
180+
snippetProvenance,
181+
it,
182+
licenses.distinct().reduce(SpdxExpression::and).sorted()
183+
)
184+
}.toSortedSet()
185+
}
186+
187+
/**
188+
* Split a [lineRange] returned by ScanOSS such as 1-321 into a [TextLocation] for the given [file].
189+
*/
190+
private fun convertLines(file: String, lineRange: String): TextLocation {
191+
val splitLines = lineRange.split("-")
192+
return if (splitLines.size == 2) {
193+
TextLocation(file, splitLines.first().toInt(), splitLines.last().toInt())
194+
} else {
195+
TextLocation(file, splitLines.first().toInt())
196+
}
197+
}

0 commit comments

Comments
 (0)