Skip to content

Commit 5aca24a

Browse files
committed
enricher: add RHCC enricher
This change introduces an enricher who's purpose is to scope down the vulnerability report for layers that have RHCC packages. This approach helps to keep the index report unchanged and therefore state is less of an issue, it also builds on existing machinary. Signed-off-by: crozzy <joseph.crosland@gmail.com>
1 parent 840e1f6 commit 5aca24a

2 files changed

Lines changed: 284 additions & 0 deletions

File tree

enricher/rhcc/rhcc.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package rhcc
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
7+
"github.com/quay/claircore"
8+
"github.com/quay/claircore/libvuln/driver"
9+
)
10+
11+
type Enricher struct{}
12+
13+
var (
14+
_ driver.Enricher = (*Enricher)(nil)
15+
)
16+
17+
const (
18+
// Type is the type of data returned from the Enricher's Enrich method.
19+
Type = `message/vnd.clair.map.vulnerability; enricher=clair.rhcc schema=??`
20+
)
21+
22+
func (e *Enricher) Name() string { return "rhcc" }
23+
24+
func (e *Enricher) Enrich(ctx context.Context, g driver.EnrichmentGetter, r *claircore.VulnerabilityReport) (string, []json.RawMessage, error) {
25+
rhLayers := []claircore.Digest{}
26+
// TODO: Should we look at repos here? Nicer to find but harder to use.
27+
for id, p := range r.Packages {
28+
if p.RepositoryHint == "rhcc" {
29+
// Grab the layers where rhcc packages exist.
30+
for _, e := range r.Environments[id] {
31+
rhLayers = append(rhLayers, e.IntroducedIn)
32+
}
33+
}
34+
}
35+
problematicPkgs := make(map[string]claircore.Digest)
36+
// Check which packages come from those layers.
37+
for pkgID, es := range r.Environments {
38+
for _, e := range es {
39+
for _, rhl := range rhLayers {
40+
if e.IntroducedIn.String() == rhl.String() && r.Packages[pkgID].RepositoryHint != "rhcc" {
41+
problematicPkgs[pkgID] = e.IntroducedIn
42+
}
43+
}
44+
}
45+
}
46+
47+
b, err := json.Marshal(problematicPkgs)
48+
if err != nil {
49+
return Type, nil, err
50+
}
51+
return Type, []json.RawMessage{b}, nil
52+
}

