Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,11 @@ process the vulnerability data. Use `-g` to generate the list of providers to pu
**note: you can skip the `pull` step if you already have a local cache of vulnerability data (with `make download-all-provider-cache`).**

The `build` command processes the cached vuln data generate a `vulnerability.db` sqlite3 file. Additionally, a `metadata.json`
is created that is used in packaging and curation of the database file by this application and downstream consuming applications.
is created that is used in packaging and curation of the database file by this application and downstream consuming applications
and a `provider-metadata.json` file is created that includes the last successful run date for each provider.
Use `-g` to generate the list of providers to pull based on the output of "vunnel list".

The `package` command archives the `vulnerability.db` and `metadata.json` files into a `tar.gz` file. Additionally, a `listing.json`
The `package` command archives the `vulnerability.db`, `metadata.json` and `provider-metadata.json` files into a `tar.gz` file. Additionally, a `listing.json`
is generated to aid in serving one or more database archives for downstream consumption, where the consuming application should
use the listing file to discover available archives available for download. The base URL used to create the download URL for each
database archive is controlled by the `package.base-url` configuration option.
Expand Down
6 changes: 3 additions & 3 deletions pkg/process/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func Build(cfg BuildConfig) error {
return err
}

writer, err := getWriter(cfg.SchemaVersion, cfg.Timestamp, cfg.Directory)
writer, err := getWriter(cfg.SchemaVersion, cfg.Timestamp, cfg.Directory, cfg.States)
if err != nil {
return err
}
Expand Down Expand Up @@ -106,7 +106,7 @@ func getProcessors(schemaVersion int) ([]data.Processor, error) {
}
}

func getWriter(schemaVersion int, dataAge time.Time, directory string) (data.Writer, error) {
func getWriter(schemaVersion int, dataAge time.Time, directory string, states provider.States) (data.Writer, error) {
switch schemaVersion {
case grypeDBv1.SchemaVersion:
return v1.NewWriter(directory, dataAge)
Expand All @@ -117,7 +117,7 @@ func getWriter(schemaVersion int, dataAge time.Time, directory string) (data.Wri
case grypeDBv4.SchemaVersion:
return v4.NewWriter(directory, dataAge)
case grypeDBv5.SchemaVersion:
return v5.NewWriter(directory, dataAge)
return v5.NewWriter(directory, dataAge, states)
default:
return nil, fmt.Errorf("unable to create writer: unsupported schema version: %+v", schemaVersion)
}
Expand Down
57 changes: 55 additions & 2 deletions pkg/process/v5/writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package v5

import (
"crypto/sha256"
"encoding/json"
"fmt"
"os"
"path"
"path/filepath"
"strings"
Expand All @@ -13,22 +15,36 @@ import (
"github.com/anchore/grype-db/internal/file"
"github.com/anchore/grype-db/internal/log"
"github.com/anchore/grype-db/pkg/data"
"github.com/anchore/grype-db/pkg/provider"
"github.com/anchore/grype/grype/db"
grypeDB "github.com/anchore/grype/grype/db/v5"
grypeDBStore "github.com/anchore/grype/grype/db/v5/store"
)

// TODO: add NVDNamespace const to grype.db package?
const nvdNamespace = "nvd:cpe"
const (
nvdNamespace = "nvd:cpe"
providerMetadataFileName = "provider-metadata.json"
)

var _ data.Writer = (*writer)(nil)

type writer struct {
dbPath string
store grypeDB.Store
states provider.States
}

type ProviderMetadata struct {
Providers []Provider `json:"providers"`
}

type Provider struct {
Name string `json:"name"`
LastSuccessfulRun time.Time `json:"lastSuccessfulRun"`
}

func NewWriter(directory string, dataAge time.Time) (data.Writer, error) {
func NewWriter(directory string, dataAge time.Time, states provider.States) (data.Writer, error) {
dbPath := path.Join(directory, grypeDB.VulnerabilityStoreFileName)
theStore, err := grypeDBStore.New(dbPath, true)
if err != nil {
Expand All @@ -42,6 +58,7 @@ func NewWriter(directory string, dataAge time.Time) (data.Writer, error) {
return &writer{
dbPath: dbPath,
store: theStore,
states: states,
}, nil
}

Expand Down Expand Up @@ -93,6 +110,24 @@ func (w writer) metadata() (*db.Metadata, error) {
return &metadata, nil
}

func NewProviderMetadata() ProviderMetadata {
return ProviderMetadata{
Providers: make([]Provider, 0),
}
}

func (w writer) ProviderMetadata() *ProviderMetadata {
metadata := NewProviderMetadata()
// Set provider time from states
for _, state := range w.states {
metadata.Providers = append(metadata.Providers, Provider{
Name: state.Provider,
LastSuccessfulRun: state.Timestamp,
})
}
return &metadata
}

func (w writer) Close() error {
w.store.Close()
metadata, err := w.metadata()
Expand All @@ -105,8 +140,14 @@ func (w writer) Close() error {
return err
}

providerMetadataPath := path.Join(filepath.Dir(w.dbPath), providerMetadataFileName)
if err = w.ProviderMetadata().Write(providerMetadataPath); err != nil {
return err
}

log.WithFields("path", w.dbPath).Info("database created")
log.WithFields("path", metadataPath).Debug("database metadata created")
log.WithFields("path", providerMetadataPath).Debug("provider metadata created")

return nil
}
Expand Down Expand Up @@ -138,3 +179,15 @@ func normalizeSeverity(metadata *grypeDB.VulnerabilityMetadata, reader grypeDB.V
}
metadata.Severity = newSeverity
}

func (p ProviderMetadata) Write(path string) error {
providerMetadataJSON, err := json.MarshalIndent(p, "", " ")
if err != nil {
return fmt.Errorf("unable to marshal provider metadata: %w", err)
}
//nolint:gosec
if err = os.WriteFile(path, providerMetadataJSON, 0644); err != nil {
return fmt.Errorf("unable to write provider metadata: %w", err)
}
return nil
}