Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add local eval fixedQueryResult test #35

Merged
merged 1 commit into from
Jan 12, 2024
Merged
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
4 changes: 4 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ require (
github.com/hasura/go-graphql-client v0.9.3
github.com/mitchellh/hashstructure/v2 v2.0.1
github.com/sirupsen/logrus v1.9.0
github.com/stretchr/testify v1.8.1
golang.org/x/oauth2 v0.13.0
google.golang.org/api v0.147.0
olympos.io/encoding/edn v0.0.0-20201019073823-d3554ca0b0a3
Expand All @@ -20,13 +21,15 @@ require (
cloud.google.com/go/compute/metadata v0.2.3 // indirect
cloud.google.com/go/iam v1.1.2 // indirect
cloud.google.com/go/longrunning v0.5.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/s2a-go v0.1.7 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.1 // indirect
github.com/googleapis/gax-go/v2 v2.12.0 // indirect
github.com/klauspost/compress v1.10.3 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
go.opencensus.io v0.24.0 // indirect
golang.org/x/crypto v0.14.0 // indirect
golang.org/x/net v0.17.0 // indirect
Expand All @@ -40,5 +43,6 @@ require (
google.golang.org/genproto/googleapis/rpc v0.0.0-20231009173412-8bfb1ae86b6c // indirect
google.golang.org/grpc v1.58.2 // indirect
google.golang.org/protobuf v1.31.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
nhooyr.io/websocket v1.8.7 // indirect
)
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
Expand Down
156 changes: 156 additions & 0 deletions policy/policy_handler/legacy/image_packages_by_digest.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
package legacy

import (
"context"
"github.com/atomist-skills/go-skill"
"github.com/atomist-skills/go-skill/policy/data"
)

// Versions of scout-cli-plugin created before the introduction of fixedQueryResults
// directly passed a []Package object in the metadata for local evaluation.
// This was then supplemented by a synchronous GraphQL call to load vulnerability data,
// so we mock the entire process to support these older versions.
// TODO remove this whole system when no longer used

const (
ImagePackagesByDigestQueryName = "image-packages-by-digest"
vulnerabilitiesByPackageQueryName = "vulnerabilities-by-package"

// language=graphql
vulnerabilitiesByPackageQuery = `
query ($context: Context!, $packageUrls: [String!]!) {
vulnerabilitiesByPackage(context: $context, packageUrls: $packageUrls) {
purl
vulnerabilities {
cvss {
severity
score
}
fixedBy
publishedAt
source
sourceId
updatedAt
url
vulnerableRange
}
}
}`
)

type (
Package struct {
Licenses []string `edn:"licenses,omitempty"` // only needed for the license policy evaluation
Name string `edn:"name"`
Namespace string `edn:"namespace"`
Version string `edn:"version"`
Purl string `edn:"purl"`
Type string `edn:"type"`
}

ImagePackagesByDigestResponse struct {
ImagePackagesByDigest *ImagePackagesByDigest `json:"imagePackagesByDigest" edn:"imagePackagesByDigest"`
}

ImagePackagesByDigest struct {
ImagePackages ImagePackages `json:"imagePackages" edn:"imagePackages"`
}

ImagePackages struct {
Packages []Packages `json:"packages" edn:"packages"`
}

Packages struct {
Package PackageWithLicenses `json:"package" edn:"package"`
}

PackageWithLicenses struct {
Licenses []string `json:"licenses" edn:"licenses"`
Name string `json:"name" edn:"name"`
Namespace *string `json:"namespace" edn:"namespace"`
Version string `json:"version" edn:"version"`
Purl string `json:"purl" edn:"purl"`
Type string `json:"type" edn:"type"`
Vulnerabilities []Vulnerability `json:"vulnerabilities" edn:"vulnerabilities"`
}

Vulnerability struct {
Cvss Cvss `json:"cvss"`
FixedBy *string `json:"fixedBy"`
PublishedAt string `json:"publishedAt"`
Source string `json:"source"`
SourceID string `json:"sourceId"`
UpdatedAt string `json:"updatedAt"`
URL *string `json:"url"`
VulnerableRange string `json:"vulnerableRange"`
}

Cvss struct {
Severity *string `json:"severity"`
Score *float32 `json:"score"`
}

VulnerabilitiesByPackageResponse struct {
VulnerabilitiesByPackage []VulnerabilitiesByPackage `json:"vulnerabilitiesByPackage"`
}

VulnerabilitiesByPackage struct {
Purl string `json:"purl"`
Vulnerabilities []Vulnerability `json:"vulnerabilities"`
}
)

func MockImagePackagesByDigest(ctx context.Context, req skill.RequestContext, sbomPkgs []Package) (ImagePackagesByDigestResponse, error) {
// separated for testing
ds, err := data.NewSyncGraphqlDataSource(ctx, req)
if err != nil {
return ImagePackagesByDigestResponse{}, err
}

return mockImagePackagesByDigest(ctx, req, sbomPkgs, ds)
}

func mockImagePackagesByDigest(ctx context.Context, req skill.RequestContext, sbomPkgs []Package, ds data.DataSource) (ImagePackagesByDigestResponse, error) {
chrispatrick marked this conversation as resolved.
Show resolved Hide resolved
purls := []string{}
for _, p := range sbomPkgs {
purls = append(purls, p.Purl)
}

var vulnsResponse VulnerabilitiesByPackageResponse
_, err := ds.Query(ctx, vulnerabilitiesByPackageQueryName, vulnerabilitiesByPackageQuery, map[string]interface{}{
"context": data.GqlContext(req),
"packageUrls": purls,
}, &vulnsResponse)
if err != nil {
return ImagePackagesByDigestResponse{}, err
}

vulns := map[string][]Vulnerability{}
for _, v := range vulnsResponse.VulnerabilitiesByPackage {
vulns[v.Purl] = v.Vulnerabilities
}

pkgs := []Packages{}
for _, a := range sbomPkgs {
ns := a.Namespace
pkgs = append(pkgs, Packages{
Package: PackageWithLicenses{
Licenses: a.Licenses,
Name: a.Name,
Namespace: &ns,
Version: a.Version,
Purl: a.Purl,
Type: a.Type,
Vulnerabilities: vulns[a.Purl],
},
})
}

return ImagePackagesByDigestResponse{
ImagePackagesByDigest: &ImagePackagesByDigest{
ImagePackages: ImagePackages{
Packages: pkgs,
},
},
}, nil
}
110 changes: 110 additions & 0 deletions policy/policy_handler/legacy/image_packages_by_digest_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package legacy

import (
"context"
"github.com/atomist-skills/go-skill"
"github.com/atomist-skills/go-skill/internal/test_util"
"github.com/atomist-skills/go-skill/policy/data"
"github.com/stretchr/testify/assert"
"testing"
)

type MockDs struct {
t *testing.T
}

func (ds MockDs) Query(ctx context.Context, queryName string, query string, variables map[string]interface{}, output interface{}) (*data.QueryResponse, error) {
assert.Equal(ds.t, queryName, vulnerabilitiesByPackageQueryName)
assert.Equal(ds.t, query, vulnerabilitiesByPackageQuery)

r := output.(*VulnerabilitiesByPackageResponse)
r.VulnerabilitiesByPackage = []VulnerabilitiesByPackage{
{
Purl: "pkg:deb/ubuntu/libpcre3@2:8.39-12ubuntu0.1?arch=amd64&upstream=pcre3&distro=ubuntu-20.04",
Vulnerabilities: []Vulnerability{{
Cvss: Cvss{
Severity: test_util.Pointer("HIGH"),
Score: test_util.Pointer(float32(7.5)),
},
FixedBy: nil,
PublishedAt: "2017-07-10T11:29:00Z",
Source: "nist",
SourceID: "CVE-2017-11164",
UpdatedAt: "2023-04-12T11:15:00Z", // 2006-01-02T15:04:05Z07:00
URL: test_util.Pointer("https://scout.docker.com/v/CVE-2017-11164"),
VulnerableRange: ">=0",
}},
},
}

return &data.QueryResponse{}, nil
}

func Test_mockImagePackagesByDigest(t *testing.T) {
lPkgs := []Package{
{
Licenses: []string{"GPL-3.0"},
Name: "libpcre3",
Namespace: "pkgNamespace",
Version: "2:8.39-12ubuntu0.1",
Purl: "pkg:deb/ubuntu/libpcre3@2:8.39-12ubuntu0.1?arch=amd64&upstream=pcre3&distro=ubuntu-20.04",
Type: "pkgType",
},
{
Licenses: []string{"AGPL"},
Name: "coreutils",
Namespace: "coreutilsNamespace",
Version: "8.30-3ubuntu2",
Purl: "pkg:deb/ubuntu/[email protected]?arch=amd64&distro=ubuntu-20.04",
Type: "coreutilsType",
},
}

actual, err := mockImagePackagesByDigest(context.TODO(), skill.RequestContext{}, lPkgs, MockDs{t})
assert.NoError(t, err)

expected := ImagePackagesByDigestResponse{
ImagePackagesByDigest: &ImagePackagesByDigest{
ImagePackages: ImagePackages{
Packages: []Packages{
{
Package: PackageWithLicenses{
Licenses: []string{"GPL-3.0"},
Name: "libpcre3",
Namespace: test_util.Pointer("pkgNamespace"),
Version: "2:8.39-12ubuntu0.1",
Purl: "pkg:deb/ubuntu/libpcre3@2:8.39-12ubuntu0.1?arch=amd64&upstream=pcre3&distro=ubuntu-20.04",
Type: "pkgType",
Vulnerabilities: []Vulnerability{{
Cvss: Cvss{
Severity: test_util.Pointer("HIGH"),
Score: test_util.Pointer(float32(7.5)),
},
FixedBy: nil,
PublishedAt: "2017-07-10T11:29:00Z",
Source: "nist",
SourceID: "CVE-2017-11164",
UpdatedAt: "2023-04-12T11:15:00Z", // 2006-01-02T15:04:05Z07:00
URL: test_util.Pointer("https://scout.docker.com/v/CVE-2017-11164"),
VulnerableRange: ">=0",
}},
},
},
{
Package: PackageWithLicenses{
Licenses: []string{"AGPL"},
Name: "coreutils",
Namespace: test_util.Pointer("coreutilsNamespace"),
Version: "8.30-3ubuntu2",
Purl: "pkg:deb/ubuntu/[email protected]?arch=amd64&distro=ubuntu-20.04",
Type: "coreutilsType",
Vulnerabilities: nil,
},
},
},
},
},
}

assert.Equal(t, expected, actual)
}
38 changes: 32 additions & 6 deletions policy/policy_handler/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,22 @@ package policy_handler

import (
"context"
"encoding/json"
"fmt"
"github.com/atomist-skills/go-skill"
"github.com/atomist-skills/go-skill/policy/data"
"github.com/atomist-skills/go-skill/policy/goals"
"github.com/atomist-skills/go-skill/policy/policy_handler/legacy"
"olympos.io/encoding/edn"
)

const eventNameLocalEval = "evaluate_goals_locally"

type SyncRequestMetadata struct {
QueryResults map[edn.Keyword]edn.RawMessage `edn:"fixedQueryResults"`
Packages []legacy.Package `edn:"packages"` // todo remove when no longer used
User string `edn:"imgConfigUser"` // The user from the image config blob // todo remove when no longer used
}

func WithLocal() Opt {
return func(h *EventHandler) {
h.subscriptionNames = append(h.subscriptionNames, eventNameLocalEval)
Expand Down Expand Up @@ -43,14 +50,33 @@ func buildLocalDataSources(ctx context.Context, req skill.RequestContext, evalMe
return []data.DataSource{}, nil
}

metaFixedData := map[string][]byte{}
for k, v := range req.Event.Context.SyncRequest.Metadata {
metaFixedData[string(k)] = v
var srMeta SyncRequestMetadata
err := edn.Unmarshal(req.Event.Context.SyncRequest.Metadata, &srMeta)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal SyncRequest metadata: %w", err)
}

fixedQueryResults := map[string][]byte{}
for k, v := range srMeta.QueryResults {
fixedQueryResults[string(k)] = v
}

if _, ok := fixedQueryResults[legacy.ImagePackagesByDigestQueryName]; !ok && len(srMeta.Packages) != 0 {
mockedQueryResult, err := legacy.MockImagePackagesByDigest(ctx, req, srMeta.Packages)
if err != nil {
return nil, err
}

pkgsEdn, err := edn.Marshal(mockedQueryResult)
if err != nil {
return nil, fmt.Errorf("failed to marshal mocked query %s: %w", legacy.ImagePackagesByDigestQueryName, err)
}

fixedQueryResults[legacy.ImagePackagesByDigestQueryName] = pkgsEdn
}
fixedDs := data.NewFixedDataSource(json.Unmarshal, metaFixedData)

return []data.DataSource{
fixedDs,
data.NewFixedDataSource(edn.Unmarshal, fixedQueryResults),
}, nil
}

Expand Down
Loading