-
Notifications
You must be signed in to change notification settings - Fork 574
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* add db metadata store Signed-off-by: Alex Goodman <[email protected]> * add functional options to gorm adapter Signed-off-by: Alex Goodman <[email protected]> --------- Signed-off-by: Alex Goodman <[email protected]>
- Loading branch information
Showing
12 changed files
with
423 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
package gormadapter | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestConfigApply(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
path string | ||
options []Option | ||
expectedPath string | ||
expectedMemory bool | ||
}{ | ||
{ | ||
name: "apply with path", | ||
path: "test.db", | ||
options: []Option{}, | ||
expectedPath: "test.db", | ||
expectedMemory: false, | ||
}, | ||
{ | ||
name: "apply with empty path (memory)", | ||
path: "", | ||
options: []Option{}, | ||
expectedPath: "", | ||
expectedMemory: true, | ||
}, | ||
{ | ||
name: "apply with truncate option", | ||
path: "test.db", | ||
options: []Option{WithTruncate(true)}, | ||
expectedPath: "test.db", | ||
expectedMemory: false, | ||
}, | ||
} | ||
|
||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
c := newConfig(tt.path, tt.options) | ||
|
||
require.Equal(t, tt.expectedPath, c.path) | ||
require.Equal(t, tt.expectedMemory, c.memory) | ||
}) | ||
} | ||
} | ||
|
||
func TestConfigShouldTruncate(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
write bool | ||
memory bool | ||
expectedTruncate bool | ||
}{ | ||
{ | ||
name: "should truncate when write is true and not memory", | ||
write: true, | ||
memory: false, | ||
expectedTruncate: true, | ||
}, | ||
{ | ||
name: "should not truncate when write is false", | ||
write: false, | ||
memory: false, | ||
expectedTruncate: false, | ||
}, | ||
{ | ||
name: "should not truncate when using in-memory DB", | ||
write: true, | ||
memory: true, | ||
expectedTruncate: false, | ||
}, | ||
} | ||
|
||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
c := config{ | ||
write: tt.write, | ||
memory: tt.memory, | ||
} | ||
require.Equal(t, tt.expectedTruncate, c.shouldTruncate()) | ||
}) | ||
} | ||
} | ||
|
||
func TestConfigConnectionString(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
path string | ||
write bool | ||
memory bool | ||
expectedConnStr string | ||
}{ | ||
{ | ||
name: "writable path", | ||
path: "test.db", | ||
write: true, | ||
expectedConnStr: "file:test.db?cache=shared", | ||
}, | ||
{ | ||
name: "read-only path", | ||
path: "test.db", | ||
write: false, | ||
expectedConnStr: "file:test.db?cache=shared&immutable=1&cache=shared&mode=ro", | ||
}, | ||
{ | ||
name: "in-memory mode", | ||
path: "", | ||
write: false, | ||
memory: true, | ||
expectedConnStr: ":memory:", | ||
}, | ||
} | ||
|
||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
c := config{ | ||
path: tt.path, | ||
write: tt.write, | ||
memory: tt.memory, | ||
} | ||
require.Equal(t, tt.expectedConnStr, c.connectionString()) | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package v6 | ||
|
||
import ( | ||
"io" | ||
"path/filepath" | ||
) | ||
|
||
const ( | ||
VulnerabilityDBFileName = "vulnerability.db" | ||
|
||
// We follow SchemaVer semantics (see https://snowplow.io/blog/introducing-schemaver-for-semantic-versioning-of-schemas) | ||
|
||
// ModelVersion indicates how many breaking schema changes there have been (which will prevent interaction with any historical data) | ||
// note: this must ALWAYS be "6" in the context of this package. | ||
ModelVersion = 6 | ||
|
||
// Revision indicates how many changes have been introduced which **may** prevent interaction with some historical data | ||
Revision = 0 | ||
|
||
// Addition indicates how many changes have been introduced that are compatible with all historical data | ||
Addition = 0 | ||
) | ||
|
||
type ReadWriter interface { | ||
Reader | ||
Writer | ||
} | ||
|
||
type Reader interface { | ||
DBMetadataStoreReader | ||
} | ||
|
||
type Writer interface { | ||
DBMetadataStoreWriter | ||
io.Closer | ||
} | ||
|
||
type Config struct { | ||
DBDirPath string | ||
} | ||
|
||
func (c *Config) DBFilePath() string { | ||
return filepath.Join(c.DBDirPath, VulnerabilityDBFileName) | ||
} | ||
|
||
func NewReader(cfg Config) (Reader, error) { | ||
return newStore(cfg, false) | ||
} | ||
|
||
func NewWriter(cfg Config) (ReadWriter, error) { | ||
return newStore(cfg, true) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
package v6 | ||
|
||
import ( | ||
"fmt" | ||
"time" | ||
|
||
"gorm.io/gorm" | ||
|
||
"github.com/anchore/grype/internal/log" | ||
) | ||
|
||
type DBMetadataStoreWriter interface { | ||
SetDBMetadata() error | ||
} | ||
|
||
type DBMetadataStoreReader interface { | ||
GetDBMetadata() (*DBMetadata, error) | ||
} | ||
|
||
type dbMetadataStore struct { | ||
db *gorm.DB | ||
} | ||
|
||
func newDBMetadataStore(db *gorm.DB) *dbMetadataStore { | ||
return &dbMetadataStore{ | ||
db: db, | ||
} | ||
} | ||
|
||
func (s *dbMetadataStore) GetDBMetadata() (*DBMetadata, error) { | ||
log.Trace("fetching DB metadata record") | ||
|
||
var model DBMetadata | ||
|
||
result := s.db.First(&model) | ||
return &model, result.Error | ||
} | ||
|
||
func (s *dbMetadataStore) SetDBMetadata() error { | ||
log.Trace("writing DB metadata record") | ||
|
||
if err := s.db.Unscoped().Where("true").Delete(&DBMetadata{}).Error; err != nil { | ||
return fmt.Errorf("failed to delete existing DB metadata record: %w", err) | ||
} | ||
|
||
ts := time.Now().UTC() | ||
instance := &DBMetadata{ | ||
BuildTimestamp: &ts, | ||
Model: ModelVersion, | ||
Revision: Revision, | ||
Addition: Addition, | ||
} | ||
|
||
if err := s.db.Create(instance).Error; err != nil { | ||
return fmt.Errorf("failed to create DB metadata record: %w", err) | ||
} | ||
|
||
return nil | ||
} |
Oops, something went wrong.