Skip to content

Commit

Permalink
Add lineage/parent_lineage to rhelv2 workflows
Browse files Browse the repository at this point in the history
  • Loading branch information
dcaravel committed Dec 2, 2024
1 parent 82abe43 commit 44eb861
Show file tree
Hide file tree
Showing 11 changed files with 74 additions and 41 deletions.
4 changes: 2 additions & 2 deletions api/v1/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ func LayerFromDatabaseModel(db database.Datastore, dbLayer database.Layer, linea
layer.Features = append(layer.Features, *feature)
}
if !uncertifiedRHEL && namespaces.IsRHELNamespace(layer.NamespaceName) {
certified, err := addRHELv2Vulns(db, &layer)
certified, err := addRHELv2Vulns(db, &layer, lineage)
if err != nil {
return layer, notes, err
}
Expand Down Expand Up @@ -212,7 +212,7 @@ func ComponentsFromDatabaseModel(db database.Datastore, dbLayer *database.Layer,
if !uncertifiedRHEL && namespaces.IsRHELNamespace(namespaceName) {
var certified bool
var err error
rhelv2PkgEnvs, certified, err = getRHELv2PkgEnvs(db, dbLayer.Name)
rhelv2PkgEnvs, certified, err = getRHELv2PkgEnvs(db, dbLayer.Name, lineage)
if err != nil {
return nil, err
}
Expand Down
8 changes: 4 additions & 4 deletions api/v1/models_rhelv2.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ const (
// certified as part of Red Hat's Scanner Certification Program.
// The returned bool indicates if full certified scanning was performed.
// This is typically only `false` for images without proper CPE information.
func addRHELv2Vulns(db database.Datastore, layer *Layer) (bool, error) {
pkgEnvs, cpesExist, err := getRHELv2PkgEnvs(db, layer.Name)
func addRHELv2Vulns(db database.Datastore, layer *Layer, lineage string) (bool, error) {
pkgEnvs, cpesExist, err := getRHELv2PkgEnvs(db, layer.Name, lineage)
if err != nil {
return false, err
}
Expand Down Expand Up @@ -197,8 +197,8 @@ func shareCPEs(layers []*database.RHELv2Layer) bool {
}

// getRHELv2PkgEnvs returns a map from package ID to package environment and a bool to indicate CPEs exist in the image.
func getRHELv2PkgEnvs(db database.Datastore, layerName string) (map[int]*database.RHELv2PackageEnv, bool, error) {
layers, err := db.GetRHELv2Layers(layerName)
func getRHELv2PkgEnvs(db database.Datastore, layerName, layerLineage string) (map[int]*database.RHELv2PackageEnv, bool, error) {
layers, err := db.GetRHELv2Layers(layerName, layerLineage)
if err != nil {
return nil, false, err
}
Expand Down
2 changes: 1 addition & 1 deletion api/v1/models_rhelv2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func newMockRHELv2Datastore() *mockRHELv2Datastore {
layers: make(map[string][]*database.RHELv2Layer),
vulns: make(map[int][]*database.RHELv2Vulnerability),
}
db.FctGetRHELv2Layers = func(layer string) ([]*database.RHELv2Layer, error) {
db.FctGetRHELv2Layers = func(layer, lineage string) ([]*database.RHELv2Layer, error) {
return db.layers[layer], nil
}
db.FctGetRHELv2Vulnerabilities = func(records []*database.RHELv2Record) (map[int][]*database.RHELv2Vulnerability, error) {
Expand Down
2 changes: 1 addition & 1 deletion database/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ type Datastore interface {
// GetRHELv2Layers retrieves the corresponding layers for the image
// represented by the given layer.
// The returned slice is sorted in order from base layer to top.
GetRHELv2Layers(layer string) ([]*RHELv2Layer, error)
GetRHELv2Layers(layer, lineage string) ([]*RHELv2Layer, error)

// GetRHELv2Vulnerabilities retrieves RHELv2 vulnerabilities based on the given records.
// The returned value maps package ID to the related vulnerabilities.
Expand Down
6 changes: 3 additions & 3 deletions database/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ type MockDatastore struct {
FctFindLayer func(name, lineage string, opts *DatastoreOptions) (Layer, error)
FctDeleteLayer func(name string) error
FctInsertRHELv2Layer func(*RHELv2Layer) error
FctGetRHELv2Layers func(layer string) ([]*RHELv2Layer, error)
FctGetRHELv2Layers func(layer, lineage string) ([]*RHELv2Layer, error)
FctGetRHELv2Vulnerabilities func(records []*RHELv2Record) (map[int][]*RHELv2Vulnerability, error)
FctListVulnerabilities func(namespaceName string, limit int, page int) ([]Vulnerability, int, error)
FctInsertVulnerabilities func(vulnerabilities []Vulnerability) error
Expand Down Expand Up @@ -82,9 +82,9 @@ func (mds *MockDatastore) InsertRHELv2Layer(layer *RHELv2Layer) error {
panic("required mock function not implemented")
}

func (mds *MockDatastore) GetRHELv2Layers(layer string) ([]*RHELv2Layer, error) {
func (mds *MockDatastore) GetRHELv2Layers(layer, layerLineage string) ([]*RHELv2Layer, error) {
if mds.FctGetRHELv2Layers != nil {
return mds.FctGetRHELv2Layers(layer)
return mds.FctGetRHELv2Layers(layer, layerLineage)
}
panic("required mock function not implemented")
}
Expand Down
12 changes: 7 additions & 5 deletions database/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,11 +205,13 @@ func (p *RHELv2Package) GetPackageVersion() string {
type RHELv2Layer struct {
Model

Hash string
ParentHash string
Dist string
Pkgs []*RHELv2Package
CPEs []string
Hash string
ParentHash string
Dist string
Pkgs []*RHELv2Package
CPEs []string
Lineage string
ParentLineage string
}

// RHELv2Components defines the RHELv2 components found in a layer.
Expand Down
24 changes: 24 additions & 0 deletions database/pgsql/migrations/00021_rhel_layer_lineage.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package migrations

import "github.com/remind101/migrate"

func init() {
RegisterMigration(migrate.Migration{
ID: 21,
Up: migrate.Queries([]string{

// The lineage column mimics the existing `layer` table. The parent_lineage column is used
// instead of equivalent parent_id column from the 'layer' table to avoid an extra query
// on insert (which would be necessary to determine the parent id).
`ALTER TABLE rhelv2_layer ADD COLUMN IF NOT EXISTS lineage varchar;`,
`ALTER TABLE rhelv2_layer ADD COLUMN IF NOT EXISTS parent_lineage varchar`,

// Create a new unique constraint that includes lineage (and drop the old constraint)
`ALTER TABLE rhelv2_layer ADD CONSTRAINT rhelv2_layer_hash_lineage_key UNIQUE (hash, lineage)`,
`ALTER TABLE rhelv2_layer DROP CONSTRAINT IF EXISTS rhelv2_layer_hash_key`,

// Create additional index to improve performance when recursively traversing parents.
`CREATE INDEX IF NOT EXISTS rhelv2_layer_parent_idx on rhelv2_layer (parent_hash, parent_lineage)`,
}),
})
}
24 changes: 14 additions & 10 deletions database/pgsql/queries.go
Original file line number Diff line number Diff line change
Expand Up @@ -264,9 +264,9 @@ const (
deleteStaleRHELv2Vulns = `DELETE FROM vuln_v2 WHERE name = ANY($1::text[]) and package_name = ANY($2::text[]) and cpe = ANY($3::text[]) and package_module = $4;`

insertRHELv2Layer = `
INSERT INTO rhelv2_layer (hash, parent_hash, dist, cpes)
VALUES ($1, $2, $3, $4)
ON CONFLICT (hash) DO NOTHING;`
INSERT INTO rhelv2_layer (hash, parent_hash, dist, cpes, lineage, parent_lineage)
VALUES ($1, $2, $3, $4, $5, $6)
ON CONFLICT (hash, lineage) DO NOTHING;`

// Inside the `WITH RECURSIVE`, the base case is the top query, and the
// recursive case is the bottom query.
Expand All @@ -276,15 +276,17 @@ const (
// This query looks for all the layers in the given layer's hierarchy.
searchRHELv2Layers = `
WITH RECURSIVE layers AS (
SELECT id, hash, parent_hash, dist, cpes
SELECT id, hash, parent_hash, dist, cpes, lineage, parent_lineage
FROM rhelv2_layer
WHERE hash = $1
UNION
SELECT l.id, l.hash, l.parent_hash, l.dist, l.cpes
WHERE hash = $1
AND lineage = $2
UNION
SELECT l.id, l.hash, l.parent_hash, l.dist, l.cpes, l.lineage, l.parent_lineage
FROM layers ll, rhelv2_layer l
WHERE ll.parent_hash = l.hash
AND ll.parent_lineage = l.lineage
)
SELECT id, hash, dist, cpes
SELECT id, hash, dist, cpes, lineage
FROM layers;`

insertRHELv2Package = `
Expand All @@ -304,7 +306,8 @@ const (
layer AS (
SELECT id AS layer_id
FROM rhelv2_layer
WHERE rhelv2_layer.hash = $5
WHERE rhelv2_layer.hash = $5
AND rhelv2_layer.lineage = $6
)
INSERT
INTO rhelv2_package_scanartifact (layer_id, package_id)
Expand All @@ -324,7 +327,8 @@ const (
rhelv2_package_scanartifact
LEFT JOIN rhelv2_package ON
rhelv2_package_scanartifact.package_id = rhelv2_package.id
JOIN rhelv2_layer ON rhelv2_layer.hash = $1
JOIN rhelv2_layer ON rhelv2_layer.hash = $1
AND rhelv2_layer.lineage = $2
WHERE
rhelv2_package_scanartifact.layer_id = rhelv2_layer.id;`

Expand Down
15 changes: 8 additions & 7 deletions database/pgsql/rhelv2_layer.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func (pgSQL *pgSQL) InsertRHELv2Layer(layer *database.RHELv2Layer) error {
return err
}

if err := pgSQL.insertRHELv2Packages(tx, layer.Hash, layer.Pkgs); err != nil {
if err := pgSQL.insertRHELv2Packages(tx, layer.Hash, layer.Pkgs, layer.Lineage); err != nil {
utils.IgnoreError(tx.Rollback)
return err
}
Expand All @@ -46,11 +46,11 @@ func (pgSQL *pgSQL) InsertRHELv2Layer(layer *database.RHELv2Layer) error {
func (pgSQL *pgSQL) insertRHELv2Layer(tx *sql.Tx, layer *database.RHELv2Layer) error {
defer metrics.ObserveQueryTime("insertRHELv2Layer", "layer", time.Now())

_, err := tx.Exec(insertRHELv2Layer, layer.Hash, layer.ParentHash, layer.Dist, pq.Array(layer.CPEs))
_, err := tx.Exec(insertRHELv2Layer, layer.Hash, layer.ParentHash, layer.Dist, pq.Array(layer.CPEs), layer.Lineage, layer.ParentLineage)
return err
}

func (pgSQL *pgSQL) insertRHELv2Packages(tx *sql.Tx, layer string, pkgs []*database.RHELv2Package) error {
func (pgSQL *pgSQL) insertRHELv2Packages(tx *sql.Tx, layer string, pkgs []*database.RHELv2Package, lineage string) error {
// Sort packages to avoid potential deadlock.
// Sort by the unique index (name, version, module, arch).
sort.SliceStable(pkgs, func(i, j int) bool {
Expand Down Expand Up @@ -91,6 +91,7 @@ func (pgSQL *pgSQL) insertRHELv2Packages(tx *sql.Tx, layer string, pkgs []*datab
pkg.Module,
pkg.Arch,
layer,
lineage,
)

if err != nil {
Expand All @@ -101,7 +102,7 @@ func (pgSQL *pgSQL) insertRHELv2Packages(tx *sql.Tx, layer string, pkgs []*datab
return nil
}

func (pgSQL *pgSQL) GetRHELv2Layers(layerHash string) ([]*database.RHELv2Layer, error) {
func (pgSQL *pgSQL) GetRHELv2Layers(layerHash, layerLineage string) ([]*database.RHELv2Layer, error) {
defer metrics.ObserveQueryTime("getRHELv2Layers", "all", time.Now())

tx, err := pgSQL.BeginTx(context.Background(), &sql.TxOptions{
Expand All @@ -111,7 +112,7 @@ func (pgSQL *pgSQL) GetRHELv2Layers(layerHash string) ([]*database.RHELv2Layer,
return nil, handleError("GetRHELv2Layers.Begin()", err)
}

rows, err := tx.Query(searchRHELv2Layers, layerHash)
rows, err := tx.Query(searchRHELv2Layers, layerHash, layerLineage)
if err != nil {
return nil, err
}
Expand All @@ -124,7 +125,7 @@ func (pgSQL *pgSQL) GetRHELv2Layers(layerHash string) ([]*database.RHELv2Layer,
rhelv2Layer database.RHELv2Layer
cpes []string
)
if err := rows.Scan(&rhelv2Layer.ID, &rhelv2Layer.Hash, &rhelv2Layer.Dist, pq.Array(&cpes)); err != nil {
if err := rows.Scan(&rhelv2Layer.ID, &rhelv2Layer.Hash, &rhelv2Layer.Dist, pq.Array(&cpes), &rhelv2Layer.Lineage); err != nil {
utils.IgnoreError(tx.Rollback)
return nil, err
}
Expand Down Expand Up @@ -176,7 +177,7 @@ func (pgSQL *pgSQL) populatePackages(tx *sql.Tx, layers []*database.RHELv2Layer)
func (pgSQL *pgSQL) getPackagesByLayer(tx *sql.Tx, layer *database.RHELv2Layer) error {
defer metrics.ObserveQueryTime("getRHELv2Layers", "packagesByLayer", time.Now())

rows, err := tx.Query(searchRHELv2Package, layer.Hash)
rows, err := tx.Query(searchRHELv2Package, layer.Hash, layer.Lineage)
if err != nil {
return err
}
Expand Down
6 changes: 3 additions & 3 deletions database/pgsql/rhelv2_layer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ func TestGetRHELv2Layers(t *testing.T) {
assert.NoError(t, err)

// Get parent layer.
layers, err := datastore.GetRHELv2Layers("sha256:howdy")
layers, err := datastore.GetRHELv2Layers("sha256:howdy", "")
assert.NoError(t, err)
assert.Len(t, layers, 1)
layer = layers[0]
Expand All @@ -132,7 +132,7 @@ func TestGetRHELv2Layers(t *testing.T) {
assert.Empty(t, layer.CPEs)

// Get 2 layered-image.
layers, err = datastore.GetRHELv2Layers("sha256:howdyhowdy")
layers, err = datastore.GetRHELv2Layers("sha256:howdyhowdy", "")
assert.NoError(t, err)
assert.Len(t, layers, 2)
layer = layers[1]
Expand Down Expand Up @@ -176,7 +176,7 @@ func TestGetRHELv2Layers(t *testing.T) {
assert.NoError(t, err)

// Get 3 layered-image.
layers, err = datastore.GetRHELv2Layers("sha256:howdyhowdyhowdy")
layers, err = datastore.GetRHELv2Layers("sha256:howdyhowdyhowdy", "")
assert.NoError(t, err)
assert.Len(t, layers, 3)
layer = layers[2]
Expand Down
12 changes: 7 additions & 5 deletions worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,11 +123,13 @@ func ProcessLayerFromReader(datastore database.Datastore, imageFormat, name, lin
parentHash = layer.Parent.Name
}
rhelv2Layer := &database.RHELv2Layer{
Hash: layer.Name,
Dist: rhelv2Components.Dist,
Pkgs: rhelv2Components.Packages,
CPEs: rhelv2Components.CPEs,
ParentHash: parentHash,
Hash: layer.Name,
Dist: rhelv2Components.Dist,
Pkgs: rhelv2Components.Packages,
CPEs: rhelv2Components.CPEs,
ParentHash: parentHash,
Lineage: lineage,
ParentLineage: parentLineage,
}

if err := datastore.InsertRHELv2Layer(rhelv2Layer); err != nil {
Expand Down

0 comments on commit 44eb861

Please sign in to comment.