enricher/rhcc/rhcc_test.go

Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
package rhcc
2+
3+
import (
4+
"context"
5+
"crypto/sha256"
6+
"encoding/json"
7+
"io"
8+
"testing"
9+
10+
"github.com/google/go-cmp/cmp"
11+
"github.com/quay/zlog"
12+
13+
"github.com/quay/claircore"
14+
"github.com/quay/claircore/libvuln/driver"
15+
)
16+
17+
func Digest(name string) claircore.Digest {
18+
h := sha256.New()
19+
io.WriteString(h, name)
20+
d, err := claircore.NewDigest("sha256", h.Sum(nil))
21+
if err != nil {
22+
panic(err)
23+
}
24+
return d
25+
}
26+
27+
func TestEnrich(t *testing.T) {
28+
t.Parallel()
29+
ctx := zlog.Test(context.Background(), t)
30+
firstLayerHash := Digest("first layer")
31+
secondLayerHash := Digest("second layer")
32+
//thirdLayerHash := Digest("third layer")
33+
tests := []struct {
34+
name string
35+
vr *claircore.VulnerabilityReport
36+
layers []*claircore.Layer
37+
want map[string]string
38+
}{
39+
{
40+
name: "vuln in package in different layer from rhcc package",
41+
vr: &claircore.VulnerabilityReport{
42+
Packages: map[string]*claircore.Package{
43+
"1": {
44+
Name: "some-rh-package-slash-image",
45+
RepositoryHint: "rhcc",
46+
Version: "v1.0.0",
47+
},
48+
"2": {
49+
Name: "grafana",
50+
Version: "v4.7.0",
51+
},
52+
},
53+
Environments: map[string][]*claircore.Environment{
54+
"1": {{IntroducedIn: firstLayerHash}},
55+
"2": {{IntroducedIn: secondLayerHash}},
56+
},
57+
Vulnerabilities: map[string]*claircore.Vulnerability{
58+
"4": {
59+
Name: "something bad with grafana",
60+
FixedInVersion: "v100.0.0",
61+
},
62+
},
63+
PackageVulnerabilities: map[string][]string{
64+
"2": {"4"},
65+
},
66+
},
67+
layers: []*claircore.Layer{
68+
{Hash: firstLayerHash},
69+
{Hash: secondLayerHash},
70+
},
71+
want: map[string]string{},
72+
},
73+
{
74+
name: "vuln in package in same layer as rhcc package",
75+
vr: &claircore.VulnerabilityReport{
76+
Packages: map[string]*claircore.Package{
77+
"1": {
78+
Name: "some-rh-package-slash-image",
79+
RepositoryHint: "rhcc",
80+
Version: "v1.0.0",
81+
},
82+
"2": {
83+
Name: "grafana",
84+
Version: "v4.7.0",
85+
},
86+
},
87+
Environments: map[string][]*claircore.Environment{
88+
"1": {{IntroducedIn: firstLayerHash}},
89+
"2": {{IntroducedIn: firstLayerHash}},
90+
},
91+
Vulnerabilities: map[string]*claircore.Vulnerability{
92+
"4": {
93+
Name: "something bad with grafana",
94+
FixedInVersion: "v100.0.0",
95+
},
96+
},
97+
PackageVulnerabilities: map[string][]string{
98+
"2": {"4"},
99+
},
100+
},
101+
layers: []*claircore.Layer{
102+
{Hash: firstLayerHash},
103+
{Hash: secondLayerHash},
104+
},
105+
want: map[string]string{"2": "sha256:362c24d1f11739a9b01cfd8867469534044b7cc36ce0f56d80b023a228a1d056"},
106+
},
107+
{
108+
name: "vuln in package in same layer as rhcc package and rhcc vuln in same layer",
109+
vr: &claircore.VulnerabilityReport{
110+
Packages: map[string]*claircore.Package{
111+
"1": {
112+
Name: "some-rh-package-slash-image",
113+
RepositoryHint: "rhcc",
114+
Version: "v1.0.0",
115+
},
116+
"2": {
117+
Name: "grafana",
118+
Version: "v4.7.0",
119+
},
120+
},
121+
Environments: map[string][]*claircore.Environment{
122+
"1": {{IntroducedIn: firstLayerHash}},
123+
"2": {{IntroducedIn: firstLayerHash}},
124+
},
125+
Vulnerabilities: map[string]*claircore.Vulnerability{
126+
"4": {
127+
Name: "something bad with grafana",
128+
FixedInVersion: "v100.0.0",
129+
},
130+
"5": {
131+
Name: "something bad ubi",
132+
FixedInVersion: "v100.0.0",
133+
},
134+
},
135+
PackageVulnerabilities: map[string][]string{
136+
"2": {"4"},
137+
"1": {"5"},
138+
},
139+
},
140+
layers: []*claircore.Layer{
141+
{Hash: firstLayerHash},
142+
{Hash: secondLayerHash},
143+
},
144+
want: map[string]string{"2": "sha256:362c24d1f11739a9b01cfd8867469534044b7cc36ce0f56d80b023a228a1d056"},
145+
},
146+
{
147+
name: "multiple rhcc packages in different layers",
148+
vr: &claircore.VulnerabilityReport{
149+
Packages: map[string]*claircore.Package{
150+
"1": {
151+
Name: "some-rh-package-slash-image",
152+
RepositoryHint: "rhcc",
153+
Version: "v1.0.0",
154+
},
155+
"2": {
156+
Name: "some-other-rh-package-slash-image",
157+
RepositoryHint: "rhcc",
158+
Version: "v1.0.0",
159+
},
160+
"3": {
161+
Name: "grafana",
162+
Version: "v4.7.0",
163+
},
164+
},
165+
Environments: map[string][]*claircore.Environment{
166+
"1": {{IntroducedIn: firstLayerHash}},
167+
"2": {{IntroducedIn: firstLayerHash}},
168+
"3": {{IntroducedIn: firstLayerHash}},
169+
},
170+
Vulnerabilities: map[string]*claircore.Vulnerability{
171+
"4": {
172+
Name: "something bad with grafana",
173+
FixedInVersion: "v100.0.0",
174+
},
175+
"5": {
176+
Name: "something bad ubi",
177+
FixedInVersion: "v100.0.0",
178+
},
179+
"6": {
180+
Name: "something bad s2i",
181+
FixedInVersion: "v100.0.0",
182+
},
183+
},
184+
PackageVulnerabilities: map[string][]string{
185+
"3": {"4"},
186+
"1": {"5"},
187+
"2": {"6"},
188+
},
189+
},
190+
layers: []*claircore.Layer{
191+
{Hash: firstLayerHash},
192+
{Hash: secondLayerHash},
193+
},
194+
want: map[string]string{"3": "sha256:362c24d1f11739a9b01cfd8867469534044b7cc36ce0f56d80b023a228a1d056"},
195+
},
196+
}
197+
198+
e := &Enricher{}
199+
nog := &noopGetter{}
200+
for _, tc := range tests {
201+
t.Run(tc.name, func(t *testing.T) {
202+
tp, data, err := e.Enrich(ctx, nog, tc.vr)
203+
if err != nil {
204+
t.Fatal(err)
205+
}
206+
if tp != "message/vnd.clair.map.vulnerability; enricher=clair.rhcc schema=??" {
207+
t.Fatal("wrong type")
208+
}
209+
got := make(map[string]string)
210+
if err := json.Unmarshal(data[0], &got); err != nil {
211+
t.Error(err)
212+
}
213+
if !cmp.Equal(got, tc.want) {
214+
t.Error(cmp.Diff(got, tc.want))
215+
}
216+
})
217+
218+
}
219+
}
220+
221+
func TestName(t *testing.T) {
222+
e := &Enricher{}
223+
if e.Name() != "rhcc" {
224+
t.Fatal("name should be rhcc")
225+
}
226+
}
227+
228+
type noopGetter struct{}
229+
230+
func (f *noopGetter) GetEnrichment(ctx context.Context, tags []string) ([]driver.EnrichmentRecord, error) {
231+
return nil, nil
232+
}

0 commit comments

Comments
 (0)