Skip to content

Commit

Permalink
add spdx parser (guacsec#108)
Browse files Browse the repository at this point in the history
* add spdx unit tests

Signed-off-by: pxp928 <[email protected]>

* update unit tests

Signed-off-by: pxp928 <[email protected]>

* fix unit test

Signed-off-by: pxp928 <[email protected]>

* updated unit tests

Signed-off-by: pxp928 <[email protected]>

* added containsEdge

Signed-off-by: pxp928 <[email protected]>

* updated unit test with contains and depends on edges

Signed-off-by: pxp928 <[email protected]>

* updated based on comments

Signed-off-by: pxp928 <[email protected]>

Signed-off-by: pxp928 <[email protected]>
  • Loading branch information
pxp928 authored Oct 7, 2022
1 parent e22e90c commit 3fa11be
Show file tree
Hide file tree
Showing 17 changed files with 1,261 additions and 42 deletions.
6 changes: 3 additions & 3 deletions cmd/guacone/cmd/files.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ var exampleCmd = &cobra.Command{
logger.Errorf("error: %v", err)
os.Exit(1)
}
ingestorFunc, err := getIngestor()
ingestorFunc, err := getIngestor(ctx)
if err != nil {
logger.Errorf("error: %v", err)
os.Exit(1)
Expand Down Expand Up @@ -151,9 +151,9 @@ func getProcessor(ctx context.Context) (func(*processor.Document) (processor.Doc
return process.Process(ctx, d)
}, nil
}
func getIngestor() (func(processor.DocumentTree) ([]assembler.Graph, error), error) {
func getIngestor(ctx context.Context) (func(processor.DocumentTree) ([]assembler.Graph, error), error) {
return func(doc processor.DocumentTree) ([]assembler.Graph, error) {
inputs, err := parser.ParseDocumentTree(doc)
inputs, err := parser.ParseDocumentTree(ctx, doc)
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/ingest/cmd/example.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ var exampleCmd = &cobra.Command{
Edges: []assembler.GuacEdge{},
}
for _, doc := range docs {
inputs, err := parser.ParseDocumentTree(doc)
inputs, err := parser.ParseDocumentTree(ctx, doc)
if err != nil {
logger.Errorf("unable to parse document: %v", err)
os.Exit(1)
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -66,5 +66,5 @@ require (

require (
github.com/sigstore/sigstore v1.4.2
github.com/spdx/tools-golang v0.3.1-0.20220818163346-5eb9315c0c55
github.com/spdx/tools-golang v0.3.1-0.20221003161519-fb7fe8874d01
)
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -285,8 +285,8 @@ github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spdx/gordf v0.0.0-20201111095634-7098f93598fb/go.mod h1:uKWaldnbMnjsSAXRurWqqrdyZen1R7kxl8TkmWk2OyM=
github.com/spdx/tools-golang v0.3.1-0.20220818163346-5eb9315c0c55 h1:vVdz7zz4iQvAyUYbjGvd35FMyQEoFjV3BvpnzzBKXZc=
github.com/spdx/tools-golang v0.3.1-0.20220818163346-5eb9315c0c55/go.mod h1:VHzvNsKAfAGqs4ZvwRL+7a0dNsL20s7lGui4K9C0xQM=
github.com/spdx/tools-golang v0.3.1-0.20221003161519-fb7fe8874d01 h1:HSwhIjCVoxeYkVPkUNH1l0ej8WBLgl7pNYz17vFOp/g=
github.com/spdx/tools-golang v0.3.1-0.20221003161519-fb7fe8874d01/go.mod h1:VHzvNsKAfAGqs4ZvwRL+7a0dNsL20s7lGui4K9C0xQM=
github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU=
github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
Expand Down
190 changes: 190 additions & 0 deletions internal/testing/ingestor/testdata/testdata.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package testdata
import (
"encoding/base64"
"encoding/json"
"reflect"

"github.com/guacsec/guac/internal/testing/ingestor/keyutil"
"github.com/guacsec/guac/pkg/assembler"
Expand All @@ -28,6 +29,8 @@ import (
)

var (
// DSSE/SLSA Testdata

// Taken from: https://slsa.dev/provenance/v0.1#example
ite6SLSA = `
{
Expand Down Expand Up @@ -151,6 +154,96 @@ var (
ArtifactDependency: mat2,
},
}

// SDPX Testdata

topLevelPack = assembler.PackageNode{
Name: "gcr.io/google-containers/alpine-latest",
Digest: nil,
Purl: "pkg:oci/alpine-latest?repository_url=gcr.io/google-containers",
CPEs: nil,
}

baselayoutPack = assembler.PackageNode{
Name: "alpine-baselayout",
Digest: nil,
Purl: "pkg:alpine/[email protected]?arch=x86_64&upstream=alpine-baselayout&distro=alpine-3.16.2",
CPEs: []string{
"cpe:2.3:a:alpine-baselayout:alpine-baselayout:3.2.0-r22:*:*:*:*:*:*:*",
"cpe:2.3:a:alpine-baselayout:alpine_baselayout:3.2.0-r22:*:*:*:*:*:*:*",
},
}

keysPack = assembler.PackageNode{
Name: "alpine-keys",
Digest: nil,
Purl: "pkg:alpine/[email protected]?arch=x86_64&upstream=alpine-keys&distro=alpine-3.16.2",
CPEs: []string{
"cpe:2.3:a:alpine-keys:alpine-keys:2.4-r1:*:*:*:*:*:*:*",
"cpe:2.3:a:alpine-keys:alpine_keys:2.4-r1:*:*:*:*:*:*:*",
"cpe:2.3:a:alpine:alpine-keys:2.4-r1:*:*:*:*:*:*:*",
"cpe:2.3:a:alpine:alpine_keys:2.4-r1:*:*:*:*:*:*:*",
},
}

baselayoutdataPack = assembler.PackageNode{
Name: "alpine-baselayout-data",
Digest: nil,
Purl: "pkg:alpine/[email protected]?arch=x86_64&upstream=alpine-baselayout&distro=alpine-3.16.2",
CPEs: []string{
"cpe:2.3:a:alpine-baselayout-data:alpine-baselayout-data:3.2.0-r22:*:*:*:*:*:*:*",
"cpe:2.3:a:alpine-baselayout-data:alpine_baselayout_data:3.2.0-r22:*:*:*:*:*:*:*",
},
}

worldFile = assembler.ArtifactNode{
Name: "/etc/apk/world",
Digest: "SHA256:713e3907167dce202d7c16034831af3d670191382a3e9026e0ac0a4023013201",
}
rootFile = assembler.ArtifactNode{
Name: "/etc/crontabs/root",
Digest: "SHA256:575d810a9fae5f2f0671c9b2c0ce973e46c7207fbe5cb8d1b0d1836a6a0470e3",
}
triggersFile = assembler.ArtifactNode{
Name: "/lib/apk/db/triggers",
Digest: "SHA256:5415cfe5f88c0af38df3b7141a3f9bc6b8178e9cf72d700658091b8f5539c7b4",
}
rsaPubFile = assembler.ArtifactNode{
Name: "/usr/share/apk/keys/[email protected]",
Digest: "SHA256:9a4cd858d9710963848e6d5f555325dc199d1c952b01cf6e64da2c15deedbd97",
}

SpdxNodes = []assembler.GuacNode{topLevelPack, baselayoutPack, baselayoutdataPack, rsaPubFile, keysPack, worldFile, rootFile, triggersFile}
SpdxEdges = []assembler.GuacEdge{
assembler.DependsOnEdge{
PackageNode: topLevelPack,
PackageDependency: baselayoutPack,
},
assembler.DependsOnEdge{
PackageNode: topLevelPack,
PackageDependency: baselayoutdataPack,
},
assembler.DependsOnEdge{
PackageNode: topLevelPack,
PackageDependency: keysPack,
},
assembler.DependsOnEdge{
PackageNode: baselayoutPack,
PackageDependency: keysPack,
},
assembler.DependsOnEdge{
ArtifactNode: rootFile,
ArtifactDependency: rsaPubFile,
},
assembler.ContainsEdge{
PackageNode: baselayoutPack,
ContainedArtifact: rootFile,
},
assembler.ContainsEdge{
PackageNode: keysPack,
ContainedArtifact: rsaPubFile,
},
}
)

type mockSigstoreVerifier struct{}
Expand Down Expand Up @@ -179,3 +272,100 @@ func (m *mockSigstoreVerifier) Verify(payloadBytes []byte) ([]verifier.Identity,
func (m *mockSigstoreVerifier) Type() verifier.VerifierType {
return "sigstore"
}

func GuacNodeSliceEqual(slice1, slice2 []assembler.GuacNode) bool {
if len(slice1) != len(slice2) {
return false
}

result := true

for _, node1 := range slice1 {
e := false
for _, node2 := range slice2 {
if node1.Type() == "Package" && node2.Type() == "Package" {
if node1.(assembler.PackageNode).Name == node2.(assembler.PackageNode).Name {
if reflect.DeepEqual(node1, node2) {
e = true
break
}
}
} else if node1.Type() == "Artifact" && node2.Type() == "Artifact" {
if node1.(assembler.ArtifactNode).Name == node2.(assembler.ArtifactNode).Name {
if reflect.DeepEqual(node1, node2) {
e = true
break
}
}
} else if node1.Type() == "Attestation" && node2.Type() == "Attestation" {
if node1.(assembler.AttestationNode).FilePath == node2.(assembler.AttestationNode).FilePath {
if reflect.DeepEqual(node1, node2) {
e = true
break
}
}
} else if node1.Type() == "Builder" && node2.Type() == "Builder" {
if node1.(assembler.BuilderNode).BuilderId == node2.(assembler.BuilderNode).BuilderId {
if reflect.DeepEqual(node1, node2) {
e = true
break
}
}
} else if node1.Type() == "Identity" && node2.Type() == "Identity" {
if node1.(assembler.IdentityNode).ID == node2.(assembler.IdentityNode).ID {
if reflect.DeepEqual(node1, node2) {
e = true
break
}
}
}
}
if !e {
result = false
}
}
return result
}

func GuacEdgeSliceEqual(slice1, slice2 []assembler.GuacEdge) bool {
if len(slice1) != len(slice2) {
return false
}

result := true
for _, edge1 := range slice1 {
e := false
for _, edge2 := range slice2 {
if edge1.Type() == "DependsOn" && edge2.Type() == "DependsOn" {
if reflect.DeepEqual(edge1, edge2) {
e = true
break
}
} else if edge1.Type() == "Contains" && edge2.Type() == "Contains" {
if reflect.DeepEqual(edge1, edge2) {
e = true
break
}
} else if edge1.Type() == "Attestation" && edge2.Type() == "Attestation" {
if reflect.DeepEqual(edge1, edge2) {
e = true
break
}
} else if edge1.Type() == "Identity" && edge2.Type() == "Identity" {
if reflect.DeepEqual(edge1, edge2) {
e = true
break
}
} else if edge1.Type() == "BuiltBy" && edge2.Type() == "BuiltBy" {
if reflect.DeepEqual(edge1, edge2) {
e = true
break
}
}
}
if !e {
result = false
}
}
return result
}
3 changes: 3 additions & 0 deletions internal/testing/processor/testdata.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ var (
//go:embed testdata/alpine-spdx.json
SpdxExampleBig []byte

//go:embed testdata/alpine-small-spdx.json
SpdxExampleAlpine []byte

// Invalid types for field spdxVersion
//go:embed testdata/invalid-spdx.json
SpdxInvalidExample []byte
Expand Down
Loading

0 comments on commit 3fa11be

Please sign in to comment.