mirror of
https://github.com/safedep/vet.git
synced 2025-12-10 00:22:08 -06:00
Add analysis rules for filter suite analyzer
This commit is contained in:
parent
2e9b5fb8e0
commit
2ca64478cf
@ -110,11 +110,7 @@ To express this policy, multiple filters are needed such as:
|
||||
|
||||
```
|
||||
vulns.critical.exists(p, true) ||
|
||||
|
||||
licenses.exists(p,
|
||||
(p != "MIT") && (p != "Apache-2.0")
|
||||
) ||
|
||||
|
||||
licenses.exists(p, (p != "MIT") && (p != "Apache-2.0")) ||
|
||||
(scorecard.scores.Maintained == 0)
|
||||
```
|
||||
|
||||
|
||||
@ -27,7 +27,7 @@ type celFilterAnalyzer struct {
|
||||
}
|
||||
|
||||
func NewCelFilterAnalyzer(fl string, failOnMatch bool) (Analyzer, error) {
|
||||
evaluator, err := filter.NewEvaluator("single-filter")
|
||||
evaluator, err := filter.NewEvaluator("single-filter", true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -1,18 +1,26 @@
|
||||
package analyzer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
"github.com/safedep/dry/utils"
|
||||
"github.com/safedep/vet/gen/filtersuite"
|
||||
"github.com/safedep/vet/pkg/analyzer/filter"
|
||||
"github.com/safedep/vet/pkg/models"
|
||||
)
|
||||
|
||||
type celFilterMatchedPackage struct {
|
||||
pkg *models.Package
|
||||
filterName string
|
||||
}
|
||||
|
||||
type celFilterSuiteAnalyzer struct {
|
||||
evaluator filter.Evaluator
|
||||
suite *filtersuite.FilterSuite
|
||||
failOnMatch bool
|
||||
evaluator filter.Evaluator
|
||||
suite *filtersuite.FilterSuite
|
||||
failOnMatch bool
|
||||
matchedPackages map[string]*celFilterMatchedPackage
|
||||
}
|
||||
|
||||
func NewCelFilterSuiteAnalyzer(path string, failOnMatch bool) (Analyzer, error) {
|
||||
@ -21,7 +29,7 @@ func NewCelFilterSuiteAnalyzer(path string, failOnMatch bool) (Analyzer, error)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
evaluator, err := filter.NewEvaluator(fs.GetName())
|
||||
evaluator, err := filter.NewEvaluator(fs.GetName(), true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -34,9 +42,10 @@ func NewCelFilterSuiteAnalyzer(path string, failOnMatch bool) (Analyzer, error)
|
||||
}
|
||||
|
||||
return &celFilterSuiteAnalyzer{
|
||||
evaluator: evaluator,
|
||||
suite: fs,
|
||||
failOnMatch: failOnMatch,
|
||||
evaluator: evaluator,
|
||||
suite: fs,
|
||||
failOnMatch: failOnMatch,
|
||||
matchedPackages: make(map[string]*celFilterMatchedPackage),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -46,13 +55,68 @@ func (f *celFilterSuiteAnalyzer) Name() string {
|
||||
|
||||
func (f *celFilterSuiteAnalyzer) Analyze(manifest *models.PackageManifest,
|
||||
handler AnalyzerEventHandler) error {
|
||||
|
||||
for _, pkg := range manifest.Packages {
|
||||
res, err := f.evaluator.EvalPackage(pkg)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if res.Matched() {
|
||||
f.queueMatchedPkg(pkg, res.GetMatchedFilter().Name())
|
||||
}
|
||||
}
|
||||
|
||||
if f.failOnMatch && (len(f.matchedPackages) > 0) {
|
||||
handler(&AnalyzerEvent{
|
||||
Source: f.Name(),
|
||||
Type: ET_AnalyzerFailOnError,
|
||||
Manifest: manifest,
|
||||
Err: fmt.Errorf("failed due to filter suite match on %s", manifest.Path),
|
||||
})
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *celFilterSuiteAnalyzer) Finish() error {
|
||||
f.renderMatchTable()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *celFilterSuiteAnalyzer) renderMatchTable() {
|
||||
tbl := table.NewWriter()
|
||||
tbl.SetStyle(table.StyleLight)
|
||||
tbl.SetOutputMirror(os.Stdout)
|
||||
tbl.AppendHeader(table.Row{"Ecosystem", "Package", "Latest",
|
||||
"Filter"})
|
||||
|
||||
for _, mp := range f.matchedPackages {
|
||||
insights := utils.SafelyGetValue(mp.pkg.Insights)
|
||||
tbl.AppendRow(table.Row{
|
||||
mp.pkg.PackageDetails.Ecosystem,
|
||||
fmt.Sprintf("%s@%s", mp.pkg.PackageDetails.Name,
|
||||
mp.pkg.PackageDetails.Version),
|
||||
utils.SafelyGetValue(insights.PackageCurrentVersion),
|
||||
mp.filterName,
|
||||
})
|
||||
}
|
||||
|
||||
tbl.Render()
|
||||
}
|
||||
|
||||
func (f *celFilterSuiteAnalyzer) queueMatchedPkg(pkg *models.Package,
|
||||
filterName string) {
|
||||
if _, ok := f.matchedPackages[pkg.Id()]; ok {
|
||||
return
|
||||
}
|
||||
|
||||
f.matchedPackages[pkg.Id()] = &celFilterMatchedPackage{
|
||||
filterName: filterName,
|
||||
pkg: pkg,
|
||||
}
|
||||
}
|
||||
|
||||
// To correctly unmarshal a []byte into protobuf message, we must use
|
||||
// protobuf SDK and not generic JSON / YAML decoder. Since there is no
|
||||
// officially supported yamlpb, equivalent to jsonpb, we convert YAML
|
||||
|
||||
@ -29,7 +29,7 @@ func TestLoadFilterSuiteFromFile(t *testing.T) {
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
"unknown field \"A\" in FilterSuite",
|
||||
"unknown field",
|
||||
},
|
||||
{
|
||||
"filter suite does not exists",
|
||||
|
||||
@ -37,12 +37,13 @@ type Evaluator interface {
|
||||
}
|
||||
|
||||
type filterEvaluator struct {
|
||||
name string
|
||||
env *cel.Env
|
||||
programs []*filterProgram
|
||||
name string
|
||||
env *cel.Env
|
||||
programs []*filterProgram
|
||||
ignoreError bool
|
||||
}
|
||||
|
||||
func NewEvaluator(name string) (Evaluator, error) {
|
||||
func NewEvaluator(name string, ignoreError bool) (Evaluator, error) {
|
||||
env, err := cel.NewEnv(
|
||||
cel.Variable(filterInputVarPkg, cel.DynType),
|
||||
cel.Variable(filterInputVarVulns, cel.DynType),
|
||||
@ -57,9 +58,10 @@ func NewEvaluator(name string) (Evaluator, error) {
|
||||
}
|
||||
|
||||
return &filterEvaluator{
|
||||
name: name,
|
||||
env: env,
|
||||
programs: []*filterProgram{},
|
||||
name: name,
|
||||
env: env,
|
||||
programs: []*filterProgram{},
|
||||
ignoreError: ignoreError,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -108,6 +110,12 @@ func (f *filterEvaluator) EvalPackage(pkg *models.Package) (*filterEvaluationRes
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
logger.Warnf("CEL evaluator error: %s", err.Error())
|
||||
|
||||
if f.ignoreError {
|
||||
continue
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -119,7 +127,6 @@ func (f *filterEvaluator) EvalPackage(pkg *models.Package) (*filterEvaluationRes
|
||||
program: prog,
|
||||
}, nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return &filterEvaluationResult{
|
||||
|
||||
@ -8,3 +8,11 @@ type filterEvaluationResult struct {
|
||||
func (r *filterEvaluationResult) Matched() bool {
|
||||
return r.match
|
||||
}
|
||||
|
||||
func (r *filterEvaluationResult) GetMatchedFilter() *filterProgram {
|
||||
if r.program == nil {
|
||||
return &filterProgram{}
|
||||
}
|
||||
|
||||
return r.program
|
||||
}
|
||||
|
||||
@ -6,15 +6,17 @@ filters:
|
||||
- name: critical-or-high-vulns
|
||||
value: |
|
||||
vulns.critical.exists(p, true) || vulns.high.exists(p, true)
|
||||
- name: ossf-best-practices
|
||||
- name: low-popularity
|
||||
value: |
|
||||
(scorecard.scores["Maintained"] == 0) ||
|
||||
(scorecard.scores["Binary-Artifacts"] == 0) ||
|
||||
(scorecard.scores["Branch-Protection"] == 0) ||
|
||||
(scorecard.scores["Code-Review"] == 0) ||
|
||||
(scorecard.scores["Dangerous-Workflow"] == 0)
|
||||
projects.exists(p, (p.type == "GITHUB") && (p.stars < 10))
|
||||
- name: risky-oss-licenses
|
||||
value: |
|
||||
licenses.exists(p, p == "GPL-2.0") ||
|
||||
licenses.exists(p, p == "GPL-3.0")
|
||||
- name: ossf-unmaintained
|
||||
value: |
|
||||
scorecard.scores["Maintained"] == 0
|
||||
- name: ossf-dangerous-workflow
|
||||
value: |
|
||||
scorecard.scores["Dangerous-Workflow"] == 0
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user