Skip to content

Commit

Permalink
model: Introduce a new copyright holder field to data model
Browse files Browse the repository at this point in the history
In German law, the author and the copyright holder can be two separate
legal entities and therefore also need to be treated separately.

Introduce a new copyright holder field that is now the primary source
for copyright holder information. Authors are still only used as
copyright holders if the `addAuthorsToCopyrights` option is enabled.

For now, all package manager implementations set empty copyright
holders. Filling the copyright holder field is left as an exercise for
future actions. Right now, the only way to add copyright holders is via
curations.

This change resolves #4519.

Signed-off-by: Rainer Bieniek <[email protected]>
Signed-off-by: Sebastian Schuberth <[email protected]>
  • Loading branch information
porsche-rbieniek authored and sschuberth committed Aug 24, 2022
1 parent 65c1565 commit 73cf1b3
Show file tree
Hide file tree
Showing 33 changed files with 174 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ class SpdxDocumentFileFunTest : WordSpec({
cpe = "cpe:2.3:a:http:curl:7.70.0:*:*:*:*:*:*:*",
definitionFilePath = vcsDir.getPathToRoot(curlPackageFile),
authors = sortedSetOf("Daniel Stenberg ([email protected])"),
copyrightHolders = sortedSetOf(),
declaredLicenses = sortedSetOf("curl"),
vcs = VcsInfo(
type = VcsType.GIT,
Expand All @@ -125,6 +126,7 @@ class SpdxDocumentFileFunTest : WordSpec({
cpe = "cpe:2.3:a:a-name:openssl:1.1.1g:*:*:*:*:*:*:*",
definitionFilePath = vcsDir.getPathToRoot(opensslPackageFile),
authors = sortedSetOf("OpenSSL Development Team"),
copyrightHolders = sortedSetOf(),
declaredLicenses = sortedSetOf("Apache-2.0"),
vcs = VcsInfo(
type = VcsType.GIT,
Expand All @@ -146,6 +148,7 @@ class SpdxDocumentFileFunTest : WordSpec({
cpe = "cpe:/a:compress:zlib:1.2.11:::en-us",
definitionFilePath = vcsDir.getPathToRoot(zlibPackageFile),
authors = sortedSetOf("Jean-loup Gailly", "Mark Adler"),
copyrightHolders = sortedSetOf(),
declaredLicenses = sortedSetOf("Zlib"),
vcs = VcsInfo(
type = VcsType.GIT,
Expand Down
2 changes: 2 additions & 0 deletions analyzer/src/main/kotlin/managers/Bower.kt
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ class Bower(
Package(
id = parsePackageId(node),
authors = parseAuthors(node),
copyrightHolders = sortedSetOf(),
declaredLicenses = parseDeclaredLicenses(node),
description = node["pkgMeta"]["description"].textValueOrEmpty(),
homepageUrl = node["pkgMeta"]["homepage"].textValueOrEmpty(),
Expand Down Expand Up @@ -252,6 +253,7 @@ class Bower(
id = projectPackage.id,
definitionFilePath = VersionControlSystem.getPathInfo(definitionFile).path,
authors = projectPackage.authors,
copyrightHolders = sortedSetOf(),
declaredLicenses = projectPackage.declaredLicenses,
vcs = projectPackage.vcs,
vcsProcessed = processProjectVcs(workingDir, projectPackage.vcs, projectPackage.homepageUrl),
Expand Down
2 changes: 2 additions & 0 deletions analyzer/src/main/kotlin/managers/Bundler.kt
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ class Bundler(
id = projectId,
definitionFilePath = VersionControlSystem.getPathInfo(definitionFile).path,
authors = authors,
copyrightHolders = sortedSetOf(),
declaredLicenses = declaredLicenses.toSortedSet(),
vcs = VcsInfo.EMPTY,
vcsProcessed = processProjectVcs(workingDir, VcsInfo.EMPTY, homepageUrl),
Expand Down Expand Up @@ -281,6 +282,7 @@ class Bundler(
return Package(
id = gemId,
authors = gemSpec.authors,
copyrightHolders = sortedSetOf(),
declaredLicenses = gemSpec.declaredLicenses,
description = gemSpec.description,
homepageUrl = gemSpec.homepageUrl,
Expand Down
2 changes: 2 additions & 0 deletions analyzer/src/main/kotlin/managers/Cargo.kt
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ class Cargo(
id = projectPkg.id,
definitionFilePath = VersionControlSystem.getPathInfo(definitionFile).path,
authors = authors,
copyrightHolders = sortedSetOf(),
declaredLicenses = projectPkg.declaredLicenses,
declaredLicensesProcessed = processDeclaredLicenses(projectPkg.declaredLicenses),
vcs = projectPkg.vcs,
Expand Down Expand Up @@ -275,6 +276,7 @@ private fun parsePackage(node: JsonNode, hashes: Map<String, String>): Package {
return Package(
id = parsePackageId(node),
authors = parseAuthors(node["authors"]),
copyrightHolders = sortedSetOf(),
declaredLicenses = declaredLicenses,
declaredLicensesProcessed = declaredLicensesProcessed,
description = node["description"].textValueOrEmpty(),
Expand Down
4 changes: 4 additions & 0 deletions analyzer/src/main/kotlin/managers/Carthage.kt
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ class Carthage(
),
definitionFilePath = VersionControlSystem.getPathInfo(definitionFile).path,
authors = sortedSetOf(),
copyrightHolders = sortedSetOf(),
declaredLicenses = sortedSetOf(),
vcs = VcsInfo.EMPTY,
vcsProcessed = processProjectVcs(workingDir, VcsInfo.EMPTY),
Expand Down Expand Up @@ -190,6 +191,7 @@ class Carthage(
version = revision
),
authors = sortedSetOf(),
copyrightHolders = sortedSetOf(),
declaredLicenses = sortedSetOf(),
description = "",
homepageUrl = projectUrl.removeSuffix(".git"),
Expand All @@ -214,6 +216,7 @@ class Carthage(
version = revision
),
authors = sortedSetOf(),
copyrightHolders = sortedSetOf(),
declaredLicenses = sortedSetOf(),
description = "",
homepageUrl = "",
Expand All @@ -232,6 +235,7 @@ class Carthage(
version = revision
),
authors = sortedSetOf(),
copyrightHolders = sortedSetOf(),
declaredLicenses = sortedSetOf(),
description = "",
homepageUrl = "",
Expand Down
2 changes: 2 additions & 0 deletions analyzer/src/main/kotlin/managers/CocoaPods.kt
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ class CocoaPods(
),
definitionFilePath = VersionControlSystem.getPathInfo(definitionFile).path,
authors = sortedSetOf(),
copyrightHolders = sortedSetOf(),
declaredLicenses = sortedSetOf(),
vcs = VcsInfo.EMPTY,
vcsProcessed = processProjectVcs(workingDir),
Expand Down Expand Up @@ -189,6 +190,7 @@ class CocoaPods(
return Package(
id = id,
authors = sortedSetOf(),
copyrightHolders = sortedSetOf(),
declaredLicenses = podspec.license.takeUnless { it.isEmpty() }?.let { sortedSetOf(it) } ?: sortedSetOf(),
description = podspec.summary,
homepageUrl = podspec.homepage,
Expand Down
2 changes: 2 additions & 0 deletions analyzer/src/main/kotlin/managers/Composer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ class Composer(
),
definitionFilePath = VersionControlSystem.getPathInfo(definitionFile).path,
authors = parseAuthors(json),
copyrightHolders = sortedSetOf(),
declaredLicenses = parseDeclaredLicenses(json),
vcs = vcs,
vcsProcessed = processProjectVcs(definitionFile.parentFile, vcs, homepageUrl),
Expand Down Expand Up @@ -268,6 +269,7 @@ class Composer(
version = version
),
authors = parseAuthors(pkgInfo),
copyrightHolders = sortedSetOf(),
declaredLicenses = parseDeclaredLicenses(pkgInfo),
description = pkgInfo["description"].textValueOrEmpty(),
homepageUrl = homepageUrl,
Expand Down
4 changes: 4 additions & 0 deletions analyzer/src/main/kotlin/managers/Conan.kt
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ class Conan(
id = projectPackage.id,
definitionFilePath = VersionControlSystem.getPathInfo(definitionFile).path,
authors = projectPackage.authors,
copyrightHolders = sortedSetOf(),
declaredLicenses = projectPackage.declaredLicenses,
vcs = projectPackage.vcs,
vcsProcessed = processProjectVcs(
Expand Down Expand Up @@ -290,6 +291,7 @@ class Conan(
return Package(
id = id,
authors = parseAuthors(node),
copyrightHolders = sortedSetOf(),
declaredLicenses = parseDeclaredLicenses(node),
description = parsePackageField(node, workingDir, "description"),
homepageUrl = homepageUrl,
Expand Down Expand Up @@ -429,6 +431,7 @@ class Conan(
version = inspectField(definitionFile.name, workingDir, "version")
),
authors = parseAuthors(node),
copyrightHolders = sortedSetOf(),
declaredLicenses = parseDeclaredLicenses(node),
description = inspectField(definitionFile.name, workingDir, "description"),
homepageUrl = node["homepage"].textValueOrEmpty(),
Expand All @@ -449,6 +452,7 @@ class Conan(
version = ""
),
authors = parseAuthors(node),
copyrightHolders = sortedSetOf(),
declaredLicenses = parseDeclaredLicenses(node),
description = "",
homepageUrl = node["homepage"].textValueOrEmpty(),
Expand Down
2 changes: 2 additions & 0 deletions analyzer/src/main/kotlin/managers/GoDep.kt
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ class GoDep(
val pkg = Package(
id = Identifier("Go", "", name, normalizeModuleVersion(version)),
authors = sortedSetOf(),
copyrightHolders = sortedSetOf(),
declaredLicenses = sortedSetOf(),
description = "",
homepageUrl = "",
Expand Down Expand Up @@ -175,6 +176,7 @@ class GoDep(
),
definitionFilePath = VersionControlSystem.getPathInfo(definitionFile).path,
authors = sortedSetOf(),
copyrightHolders = sortedSetOf(),
declaredLicenses = sortedSetOf(),
vcs = VcsInfo.EMPTY,
vcsProcessed = projectVcs,
Expand Down
2 changes: 2 additions & 0 deletions analyzer/src/main/kotlin/managers/GoMod.kt
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ class GoMod(
),
definitionFilePath = VersionControlSystem.getPathInfo(definitionFile).path,
authors = sortedSetOf(), // Go mod doesn't support author information.
copyrightHolders = sortedSetOf(), // Go mod doesn't support copyright holders.
declaredLicenses = sortedSetOf(), // Go mod doesn't support declared licenses.
vcs = projectVcs,
vcsProcessed = projectVcs,
Expand Down Expand Up @@ -284,6 +285,7 @@ class GoMod(
return Package(
id = toId(),
authors = sortedSetOf(), // Go mod doesn't support author information.
copyrightHolders = sortedSetOf(), // Go mod doesn't support copyright holders
declaredLicenses = sortedSetOf(), // Go mod doesn't support declared licenses.
description = "",
homepageUrl = "",
Expand Down
1 change: 1 addition & 0 deletions analyzer/src/main/kotlin/managers/Gradle.kt
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ class Gradle(
id = projectId,
definitionFilePath = VersionControlSystem.getPathInfo(definitionFile).path,
authors = sortedSetOf(),
copyrightHolders = sortedSetOf(),
declaredLicenses = sortedSetOf(),
vcs = VcsInfo.EMPTY,
vcsProcessed = processProjectVcs(definitionFile.parentFile),
Expand Down
1 change: 1 addition & 0 deletions analyzer/src/main/kotlin/managers/Maven.kt
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ class Maven(
id = projectId,
definitionFilePath = VersionControlSystem.getPathInfo(definitionFile).path,
authors = MavenSupport.parseAuthors(mavenProject),
copyrightHolders = sortedSetOf(),
declaredLicenses = declaredLicenses,
declaredLicensesProcessed = declaredLicensesProcessed,
vcs = vcsFromPackage,
Expand Down
2 changes: 2 additions & 0 deletions analyzer/src/main/kotlin/managers/Npm.kt
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,7 @@ open class Npm(
val module = Package(
id = id,
authors = authors,
copyrightHolders = sortedSetOf(),
declaredLicenses = declaredLicenses,
description = description,
homepageUrl = homepageUrl,
Expand Down Expand Up @@ -560,6 +561,7 @@ open class Npm(
),
definitionFilePath = VersionControlSystem.getPathInfo(packageJson).path,
authors = authors,
copyrightHolders = sortedSetOf(),
declaredLicenses = declaredLicenses,
vcs = vcsFromPackage,
vcsProcessed = processProjectVcs(projectDir, vcsFromPackage, homepageUrl),
Expand Down
2 changes: 2 additions & 0 deletions analyzer/src/main/kotlin/managers/Pip.kt
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ class Pip(
),
definitionFilePath = VersionControlSystem.getPathInfo(definitionFile).path,
authors = authors,
copyrightHolders = sortedSetOf(),
declaredLicenses = declaredLicenses,
vcs = VcsInfo.EMPTY,
vcsProcessed = processProjectVcs(workingDir, VcsInfo.EMPTY, setupHomepage),
Expand Down Expand Up @@ -726,6 +727,7 @@ private fun Package.enrichWith(other: Package?): Package =
homepageUrl = homepageUrl.takeUnless { it.isBlank() } ?: other.homepageUrl,
description = description.takeUnless { it.isBlank() } ?: other.description,
authors = authors.takeUnless { it.isEmpty() } ?: other.authors,
copyrightHolders = copyrightHolders.takeUnless { it.isEmpty() } ?: other.copyrightHolders,
declaredLicenses = declaredLicenses.takeUnless { it.isEmpty() } ?: other.declaredLicenses,
declaredLicensesProcessed = declaredLicensesProcessed.takeUnless { declaredLicenses.isEmpty() }
?: other.declaredLicensesProcessed,
Expand Down
2 changes: 2 additions & 0 deletions analyzer/src/main/kotlin/managers/Pub.kt
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,7 @@ class Pub(
),
definitionFilePath = VersionControlSystem.getPathInfo(definitionFile).path,
authors = authors,
copyrightHolders = sortedSetOf(),
// Pub does not declare any licenses in the pubspec files, therefore we keep this empty.
declaredLicenses = sortedSetOf(),
vcs = vcs,
Expand Down Expand Up @@ -532,6 +533,7 @@ class Pub(
packages[id] = Package(
id,
authors = authors,
copyrightHolders = sortedSetOf(),
// Pub does not declare any licenses in the pubspec files, therefore we keep this empty.
declaredLicenses = sortedSetOf(),
description = description,
Expand Down
2 changes: 2 additions & 0 deletions analyzer/src/main/kotlin/managers/SpdxDocumentFile.kt
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,7 @@ class SpdxDocumentFile(
purl = locateExternalReference(SpdxExternalReference.Type.Purl) ?: id.toPurl(),
cpe = locateCpe(),
authors = originator.wrapPresentInSortedSet(),
copyrightHolders = sortedSetOf(),
declaredLicenses = sortedSetOf(licenseDeclared),
concludedLicense = getConcludedLicense(),
description = packageDescription,
Expand Down Expand Up @@ -516,6 +517,7 @@ class SpdxDocumentFile(
cpe = projectPackage.locateCpe(),
definitionFilePath = VersionControlSystem.getPathInfo(definitionFile).path,
authors = projectPackage.originator.wrapPresentInSortedSet(),
copyrightHolders = sortedSetOf(),
declaredLicenses = sortedSetOf(projectPackage.licenseDeclared),
vcs = processProjectVcs(definitionFile.parentFile, VcsInfo.EMPTY),
homepageUrl = projectPackage.homepage.mapNotPresentToEmpty(),
Expand Down
2 changes: 2 additions & 0 deletions analyzer/src/main/kotlin/managers/Stack.kt
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ class Stack(
id = projectId,
definitionFilePath = VersionControlSystem.getPathInfo(definitionFile).path,
authors = projectPackage.authors,
copyrightHolders = sortedSetOf(),
declaredLicenses = projectPackage.declaredLicenses,
vcs = projectPackage.vcs,
vcsProcessed = processProjectVcs(workingDir, projectPackage.vcs, projectPackage.homepageUrl),
Expand Down Expand Up @@ -350,6 +351,7 @@ class Stack(
.map(String::trim)
.filter(String::isNotEmpty)
.mapTo(sortedSetOf(), ::parseAuthorString),
copyrightHolders = sortedSetOf(),
declaredLicenses = map["license"]?.let { sortedSetOf(it) } ?: sortedSetOf(),
description = map["description"].orEmpty(),
homepageUrl = homepageUrl,
Expand Down
1 change: 1 addition & 0 deletions analyzer/src/main/kotlin/managers/utils/MavenSupport.kt
Original file line number Diff line number Diff line change
Expand Up @@ -726,6 +726,7 @@ class MavenSupport(private val workspaceReader: WorkspaceReader) {
version = mavenProject.version
),
authors = parseAuthors(mavenProject),
copyrightHolders = sortedSetOf(),
declaredLicenses = declaredLicenses,
declaredLicensesProcessed = declaredLicensesProcessed,
description = mavenProject.description.orEmpty(),
Expand Down
2 changes: 2 additions & 0 deletions analyzer/src/main/kotlin/managers/utils/NuGetSupport.kt
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ class NuGetSupport(serviceIndexUrls: List<String> = listOf(DEFAULT_SERVICE_INDEX
Package(
id = getIdentifier(id, version),
authors = parseAuthors(all.spec),
copyrightHolders = sortedSetOf(),
declaredLicenses = parseLicenses(all.spec),
description = description.orEmpty(),
homepageUrl = homepageUrl,
Expand Down Expand Up @@ -368,6 +369,7 @@ private fun PackageManager.getProject(
),
definitionFilePath = VersionControlSystem.getPathInfo(definitionFile).path,
authors = parseAuthors(spec),
copyrightHolders = sortedSetOf(),
declaredLicenses = parseLicenses(spec),
vcs = VcsInfo.EMPTY,
vcsProcessed = PackageManager.processProjectVcs(workingDir),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
package org.ossreviewtoolkit.analyzer.managers.utils

import io.kotest.core.spec.style.StringSpec
import io.kotest.matchers.collections.beEmpty
import io.kotest.matchers.collections.containExactly
import io.kotest.matchers.should
import io.kotest.matchers.shouldBe
Expand Down Expand Up @@ -76,6 +77,7 @@ class NpmDependencyHandlerTest : StringSpec({
id shouldBe Identifier("NPM", "", "bonjour", "3.5.0")
declaredLicenses should containExactly("MIT")
authors should containExactly("Thomas Watson Steen")
copyrightHolders should beEmpty()
homepageUrl shouldBe "https://github.com/watson/bonjour/local"
description shouldBe "A Bonjour/Zeroconf implementation in pure JavaScript (local)"
}
Expand Down
9 changes: 9 additions & 0 deletions model/src/main/kotlin/Package.kt
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,13 @@ data class Package(
@JsonInclude(JsonInclude.Include.NON_DEFAULT)
val authors: SortedSet<String> = sortedSetOf(),

/**
* The list of copyright holders declared for this package. These might be different from the list of [authors]
* if all or parts of the copyright has been transferred.
*/
@JsonInclude(JsonInclude.Include.NON_DEFAULT)
val copyrightHolders: SortedSet<String> = sortedSetOf(),

/**
* The list of licenses the authors have declared for this package. This does not necessarily correspond to the
* licenses as detected by a scanner. Both need to be taken into account for any conclusions.
Expand Down Expand Up @@ -138,6 +145,7 @@ data class Package(
id = Identifier.EMPTY,
purl = "",
authors = sortedSetOf(),
copyrightHolders = sortedSetOf(),
declaredLicenses = sortedSetOf(),
declaredLicensesProcessed = ProcessedDeclaredLicense.EMPTY,
concludedLicense = null,
Expand Down Expand Up @@ -167,6 +175,7 @@ data class Package(

return PackageCurationData(
authors = authors.takeIf { it != other.authors },
declaredCopyrights = copyrightHolders.takeIf { it != other.copyrightHolders },
description = description.takeIf { it != other.description },
homepageUrl = homepageUrl.takeIf { it != other.homepageUrl },
binaryArtifact = binaryArtifact.takeIf { it != other.binaryArtifact },
Expand Down

0 comments on commit 73cf1b3

Please sign in to comment.