Skip to content

Commit

Permalink
rhel: move IgnoreUnpatched config key from updater to matcher
Browse files Browse the repository at this point in the history
Previously the IgnoreUnpatched config key was a part of the RHEL
updater and would dictate whether or not the updater would ingest
unpatched vulnerabilities. This change moves that key to the RHEL
matcher and dictates whether the matcher should check for a
fixed_in_version when querying potential vulnerabilities. This makes the
config option more usable at the expense of DB size.

Signed-off-by: crozzy <[email protected]>
  • Loading branch information
crozzy committed Aug 14, 2024
1 parent 6063f57 commit 9380870
Show file tree
Hide file tree
Showing 8 changed files with 83 additions and 22 deletions.
3 changes: 3 additions & 0 deletions datastore/postgres/querybuilder.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

"github.com/doug-martin/goqu/v8"
_ "github.com/doug-martin/goqu/v8/dialect/postgres"
"github.com/doug-martin/goqu/v8/exp"

"github.com/quay/claircore"
"github.com/quay/claircore/datastore"
Expand Down Expand Up @@ -70,6 +71,8 @@ func buildGetQuery(record *claircore.IndexRecord, opts *datastore.GetOpts) (stri
ex = goqu.Ex{"dist_arch": record.Distribution.Arch}
case driver.RepositoryName:
ex = goqu.Ex{"repo_name": record.Repository.Name}
case driver.HasFixedInVersion:
ex = goqu.Ex{"fixed_in_version": goqu.Op{exp.NeqOp.String(): ""}}
default:
return "", fmt.Errorf("was provided unknown matcher: %v", m)
}
Expand Down
14 changes: 14 additions & 0 deletions datastore/postgres/querybuilder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,20 @@ func TestGetQueryBuilderDeterministicArgs(t *testing.T) {
}
},
},
{
name: "FixedInVersion",
expectedQuery: preamble + both +
`("fixed_in_version" != '')` + epilogue,
matchExps: []driver.MatchConstraint{driver.HasFixedInVersion},
indexRecord: func() *claircore.IndexRecord {
pkgs := test.GenUniquePackages(1)
dists := test.GenUniqueDistributions(1)
return &claircore.IndexRecord{
Package: pkgs[0],
Distribution: dists[0],
}
},
},
}

// This is safe to do because SQL doesn't care about what whitespace is
Expand Down
2 changes: 2 additions & 0 deletions libvuln/driver/matcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ const (
DistributionPrettyName
// should match claircore.Package.Repository.Name => claircore.Vulnerability.Package.Repository.Name
RepositoryName
// should match claircore.Vulnerability.FixedInVersion != ""
HasFixedInVersion
)

// Matcher is an interface which a Controller uses to query the vulnstore for vulnerabilities.
Expand Down
2 changes: 1 addition & 1 deletion matchers/defaults/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,13 @@ var defaultMatchers = []driver.Matcher{
&photon.Matcher{},
&python.Matcher{},
rhcc.Matcher,
&rhel.Matcher{},
&ruby.Matcher{},
&suse.Matcher{},
&ubuntu.Matcher{},
}

