Add reporting interface

This commit is contained in:
abhisek 2023-01-26 16:57:54 +05:30
parent 33fadddf2f
commit 73624a8a6e
No known key found for this signature in database
GPG Key ID: CB92A4990C02A88F
6 changed files with 178 additions and 5 deletions

6
pkg/policy/policy.go Normal file
View File

@ -0,0 +1,6 @@
package policy
type PolicyEvent struct {
}
type PolicyEventHandler func(event *PolicyEvent) error

83
pkg/reporter/markdown.go Normal file
View 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)
}

View 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
View 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
}

View File

@ -5,6 +5,7 @@ import (
"github.com/safedep/vet/pkg/common/logger"
"github.com/safedep/vet/pkg/common/utils"
"github.com/safedep/vet/pkg/models"
"github.com/safedep/vet/pkg/reporter"
)
type Config struct {
@ -17,15 +18,18 @@ type packageManifestScanner struct {
config Config
enrichers []PackageMetaEnricher
analyzers []analyzer.Analyzer
reporters []reporter.Reporter
}
func NewPackageManifestScanner(config Config,
enrichers []PackageMetaEnricher,
analyzers []analyzer.Analyzer) *packageManifestScanner {
analyzers []analyzer.Analyzer,
reporters []reporter.Reporter) *packageManifestScanner {
return &packageManifestScanner{
config: config,
enrichers: enrichers,
analyzers: analyzers,
reporters: reporters,
}
}
@ -72,18 +76,28 @@ func (s *packageManifestScanner) analyzeManifests(manifests []*models.PackageMan
err = s.analyzeManifest(manifest)
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)
}
}
s.finishReporting()
return nil
}
func (s *packageManifestScanner) analyzeManifest(manifest *models.PackageManifest) error {
for _, task := range s.analyzers {
err := task.Analyze(manifest, func(event *analyzer.AnalyzerEvent) error {
// Handle analyzer event
for _, r := range s.reporters {
r.AddAnalyzerEvent(event)
}
return nil
})
if err != nil {
@ -94,6 +108,23 @@ func (s *packageManifestScanner) analyzeManifest(manifest *models.PackageManifes
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 {
// FIXME: Potential deadlock situation in case of channel buffer is full
// because the goroutines perform both read and write to channel. Write occurs

21
scan.go
View File

@ -4,9 +4,11 @@ import (
"fmt"
"os"
"github.com/safedep/dry/utils"
"github.com/safedep/vet/pkg/analyzer"
"github.com/safedep/vet/pkg/common/logger"
"github.com/safedep/vet/pkg/parser"
"github.com/safedep/vet/pkg/reporter"
"github.com/safedep/vet/pkg/scanner"
"github.com/spf13/cobra"
)
@ -21,6 +23,7 @@ var (
dumpJsonManifest bool
dumpJsonManifestDir string
celFilterExpression string
markdownReportPath string
)
func newScanCommand() *cobra.Command {
@ -56,6 +59,8 @@ func newScanCommand() *cobra.Command {
"Dump dir for enriched JSON docs")
cmd.Flags().StringVarP(&celFilterExpression, "filter-cel", "", "",
"Filter and print packages using CEL")
cmd.Flags().StringVarP(&markdownReportPath, "report-markdown", "", "",
"Generate consolidated markdown report to file")
cmd.AddCommand(listParsersCommand())
return cmd
@ -96,7 +101,7 @@ func internalStartScan() error {
analyzers = append(analyzers, task)
}
if len(celFilterExpression) > 0 {
if !utils.IsEmptyString(celFilterExpression) {
task, err := analyzer.NewCelFilterAnalyzer(celFilterExpression)
if err != nil {
return err
@ -105,6 +110,18 @@ func internalStartScan() error {
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{
scanner.NewInsightBasedPackageEnricher(),
}
@ -113,7 +130,7 @@ func internalStartScan() error {
TransitiveAnalysis: transitiveAnalysis,
TransitiveDepth: transitiveDepth,
ConcurrentAnalyzer: concurrency,
}, enrichers, analyzers)
}, enrichers, analyzers, reporters)
var err error
if len(lockfiles) > 0 {