Skip to content

Commit

Permalink
add schema validation & fix schema status logic
Browse files Browse the repository at this point in the history
  • Loading branch information
wagoodman committed Jul 30, 2020
1 parent 8d84dfe commit e1b4ea5
Show file tree
Hide file tree
Showing 12 changed files with 83 additions and 75 deletions.
7 changes: 6 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ bootstrap: ## Download and install all go dependencies (+ prep tooling in the ./
[ -f "$(TEMPDIR)/goreleaser" ] || curl -sfL https://install.goreleaser.com/github.com/goreleaser/goreleaser.sh | sh -s -- -b $(TEMPDIR)/ v0.140.0

.PHONY: static-analysis
static-analysis: lint check-licenses
static-analysis: lint check-licenses validate-schema

.PHONY: lint
lint: ## Run gofmt + golangci lint checks
Expand All @@ -95,6 +95,11 @@ lint: ## Run gofmt + golangci lint checks
$(eval MALFORMED_FILENAMES := $(shell find . | grep -e ':'))
@bash -c "[[ '$(MALFORMED_FILENAMES)' == '' ]] || (printf '\nfound unsupported filename characters:\n$(MALFORMED_FILENAMES)\n\n' && false)"

.PHONY: validate-schema
validate-schema:
# ensure the codebase is only referencing a single grype-db schema version, multiple is not allowed
python test/validate_schema.py

lint-fix: ## Auto-format all source code + run golangci lint fixers
$(call title,Running lint fixers)
gofmt -w -s .
Expand Down
6 changes: 1 addition & 5 deletions cmd/db_check.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,7 @@ func init() {
}

