Skip to content

Commit 82e3e3c

Browse files
committed
postgres/v2: add new postgres store package
Signed-off-by: Hank Donnay <[email protected]>
1 parent 74056e3 commit 82e3e3c

File tree

144 files changed

+8874
-4
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

144 files changed

+8874
-4
lines changed
Lines changed: 300 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,300 @@
1+
package postgres
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"os"
7+
"path/filepath"
8+
"testing"
9+
10+
"github.com/jackc/pgx/v5/pgxpool"
11+
"github.com/quay/zlog"
12+
13+
"github.com/quay/claircore"
14+
"github.com/quay/claircore/indexer"
15+
"github.com/quay/claircore/pkg/omnimatcher"
16+
"github.com/quay/claircore/test/integration"
17+
pgtest "github.com/quay/claircore/test/postgres/v2"
18+
)
19+
20+
type affectedE2E struct {
21+
store indexer.Store
22+
pool *pgxpool.Pool
23+
ctx context.Context
24+
ir claircore.IndexReport
25+
vr claircore.VulnerabilityReport
26+
}
27+
28+
func TestAffectedE2E(t *testing.T) {
29+
integration.NeedDB(t)
30+
ctx := zlog.Test(context.Background(), t)
31+
cfg := pgtest.TestIndexerDB(ctx, t)
32+
store, err := NewIndexer(ctx, cfg, WithMigrations)
33+
if err != nil {
34+
t.Fatal(err)
35+
}
36+
defer store.Close(ctx)
37+
pool, err := pgxpool.NewWithConfig(ctx, cfg)
38+
if err != nil {
39+
t.Fatal(err)
40+
}
41+
t.Cleanup(pool.Close)
42+
43+
table := []struct {
44+
// name of the defined affectedE2E test
45+
name string
46+
// file name of index report in ./testdata
47+
irFName string
48+
// file name of vuln report in ./testdata
49+
vrFName string
50+
}{
51+
// these fixtures
52+
// were generated against the same database
53+
// to ensure all ids are sequentially increasing
54+
//
55+
// if fixtures are added you must generate
56+
// this current set *and* your new fixtures against the same database
57+
// to ensure there are no ID overlaps
58+
//
59+
// generate them via go generate github.com/quay/claircore/datastore/postgres
60+
{
61+
name: "amazonlinux 1",
62+
irFName: "docker.io-library-amazonlinux-1.index.json",
63+
vrFName: "docker.io-library-amazonlinux-1.report.json",
64+
},
65+
{
66+
name: "debian 8",
67+
irFName: "docker.io-library-debian-8.index.json",
68+
vrFName: "docker.io-library-debian-8.report.json",
69+
},
70+
{
71+
name: "debian 9",
72+
irFName: "docker.io-library-debian-9.index.json",
73+
vrFName: "docker.io-library-debian-9.report.json",
74+
},
75+
{
76+
name: "debian 10",
77+
irFName: "docker.io-library-debian-10.index.json",
78+
vrFName: "docker.io-library-debian-10.report.json",
79+
},
80+
{
81+
name: "ubi 8",
82+
irFName: "registry.access.redhat.com-ubi8-ubi.index.json",
83+
vrFName: "registry.access.redhat.com-ubi8-ubi.report.json",
84+
},
85+
{
86+
name: "ubuntu 16.04",
87+
irFName: "docker.io-library-ubuntu-16.04.index.json",
88+
vrFName: "docker.io-library-ubuntu-16.04.report.json",
89+
},
90+
{
91+
name: "ubuntu 18.04",
92+
irFName: "docker.io-library-ubuntu-18.04.index.json",
93+
vrFName: "docker.io-library-ubuntu-18.04.report.json",
94+
},
95+
{
96+
name: "ubuntu 19.10",
97+
irFName: "docker.io-library-ubuntu-19.10.index.json",
98+
vrFName: "docker.io-library-ubuntu-19.10.report.json",
99+
},
100+
{
101+
name: "ubuntu 20.04",
102+
irFName: "docker.io-library-ubuntu-20.04.index.json",
103+
vrFName: "docker.io-library-ubuntu-20.04.report.json",
104+
},
105+
{
106+
name: "mitmproxy 4.0.1",
107+
irFName: "docker.io-mitmproxy-mitmproxy-4.0.1.index.json",
108+
vrFName: "docker.io-mitmproxy-mitmproxy-4.0.1.report.json",
109+
},
110+
}
111+
112+
for _, tt := range table {
113+
// grab and deserialize test data
114+
irPath := filepath.Join("testdata", tt.irFName)
115+
vrPath := filepath.Join("testdata", tt.vrFName)
116+
irFD, err := os.Open(irPath)
117+
if err != nil {
118+
t.Fatalf("fd open for ir failed: %v", err)
119+
}
120+
vrFD, err := os.Open(vrPath)
121+
if err != nil {
122+
t.Fatalf("fd open for vr failed: %v", err)
123+
}
124+
125+
var ir claircore.IndexReport
126+
var vr claircore.VulnerabilityReport
127+
128+
err = json.NewDecoder(irFD).Decode(&ir)
129+
if err != nil {
130+
t.Fatalf("could not decode ir: %v", err)
131+
}
132+
133+
err = json.NewDecoder(vrFD).Decode(&vr)
134+
if err != nil {
135+
t.Fatalf("could not decode vr: %v", err)
136+
}
137+
138+
// create and run e2e test
139+
e2e := &affectedE2E{
140+
store: store,
141+
pool: pool,
142+
ctx: ctx,
143+
ir: ir,
144+
vr: vr,
145+
}
146+
t.Run(tt.name, e2e.Run)
147+
}
148+
}
149+
150+
func (e *affectedE2E) Run(t *testing.T) {
151+
type subtest struct {
152+
name string
153+
do func(t *testing.T)
154+
}
155+
subtests := [...]subtest{
156+
{"IndexArtifacts", e.IndexArtifacts},
157+
{"IndexManifest", e.IndexManifest},
158+
{"AffectedManifests", e.AffectedManifests},
159+
}
160+
if len(e.vr.Vulnerabilities) == 0 {
161+
t.Fatal("bad test harness: no vulnerabilities")
162+
}
163+
for _, subtest := range subtests {
164+
if !t.Run(subtest.name, subtest.do) {
165+
t.FailNow()
166+
}
167+
}
168+
}
169+
170+
// IndexArtifacts manually writes all the necessary
171+
// artifacts to the db.
172+
//
173+
// this is required so foreign key constraints do not
174+
// fail in later tests.
175+
func (e *affectedE2E) IndexArtifacts(t *testing.T) {
176+
ctx := zlog.Test(e.ctx, t)
177+
const (
178+
insertManifest = `
179+
INSERT INTO manifest
180+
(hash)
181+
VALUES ($1)
182+
ON CONFLICT DO NOTHING;
183+
`
184+
insertPkg = `
185+
INSERT INTO package (name, kind, version, norm_kind, norm_version, module, arch, id)
186+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
187+
ON CONFLICT DO NOTHING;
188+
`
189+
insertDist = `
190+
INSERT INTO dist
191+
(name, did, version, version_code_name, version_id, arch, cpe, pretty_name, id)
192+
VALUES
193+
($1, $2, $3, $4, $5, $6, $7, $8, $9)
194+
ON CONFLICT DO NOTHING;
195+
`
196+
insertRepo = `
197+
INSERT INTO repo
198+
(name, key, uri, id)
199+
VALUES ($1, $2, $3, $4)
200+
ON CONFLICT DO NOTHING;
201+
`
202+
)
203+
_, err := e.pool.Exec(ctx, insertManifest, e.ir.Hash.String())
204+
if err != nil {
205+
t.Fatalf("failed to insert manifest: %v", err)
206+
}
207+
for _, pkg := range e.ir.Packages {
208+
_, err := e.pool.Exec(ctx, insertPkg,
209+
pkg.Name,
210+
pkg.Kind,
211+
pkg.Version,
212+
pkg.NormalizedVersion.Kind,
213+
pkg.NormalizedVersion,
214+
pkg.Module,
215+
pkg.Arch,
216+
pkg.ID,
217+
)
218+
if err != nil {
219+
t.Fatalf("failed to insert package: %v", err)
220+
}
221+
if pkg.Source != nil {
222+
pkg := pkg.Source
223+
_, err := e.pool.Exec(ctx, insertPkg,
224+
pkg.Name,
225+
pkg.Kind,
226+
pkg.Version,
227+
pkg.NormalizedVersion.Kind,
228+
pkg.NormalizedVersion,
229+
pkg.Module,
230+
pkg.Arch,
231+
pkg.ID,
232+
)
233+
if err != nil {
234+
t.Fatalf("failed to insert source package: %v", err)
235+
}
236+
}
237+
}
238+
for _, dist := range e.ir.Distributions {
239+
_, err := e.pool.Exec(ctx, insertDist,
240+
dist.Name,
241+
dist.DID,
242+
dist.Version,
243+
dist.VersionCodeName,
244+
dist.VersionID,
245+
dist.Arch,
246+
dist.CPE,
247+
dist.PrettyName,
248+
dist.ID,
249+
)
250+
if err != nil {
251+
t.Fatalf("failed to insert dist: %v", err)
252+
}
253+
}
254+
for _, repo := range e.ir.Repositories {
255+
_, err := e.pool.Exec(ctx, insertRepo,
256+
repo.Name,
257+
repo.Key,
258+
repo.URI,
259+
repo.ID,
260+
)
261+
if err != nil {
262+
t.Fatalf("failed to insert repo: %v", err)
263+
}
264+
}
265+
}
266+
267+
// IndexManifest confirms the contents of a manifest
268+
// can be written to the manifest index table.
269+
func (e *affectedE2E) IndexManifest(t *testing.T) {
270+
ctx := zlog.Test(e.ctx, t)
271+
err := e.store.IndexManifest(ctx, &e.ir)
272+
if err != nil {
273+
t.Fatalf("failed to index manifest: %v", err)
274+
}
275+
}
276+
277+
// AffectedManifests confirms each vulnerability
278+
// in the vulnereability report reports the associated
279+
// manifest is affected.
280+
func (e *affectedE2E) AffectedManifests(t *testing.T) {
281+
ctx := zlog.Test(e.ctx, t)
282+
om := omnimatcher.New(nil)
283+
for _, vuln := range e.vr.Vulnerabilities {
284+
t.Logf("vulnerability: %s (%s)", vuln.Name, vuln.Package.Name)
285+
hashes, err := e.store.AffectedManifests(ctx, *vuln, om.Vulnerable)
286+
if err != nil {
287+
t.Fatalf("failed to retrieve affected manifest for vuln %s: %v", vuln.ID, err)
288+
}
289+
290+
if len(hashes) != 1 {
291+
t.Fatalf("got: len(hashes)==%d, want: len(hashes)==1", len(hashes))
292+
}
293+
294+
got := hashes[0].String()
295+
wanted := e.ir.Hash.String()
296+
if got != wanted {
297+
t.Fatalf("got: %v, want: %v", got, wanted)
298+
}
299+
}
300+
}

0 commit comments

Comments
 (0)