Skip to content

Commit

Permalink
feat: Add support for new Copyrights and schema updates
Browse files Browse the repository at this point in the history
- **Added**: New JSON schema version `16.0.16` with support for the new `Copyrights`.
- **Modified**: Updated the `JSONSchemaVersion` parameter to use the new schema.

- **Added**: New `Copyrights` field to the `Package` and `PackageBasicData` structs, similar to the existing `Licenses` field.
- **Added**: New `Copyright` struct.
- **Implemented**: Sorting methods for the `Copyright` struct.

- **Changed**: Updated the `PackageCopyrightText` to use `helpers.GetCopyrights(p.Copyrights)`, which formats the copyright text and returns a string. Example output: "Copyright 2014-2014 Matt Zabriskie & Collaborators".

- **Added**: `Copyrights` assignment to the `toSyftPackage` function.

Signed-off-by: dor-hayun <[email protected]>
  • Loading branch information
dor-hayun committed Aug 28, 2024
1 parent cf9bb13 commit b113b35
Show file tree
Hide file tree
Showing 37 changed files with 524 additions and 105 deletions.
29 changes: 27 additions & 2 deletions internal/cmptest/common_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ import (
)

func DefaultCommonOptions() []cmp.Option {
return CommonOptions(nil, nil)
return CommonOptions(nil, nil, nil)
}

func CommonOptions(licenseCmp LicenseComparer, locationCmp LocationComparer) []cmp.Option {
//nolint:funlen
func CommonOptions(licenseCmp LicenseComparer, locationCmp LocationComparer, copyrightCmp CopyrightComparer) []cmp.Option {
if licenseCmp == nil {
licenseCmp = DefaultLicenseComparer
}
Expand All @@ -21,6 +22,10 @@ func CommonOptions(licenseCmp LicenseComparer, locationCmp LocationComparer) []c
locationCmp = DefaultLocationComparer
}

if copyrightCmp == nil {
copyrightCmp = DefaultCopyrightComparer
}

return []cmp.Option{
cmpopts.IgnoreFields(pkg.Package{}, "id"), // note: ID is not deterministic for test purposes
cmpopts.SortSlices(pkg.Less),
Expand Down Expand Up @@ -61,11 +66,31 @@ func CommonOptions(licenseCmp LicenseComparer, locationCmp LocationComparer) []c
return true
},
),
cmp.Comparer(
func(x, y pkg.CopyrightsSet) bool {
xs := x.ToSlice()
ys := y.ToSlice()

if len(xs) != len(ys) {
return false
}
for i, xe := range xs {
ye := ys[i]
if !copyrightCmp(xe, ye) {
return false
}
}
return true
},
),
cmp.Comparer(
locationCmp,
),
cmp.Comparer(
licenseCmp,
),
cmp.Comparer(
copyrightCmp,
),
}
}
16 changes: 16 additions & 0 deletions internal/cmptest/copyright.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package cmptest

import (
"github.com/anchore/syft/syft/pkg"
"github.com/google/go-cmp/cmp"
)

type CopyrightComparer func(x, y pkg.Copyright) bool

func DefaultCopyrightComparer(x, y pkg.Copyright) bool {
return cmp.Equal(x, y, cmp.Comparer(
func(x, y string) bool {
return x == y
},
))
}
2 changes: 1 addition & 1 deletion internal/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ package internal
const (
// JSONSchemaVersion is the current schema version output by the JSON encoder
// This is roughly following the "SchemaVer" guidelines for versioning the JSON schema. Please see schema/json/README.md for details on how to increment.
JSONSchemaVersion = "16.0.15"
JSONSchemaVersion = "16.0.16"
)
1 change: 1 addition & 0 deletions internal/relationship/binary/binary_dependencies_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,7 @@ func relationshipComparer(x, y []artifact.Relationship) string {
artifact.Relationship{},
file.LocationSet{},
pkg.LicenseSet{},
pkg.CopyrightsSet{},
), cmpopts.SortSlices(lessRelationships))
}

