Skip to content
Open
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
17 changes: 17 additions & 0 deletions model/src/main/kotlin/Provenance.kt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize
import com.fasterxml.jackson.databind.deser.std.StdDeserializer
import com.fasterxml.jackson.module.kotlin.treeToValue

import java.io.File

/**
* Provenance information about the origin of source code.
*/
Expand All @@ -45,6 +47,8 @@ sealed interface KnownProvenance : Provenance

sealed interface RemoteProvenance : KnownProvenance

sealed interface LocalProvenance : KnownProvenance

/**
* Provenance information for a source artifact.
*/
Expand Down Expand Up @@ -83,6 +87,19 @@ data class RepositoryProvenance(
override fun matches(pkg: Package): Boolean = vcsInfo == pkg.vcsProcessed
}

/**
* Provenance information for a local directory path.
*/
data class DirectoryProvenance(
val canonicalPath: File
) : LocalProvenance {
/**
* Return false for any [pkg] as a [Package] by definition is coming from a remote, and is not stored in a local
* directory path (which would be a [Project]).
*/
override fun matches(pkg: Package): Boolean = false
}

/**
* A custom deserializer for polymorphic deserialization of [Provenance] without requiring type information.
*/
Expand Down
2 changes: 1 addition & 1 deletion model/src/main/kotlin/ProvenanceResolutionResult.kt
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ data class ProvenanceResolutionResult(
* The resolved provenance of the package. Can only be null if a [packageProvenanceResolutionIssue] occurred.
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
val packageProvenance: KnownProvenance? = null,
val packageProvenance: RemoteProvenance? = null,

/**
* The (recursive) sub-repositories of [packageProvenance]. The map can only be empty if a
Expand Down
2 changes: 2 additions & 0 deletions model/src/main/kotlin/utils/FileProvenanceFileStorage.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import java.io.InputStream
import org.apache.logging.log4j.kotlin.logger

import org.ossreviewtoolkit.model.ArtifactProvenance
import org.ossreviewtoolkit.model.DirectoryProvenance
import org.ossreviewtoolkit.model.HashAlgorithm
import org.ossreviewtoolkit.model.KnownProvenance
import org.ossreviewtoolkit.model.RepositoryProvenance
Expand Down Expand Up @@ -81,6 +82,7 @@ private fun KnownProvenance.hash(): String {
val key = when (this) {
is ArtifactProvenance -> "${sourceArtifact.url}${sourceArtifact.hash.value}"
is RepositoryProvenance -> "${vcsInfo.type}${vcsInfo.url}$resolvedRevision"
is DirectoryProvenance -> "$canonicalPath"
}

return HashAlgorithm.SHA1.calculate(key.toByteArray())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import org.jetbrains.exposed.sql.insert
import org.jetbrains.exposed.sql.selectAll

import org.ossreviewtoolkit.model.ArtifactProvenance
import org.ossreviewtoolkit.model.DirectoryProvenance
import org.ossreviewtoolkit.model.KnownProvenance
import org.ossreviewtoolkit.model.RepositoryProvenance
import org.ossreviewtoolkit.model.utils.DatabaseUtils.checkDatabaseEncoding
Expand Down Expand Up @@ -121,4 +122,5 @@ private fun KnownProvenance.storageKey(): String =
is ArtifactProvenance -> "source-artifact|${sourceArtifact.url}|${sourceArtifact.hash}"
// The trailing "|" is kept for backward compatibility because there used to be an additional parameter.
is RepositoryProvenance -> "vcs|${vcsInfo.type}|${vcsInfo.url}|$resolvedRevision|"
is DirectoryProvenance -> "directory|$canonicalPath"
}
7 changes: 6 additions & 1 deletion model/src/main/kotlin/utils/PurlExtensions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import org.ossreviewtoolkit.model.Identifier
import org.ossreviewtoolkit.model.Package
import org.ossreviewtoolkit.model.Provenance
import org.ossreviewtoolkit.model.RemoteArtifact
import org.ossreviewtoolkit.model.RemoteProvenance
import org.ossreviewtoolkit.model.RepositoryProvenance
import org.ossreviewtoolkit.model.UnknownProvenance
import org.ossreviewtoolkit.model.VcsInfo
Expand Down Expand Up @@ -101,7 +102,11 @@ fun Provenance.toPurlExtras(): PurlExtras =
)
}

is UnknownProvenance -> PurlExtras()
/**
* Purls refer to packages that have been published and thus always have a remove provenance. So just return
* empty extras in all other cases.
*/
!is RemoteProvenance -> PurlExtras()
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import io.kotest.core.listeners.TestListener
import io.kotest.core.spec.style.WordSpec
import io.kotest.matchers.shouldBe

import org.ossreviewtoolkit.model.KnownProvenance
import org.ossreviewtoolkit.model.RemoteProvenance
import org.ossreviewtoolkit.model.RepositoryProvenance
import org.ossreviewtoolkit.model.VcsInfo
import org.ossreviewtoolkit.model.VcsType
Expand Down Expand Up @@ -78,6 +78,6 @@ private fun createRepositoryProvenance(
) = RepositoryProvenance(vcsInfo, resolvedRevision)

private fun createNestedProvenance(
root: KnownProvenance,
root: RemoteProvenance,
subRepositories: Map<String, RepositoryProvenance> = emptyMap()
) = NestedProvenance(root, subRepositories)
23 changes: 12 additions & 11 deletions scanner/src/main/kotlin/ScanController.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import org.ossreviewtoolkit.model.Issue
import org.ossreviewtoolkit.model.KnownProvenance
import org.ossreviewtoolkit.model.Package
import org.ossreviewtoolkit.model.Provenance
import org.ossreviewtoolkit.model.RemoteProvenance
import org.ossreviewtoolkit.model.RepositoryProvenance
import org.ossreviewtoolkit.model.ScanResult
import org.ossreviewtoolkit.model.ScanSummary
Expand Down Expand Up @@ -73,19 +74,19 @@ internal class ScanController(
/**
* A map of [KnownProvenance]s to their resolved [NestedProvenance]s.
*/
private val nestedProvenances = mutableMapOf<KnownProvenance, NestedProvenance>()
private val nestedProvenances = mutableMapOf<RemoteProvenance, NestedProvenance>()

/**
* A map of package [Identifier]s to their resolved [KnownProvenance]s. These provenances are used to filter the
* scan results for a package based on the VCS path.
*/
private val packageProvenances = mutableMapOf<Identifier, KnownProvenance>()
private val packageProvenances = mutableMapOf<Identifier, RemoteProvenance>()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is changed, the docs need to be adjusted as well.

Copy link
Member

@sschuberth sschuberth Mar 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change requires some careful thinking: We actually do want to be able to scan projects with DirectoryProvenance in the end, at least in the case when analyzer and scanner are run on the same machine. So is it really correct to limit us to RemoteProvenance here?

Copy link
Contributor Author

@pepper-jk pepper-jk Mar 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are probably multiple places, where the limit to RemoteProvenance is not correct in order to handle the DirectoryProvenance, once it is fully implemented.

But right now, while the class is dormant, it is either this or cast the arguments. Otherwise we would have to handle it everywhere from the get go as well.

side note: as this attribute is named packageProvenances, we probably need to address the shift from packages to projects as (primary) input for the scanner at some point, since you repeatedly stated before that a DirectoryProvenace can not be a Package due to lack of a remote.


/**
* A map of package [Identifier]s to their resolved [KnownProvenance]s with the VCS path removed. These provenances
* are used during scanning to make sure that always the full repositories are scanned.
*/
private val packageProvenancesWithoutVcsPath = mutableMapOf<Identifier, KnownProvenance>()
private val packageProvenancesWithoutVcsPath = mutableMapOf<Identifier, RemoteProvenance>()

/**
* The [ScanResult]s for each [KnownProvenance] and [ScannerWrapper].
Expand Down Expand Up @@ -130,7 +131,7 @@ internal class ScanController(
/**
* Set the [provenance] for the package denoted by [id], overwriting any existing values.
*/
fun putPackageProvenance(id: Identifier, provenance: KnownProvenance) {
fun putPackageProvenance(id: Identifier, provenance: RemoteProvenance) {
packageProvenances[id] = provenance
packageProvenancesWithoutVcsPath[id] = when (provenance) {
is RepositoryProvenance -> provenance.copy(vcsInfo = provenance.vcsInfo.copy(path = ""))
Expand All @@ -142,7 +143,7 @@ internal class ScanController(
* Set the [nestedProvenance] corresponding to the given [package provenance][root], overwriting any existing
* values.
*/
fun putNestedProvenance(root: KnownProvenance, nestedProvenance: NestedProvenance) {
fun putNestedProvenance(root: RemoteProvenance, nestedProvenance: NestedProvenance) {
nestedProvenances[root] = nestedProvenance
}

Expand All @@ -165,7 +166,7 @@ internal class ScanController(
/**
* Return all [KnownProvenance]s contained in [nestedProvenances].
*/
fun getAllProvenances(): Set<KnownProvenance> =
fun getAllProvenances(): Set<RemoteProvenance> =
nestedProvenances.values.flatMapTo(mutableSetOf()) { it.allProvenances }

/**
Expand All @@ -177,7 +178,7 @@ internal class ScanController(
/**
* Return all provenances including sub-repositories associated with the identifiers of the packages they belong to.
*/
fun getIdsByProvenance(): Map<KnownProvenance, Set<Identifier>> =
fun getIdsByProvenance(): Map<RemoteProvenance, Set<Identifier>> =
buildMap<_, MutableSet<Identifier>> {
getNestedProvenancesByPackage().forEach { (pkg, nestedProvenance) ->
nestedProvenance.allProvenances.forEach { provenance ->
Expand Down Expand Up @@ -244,8 +245,8 @@ internal class ScanController(
* 'components/conanfile.txt'. This is because scanner interfaces receive packages as input, and this aims at
* providing a deterministic ordering when choosing a reference package for packages with the same provenance.
*/
fun getPackagesConsolidatedByProvenance(): Map<KnownProvenance, List<Package>> {
val packagesByProvenance = mutableMapOf<KnownProvenance, MutableSet<Package>>()
fun getPackagesConsolidatedByProvenance(): Map<RemoteProvenance, List<Package>> {
val packagesByProvenance = mutableMapOf<RemoteProvenance, MutableSet<Package>>()
val comparator = compareBy<Package, String>(PATH_STRING_COMPARATOR) { it.id.name }.thenBy { it.id }

packages.forEach { pkg ->
Expand All @@ -267,7 +268,7 @@ internal class ScanController(
fun getPackagesForProvenanceWithoutVcsPath(provenance: KnownProvenance): Set<Identifier> =
packageProvenancesWithoutVcsPath.filter { (_, packageProvenance) -> packageProvenance == provenance }.keys

fun getPackageProvenance(id: Identifier): KnownProvenance? = packageProvenances[id]
fun getPackageProvenance(id: Identifier): RemoteProvenance? = packageProvenances[id]

/**
* Return the package provenanceResolutionIssue associated with the given [id].
Expand All @@ -277,7 +278,7 @@ internal class ScanController(
/**
* Return all [KnownProvenance]s for the [packages] with the VCS path removed.
*/
fun getPackageProvenancesWithoutVcsPath(): Set<KnownProvenance> = packageProvenancesWithoutVcsPath.values.toSet()
fun getPackageProvenancesWithoutVcsPath(): Set<RemoteProvenance> = packageProvenancesWithoutVcsPath.values.toSet()

/**
* Return all [PackageScannerWrapper]s.
Expand Down
3 changes: 2 additions & 1 deletion scanner/src/main/kotlin/Scanner.kt
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import org.ossreviewtoolkit.model.OrtResult
import org.ossreviewtoolkit.model.Package
import org.ossreviewtoolkit.model.PackageType
import org.ossreviewtoolkit.model.ProvenanceResolutionResult
import org.ossreviewtoolkit.model.RemoteProvenance
import org.ossreviewtoolkit.model.ScanResult
import org.ossreviewtoolkit.model.ScannerRun
import org.ossreviewtoolkit.model.TextLocation
Expand Down Expand Up @@ -585,7 +586,7 @@ class Scanner(
}

private fun scanPath(
provenance: KnownProvenance,
provenance: RemoteProvenance,
scanners: List<PathScannerWrapper>,
context: ScanContext,
controller: ScanController
Expand Down
5 changes: 3 additions & 2 deletions scanner/src/main/kotlin/provenance/NestedProvenance.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore

import org.ossreviewtoolkit.model.ArtifactProvenance
import org.ossreviewtoolkit.model.KnownProvenance
import org.ossreviewtoolkit.model.RemoteProvenance
import org.ossreviewtoolkit.model.RepositoryProvenance

/**
Expand All @@ -32,7 +33,7 @@ data class NestedProvenance(
/**
* The root provenance that contains the [nested provenances][subRepositories].
*/
val root: KnownProvenance,
val root: RemoteProvenance,

/**
* If [root] is a [RepositoryProvenance] this map contains all paths which contain nested repositories associated
Expand All @@ -45,7 +46,7 @@ data class NestedProvenance(
* The set of all contained [KnownProvenance]s.
*/
@JsonIgnore
val allProvenances: Set<KnownProvenance> =
val allProvenances: Set<RemoteProvenance> =
buildSet {
add(root)
addAll(subRepositories.values)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ import org.apache.logging.log4j.kotlin.logger

import org.ossreviewtoolkit.downloader.WorkingTreeCache
import org.ossreviewtoolkit.model.ArtifactProvenance
import org.ossreviewtoolkit.model.KnownProvenance
import org.ossreviewtoolkit.model.Provenance
import org.ossreviewtoolkit.model.RemoteProvenance
import org.ossreviewtoolkit.model.RepositoryProvenance

/**
Expand All @@ -36,7 +36,7 @@ interface NestedProvenanceResolver {
* [NestedProvenance] always contains only the provided [ArtifactProvenance]. For a [RepositoryProvenance] the
* resolver looks for nested repositories, for example Git submodules or Mercurial subrepositories.
*/
suspend fun resolveNestedProvenance(provenance: KnownProvenance): NestedProvenance
suspend fun resolveNestedProvenance(provenance: RemoteProvenance): NestedProvenance
}

/**
Expand All @@ -46,7 +46,7 @@ class DefaultNestedProvenanceResolver(
private val storage: NestedProvenanceStorage,
private val workingTreeCache: WorkingTreeCache
) : NestedProvenanceResolver {
override suspend fun resolveNestedProvenance(provenance: KnownProvenance): NestedProvenance {
override suspend fun resolveNestedProvenance(provenance: RemoteProvenance): NestedProvenance {
return when (provenance) {
is ArtifactProvenance -> NestedProvenance(root = provenance, subRepositories = emptyMap())
is RepositoryProvenance -> resolveNestedRepository(provenance)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ package org.ossreviewtoolkit.scanner.provenance

import org.ossreviewtoolkit.model.KnownProvenance
import org.ossreviewtoolkit.model.OrtResult
import org.ossreviewtoolkit.model.RemoteProvenance
import org.ossreviewtoolkit.model.RepositoryProvenance
import org.ossreviewtoolkit.model.ScanResult
import org.ossreviewtoolkit.model.ScanSummary
Expand All @@ -38,7 +39,7 @@ data class NestedProvenanceScanResult(
/**
* A map of [KnownProvenance]s from [nestedProvenance] associated with lists of [ScanResult]s.
*/
val scanResults: Map<KnownProvenance, List<ScanResult>>
val scanResults: Map<RemoteProvenance, List<ScanResult>>
) {
/**
* Return true if [scanResults] contains at least one scan result for each of the [KnownProvenance]s contained in
Expand Down Expand Up @@ -107,7 +108,7 @@ data class NestedProvenanceScanResult(
}
}

fun KnownProvenance.withVcsPath() =
fun RemoteProvenance.withVcsPath() =
when (this) {
is RepositoryProvenance -> {
val pathWithinProvenance = pathsWithinProvenances.getValue(this)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@ import org.apache.logging.log4j.kotlin.logger

import org.ossreviewtoolkit.downloader.WorkingTreeCache
import org.ossreviewtoolkit.model.ArtifactProvenance
import org.ossreviewtoolkit.model.KnownProvenance
import org.ossreviewtoolkit.model.Package
import org.ossreviewtoolkit.model.Provenance
import org.ossreviewtoolkit.model.RemoteArtifact
import org.ossreviewtoolkit.model.RemoteProvenance
import org.ossreviewtoolkit.model.RepositoryProvenance
import org.ossreviewtoolkit.model.SourceCodeOrigin
import org.ossreviewtoolkit.model.VcsInfo
Expand All @@ -54,7 +54,7 @@ interface PackageProvenanceResolver {
*
* Throws an [IOException] if the provenance cannot be resolved.
*/
suspend fun resolveProvenance(pkg: Package, defaultSourceCodeOrigins: List<SourceCodeOrigin>): KnownProvenance
suspend fun resolveProvenance(pkg: Package, defaultSourceCodeOrigins: List<SourceCodeOrigin>): RemoteProvenance
}

/**
Expand All @@ -74,7 +74,7 @@ class DefaultPackageProvenanceResolver(
override suspend fun resolveProvenance(
pkg: Package,
defaultSourceCodeOrigins: List<SourceCodeOrigin>
): KnownProvenance {
): RemoteProvenance {
val errors = mutableMapOf<SourceCodeOrigin, Throwable>()
val sourceCodeOrigins = pkg.sourceCodeOrigins ?: defaultSourceCodeOrigins

Expand Down
6 changes: 3 additions & 3 deletions scanner/src/main/kotlin/provenance/ProvenanceDownloader.kt
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ import org.ossreviewtoolkit.downloader.DownloadException
import org.ossreviewtoolkit.downloader.Downloader
import org.ossreviewtoolkit.downloader.WorkingTreeCache
import org.ossreviewtoolkit.model.ArtifactProvenance
import org.ossreviewtoolkit.model.KnownProvenance
import org.ossreviewtoolkit.model.Package
import org.ossreviewtoolkit.model.RemoteProvenance
import org.ossreviewtoolkit.model.RepositoryProvenance
import org.ossreviewtoolkit.model.config.DownloaderConfiguration
import org.ossreviewtoolkit.utils.common.safeDeleteRecursively
Expand All @@ -51,7 +51,7 @@ fun interface ProvenanceDownloader {
*
* Throws a [DownloadException] if the download fails.
*/
fun download(provenance: KnownProvenance): File
fun download(provenance: RemoteProvenance): File

/**
* Download the source code specified by the provided [nestedProvenance] incl. sub-repositories and return the path
Expand Down Expand Up @@ -86,7 +86,7 @@ class DefaultProvenanceDownloader(
) : ProvenanceDownloader {
private val downloader = Downloader(config)

override fun download(provenance: KnownProvenance): File {
override fun download(provenance: RemoteProvenance): File {
val downloadDir = createOrtTempDir()

when (provenance) {
Expand Down
Loading
Loading