mirror of
https://github.com/safedep/vet.git
synced 2025-12-12 04:24:39 -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) ||
|
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)
|
(scorecard.scores.Maintained == 0)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@ -27,7 +27,7 @@ type celFilterAnalyzer struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewCelFilterAnalyzer(fl string, failOnMatch bool) (Analyzer, error) {
|
func NewCelFilterAnalyzer(fl string, failOnMatch bool) (Analyzer, error) {
|
||||||
evaluator, err := filter.NewEvaluator("single-filter")
|
evaluator, err := filter.NewEvaluator("single-filter", true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,18 +1,26 @@
|
|||||||
package analyzer
|
package analyzer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/jedib0t/go-pretty/v6/table"
|
||||||
"github.com/safedep/dry/utils"
|
"github.com/safedep/dry/utils"
|
||||||
"github.com/safedep/vet/gen/filtersuite"
|
"github.com/safedep/vet/gen/filtersuite"
|
||||||
"github.com/safedep/vet/pkg/analyzer/filter"
|
"github.com/safedep/vet/pkg/analyzer/filter"
|
||||||
"github.com/safedep/vet/pkg/models"
|
"github.com/safedep/vet/pkg/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type celFilterMatchedPackage struct {
|
||||||
|
pkg *models.Package
|
||||||
|
filterName string
|
||||||
|
}
|
||||||
|
|
||||||
type celFilterSuiteAnalyzer struct {
|
type celFilterSuiteAnalyzer struct {
|
||||||
evaluator filter.Evaluator
|
evaluator filter.Evaluator
|
||||||
suite *filtersuite.FilterSuite
|
suite *filtersuite.FilterSuite
|
||||||
failOnMatch bool
|
failOnMatch bool
|
||||||
|
matchedPackages map[string]*celFilterMatchedPackage
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCelFilterSuiteAnalyzer(path string, failOnMatch bool) (Analyzer, error) {
|
func NewCelFilterSuiteAnalyzer(path string, failOnMatch bool) (Analyzer, error) {
|
||||||
@ -21,7 +29,7 @@ func NewCelFilterSuiteAnalyzer(path string, failOnMatch bool) (Analyzer, error)
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
evaluator, err := filter.NewEvaluator(fs.GetName())
|
evaluator, err := filter.NewEvaluator(fs.GetName(), true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -37,6 +45,7 @@ func NewCelFilterSuiteAnalyzer(path string, failOnMatch bool) (Analyzer, error)
|
|||||||
evaluator: evaluator,
|
evaluator: evaluator,
|
||||||
suite: fs,
|
suite: fs,
|
||||||
failOnMatch: failOnMatch,
|
failOnMatch: failOnMatch,
|
||||||
|
matchedPackages: make(map[string]*celFilterMatchedPackage),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,13 +55,68 @@ func (f *celFilterSuiteAnalyzer) Name() string {
|
|||||||
|
|
||||||
func (f *celFilterSuiteAnalyzer) Analyze(manifest *models.PackageManifest,
|
func (f *celFilterSuiteAnalyzer) Analyze(manifest *models.PackageManifest,
|
||||||
handler AnalyzerEventHandler) error {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *celFilterSuiteAnalyzer) Finish() error {
|
func (f *celFilterSuiteAnalyzer) Finish() error {
|
||||||
|
f.renderMatchTable()
|
||||||
return nil
|
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
|
// To correctly unmarshal a []byte into protobuf message, we must use
|
||||||
// protobuf SDK and not generic JSON / YAML decoder. Since there is no
|
// protobuf SDK and not generic JSON / YAML decoder. Since there is no
|
||||||
// officially supported yamlpb, equivalent to jsonpb, we convert YAML
|
// officially supported yamlpb, equivalent to jsonpb, we convert YAML
|
||||||
|
|||||||
@ -29,7 +29,7 @@ func TestLoadFilterSuiteFromFile(t *testing.T) {
|
|||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
0,
|
0,
|
||||||
"unknown field \"A\" in FilterSuite",
|
"unknown field",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filter suite does not exists",
|
"filter suite does not exists",
|
||||||
|
|||||||
@ -40,9 +40,10 @@ type filterEvaluator struct {
|
|||||||
name string
|
name string
|
||||||
env *cel.Env
|
env *cel.Env
|
||||||
programs []*filterProgram
|
programs []*filterProgram
|
||||||
|
ignoreError bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewEvaluator(name string) (Evaluator, error) {
|
func NewEvaluator(name string, ignoreError bool) (Evaluator, error) {
|
||||||
env, err := cel.NewEnv(
|
env, err := cel.NewEnv(
|
||||||
cel.Variable(filterInputVarPkg, cel.DynType),
|
cel.Variable(filterInputVarPkg, cel.DynType),
|
||||||
cel.Variable(filterInputVarVulns, cel.DynType),
|
cel.Variable(filterInputVarVulns, cel.DynType),
|
||||||
@ -60,6 +61,7 @@ func NewEvaluator(name string) (Evaluator, error) {
|
|||||||
name: name,
|
name: name,
|
||||||
env: env,
|
env: env,
|
||||||
programs: []*filterProgram{},
|
programs: []*filterProgram{},
|
||||||
|
ignoreError: ignoreError,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,6 +110,12 @@ func (f *filterEvaluator) EvalPackage(pkg *models.Package) (*filterEvaluationRes
|
|||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
logger.Warnf("CEL evaluator error: %s", err.Error())
|
||||||
|
|
||||||
|
if f.ignoreError {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,7 +127,6 @@ func (f *filterEvaluator) EvalPackage(pkg *models.Package) (*filterEvaluationRes
|
|||||||
program: prog,
|
program: prog,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return &filterEvaluationResult{
|
return &filterEvaluationResult{
|
||||||
|
|||||||
@ -8,3 +8,11 @@ type filterEvaluationResult struct {
|
|||||||
func (r *filterEvaluationResult) Matched() bool {
|
func (r *filterEvaluationResult) Matched() bool {
|
||||||
return r.match
|
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
|
- name: critical-or-high-vulns
|
||||||
value: |
|
value: |
|
||||||
vulns.critical.exists(p, true) || vulns.high.exists(p, true)
|
vulns.critical.exists(p, true) || vulns.high.exists(p, true)
|
||||||
- name: ossf-best-practices
|
- name: low-popularity
|
||||||
value: |
|
value: |
|
||||||
(scorecard.scores["Maintained"] == 0) ||
|
projects.exists(p, (p.type == "GITHUB") && (p.stars < 10))
|
||||||
(scorecard.scores["Binary-Artifacts"] == 0) ||
|
|
||||||
(scorecard.scores["Branch-Protection"] == 0) ||
|
|
||||||
(scorecard.scores["Code-Review"] == 0) ||
|
|
||||||
(scorecard.scores["Dangerous-Workflow"] == 0)
|
|
||||||
- name: risky-oss-licenses
|
- name: risky-oss-licenses
|
||||||
value: |
|
value: |
|
||||||
licenses.exists(p, p == "GPL-2.0") ||
|
licenses.exists(p, p == "GPL-2.0") ||
|
||||||
licenses.exists(p, p == "GPL-3.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