func runDbCheckCmd(_ *cobra.Command, _ []string) int {
dbCurator, err := db.NewCurator(appConfig.Db.ToCuratorConfig())
if err != nil {
log.Errorf("could not curate database: %+v", err)
return 1
}
dbCurator := db.NewCurator(appConfig.Db.ToCuratorConfig())

updateAvailable, _, err := dbCurator.IsUpdateAvailable()
if err != nil {
Expand Down
9 changes: 2 additions & 7 deletions cmd/db_delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,9 @@ func init() {
}

func runDbDeleteCmd(_ *cobra.Command, _ []string) int {
dbCurator, err := db.NewCurator(appConfig.Db.ToCuratorConfig())
if err != nil {
log.Errorf("could not curate database: %w", err)
return 1
}
dbCurator := db.NewCurator(appConfig.Db.ToCuratorConfig())

err = dbCurator.Delete()
if err != nil {
if err := dbCurator.Delete(); err != nil {
log.Errorf("unable to delete vulnerability database: %+v", err)
return 1
}
Expand Down
9 changes: 2 additions & 7 deletions cmd/db_import.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,9 @@ func init() {
}

func runDbImportCmd(_ *cobra.Command, args []string) int {
dbCurator, err := db.NewCurator(appConfig.Db.ToCuratorConfig())
if err != nil {
log.Errorf("could not curate database: %w", err)
return 1
}
dbCurator := db.NewCurator(appConfig.Db.ToCuratorConfig())

err = dbCurator.ImportFrom(args[0])
if err != nil {
if err := dbCurator.ImportFrom(args[0]); err != nil {
log.Errorf("unable to import vulnerability database: %+v", err)
return 1
}
Expand Down
35 changes: 17 additions & 18 deletions cmd/db_status.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ var statusCmd = &cobra.Command{
Use: "status",
Short: "display database status",
Run: func(cmd *cobra.Command, args []string) {
os.Exit(runDbStatusCmd(cmd, args))
err := runDbStatusCmd(cmd, args)
if err != nil {
log.Errorf(err.Error())
os.Exit(1)
}
},
}

Expand All @@ -26,30 +30,25 @@ func init() {
dbCmd.AddCommand(statusCmd)
}

func runDbStatusCmd(_ *cobra.Command, _ []string) int {
dbCurator, err := db.NewCurator(appConfig.Db.ToCuratorConfig())
if err != nil {
log.Errorf("could not curate database: %w", err)
return 1
}

func runDbStatusCmd(_ *cobra.Command, _ []string) error {
dbCurator := db.NewCurator(appConfig.Db.ToCuratorConfig())
status := dbCurator.Status()

if showSupportedDbSchema {
// Note: the output for this option cannot change as it supports the nightly DB generation job
fmt.Println(status.RequiredSchemeVersion)
return 0
// note: the output for this option cannot change as it supports the nightly DB generation job
fmt.Println(status.RequiredSchemaVersion)
return nil
}

if status.Err != nil {
return status.Err
}

fmt.Println("Location: ", status.Location)
fmt.Println("Built: ", status.Age.String())
fmt.Println("Current DB Version: ", status.CurrentSchemaVersion)
fmt.Println("Require DB Version: ", status.RequiredSchemeVersion)
if status.Err != nil {
fmt.Printf("Status: INVALID [%+v]\n", status.Err)
} else {
fmt.Println("Status: Valid")
}
fmt.Println("Require DB Version: ", status.RequiredSchemaVersion)
fmt.Println("Status: Valid")

return 0
return nil
}
6 changes: 1 addition & 5 deletions cmd/db_update.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,7 @@ func init() {
}

func runDbUpdateCmd(_ *cobra.Command, _ []string) int {
dbCurator, err := db.NewCurator(appConfig.Db.ToCuratorConfig())
if err != nil {
log.Errorf("could not curate database: %+v", err)
return 1
}
dbCurator := db.NewCurator(appConfig.Db.ToCuratorConfig())

updateAvailable, updateEntry, err := dbCurator.IsUpdateAvailable()
if err != nil {
Expand Down
22 changes: 12 additions & 10 deletions grype/db/curator.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,13 @@ type Curator struct {
targetSchema int
}

func NewCurator(cfg Config) (Curator, error) {
func NewCurator(cfg Config) Curator {
return Curator{
config: cfg,
fs: afero.NewOsFs(),
targetSchema: v1.SchemaVersion,
client: &file.HashiGoGetter{},
}, nil
}
}

func (c *Curator) GetStore() (v1.VulnerabilityStoreReader, error) {
Expand All @@ -54,22 +54,24 @@ func (c *Curator) GetStore() (v1.VulnerabilityStoreReader, error) {
func (c *Curator) Status() Status {
metadata, err := curation.NewMetadataFromDir(c.fs, c.config.DbDir)
if err != nil {
err = fmt.Errorf("failed to parse database metadata (%s): %w", c.config.DbDir, err)
return Status{
RequiredSchemaVersion: c.targetSchema,
Err: fmt.Errorf("failed to parse database metadata (%s): %w", c.config.DbDir, err),
}
}
if metadata == nil {
err = fmt.Errorf("database metadata not found at %q", c.config.DbDir)
}

if err == nil {
err = c.Validate()
return Status{
RequiredSchemaVersion: c.targetSchema,
Err: fmt.Errorf("database metadata not found at %q", c.config.DbDir),
}
}

return Status{
Age: metadata.Built,
CurrentSchemaVersion: metadata.Version,
RequiredSchemeVersion: v1.SchemaVersion,
RequiredSchemaVersion: c.targetSchema,
Location: c.config.DbDir,
Err: err,
Err: c.Validate(),
}
}

Expand Down
21 changes: 6 additions & 15 deletions grype/db/curator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,18 +53,15 @@ func (g *testGetter) GetToDir(dst, src string) error {
return afero.WriteFile(g.fs, dst, []byte(g.dir[src]), 0755)
}

func newTestCurator(fs afero.Fs, getter file.Getter, dbDir, metadataUrl string) (Curator, error) {
c, err := NewCurator(Config{
func newTestCurator(fs afero.Fs, getter file.Getter, dbDir, metadataUrl string) Curator {
c := NewCurator(Config{
DbDir: dbDir,
ListingURL: metadataUrl,
})
if err != nil {
return Curator{}, err
}

c.client = getter
c.fs = fs
return c, err
return c
}

func TestCuratorDownload(t *testing.T) {
Expand Down Expand Up @@ -95,10 +92,7 @@ func TestCuratorDownload(t *testing.T) {
}
fs := afero.NewMemMapFs()
getter := newTestGetter(fs, files, dirs)
cur, err := newTestCurator(fs, getter, "/tmp/dbdir", metadataUrl)
if err != nil {
t.Fatalf("failed making curator: %+v", err)
}
cur := newTestCurator(fs, getter, "/tmp/dbdir", metadataUrl)

path, err := cur.download(test.entry)

Expand Down Expand Up @@ -163,14 +157,11 @@ func TestCuratorValidate(t *testing.T) {

fs := afero.NewOsFs()
getter := newTestGetter(fs, nil, nil)
cur, err := newTestCurator(fs, getter, "/tmp/dbdir", metadataUrl)
if err != nil {
t.Fatalf("failed making curator: %+v", err)
}
cur := newTestCurator(fs, getter, "/tmp/dbdir", metadataUrl)

cur.targetSchema = test.constraint

err = cur.validate(test.fixture)
err := cur.validate(test.fixture)

if err == nil && test.err {
t.Errorf("expected an error but got none")
Expand Down
2 changes: 1 addition & 1 deletion grype/db/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import "time"
type Status struct {
Age time.Time
CurrentSchemaVersion int
RequiredSchemeVersion int
RequiredSchemaVersion int
Location string
Err error
}
5 changes: 1 addition & 4 deletions grype/lib.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,7 @@ func FindVulnerabilitiesForPackage(provider vulnerability.Provider, d distro.Dis
}

func LoadVulnerabilityDb(cfg db.Config, update bool) (vulnerability.Provider, error) {
dbCurator, err := db.NewCurator(cfg)
if err != nil {
return nil, fmt.Errorf("could not curate database: %w", err)
}
dbCurator := db.NewCurator(cfg)

if update {
updateAvailable, updateEntry, err := dbCurator.IsUpdateAvailable()
Expand Down
4 changes: 2 additions & 2 deletions test/inline-compare/compare.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def vulnerabilities(self):
return vulnerabilities, metadata


class grype:
class Grype:

report_tmpl = "{image}.json"

Expand Down Expand Up @@ -89,7 +89,7 @@ def main(image):
inline = InlineScan(image=image, report_dir="inline-reports")
inline_vulnerabilities, inline_metadata = inline.vulnerabilities()

grype = grype(image=image, report_dir="grype-reports")
grype = Grype(image=image, report_dir="grype-reports")
grype_vulnerabilities, grype_metadata = grype.vulnerabilities()

if len(grype_vulnerabilities) == 0 and len(inline_vulnerabilities) == 0:
Expand Down
32 changes: 32 additions & 0 deletions test/validate_schema.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#!/usr/bin/env python2
import re
import os
import sys

pattern = re.compile(r'github.com/anchore/grype-db/pkg/db/v(?P<version>\d+)')

def main():
schema_versions_found = set()

for root, dirs, files in os.walk("."):
for file in files:
if not file.endswith(".go"):
continue
with open(os.path.join(root, file)) as f:
for match in pattern.findall(f.read(), re.MULTILINE):
schema_versions_found.add(match)

num_schemas = len(schema_versions_found)
if num_schemas != 1:
sys.exit("Found multiple schemas: %s" % repr(schema_versions_found))

try:
for x in schema_versions_found:
int(x)
except Exception:
sys.exit("Non-numeric schema found: %s" % repr(schema_versions_found))

print("Schemas Found: %s" % repr(schema_versions_found))

if __name__ == "__main__":
main()

0 comments on commit e1b4ea5

Please sign in to comment.