mirror of
https://github.com/safedep/vet.git
synced 2025-12-12 04:24:39 -06:00
commit
b47355bc03
30
docs/why-vet.md
Normal file
30
docs/why-vet.md
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# Why vet?
|
||||||
|
|
||||||
|
> It has been estimated that Free and Open Source Software (FOSS) constitutes 70-90% of any given piece of modern software solutions.
|
||||||
|
|
||||||
|
<!-- Problem Space -->
|
||||||
|
Product security practices target software developed and deployed internally.
|
||||||
|
They do not cover software consumed from external sources in form of libraries
|
||||||
|
from the Open Source ecosystem. The growing risk of vulnerable, unmaintained
|
||||||
|
and malicious dependencies establishes the need for product security teams to
|
||||||
|
vet 3rd party dependencies before consumption.
|
||||||
|
|
||||||
|
<!-- Current State -->
|
||||||
|
Vetting open source packages is largely a manual and opinionated process
|
||||||
|
involving engineering teams as the requester and security teams as the service
|
||||||
|
provider. A typical OSS vetting process involves auditing dependencies to
|
||||||
|
ensure security, popularity, license compliance, trusted publisher etc. The
|
||||||
|
manual nature of this activity increases cycle time and slows down engineering
|
||||||
|
velocity, especially for evolving products.
|
||||||
|
|
||||||
|
<!-- What vet aims to solve -->
|
||||||
|
`vet` tool solves the problem of OSS dependency vetting by providing a policy
|
||||||
|
driven automated analysis of libraries. It can be seamlessly integrated with
|
||||||
|
any CI tool or used in developer / security engineer's local environment.
|
||||||
|
|
||||||
|
:link: [Get Started](https://github.com/safedep/vet)
|
||||||
|
|
||||||
|
## Reference
|
||||||
|
|
||||||
|
* https://slsa.dev/spec/v0.1/threats
|
||||||
|
* https://www.linuxfoundation.org/blog/blog/a-summary-of-census-ii-open-source-software-application-libraries-the-world-depends-on
|
||||||
@ -71,6 +71,14 @@ func (f *celFilterAnalyzer) Analyze(manifest *models.PackageManifest,
|
|||||||
|
|
||||||
f.stat.IncMatchedPackage()
|
f.stat.IncMatchedPackage()
|
||||||
f.packages[pkg.Id()] = pkg
|
f.packages[pkg.Id()] = pkg
|
||||||
|
|
||||||
|
handler(&AnalyzerEvent{
|
||||||
|
Source: f.Name(),
|
||||||
|
Type: ET_FilterExpressionMatched,
|
||||||
|
Manifest: manifest,
|
||||||
|
Package: pkg,
|
||||||
|
Message: "cli-filter",
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@ -78,7 +78,7 @@ func (f *celFilterSuiteAnalyzer) Analyze(manifest *models.PackageManifest,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if res.Matched() {
|
if res.Matched() {
|
||||||
f.queueMatchedPkg(pkg, res.GetMatchedFilter().Name())
|
f.handleMatchedPkg(pkg, res.GetMatchedFilter().Name(), handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -123,8 +123,8 @@ func (f *celFilterSuiteAnalyzer) renderMatchTable() {
|
|||||||
tbl.Render()
|
tbl.Render()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *celFilterSuiteAnalyzer) queueMatchedPkg(pkg *models.Package,
|
func (f *celFilterSuiteAnalyzer) handleMatchedPkg(pkg *models.Package,
|
||||||
filterName string) {
|
filterName string, handler AnalyzerEventHandler) {
|
||||||
if _, ok := f.matchedPackages[pkg.Id()]; ok {
|
if _, ok := f.matchedPackages[pkg.Id()]; ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -134,6 +134,14 @@ func (f *celFilterSuiteAnalyzer) queueMatchedPkg(pkg *models.Package,
|
|||||||
filterName: filterName,
|
filterName: filterName,
|
||||||
pkg: pkg,
|
pkg: pkg,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handler(&AnalyzerEvent{
|
||||||
|
Source: f.Name(),
|
||||||
|
Type: ET_FilterExpressionMatched,
|
||||||
|
Manifest: pkg.Manifest,
|
||||||
|
Package: pkg,
|
||||||
|
Message: filterName,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// To correctly unmarshal a []byte into protobuf message, we must use
|
// To correctly unmarshal a []byte into protobuf message, we must use
|
||||||
|
|||||||
@ -3,3 +3,7 @@ package analyzer
|
|||||||
func (ev *AnalyzerEvent) IsFailOnError() bool {
|
func (ev *AnalyzerEvent) IsFailOnError() bool {
|
||||||
return ev.Type == ET_AnalyzerFailOnError
|
return ev.Type == ET_AnalyzerFailOnError
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ev *AnalyzerEvent) IsFilterMatch() bool {
|
||||||
|
return ev.Type == ET_FilterExpressionMatched
|
||||||
|
}
|
||||||
|
|||||||
@ -21,6 +21,12 @@ type MarkdownReportingConfig struct {
|
|||||||
Path string
|
Path string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type markdownTemplateInputViolation struct {
|
||||||
|
Ecosystem string
|
||||||
|
PkgName string
|
||||||
|
Message string
|
||||||
|
}
|
||||||
|
|
||||||
type markdownTemplateInputRemediation struct {
|
type markdownTemplateInputRemediation struct {
|
||||||
Pkg *models.Package
|
Pkg *models.Package
|
||||||
PkgRemediationName string
|
PkgRemediationName string
|
||||||
@ -36,6 +42,7 @@ type markdownTemplateInputResultSummary struct {
|
|||||||
type markdownTemplateInput struct {
|
type markdownTemplateInput struct {
|
||||||
Remediations map[string][]markdownTemplateInputRemediation
|
Remediations map[string][]markdownTemplateInputRemediation
|
||||||
Summary map[string]markdownTemplateInputResultSummary
|
Summary map[string]markdownTemplateInputResultSummary
|
||||||
|
Violations []markdownTemplateInputViolation
|
||||||
ManifestsCount int
|
ManifestsCount int
|
||||||
PackagesCount int
|
PackagesCount int
|
||||||
}
|
}
|
||||||
@ -47,6 +54,7 @@ type markdownReportGenerator struct {
|
|||||||
config MarkdownReportingConfig
|
config MarkdownReportingConfig
|
||||||
summaryReporter Reporter
|
summaryReporter Reporter
|
||||||
templateInput markdownTemplateInput
|
templateInput markdownTemplateInput
|
||||||
|
violations map[string]*analyzer.AnalyzerEvent
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMarkdownReportGenerator(config MarkdownReportingConfig) (Reporter, error) {
|
func NewMarkdownReportGenerator(config MarkdownReportingConfig) (Reporter, error) {
|
||||||
@ -54,6 +62,7 @@ func NewMarkdownReportGenerator(config MarkdownReportingConfig) (Reporter, error
|
|||||||
return &markdownReportGenerator{
|
return &markdownReportGenerator{
|
||||||
config: config,
|
config: config,
|
||||||
summaryReporter: summaryReporter,
|
summaryReporter: summaryReporter,
|
||||||
|
violations: make(map[string]*analyzer.AnalyzerEvent),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,7 +74,26 @@ func (r *markdownReportGenerator) AddManifest(manifest *models.PackageManifest)
|
|||||||
r.summaryReporter.AddManifest(manifest)
|
r.summaryReporter.AddManifest(manifest)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *markdownReportGenerator) AddAnalyzerEvent(event *analyzer.AnalyzerEvent) {}
|
func (r *markdownReportGenerator) AddAnalyzerEvent(event *analyzer.AnalyzerEvent) {
|
||||||
|
if !event.IsFilterMatch() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if event.Package == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if event.Package.Manifest == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
pkgId := event.Package.Id()
|
||||||
|
if _, ok := r.violations[pkgId]; ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
r.violations[pkgId] = event
|
||||||
|
}
|
||||||
|
|
||||||
func (r *markdownReportGenerator) AddPolicyEvent(event *policy.PolicyEvent) {}
|
func (r *markdownReportGenerator) AddPolicyEvent(event *policy.PolicyEvent) {}
|
||||||
|
|
||||||
@ -103,6 +131,20 @@ func (r *markdownReportGenerator) Finish() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
violations := []markdownTemplateInputViolation{}
|
||||||
|
for _, v := range r.violations {
|
||||||
|
var msg string
|
||||||
|
if msg, ok = v.Message.(string); !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
violations = append(violations, markdownTemplateInputViolation{
|
||||||
|
Ecosystem: v.Manifest.Ecosystem,
|
||||||
|
PkgName: fmt.Sprintf("%s@%s", v.Package.Name, v.Package.Version),
|
||||||
|
Message: msg,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
tmpl, err := template.New("markdown").Parse(markdownTemplate)
|
tmpl, err := template.New("markdown").Parse(markdownTemplate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -119,5 +161,6 @@ func (r *markdownReportGenerator) Finish() error {
|
|||||||
ManifestsCount: sr.summary.manifests,
|
ManifestsCount: sr.summary.manifests,
|
||||||
PackagesCount: sr.summary.packages,
|
PackagesCount: sr.summary.packages,
|
||||||
Summary: summaries,
|
Summary: summaries,
|
||||||
|
Violations: violations,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,6 +15,18 @@
|
|||||||
| {{ $key }} | {{ $value.Ecosystem }} | {{ $value.PackageCount }} | {{ $value.PackageWithIssuesCount }} |
|
| {{ $key }} | {{ $value.Ecosystem }} | {{ $value.PackageCount }} | {{ $value.PackageWithIssuesCount }} |
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
|
## Policy Violation
|
||||||
|
|
||||||
|
{{ if .Violations }}
|
||||||
|
| Ecosystem | Package | Reason |
|
||||||
|
|-----------|---------|--------|
|
||||||
|
{{- range $value := .Violations }}
|
||||||
|
| {{ $value.Ecosystem }} | {{ $value.PkgName }} | {{ $value.Message }} |
|
||||||
|
{{- end }}
|
||||||
|
{{ else }}
|
||||||
|
> No policy violation found or policy not configured during scan
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
## Remediation Advice
|
## Remediation Advice
|
||||||
|
|
||||||
The table below lists advice for dependency upgrade to mitigate one or more
|
The table below lists advice for dependency upgrade to mitigate one or more
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user