Skip to content

Commit

Permalink
feat: Add SLSA tag in summary report when available (#301)
Browse files Browse the repository at this point in the history
  • Loading branch information
abhisek authored Dec 28, 2024
1 parent 7daa072 commit 141e984
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 2 deletions.
23 changes: 23 additions & 0 deletions pkg/models/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,22 @@ func GetModelEcosystem(ecosystem packagev1.Ecosystem) string {
}
}

type ProvenanceType string

const (
ProvenanceTypeSlsa = ProvenanceType("slsa")
)

// Represents an abstract provenance of a package provided
// by different sources such as deps.dev or other sources
type Provenance struct {
Type ProvenanceType `json:"type"`
CommitSHA string `json:"commit_sha"`
SourceRepository string `json:"source_url"`
Url string `json:"url"`
Verified bool `json:"verified"`
}

// Represents a package such as a version of a library defined as a dependency
// in Gemfile.lock, pom.xml etc.
type Package struct {
Expand All @@ -317,6 +333,9 @@ type Package struct {
// Depth of this package in dependency tree
Depth int `json:"depth"`

// Optional provenances for this package
Provenances []*Provenance `json:"provenances"`

// Manifest from where this package was found directly or indirectly
Manifest *PackageManifest `json:"-"`
}
Expand Down Expand Up @@ -349,6 +368,10 @@ func (p *Package) GetVersion() string {
return p.Version
}

func (p *Package) GetProvenances() []*Provenance {
return p.Provenances
}

func (p *Package) ShortName() string {
return fmt.Sprintf("pkg:%s/%s@%s",
strings.ToLower(string(p.Ecosystem)),
Expand Down
60 changes: 58 additions & 2 deletions pkg/reporter/summary.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,12 @@ type summaryReporter struct {
unpopular int
drifts int
}

provenance struct {
none int
verified int
unverified int
}
}

// Map of pkgId and associated meta for building remediation advice
Expand Down Expand Up @@ -122,6 +128,7 @@ func (r *summaryReporter) AddManifest(manifest *models.PackageManifest) {
r.processForMalware(pkg)
r.processForPopularity(pkg)
r.processForVersionDrift(pkg)
r.processForProvenance(pkg)

r.summary.packages += 1
return nil
Expand Down Expand Up @@ -225,6 +232,27 @@ func (r *summaryReporter) processForMalware(pkg *models.Package) {
}
}

func (r *summaryReporter) processForProvenance(pkg *models.Package) {
if len(pkg.GetProvenances()) == 0 {
r.summary.provenance.none += 1
return
}

verified := false
for _, p := range pkg.GetProvenances() {
if p.Verified {
verified = true
break
}
}

if verified {
r.summary.provenance.verified += 1
} else {
r.summary.provenance.unverified += 1
}
}

func (r *summaryReporter) processForVulns(pkg *models.Package) {
insight := utils.SafelyGetValue(pkg.Insights)
vulns := utils.SafelyGetValue(insight.Vulnerabilities)
Expand Down Expand Up @@ -304,6 +332,8 @@ func (r *summaryReporter) Finish() error {
fmt.Println()
fmt.Println(text.FgHiYellow.Sprint(summaryListPrependText, r.popularityCountStatement()))
fmt.Println()
fmt.Println(text.FgHiYellow.Sprint(summaryListPrependText, r.provenanceStatement()))
fmt.Println()
fmt.Println(text.FgHiYellow.Sprint(summaryListPrependText, r.majorVersionDriftStatement()))
fmt.Println()
fmt.Println(text.Faint.Sprint(summaryListPrependText, r.manifestCountStatement()))
Expand Down Expand Up @@ -421,7 +451,7 @@ func (r *summaryReporter) renderRemediationAdvice() {
return
}

fmt.Println(text.Bold.Sprint("Consider upgrading the following libraries for maximum impact:"))
fmt.Println(text.Bold.Sprint(fmt.Sprintf("Top %d libraries to upgrade ...", r.config.MaxAdvice)))
fmt.Println()

tbl := table.NewWriter()
Expand Down Expand Up @@ -472,7 +502,7 @@ func (r *summaryReporter) addRemediationAdviceTableRows(tbl table.Writer,
// Add the package as a table row
tbl.AppendRow(table.Row{
string(sp.pkg.Ecosystem),
r.packageNameForRemediationAdvice(sp.pkg),
r.packageNameForRemediationAdvice(sp.pkg) + " " + r.slsaTagFor(sp.pkg),
r.packageUpdateVersionForRemediationAdvice(sp.pkg),
sp.score,
r.packageVulnerabilityRiskText(sp.pkg),
Expand Down Expand Up @@ -607,6 +637,26 @@ func (r *summaryReporter) packageNameForRemediationAdvice(pkg *models.Package) s
pkg.PackageDetails.Version)
}

func (r *summaryReporter) slsaTagFor(pkg *models.Package) string {
var slsaProvenance *models.Provenance
for _, p := range pkg.GetProvenances() {
if p.Type == models.ProvenanceTypeSlsa {
slsaProvenance = p
break
}
}

if slsaProvenance != nil {
if slsaProvenance.Verified {
return text.BgGreen.Sprint(" slsa: verified ")
} else {
return text.BgRed.Sprint(" slsa: unverified ")
}
}

return ""
}

func (r *summaryReporter) packageUpdateVersionForRemediationAdvice(pkg *models.Package) string {
insight := utils.SafelyGetValue(pkg.Insights)
insightsCurrentVersion := utils.SafelyGetValue(insight.PackageCurrentVersion)
Expand Down Expand Up @@ -640,6 +690,12 @@ func (r *summaryReporter) popularityCountStatement() string {
r.summary.metrics.unpopular)
}

func (r *summaryReporter) provenanceStatement() string {
return fmt.Sprintf("Provenance: %d verified, %d unverified, %d missing",
r.summary.provenance.verified, r.summary.provenance.unverified,
r.summary.provenance.none)
}

func (r *summaryReporter) majorVersionDriftStatement() string {
return fmt.Sprintf("%d libraries are out of date with major version drift in direct dependencies",
r.summary.metrics.drifts)
Expand Down
24 changes: 24 additions & 0 deletions pkg/scanner/enrich_insightsv2.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,35 @@ func (e *insightsBasedPackageEnricherV2) applyInsights(pkg *models.Package,
// Apply the V1 insights to the package
pkg.Insights = insightsv1

// Apply provenance if available
pkg.Provenances = e.getProvenances(res)

// Finally, store the new insights model :)
pkg.InsightsV2 = res.GetInsight()
return nil
}

func (e *insightsBasedPackageEnricherV2) getProvenances(res *insightsv2.GetPackageVersionInsightResponse) []*models.Provenance {
pkgProvenances := []*models.Provenance{}

provenances := res.GetInsight().GetSlsaProvenances()
if len(provenances) == 0 {
return pkgProvenances
}

for _, p := range provenances {
pkgProvenances = append(pkgProvenances, &models.Provenance{
Type: models.ProvenanceTypeSlsa,
SourceRepository: p.GetSourceRepository(),
CommitSHA: p.GetCommitSha(),
Url: p.GetUrl(),
Verified: p.GetVerified(),
})
}

return pkgProvenances
}

func (e *insightsBasedPackageEnricherV2) convertInsightsV2ToV1(pvi *packagev1.PackageVersionInsight) (*insightapi.PackageVersionInsight, error) {
insights := &insightapi.PackageVersionInsight{}

Expand Down
1 change: 1 addition & 0 deletions test/scenarios/all.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ bash $E2E_THIS_DIR/scenario-4-lfp-fail-fast.sh
bash $E2E_THIS_DIR/scenario-5-gradle-depgraph-build.sh
bash $E2E_THIS_DIR/scenario-6-manifest-flag.sh
bash $E2E_THIS_DIR/scenario-7-rubygems-project-url.sh
bash $E2E_THIS_DIR/scenario-8-summary-report.sh
14 changes: 14 additions & 0 deletions test/scenarios/scenario-8-summary-report.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/bash

set -ex

if [ "$E2E_VET_INSIGHTS_V2" != "true" ]; then
echo "Skipping scenario-8-summary-report.sh as E2E_INSIGHTS_V2 is not set to true"
exit 0
fi

$(echo \
$E2E_VET_SCAN_CMD \
scan --purl pkg:/npm/@clerk/nextjs@6.9.6
) | grep "slsa: verified"

0 comments on commit 141e984

Please sign in to comment.