Skip to content

Commit 2d799f9

Browse files
committed
spdx: Add converter for index reports
Adding a function to be able to convert index reports into SPDX documents. Signed-off-by: crozzy <[email protected]>
1 parent bf22ee3 commit 2d799f9

File tree

4 files changed

+154
-0
lines changed

4 files changed

+154
-0
lines changed

go.mod

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ require (
2222
github.com/quay/zlog v1.1.7
2323
github.com/remind101/migrate v0.0.0-20170729031349-52c1edff7319
2424
github.com/rs/zerolog v1.30.0
25+
github.com/spdx/tools-golang v0.5.3
2526
github.com/ulikunitz/xz v0.5.11
2627
go.opentelemetry.io/otel v1.21.0
2728
go.opentelemetry.io/otel/trace v1.21.0
@@ -35,6 +36,7 @@ require (
3536
)
3637

3738
require (
39+
github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092 // indirect
3840
github.com/beorn7/perks v1.0.1 // indirect
3941
github.com/cespare/xxhash/v2 v2.2.0 // indirect
4042
github.com/davecgh/go-spew v1.1.1 // indirect

go.sum

+8
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3Q
55
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
66
github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=
77
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
8+
github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092 h1:aM1rlcoLz8y5B2r4tTLMiVTrMtpfY0O8EScKJxaSaEc=
9+
github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092/go.mod h1:rYqSE9HbjzpHTI74vwPvae4ZVYZd1lue2ta6xHPdblA=
810
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
911
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
1012
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
@@ -176,6 +178,9 @@ github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXY
176178
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
177179
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
178180
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
181+
github.com/spdx/gordf v0.0.0-20201111095634-7098f93598fb/go.mod h1:uKWaldnbMnjsSAXRurWqqrdyZen1R7kxl8TkmWk2OyM=
182+
github.com/spdx/tools-golang v0.5.3 h1:ialnHeEYUC4+hkm5vJm4qz2x+oEJbS0mAMFrNXdQraY=
183+
github.com/spdx/tools-golang v0.5.3/go.mod h1:/ETOahiAo96Ob0/RAIBmFZw6XN0yTnyr/uFZm2NTMhI=
179184
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
180185
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
181186
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
@@ -191,6 +196,7 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
191196
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
192197
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
193198
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
199+
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
194200
github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8=
195201
github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
196202
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
@@ -318,6 +324,7 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8
318324
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
319325
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
320326
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
327+
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
321328
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
322329
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
323330
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
@@ -346,3 +353,4 @@ modernc.org/tcl v1.15.2 h1:C4ybAYCGJw968e+Me18oW55kD/FexcHbqH2xak1ROSY=
346353
modernc.org/token v1.0.1 h1:A3qvTqOwexpfZZeyI0FeGPDlSWX5pjZu9hF4lU+EKWg=
347354
modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
348355
modernc.org/z v1.7.3 h1:zDJf6iHjrnB+WRD88stbXokugjyc0/pB91ri1gO6LZY=
356+
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=

pkg/sbom/spdx/spdx.go

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package spdx
2+
3+
import (
4+
"fmt"
5+
"runtime/debug"
6+
"time"
7+
8+
"github.com/spdx/tools-golang/spdx/v2/common"
9+
spdxtools "github.com/spdx/tools-golang/spdx/v2/v2_3"
10+
11+
"github.com/quay/claircore"
12+
)
13+
14+
func ParseIndexReport(vr *claircore.IndexReport) (*spdxtools.Document, error) {
15+
// Initial metadata
16+
out := &spdxtools.Document{
17+
SPDXVersion: spdxtools.Version,
18+
DataLicense: spdxtools.DataLicense,
19+
SPDXIdentifier: "DOCUMENT",
20+
DocumentName: "SPDX-claircore-" + vr.Hash.String(),
21+
// This would be nice to have but don't know how we'd get context w/o
22+
// having to accept it as an argument.
23+
// DocumentNamespace: "https://clairproject.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301",
24+
CreationInfo: &spdxtools.CreationInfo{
25+
Creators: []common.Creator{
26+
{CreatorType: "Tool", Creator: "Claircore"},
27+
{CreatorType: "Organization", Creator: "Clair"},
28+
},
29+
Created: time.Now().Format("2006-01-02T15:04:05Z"),
30+
},
31+
DocumentComment: fmt.Sprintf("This document was created using claircore (%s).", getVersion()),
32+
}
33+
34+
for _, p := range vr.Packages {
35+
pkgDB := ""
36+
for _, e := range vr.Environments[p.ID] {
37+
if e.PackageDB != "" {
38+
pkgDB = e.PackageDB
39+
}
40+
}
41+
pkg := &spdxtools.Package{
42+
PackageName: p.Name,
43+
PackageSPDXIdentifier: common.ElementID("SPDXRef-" + p.ID),
44+
PackageVersion: p.Version,
45+
PackageFileName: pkgDB,
46+
PackageDownloadLocation: "NOASSERTION",
47+
FilesAnalyzed: true,
48+
}
49+
out.Packages = append(out.Packages, pkg)
50+
}
51+
return out, nil
52+
}
53+
54+
// GetVersion is copied from Clair and can hopefully give some
55+
// context as to which revision of claircore was used.
56+
func getVersion() string {
57+
info, infoOK := debug.ReadBuildInfo()
58+
var core string
59+
if infoOK {
60+
for _, m := range info.Deps {
61+
if m.Path != "github.com/quay/claircore" {
62+
continue
63+
}
64+
core = m.Version
65+
if m.Replace != nil && m.Replace.Version != m.Version {
66+
core = m.Replace.Version
67+
}
68+
}
69+
}
70+
if core == "" {
71+
core = "unknown revision"
72+
}
73+
return core
74+
}

pkg/sbom/spdx/spdx_test.go

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package spdx
2+
3+
import (
4+
"bytes"
5+
"fmt"
6+
"strings"
7+
"testing"
8+
9+
"github.com/quay/claircore"
10+
11+
"github.com/spdx/tools-golang/tagvalue"
12+
)
13+
14+
func TestParseIndexReport(t *testing.T) {
15+
//ctx := context.Background()
16+
for _, ir := range testIndexReports {
17+
t.Run("TODO", func(t *testing.T) {
18+
19+
s, err := ParseIndexReport(ir)
20+
if err != nil {
21+
t.Fatal(err)
22+
}
23+
if len(s.Packages) != 2 {
24+
t.Error("expecting 2 packages")
25+
}
26+
w := &bytes.Buffer{}
27+
err = tagvalue.Write(s, w)
28+
if err != nil {
29+
t.Fatal(err)
30+
}
31+
fmt.Println(string(w.Bytes()))
32+
33+
})
34+
}
35+
t.Error()
36+
}
37+
38+
var testIndexReports = []*claircore.IndexReport{
39+
{
40+
Hash: claircore.MustParseDigest(`sha256:` + strings.Repeat(`a`, 64)),
41+
Packages: map[string]*claircore.Package{
42+
"123": {
43+
ID: "123",
44+
Name: "package A",
45+
Version: "v1.0.0",
46+
},
47+
"456": {
48+
ID: "456",
49+
Name: "package B",
50+
Version: "v2.0.0",
51+
},
52+
},
53+
Environments: map[string][]*claircore.Environment{
54+
"123": {
55+
{
56+
PackageDB: "var/lib/dpkg/status",
57+
IntroducedIn: claircore.MustParseDigest(`sha256:` + strings.Repeat(`b`, 64)),
58+
RepositoryIDs: []string{"11"},
59+
},
60+
},
61+
"456": {
62+
{
63+
PackageDB: "maven:opt/couchbase/lib/cbas/repo/eventstream-1.0.1.jar",
64+
IntroducedIn: claircore.MustParseDigest(`sha256:` + strings.Repeat(`c`, 64)),
65+
RepositoryIDs: []string{"12"},
66+
},
67+
},
68+
},
69+
},
70+
}

0 commit comments

Comments
 (0)