Expand Down
34 changes: 33 additions & 1 deletion schema/json/schema-latest.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "anchore.io/schema/syft/json/16.0.15/document",
"$id": "anchore.io/schema/syft/json/16.0.16/document",
"$ref": "#/$defs/Document",
"$defs": {
"AlpmDbEntry": {
Expand Down Expand Up @@ -370,6 +370,28 @@
"path"
]
},
"Copyright": {
"properties": {
"url": {
"type": "string"
},
"author": {
"type": "string"
},
"startYear": {
"type": "string"
},
"endYear": {
"type": "string"
}
},
"type": "object",
"required": [
"author",
"startYear",
"endYear"
]
},
"DartPubspecLockEntry": {
"properties": {
"name": {
Expand Down Expand Up @@ -1462,6 +1484,9 @@
"licenses": {
"$ref": "#/$defs/licenses"
},
"copyrights": {
"$ref": "#/$defs/copyrights"
},
"language": {
"type": "string"
},
Expand Down Expand Up @@ -1626,6 +1651,7 @@
"foundBy",
"locations",
"licenses",
"copyrights",
"language",
"cpes",
"purl"
Expand Down Expand Up @@ -2566,6 +2592,12 @@
"pluginInstallDirectory"
]
},
"copyrights": {
"items": {
"$ref": "#/$defs/Copyright"
},
"type": "array"
},
"cpes": {
"items": {
"$ref": "#/$defs/CPE"
Expand Down
4 changes: 2 additions & 2 deletions syft/format/common/spdxhelpers/to_format_model.go
Original file line number Diff line number Diff line change
Expand Up @@ -444,8 +444,8 @@ func toPackages(rels *relationship.Index, catalog *pkg.Collection, sbom sbom.SBO
// NOASSERTION, if
// (i) the SPDX document creator has made no attempt to determine this field; or
// (ii) the SPDX document creator has intentionally provided no information (no meaning should be implied by doing so).
//
PackageCopyrightText: noAssertion,
// (iii) Get the formatted copyright text if available, otherwise return NOASSERTION
PackageCopyrightText: helpers.GetCopyrights(p.Copyrights),

// 7.18: Package Summary Description
// Cardinality: optional, one
Expand Down
1 change: 1 addition & 0 deletions syft/format/common/spdxhelpers/to_syft_model_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,7 @@ func Test_convertToAndFromFormat(t *testing.T) {
cmpopts.IgnoreUnexported(pkg.Collection{}),
cmpopts.IgnoreUnexported(pkg.Package{}),
cmpopts.IgnoreUnexported(pkg.LicenseSet{}),
cmpopts.IgnoreUnexported(pkg.CopyrightsSet{}),
cmpopts.IgnoreFields(sbom.Artifacts{}, "FileMetadata", "FileDigests"),
); diff != "" {
t.Fatalf("packages do not match:\n%s", diff)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
}
}
],
"copyright":"NOASSERTION",
"cpe": "cpe:2.3:*:some:package:2:*:*:*:*:*:*:*",
"purl": "a-purl-2",
"properties": [
Expand Down Expand Up @@ -62,6 +63,7 @@
},
{
"bom-ref":"redacted",
"copyright":"NOASSERTION",
"type": "library",
"name": "package-2",
"version": "2.0.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
}
}
],
"copyright":"NOASSERTION",
"cpe": "cpe:2.3:*:some:package:1:*:*:*:*:*:*:*",
"purl": "a-purl-1",
"properties": [
Expand Down Expand Up @@ -67,6 +68,7 @@
},
{
"bom-ref":"redacted",
"copyright":"NOASSERTION",
"type": "library",
"name": "package-2",
"version": "2.0.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
<id>MIT</id>
</license>
</licenses>
<copyright>NOASSERTION</copyright>
<cpe>cpe:2.3:*:some:package:2:*:*:*:*:*:*:*</cpe>
<purl>a-purl-2</purl>
<properties>
Expand All @@ -37,6 +38,7 @@
<component bom-ref="redacted" type="library">
<name>package-2</name>
<version>2.0.1</version>
<copyright>NOASSERTION</copyright>
<cpe>cpe:2.3:*:some:package:2:*:*:*:*:*:*:*</cpe>
<purl>pkg:deb/debian/[email protected]</purl>
<properties>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
<id>MIT</id>
</license>
</licenses>
<copyright>NOASSERTION</copyright>
<cpe>cpe:2.3:*:some:package:1:*:*:*:*:*:*:*</cpe>
<purl>a-purl-1</purl>
<properties>
Expand All @@ -39,6 +40,7 @@
<component bom-ref="redacted" type="library">
<name>package-2</name>
<version>2.0.1</version>
<copyright>NOASSERTION</copyright>
<cpe>cpe:2.3:*:some:package:2:*:*:*:*:*:*:*</cpe>
<purl>pkg:deb/debian/[email protected]</purl>
<properties>
Expand Down
1 change: 1 addition & 0 deletions syft/format/internal/cyclonedxutil/helpers/component.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ func EncodeComponent(p pkg.Package) cyclonedx.Component {
Version: p.Version,
PackageURL: p.PURL,
Licenses: encodeLicenses(p),
Copyright: encodeCopyrights(p),
CPE: encodeSingleCPE(p),
Author: encodeAuthor(p),
Publisher: encodePublisher(p),
Expand Down
3 changes: 3 additions & 0 deletions syft/format/internal/cyclonedxutil/helpers/component_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ func Test_encodeCompomentType(t *testing.T) {
Value: "go-module",
},
},
Copyright: noAssertion,
},
},
{
Expand All @@ -206,6 +207,8 @@ func Test_encodeCompomentType(t *testing.T) {
Value: "binary",
},
},

