mirror of
https://github.com/anchore/grype
synced 2024-11-10 06:34:13 +00:00
Add db list command (#506)
* add db list command Signed-off-by: Alex Goodman <alex.goodman@anchore.com> * add stderr print helper Signed-off-by: Alex Goodman <alex.goodman@anchore.com> * update docs to with details about listing files and DB curation Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
This commit is contained in:
parent
2867dc0118
commit
86b7d165e2
10 changed files with 114 additions and 20 deletions
10
README.md
10
README.md
|
@ -272,7 +272,9 @@ You can set the cache directory path using the environment variable `GRYPE_DB_CA
|
|||
|
||||
By default, Grype checks for a new database on every run, by making a network call over the Internet. You can tell Grype not to perform this check by setting the environment variable `GRYPE_DB_AUTO_UPDATE` to `false`.
|
||||
|
||||
As long as you place Grype's `vulnerability.db` and `metadata.json` files in the cache directory for the expected schema version, Grype has no need to access the network.
|
||||
As long as you place Grype's `vulnerability.db` and `metadata.json` files in the cache directory for the expected schema version, Grype has no need to access the network. Additionally, you can get a listing of the database archives available for download from the `grype db list` command in an online environment, download the database archive, transfer it to your offline environment, and use `grype db import <db-archive-path>` to use the given database in an offline capacity.
|
||||
|
||||
If you would like to distribute your own Grype databases internally without needing to use `db import` manually you can leverage Grype's DB update mechanism. To do this you can craft your own `listing.json` file similar to the one found publically (see `grype db list -o raw` for an example of our public `listing.json` file) and change the download URL to point to an internal endpoint (e.g. a private S3 bucket, an internal file server, etc). Any internal installation of Grype can receive database updates automatically by configuring the `db.update-url` (same as the `GRYPE_DB_UPDATE_URL` environment variable) to point to the hosted `listing.json` file you've crafted.
|
||||
|
||||
#### CLI commands for database management
|
||||
|
||||
|
@ -282,7 +284,11 @@ Grype provides database-specific CLI commands for users that want to control the
|
|||
|
||||
`grype db check` — see if updates are available for the database
|
||||
|
||||
`grype db update` — ensure the latest database has been downloaded to the cache directory (Grype performs this operation at the beginnign of every scan by default)
|
||||
`grype db update` — ensure the latest database has been downloaded to the cache directory (Grype performs this operation at the beginning of every scan by default)
|
||||
|
||||
`grype db list` — download the listing file configured at `db.update-url` and show databases that are available for download
|
||||
|
||||
`grype db import` — provide grype with a database archive to explicitly use (useful for offline DB updates)
|
||||
|
||||
Find complete information on Grype's database commands by running `grype db --help`.
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ func init() {
|
|||
|
||||
func Execute() {
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
fmt.Fprintln(os.Stderr, err.Error())
|
||||
_ = stderrPrintLnf(err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,15 +26,12 @@ func runDBCheckCmd(_ *cobra.Command, _ []string) error {
|
|||
|
||||
updateAvailable, _, err := dbCurator.IsUpdateAvailable()
|
||||
if err != nil {
|
||||
// TODO: should this be so fatal? we can certainly continue with a warning...
|
||||
return fmt.Errorf("unable to check for vulnerability database update: %+v", err)
|
||||
}
|
||||
|
||||
if !updateAvailable {
|
||||
fmt.Println("No update available")
|
||||
return nil
|
||||
return stderrPrintLnf("No update available")
|
||||
}
|
||||
|
||||
fmt.Println("Update available!")
|
||||
return nil
|
||||
return stderrPrintLnf("Update available!")
|
||||
}
|
||||
|
|
|
@ -28,6 +28,5 @@ func runDBDeleteCmd(_ *cobra.Command, _ []string) error {
|
|||
return fmt.Errorf("unable to delete vulnerability database: %+v", err)
|
||||
}
|
||||
|
||||
fmt.Println("Vulnerability database deleted")
|
||||
return nil
|
||||
return stderrPrintLnf("Vulnerability database deleted")
|
||||
}
|
||||
|
|
|
@ -31,6 +31,5 @@ func runDBImportCmd(_ *cobra.Command, args []string) error {
|
|||
return fmt.Errorf("unable to import vulnerability database: %+v", err)
|
||||
}
|
||||
|
||||
fmt.Println("Vulnerability database imported")
|
||||
return nil
|
||||
return stderrPrintLnf("Vulnerability database imported")
|
||||
}
|
||||
|
|
76
cmd/db_list.go
Normal file
76
cmd/db_list.go
Normal file
|
@ -0,0 +1,76 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/anchore/grype/grype/db"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var dbListOutputFormat string
|
||||
|
||||
var dbListCmd = &cobra.Command{
|
||||
Use: "list",
|
||||
Short: "list all DBs available according to the listing URL",
|
||||
Args: cobra.ExactArgs(0),
|
||||
RunE: runDBListCmd,
|
||||
}
|
||||
|
||||
func init() {
|
||||
dbListCmd.Flags().StringVarP(&dbListOutputFormat, "output", "o", "text", "format to display results (available=[text, raw, json])")
|
||||
|
||||
dbCmd.AddCommand(dbListCmd)
|
||||
}
|
||||
|
||||
func runDBListCmd(_ *cobra.Command, _ []string) error {
|
||||
dbCurator, err := db.NewCurator(appConfig.DB.ToCuratorConfig())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
listing, err := dbCurator.ListingFromURL()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
supportedSchema := dbCurator.SupportedSchema()
|
||||
available, exists := listing.Available[supportedSchema]
|
||||
|
||||
if len(available) == 0 || !exists {
|
||||
return stderrPrintLnf("No databases available for the current schema (%d)", supportedSchema)
|
||||
}
|
||||
|
||||
switch dbListOutputFormat {
|
||||
case "text":
|
||||
// summarize each listing entry for the current DB schema
|
||||
for _, l := range available {
|
||||
fmt.Printf("Built: %s\n", l.Built)
|
||||
fmt.Printf("URL: %s\n", l.URL)
|
||||
fmt.Printf("Checksum: %s\n\n", l.Checksum)
|
||||
}
|
||||
|
||||
fmt.Printf("%d databases available for schema %d\n", len(available), supportedSchema)
|
||||
case "json":
|
||||
// show entries for the current schema
|
||||
enc := json.NewEncoder(os.Stdout)
|
||||
enc.SetEscapeHTML(false)
|
||||
enc.SetIndent("", " ")
|
||||
if err := enc.Encode(&available); err != nil {
|
||||
return fmt.Errorf("failed to db listing information: %+v", err)
|
||||
}
|
||||
case "raw":
|
||||
// show the entire listing file
|
||||
enc := json.NewEncoder(os.Stdout)
|
||||
enc.SetEscapeHTML(false)
|
||||
enc.SetIndent("", " ")
|
||||
if err := enc.Encode(&listing); err != nil {
|
||||
return fmt.Errorf("failed to db listing information: %+v", err)
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unsupported output format: %s", dbListOutputFormat)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -31,10 +31,8 @@ func runDBUpdateCmd(_ *cobra.Command, _ []string) error {
|
|||
}
|
||||
|
||||
if updated {
|
||||
fmt.Println("Vulnerability database updated!")
|
||||
return nil
|
||||
return stderrPrintLnf("Vulnerability database updated!")
|
||||
}
|
||||
|
||||
fmt.Println("No vulnerability database update available")
|
||||
return nil
|
||||
return stderrPrintLnf("No vulnerability database update available")
|
||||
}
|
||||
|
|
15
cmd/util.go
Normal file
15
cmd/util.go
Normal file
|
@ -0,0 +1,15 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func stderrPrintLnf(message string, args ...interface{}) error {
|
||||
if !strings.HasSuffix(message, "\n") {
|
||||
message += "\n"
|
||||
}
|
||||
_, err := fmt.Fprintf(os.Stderr, message, args...)
|
||||
return err
|
||||
}
|
|
@ -11,7 +11,7 @@ import (
|
|||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var outputFormat string
|
||||
var versionOutputFormat string
|
||||
|
||||
var versionCmd = &cobra.Command{
|
||||
Use: "version",
|
||||
|
@ -20,14 +20,14 @@ var versionCmd = &cobra.Command{
|
|||
}
|
||||
|
||||
func init() {
|
||||
versionCmd.Flags().StringVarP(&outputFormat, "output", "o", "text", "format to show version information (available=[text, json])")
|
||||
versionCmd.Flags().StringVarP(&versionOutputFormat, "output", "o", "text", "format to display results (available=[text, json])")
|
||||
|
||||
rootCmd.AddCommand(versionCmd)
|
||||
}
|
||||
|
||||
func printVersion(_ *cobra.Command, _ []string) error {
|
||||
versionInfo := version.FromBuild()
|
||||
switch outputFormat {
|
||||
switch versionOutputFormat {
|
||||
case "text":
|
||||
fmt.Println("Application: ", internal.ApplicationName)
|
||||
fmt.Println("Version: ", versionInfo.Version)
|
||||
|
@ -57,7 +57,7 @@ func printVersion(_ *cobra.Command, _ []string) error {
|
|||
return fmt.Errorf("failed to show version information: %+v", err)
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unsupported output format: %s", outputFormat)
|
||||
return fmt.Errorf("unsupported output format: %s", versionOutputFormat)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -65,6 +65,10 @@ func NewCurator(cfg Config) (Curator, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
func (c Curator) SupportedSchema() int {
|
||||
return c.targetSchema
|
||||
}
|
||||
|
||||
func (c *Curator) GetStore() (*reader.Reader, error) {
|
||||
// ensure the DB is ok
|
||||
err := c.Validate()
|
||||
|
|
Loading…
Reference in a new issue