mirror of
https://github.com/safedep/vet.git
synced 2025-12-11 09:25:44 -06:00
Add reporting interface
This commit is contained in:
parent
33fadddf2f
commit
73624a8a6e
6
pkg/policy/policy.go
Normal file
6
pkg/policy/policy.go
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package policy
|
||||||
|
|
||||||
|
type PolicyEvent struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
type PolicyEventHandler func(event *PolicyEvent) error
|
||||||
83
pkg/reporter/markdown.go
Normal file
83
pkg/reporter/markdown.go
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
package reporter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
"text/template"
|
||||||
|
|
||||||
|
"github.com/safedep/vet/pkg/analyzer"
|
||||||
|
"github.com/safedep/vet/pkg/common/logger"
|
||||||
|
"github.com/safedep/vet/pkg/models"
|
||||||
|
"github.com/safedep/vet/pkg/policy"
|
||||||
|
|
||||||
|
_ "embed"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed markdown.template.md
|
||||||
|
var markdownTemplate string
|
||||||
|
|
||||||
|
type MarkdownReportingConfig struct {
|
||||||
|
Path string
|
||||||
|
}
|
||||||
|
|
||||||
|
type markdownTemplateInput struct {
|
||||||
|
Manifests []*models.PackageManifest
|
||||||
|
AnalyzerEvents []*analyzer.AnalyzerEvent
|
||||||
|
PolicyEvents []*policy.PolicyEvent
|
||||||
|
}
|
||||||
|
|
||||||
|
type markdownReportGenerator struct {
|
||||||
|
m sync.Mutex
|
||||||
|
config MarkdownReportingConfig
|
||||||
|
templateInput markdownTemplateInput
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMarkdownReportGenerator(config MarkdownReportingConfig) (Reporter, error) {
|
||||||
|
return &markdownReportGenerator{
|
||||||
|
config: config,
|
||||||
|
templateInput: markdownTemplateInput{
|
||||||
|
Manifests: make([]*models.PackageManifest, 0),
|
||||||
|
AnalyzerEvents: make([]*analyzer.AnalyzerEvent, 0),
|
||||||
|
PolicyEvents: make([]*policy.PolicyEvent, 0),
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *markdownReportGenerator) Name() string {
|
||||||
|
return "Markdown Report Generator"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *markdownReportGenerator) AddManifest(manifest *models.PackageManifest) {
|
||||||
|
r.m.Lock()
|
||||||
|
defer r.m.Unlock()
|
||||||
|
r.templateInput.Manifests = append(r.templateInput.Manifests, manifest)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *markdownReportGenerator) AddAnalyzerEvent(event *analyzer.AnalyzerEvent) {
|
||||||
|
r.m.Lock()
|
||||||
|
defer r.m.Unlock()
|
||||||
|
r.templateInput.AnalyzerEvents = append(r.templateInput.AnalyzerEvents, event)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *markdownReportGenerator) AddPolicyEvent(event *policy.PolicyEvent) {
|
||||||
|
r.m.Lock()
|
||||||
|
defer r.m.Unlock()
|
||||||
|
r.templateInput.PolicyEvents = append(r.templateInput.PolicyEvents, event)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *markdownReportGenerator) Finish() error {
|
||||||
|
logger.Infof("Generating consolidated markdown report: %s", r.config.Path)
|
||||||
|
|
||||||
|
tmpl, err := template.New("markdown").Parse(markdownTemplate)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
file, err := os.Create(r.config.Path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer file.Close()
|
||||||
|
return tmpl.Execute(file, r.templateInput)
|
||||||
|
}
|
||||||
17
pkg/reporter/markdown.template.md
Normal file
17
pkg/reporter/markdown.template.md
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# Vet Report
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
* {{ len .Manifests }} manifest(s) were scanned
|
||||||
|
* {{ len .AnalyzerEvents }} analyzer event(s) were generated
|
||||||
|
* {{ len .PolicyEvents }} policy violation(s) were observed
|
||||||
|
|
||||||
|
## Details
|
||||||
|
|
||||||
|
The scan was performed on following manifests:
|
||||||
|
{{ range $m := .Manifests }}
|
||||||
|
* [{{ $m.Ecosystem }}] {{ $m.Path }}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
19
pkg/reporter/reporter.go
Normal file
19
pkg/reporter/reporter.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package reporter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/safedep/vet/pkg/analyzer"
|
||||||
|
"github.com/safedep/vet/pkg/models"
|
||||||
|
"github.com/safedep/vet/pkg/policy"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Reporter interface {
|
||||||
|
Name() string
|
||||||
|
|
||||||
|
// Feed collected data to reporting module
|
||||||
|
AddManifest(manifest *models.PackageManifest)
|
||||||
|
AddAnalyzerEvent(event *analyzer.AnalyzerEvent)
|
||||||
|
AddPolicyEvent(event *policy.PolicyEvent)
|
||||||
|
|
||||||
|
// Inform reporting module to finalise (e.g. write report to file)
|
||||||
|
Finish() error
|
||||||
|
}
|
||||||
@ -5,6 +5,7 @@ import (
|
|||||||
"github.com/safedep/vet/pkg/common/logger"
|
"github.com/safedep/vet/pkg/common/logger"
|
||||||
"github.com/safedep/vet/pkg/common/utils"
|
"github.com/safedep/vet/pkg/common/utils"
|
||||||
"github.com/safedep/vet/pkg/models"
|
"github.com/safedep/vet/pkg/models"
|
||||||
|
"github.com/safedep/vet/pkg/reporter"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
@ -17,15 +18,18 @@ type packageManifestScanner struct {
|
|||||||
config Config
|
config Config
|
||||||
enrichers []PackageMetaEnricher
|
enrichers []PackageMetaEnricher
|
||||||
analyzers []analyzer.Analyzer
|
analyzers []analyzer.Analyzer
|
||||||
|
reporters []reporter.Reporter
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPackageManifestScanner(config Config,
|
func NewPackageManifestScanner(config Config,
|
||||||
enrichers []PackageMetaEnricher,
|
enrichers []PackageMetaEnricher,
|
||||||
analyzers []analyzer.Analyzer) *packageManifestScanner {
|
analyzers []analyzer.Analyzer,
|
||||||
|
reporters []reporter.Reporter) *packageManifestScanner {
|
||||||
return &packageManifestScanner{
|
return &packageManifestScanner{
|
||||||
config: config,
|
config: config,
|
||||||
enrichers: enrichers,
|
enrichers: enrichers,
|
||||||
analyzers: analyzers,
|
analyzers: analyzers,
|
||||||
|
reporters: reporters,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,18 +76,28 @@ func (s *packageManifestScanner) analyzeManifests(manifests []*models.PackageMan
|
|||||||
|
|
||||||
err = s.analyzeManifest(manifest)
|
err = s.analyzeManifest(manifest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Errorf("Failed to analyze %s manifest %v : %v",
|
logger.Errorf("Failed to analyze %s manifest %s : %v",
|
||||||
|
manifest.Ecosystem, manifest.Path, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = s.reportManifest(manifest)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("Failed to report %s manifest %s : %v",
|
||||||
manifest.Ecosystem, manifest.Path, err)
|
manifest.Ecosystem, manifest.Path, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s.finishReporting()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *packageManifestScanner) analyzeManifest(manifest *models.PackageManifest) error {
|
func (s *packageManifestScanner) analyzeManifest(manifest *models.PackageManifest) error {
|
||||||
for _, task := range s.analyzers {
|
for _, task := range s.analyzers {
|
||||||
err := task.Analyze(manifest, func(event *analyzer.AnalyzerEvent) error {
|
err := task.Analyze(manifest, func(event *analyzer.AnalyzerEvent) error {
|
||||||
// Handle analyzer event
|
for _, r := range s.reporters {
|
||||||
|
r.AddAnalyzerEvent(event)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -94,6 +108,23 @@ func (s *packageManifestScanner) analyzeManifest(manifest *models.PackageManifes
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *packageManifestScanner) reportManifest(manifest *models.PackageManifest) error {
|
||||||
|
for _, r := range s.reporters {
|
||||||
|
r.AddManifest(manifest)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *packageManifestScanner) finishReporting() {
|
||||||
|
for _, r := range s.reporters {
|
||||||
|
err := r.Finish()
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("Reporter: %s failed with %v", r.Name(), err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (s *packageManifestScanner) enrichManifest(manifest *models.PackageManifest) error {
|
func (s *packageManifestScanner) enrichManifest(manifest *models.PackageManifest) error {
|
||||||
// FIXME: Potential deadlock situation in case of channel buffer is full
|
// FIXME: Potential deadlock situation in case of channel buffer is full
|
||||||
// because the goroutines perform both read and write to channel. Write occurs
|
// because the goroutines perform both read and write to channel. Write occurs
|
||||||
|
|||||||
21
scan.go
21
scan.go
@ -4,9 +4,11 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/safedep/dry/utils"
|
||||||
"github.com/safedep/vet/pkg/analyzer"
|
"github.com/safedep/vet/pkg/analyzer"
|
||||||
"github.com/safedep/vet/pkg/common/logger"
|
"github.com/safedep/vet/pkg/common/logger"
|
||||||
"github.com/safedep/vet/pkg/parser"
|
"github.com/safedep/vet/pkg/parser"
|
||||||
|
"github.com/safedep/vet/pkg/reporter"
|
||||||
"github.com/safedep/vet/pkg/scanner"
|
"github.com/safedep/vet/pkg/scanner"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
@ -21,6 +23,7 @@ var (
|
|||||||
dumpJsonManifest bool
|
dumpJsonManifest bool
|
||||||
dumpJsonManifestDir string
|
dumpJsonManifestDir string
|
||||||
celFilterExpression string
|
celFilterExpression string
|
||||||
|
markdownReportPath string
|
||||||
)
|
)
|
||||||
|
|
||||||
func newScanCommand() *cobra.Command {
|
func newScanCommand() *cobra.Command {
|
||||||
@ -56,6 +59,8 @@ func newScanCommand() *cobra.Command {
|
|||||||
"Dump dir for enriched JSON docs")
|
"Dump dir for enriched JSON docs")
|
||||||
cmd.Flags().StringVarP(&celFilterExpression, "filter-cel", "", "",
|
cmd.Flags().StringVarP(&celFilterExpression, "filter-cel", "", "",
|
||||||
"Filter and print packages using CEL")
|
"Filter and print packages using CEL")
|
||||||
|
cmd.Flags().StringVarP(&markdownReportPath, "report-markdown", "", "",
|
||||||
|
"Generate consolidated markdown report to file")
|
||||||
|
|
||||||
cmd.AddCommand(listParsersCommand())
|
cmd.AddCommand(listParsersCommand())
|
||||||
return cmd
|
return cmd
|
||||||
@ -96,7 +101,7 @@ func internalStartScan() error {
|
|||||||
analyzers = append(analyzers, task)
|
analyzers = append(analyzers, task)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(celFilterExpression) > 0 {
|
if !utils.IsEmptyString(celFilterExpression) {
|
||||||
task, err := analyzer.NewCelFilterAnalyzer(celFilterExpression)
|
task, err := analyzer.NewCelFilterAnalyzer(celFilterExpression)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -105,6 +110,18 @@ func internalStartScan() error {
|
|||||||
analyzers = append(analyzers, task)
|
analyzers = append(analyzers, task)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reporters := []reporter.Reporter{}
|
||||||
|
if !utils.IsEmptyString(markdownReportPath) {
|
||||||
|
rp, err := reporter.NewMarkdownReportGenerator(reporter.MarkdownReportingConfig{
|
||||||
|
Path: markdownReportPath,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
reporters = append(reporters, rp)
|
||||||
|
}
|
||||||
|
|
||||||
enrichers := []scanner.PackageMetaEnricher{
|
enrichers := []scanner.PackageMetaEnricher{
|
||||||
scanner.NewInsightBasedPackageEnricher(),
|
scanner.NewInsightBasedPackageEnricher(),
|
||||||
}
|
}
|
||||||
@ -113,7 +130,7 @@ func internalStartScan() error {
|
|||||||
TransitiveAnalysis: transitiveAnalysis,
|
TransitiveAnalysis: transitiveAnalysis,
|
||||||
TransitiveDepth: transitiveDepth,
|
TransitiveDepth: transitiveDepth,
|
||||||
ConcurrentAnalyzer: concurrency,
|
ConcurrentAnalyzer: concurrency,
|
||||||
}, enrichers, analyzers)
|
}, enrichers, analyzers, reporters)
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
if len(lockfiles) > 0 {
|
if len(lockfiles) > 0 {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user