Copyright: noAssertion,
},
},
}
Expand Down
34 changes: 33 additions & 1 deletion syft/format/internal/cyclonedxutil/helpers/licenses.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@ import (
"strings"

"github.com/CycloneDX/cyclonedx-go"

"github.com/anchore/syft/internal/spdxlicense"
"github.com/anchore/syft/syft/pkg"
)

const (
noAssertion = "NOASSERTION"
copyrightPrefix = "Copyright"
)

// This should be a function that just surfaces licenses already validated in the package struct
func encodeLicenses(p pkg.Package) *cyclonedx.Licenses {
spdx, other, ex := separateLicenses(p)
Expand Down Expand Up @@ -198,3 +202,31 @@ func reduceOuter(expression string) string {

return sb.String()
}

func encodeCopyrights(p pkg.Package) string {
if p.Copyrights.Empty() {
return noAssertion
}

var strArr []string

for _, c := range p.Copyrights.ToSlice() {
var sb strings.Builder
sb.WriteString(copyrightPrefix)

// Construct the string with Start Year, End Year, and Author
if c.StartYear != "" {
sb.WriteString(" " + c.StartYear)
}
if c.EndYear != "" {
sb.WriteString("-" + c.EndYear)
}
if c.Author != "" {
sb.WriteString(" " + c.Author)
}

strArr = append(strArr, sb.String())
}

return strings.Join(strArr, ", ")
}
45 changes: 45 additions & 0 deletions syft/format/internal/spdxutil/helpers/copyright.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package helpers

import (
"strings"

"github.com/anchore/syft/syft/pkg"
)

const (
noAssertion = "NOASSERTION"
copyrightPrefix = "Copyright"
)

func GetCopyrights(copyrights pkg.CopyrightsSet) string {
result := noAssertion

for _, c := range copyrights.ToSlice() {
var sb strings.Builder

sb.WriteString(copyrightPrefix)

// Start Year
if c.StartYear != "" {
sb.WriteString(" ")
sb.WriteString(c.StartYear)
}

// End Year
if c.EndYear != "" {
sb.WriteString("-")
sb.WriteString(c.EndYear)
}

// Author
if c.Author != "" {
sb.WriteString(" ")
sb.WriteString(c.Author)
}

// Assign the formatted string to result
result = sb.String()
}

return result
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
},
"packages": [
{
"SPDXID": "SPDXRef-Package-files-analyzed-false-7d37ba9d2f7c574b",
"SPDXID": "SPDXRef-Package-files-analyzed-false-0950a383541717dc",
"copyrightText": "NOASSERTION",
"downloadLocation": "NOASSERTION",
"filesAnalyzed": false,
Expand All @@ -27,7 +27,7 @@
},
{
"name": "files-analyzed-true",
"SPDXID": "SPDXRef-Package-files-analyzed-true-035066c2086b8bb4",
"SPDXID": "SPDXRef-Package-files-analyzed-true-1d0a8d923f0cd238",
"versionInfo": "v1",
"supplier": "NOASSERTION",
"downloadLocation": "NOASSERTION",
Expand Down Expand Up @@ -77,18 +77,18 @@
],
"relationships": [
{
"spdxElementId": "SPDXRef-Package-files-analyzed-true-035066c2086b8bb4",
"spdxElementId": "SPDXRef-Package-files-analyzed-true-1d0a8d923f0cd238",
"relatedSpdxElement": "SPDXRef-File-some-file-2c5bc344430decac",
"relationshipType": "CONTAINS"
},
{
"spdxElementId": "SPDXRef-DocumentRoot-Unknown-",
"relatedSpdxElement": "SPDXRef-Package-files-analyzed-false-7d37ba9d2f7c574b",
"relatedSpdxElement": "SPDXRef-Package-files-analyzed-false-0950a383541717dc",
"relationshipType": "CONTAINS"
},
{
"spdxElementId": "SPDXRef-DocumentRoot-Unknown-",
"relatedSpdxElement": "SPDXRef-Package-files-analyzed-true-035066c2086b8bb4",
"relatedSpdxElement": "SPDXRef-Package-files-analyzed-true-1d0a8d923f0cd238",
"relationshipType": "CONTAINS"
},
{
Expand Down
Loading

0 comments on commit b113b35

Please sign in to comment.