func inner(ctx context.Context) error {
registry.Register("rhel", &rhel.MatcherFactory{})
for _, m := range defaultMatchers {
mf := driver.MatcherStatic(m)
registry.Register(m.Name(), mf)
Expand Down
12 changes: 8 additions & 4 deletions rhel/matcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ import (
)

// Matcher implements driver.Matcher.
type Matcher struct{}
type Matcher struct {
ignoreUnpatched bool
}

var _ driver.Matcher = (*Matcher)(nil)

Expand All @@ -28,10 +30,12 @@ func (*Matcher) Filter(record *claircore.IndexRecord) bool {
}

// Query implements driver.Matcher.
func (*Matcher) Query() []driver.MatchConstraint {
return []driver.MatchConstraint{
driver.PackageModule,
func (m *Matcher) Query() []driver.MatchConstraint {
mcs := []driver.MatchConstraint{driver.PackageModule}
if m.ignoreUnpatched {
mcs = append(mcs, driver.HasFixedInVersion)
}
return mcs
}

// IsCPESubstringMatch is a Red Hat specific hack that handles the "CPE patterns" in the VEX
Expand Down
45 changes: 45 additions & 0 deletions rhel/matcherfactory.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package rhel

import (
"context"
"net/http"

"github.com/quay/zlog"

"github.com/quay/claircore/libvuln/driver"
)

var (
_ driver.MatcherFactory = (*MatcherFactory)(nil)
_ driver.MatcherConfigurable = (*MatcherFactory)(nil)
)

type MatcherFactory struct {
ignoreUnpatched bool
}

// MatcherFactory implements [driver.MatcherFactory]
func (f *MatcherFactory) Matcher(ctx context.Context) ([]driver.Matcher, error) {
m := &Matcher{
ignoreUnpatched: f.ignoreUnpatched,
}
return []driver.Matcher{m}, nil
}

type MatcherFactoryConfig struct {
IgnoreUnpatched bool `json:"ignore_unpatched" yaml:"ignore_unpatched"`
}

// MatcherFactory implements driver.MatcherConfigurable.
func (f *MatcherFactory) Configure(ctx context.Context, cfg driver.MatcherConfigUnmarshaler, _ *http.Client) error {
var fc MatcherFactoryConfig
if err := cfg(&fc); err != nil {
return err
}
f.ignoreUnpatched = fc.IgnoreUnpatched
zlog.Info(ctx).
Str("component", "rhel/MatcherFactory.Configure").
Bool("ignore_unpatched", f.ignoreUnpatched).
Msg("configured")
return nil
}
10 changes: 4 additions & 6 deletions rhel/vex/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,11 @@ func (u *Updater) DeltaParse(ctx context.Context, contents io.ReadCloser) ([]*cl
return nil, nil, err
}
out[name] = fixedVulns
if !u.ignoreUnpatched {
knownAffectedVulns, err := creator.knownAffectedVulnerabilities(ctx, v, protoVuln)
if err != nil {
return nil, nil, err
}
out[name] = append(out[name], knownAffectedVulns...)
knownAffectedVulns, err := creator.knownAffectedVulnerabilities(ctx, v, protoVuln)
if err != nil {
return nil, nil, err
}
out[name] = append(out[name], knownAffectedVulns...)
}
}
vulns := []*claircore.Vulnerability{}
Expand Down
17 changes: 6 additions & 11 deletions rhel/vex/updater.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,16 @@ const (
//
// [Configure] must be called before [UpdaterSet].
type Factory struct {
c *http.Client
base *url.URL
ignoreUnpatched bool
c *http.Client
base *url.URL
}

// UpdaterSet constructs one Updater
func (f *Factory) UpdaterSet(_ context.Context) (driver.UpdaterSet, error) {
us := driver.NewUpdaterSet()
u := &Updater{
url: f.base,
client: f.c,
ignoreUnpatched: f.ignoreUnpatched,
url: f.base,
client: f.c,
}
err := us.Add(u)
if err != nil {
Expand All @@ -69,8 +67,6 @@ type FactoryConfig struct {
//
// Must include the trailing slash.
URL string `json:"url" yaml:"url"`
// IgnoreUnpatched dictates whether to ingest known affected advisories from the VEX security data.
IgnoreUnpatched bool `json:"ignore_unpatched" yaml:"ignore_unpatched"`
}

// Configure implements driver.Configurable
Expand Down Expand Up @@ -98,9 +94,8 @@ func (f *Factory) Configure(ctx context.Context, cf driver.ConfigUnmarshaler, c
// Updater is responsible from reading VEX data served at the URL
// and creating vulnerabilities.
type Updater struct {
url *url.URL
client *http.Client
ignoreUnpatched bool
url *url.URL
client *http.Client
}

// fingerprint is used to track the state of the changes.csv and deletions.csv endpoints.
Expand Down

0 comments on commit 9380870

Please sign in to comment.