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

Decouple Trusty engine from Trusty SDK structs. #5011

Merged
merged 1 commit into from
Nov 20, 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
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ require (
golang.org/x/mod v0.22.0
golang.org/x/net v0.31.0 // indirect
golang.org/x/sys v0.27.0 // indirect
golang.org/x/text v0.20.0 // indirect
golang.org/x/text v0.20.0
google.golang.org/genproto/googleapis/rpc v0.0.0-20241104194629-dd2ea8efbc28 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
Expand Down
94 changes: 37 additions & 57 deletions internal/engine/eval/trusty/actions.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,9 @@ import (
"slices"
"strings"
template "text/template"
"unicode"

"github.com/google/go-github/v63/github"
"github.com/rs/zerolog"
trustytypes "github.com/stacklok/trusty-sdk-go/pkg/v1/types"

"github.com/mindersec/minder/internal/constants"
"github.com/mindersec/minder/internal/engine/eval/pr_actions"
Expand Down Expand Up @@ -194,7 +192,7 @@ type dependencyAlternatives struct {
BlockPR bool

// trustyReply is the complete response from trusty for this package
trustyReply *trustytypes.Reply
trustyReply *trustyReport
}

// summaryPrHandler is a prStatusHandler that adds a summary text to the PR as a comment.
Expand Down Expand Up @@ -276,8 +274,8 @@ func (sph *summaryPrHandler) generateSummary() (string, error) {
for _, alternative := range sph.trackedAlternatives {
if _, ok := lowScorePackages[alternative.Dependency.Name]; !ok {
var score float64
if alternative.trustyReply.Summary.Score != nil {
score = *alternative.trustyReply.Summary.Score
if alternative.trustyReply.Score != nil {
score = *alternative.trustyReply.Score
}

packageUIURL, err := url.JoinPath(
Expand All @@ -300,37 +298,42 @@ func (sph *summaryPrHandler) generateSummary() (string, error) {
if slices.Contains(alternative.Reasons, TRUSTY_MALICIOUS_PKG) {
malicious = append(malicious, maliciousTemplateData{
templatePackageData: packageData,
Summary: alternative.trustyReply.PackageData.Malicious.Summary,
Details: preprocessDetails(alternative.trustyReply.PackageData.Malicious.Details),
Summary: alternative.trustyReply.Malicious.Summary,
Details: preprocessDetails(alternative.trustyReply.Malicious.Details),
})
continue
}

lowScorePackages[alternative.Dependency.Name] = templatePackage{
templatePackageData: packageData,
Deprecated: alternative.trustyReply.PackageData.Deprecated,
Archived: alternative.trustyReply.PackageData.Archived,
ScoreComponents: buildScoreMatrix(alternative),
Deprecated: alternative.trustyReply.IsDeprecated,
Archived: alternative.trustyReply.IsArchived,
ScoreComponents: buildScoreMatrix(alternative.trustyReply.ScoreComponents),
Alternatives: []templateAlternative{},
Provenance: buildProvenanceStruct(alternative.trustyReply),
}
}

for _, altData := range alternative.trustyReply.Alternatives.Packages {
if altData.Score <= lowScorePackages[alternative.Dependency.Name].Score {
for _, altData := range alternative.trustyReply.Alternatives {
// Note: now that the score is deprecated and
// effectively `nil` for all packages, this
// loop will always discard all alternatives,
// rendering the whole block dead code.
//
// Since (1) we don't have score anymore, and
// (2) we don't suggest malicious packages, I
// suggest getting rid of this check
// altogether.
if altData.Score != nil && *altData.Score <= lowScorePackages[alternative.Dependency.Name].Score {
continue
}

altPackageData := templateAlternative{
templatePackageData: templatePackageData{
Ecosystem: alternative.Dependency.Ecosystem.AsString(),
Ecosystem: altData.PackageType,
PackageName: altData.PackageName,
TrustyURL: fmt.Sprintf(
"%s%s/%s", constants.TrustyHttpURL,
strings.ToLower(alternative.Dependency.Ecosystem.AsString()),
url.PathEscape(altData.PackageName),
),
Score: altData.Score,
TrustyURL: altData.TrustyURL,
Score: *altData.Score,
},
}

Expand All @@ -344,27 +347,27 @@ func (sph *summaryPrHandler) generateSummary() (string, error) {
}

// buildProvenanceStruct builds the provenance data structure for the PR template
func buildProvenanceStruct(r *trustytypes.Reply) *templateProvenance {
func buildProvenanceStruct(r *trustyReport) *templateProvenance {
if r == nil || r.Provenance == nil {
return nil
}
var provenance *templateProvenance
if r.Provenance != nil {
provenance = &templateProvenance{}
if r.Provenance.Description.Historical.Overlap != 0 {
if r.Provenance.Historical != nil && r.Provenance.Historical.Overlap != 0 {
provenance.Historical = &templateHistoricalProvenance{
NumVersions: int(r.Provenance.Description.Historical.Versions),
NumTags: int(r.Provenance.Description.Historical.Tags),
MatchedVersions: int(r.Provenance.Description.Historical.Common),
NumVersions: int(r.Provenance.Historical.Versions),
NumTags: int(r.Provenance.Historical.Tags),
MatchedVersions: int(r.Provenance.Historical.Common),
}
}

if r.Provenance.Description.Sigstore.Issuer != "" {
if r.Provenance.Sigstore != nil && r.Provenance.Sigstore.Issuer != "" {
provenance.Sigstore = &templateSigstoreProvenance{
SourceRepository: r.Provenance.Description.Sigstore.SourceRepository,
Workflow: r.Provenance.Description.Sigstore.Workflow,
Issuer: r.Provenance.Description.Sigstore.Issuer,
RekorURI: r.Provenance.Description.Sigstore.Transparency,
SourceRepository: r.Provenance.Sigstore.SourceRepository,
Workflow: r.Provenance.Sigstore.Workflow,
Issuer: r.Provenance.Sigstore.Issuer,
RekorURI: r.Provenance.Sigstore.RekorURI,
}
}

Expand All @@ -377,35 +380,12 @@ func buildProvenanceStruct(r *trustytypes.Reply) *templateProvenance {

// buildScoreMatrix builds the score components matrix that populates
// the score table in the PR comment template
func buildScoreMatrix(alternative dependencyAlternatives) []templateScoreComponent {
//
//nolint:gosimple // This code is legacy and should be removed
func buildScoreMatrix(components []scoreComponent) []templateScoreComponent {
scoreComp := []templateScoreComponent{}
if alternative.trustyReply.Summary.Description != nil {
for l, v := range alternative.trustyReply.Summary.Description {
switch l {
case "activity":
l = "Package activity"
case "activity_user":
l = "User activity"
case "provenance":
l = "Provenance"
case "typosquatting":
if v.(float64) > 5.00 {
continue
}
v = "⚠️ Dependency may be trying to impersonate a well known package"
l = "Typosquatting"
case "activity_repo":
l = "Repository activity"
default:
if len(l) > 1 {
l = string(unicode.ToUpper([]rune(l)[0])) + l[1:]
}
}
scoreComp = append(scoreComp, templateScoreComponent{
Label: l,
Value: v,
})
}
for _, component := range components {
scoreComp = append(scoreComp, templateScoreComponent(component))
}
return scoreComp
}
Expand Down
68 changes: 29 additions & 39 deletions internal/engine/eval/trusty/actions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ package trusty
import (
"testing"

trustytypes "github.com/stacklok/trusty-sdk-go/pkg/v1/types"
"github.com/stretchr/testify/require"

v1 "github.com/mindersec/minder/pkg/api/protobuf/go/minder/v1"
Expand All @@ -26,28 +25,25 @@ func TestBuildProvenanceStruct(t *testing.T) {
t.Parallel()
for _, tc := range []struct {
name string
sut *trustytypes.Reply
sut *trustyReport
mustNil bool
expected *templateProvenance
}{
{
name: "full-response",
sut: &trustytypes.Reply{
Provenance: &trustytypes.Provenance{
Score: 8.0,
Description: trustytypes.ProvenanceDescription{
Historical: trustytypes.HistoricalProvenance{
Tags: 10,
Common: 8,
Overlap: 80,
Versions: 10,
},
Sigstore: trustytypes.SigstoreProvenance{
Issuer: "CN=sigstore-intermediate,O=sigstore.dev",
Workflow: ".github/workflows/build_and_deploy.yml",
SourceRepository: "https://github.com/vercel/next.js",
Transparency: "https://search.sigstore.dev/?logIndex=88381843",
},
sut: &trustyReport{
Provenance: &provenance{
Historical: &historicalProvenance{
Tags: 10,
Common: 8,
Overlap: 80,
Versions: 10,
},
Sigstore: &sigstoreProvenance{
Issuer: "CN=sigstore-intermediate,O=sigstore.dev",
Workflow: ".github/workflows/build_and_deploy.yml",
SourceRepository: "https://github.com/vercel/next.js",
RekorURI: "https://search.sigstore.dev/?logIndex=88381843",
},
},
},
Expand All @@ -68,16 +64,13 @@ func TestBuildProvenanceStruct(t *testing.T) {
},
{
name: "only-historical",
sut: &trustytypes.Reply{
Provenance: &trustytypes.Provenance{
Score: 8.0,
Description: trustytypes.ProvenanceDescription{
Historical: trustytypes.HistoricalProvenance{
Tags: 10,
Common: 8,
Overlap: 80,
Versions: 10,
},
sut: &trustyReport{
Provenance: &provenance{
Historical: &historicalProvenance{
Tags: 10,
Common: 8,
Overlap: 80,
Versions: 10,
},
},
},
Expand All @@ -92,16 +85,13 @@ func TestBuildProvenanceStruct(t *testing.T) {
},
{
name: "only-sigstore",
sut: &trustytypes.Reply{
Provenance: &trustytypes.Provenance{
Score: 8.0,
Description: trustytypes.ProvenanceDescription{
Sigstore: trustytypes.SigstoreProvenance{
Issuer: "CN=sigstore-intermediate,O=sigstore.dev",
Workflow: ".github/workflows/build_and_deploy.yml",
SourceRepository: "https://github.com/vercel/next.js",
Transparency: "https://search.sigstore.dev/?logIndex=88381843",
},
sut: &trustyReport{
Provenance: &provenance{
Sigstore: &sigstoreProvenance{
Issuer: "CN=sigstore-intermediate,O=sigstore.dev",
Workflow: ".github/workflows/build_and_deploy.yml",
SourceRepository: "https://github.com/vercel/next.js",
RekorURI: "https://search.sigstore.dev/?logIndex=88381843",
},
},
},
Expand All @@ -122,7 +112,7 @@ func TestBuildProvenanceStruct(t *testing.T) {
},
{
name: "no-provenance",
sut: &trustytypes.Reply{},
sut: &trustyReport{},
mustNil: true,
},
} {
Expand Down
Loading