Skip to content

Commit

Permalink
feat: add grype db providers command
Browse files Browse the repository at this point in the history
- currently reads content of `provider-metadata.json` file
- added flag `-o`/`--output` flags which accept `json` and `table`
- update  method `getDBProviders()` and type `dbProviderMetadata` for db schema `v6`

Signed-off-by: Adnan Gulegulzar <[email protected]>
  • Loading branch information
ADorigi committed Oct 9, 2024
1 parent 72d07ba commit d651464
Show file tree
Hide file tree
Showing 2 changed files with 139 additions and 0 deletions.
1 change: 1 addition & 0 deletions cmd/grype/cli/commands/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ func DB(app clio.Application) *cobra.Command {
DBStatus(app),
DBUpdate(app),
DBSearch(app),
DBProviders(app),
)

return db
Expand Down
138 changes: 138 additions & 0 deletions cmd/grype/cli/commands/db_providers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
package commands

import (
"encoding/json"
"fmt"
"io"
"os"
"path"
"strings"

"github.com/anchore/clio"
"github.com/anchore/grype/grype/db/legacy/distribution"
"github.com/anchore/grype/internal/bus"
"github.com/olekukonko/tablewriter"
"github.com/spf13/cobra"
)

const metadataFileName = "provider-metadata.json"

type dbProviderMetadata struct {
Name string `json:"name"`
LastSuccessfulRun string `json:"lastSuccessfulRun"`
}

type dbProviders struct {
Providers []dbProviderMetadata `json:"providers"`
}

type dbProvidersOptions struct {
Output string `yaml:"output" json:"output"`
}

var _ clio.FlagAdder = (*dbProvidersOptions)(nil)

func (d *dbProvidersOptions) AddFlags(flags clio.FlagSet) {
flags.StringVarP(&d.Output, "output", "o", "format to display results (available=[table, json])")
}

func DBProviders(app clio.Application) *cobra.Command {
opts := &dbProvidersOptions{
Output: "json",
}

return app.SetupCommand(&cobra.Command{
Use: "providers",
Short: "list vulnerability database providers",
Args: cobra.ExactArgs(0),
RunE: func(_ *cobra.Command, _ []string) error {
return runDBProviders(opts, app)
},
}, opts)
}

func runDBProviders(opts *dbProvidersOptions, app clio.Application) error {

providers, err := getDBProviders(app)
if err != nil {
return err
}

sb := &strings.Builder{}

switch opts.Output {
case "table":
displayDBProvidersTable(providers.Providers, sb)
case "json":
err = displayDBProvidersJSON(providers, sb)
if err != nil {
return err
}
default:
return fmt.Errorf("unsupported output format: %s", opts.Output)
}
bus.Report(sb.String())

return nil
}

func getDBProviders(app clio.Application) (*dbProviders, error) {

dbCurator, err := distribution.NewCurator(dbOptionsDefault(app.ID()).DB.ToCuratorConfig())
if err != nil {
return nil, err
}

metadataFileLocation := dbCurator.Status().Location
metadataFile := path.Join(metadataFileLocation, metadataFileName)

file, err := os.Open(metadataFile)
if err != nil {
if os.IsNotExist(err) {
return nil, fmt.Errorf("file not found: %v", err)
} else {
return nil, fmt.Errorf("Error opening file: %v", err)
}
}
defer file.Close()

var providers dbProviders
fileBytes, err := io.ReadAll(file)
if err != nil {
return nil, fmt.Errorf("error reading file: %v", err)
}
err = json.Unmarshal(fileBytes, &providers)
if err != nil {
return nil, fmt.Errorf("cannot unmarshal providers: %v", err)
}

return &providers, nil

}

func displayDBProvidersTable(providers []dbProviderMetadata, output io.Writer) {

rows := [][]string{}
for _, provider := range providers {
rows = append(rows, []string{provider.Name, provider.LastSuccessfulRun})
}

table := tablewriter.NewWriter(output)
table.SetHeader([]string{"Name", "Last Successful Run"})

table.AppendBulk(rows)
table.Render()

}

func displayDBProvidersJSON(providers *dbProviders, output io.Writer) error {

encoder := json.NewEncoder(output)
encoder.SetEscapeHTML(false)
encoder.SetIndent("", " ")
err := encoder.Encode(providers)
if err != nil {
return fmt.Errorf("cannot display json: %v", err)
}
return nil
}

0 comments on commit d651464

Please sign in to comment.