@@ -2,67 +2,116 @@ package libvuln
22
33import (
44 "context"
5- "fmt "
5+ "errors "
66 "io"
77 "log/slog"
8+ "slices"
89
910 "github.com/google/uuid"
1011 "github.com/jackc/pgx/v5/pgxpool"
1112
13+ "github.com/quay/claircore"
1214 "github.com/quay/claircore/datastore/postgres"
1315 "github.com/quay/claircore/libvuln/driver"
1416 "github.com/quay/claircore/libvuln/jsonblob"
1517)
1618
19+ // BUG(hank) The OfflineImport function is a wart, needed to work around
20+ // some package namespacing issues. It should get refactored if claircore
21+ // gets merged into clair.
22+
1723// OfflineImport takes the format written into the io.Writer provided to
1824// NewOfflineUpdater and imports the contents into the provided pgxpool.Pool.
1925//
2026// The format provided on "in" should be the same output from [jsonblob.Store], with
2127// any compression undone.
2228func OfflineImport (ctx context.Context , pool * pgxpool.Pool , in io.Reader ) error {
23- // BUG(hank) The OfflineImport function is a wart, needed to work around
24- // some package namespacing issues. It should get refactored if claircore
25- // gets merged into clair.
2629 s := postgres .NewMatcherStore (pool )
27- l , err := jsonblob .Load (ctx , in )
30+ ld , err := jsonblob .NewLoader (ctx , in )
2831 if err != nil {
2932 return err
3033 }
31-
32- ops , err := s .GetUpdateOperations (ctx , driver .VulnerabilityKind )
34+ vulns , err := s .GetUpdateOperations (ctx , driver .VulnerabilityKind )
35+ if err != nil {
36+ return err
37+ }
38+ enrichers , err := s .GetUpdateOperations (ctx , driver .EnrichmentKind )
3339 if err != nil {
3440 return err
3541 }
3642
37- Update:
38- for l .Next () {
39- e := l .Entry ()
40- log := slog .With ("updater" , e .Updater )
41- for _ , op := range ops [e .Updater ] {
42- // This only helps if updaters don't keep something that
43- // changes in the fingerprint.
44- if op .Fingerprint == e .Fingerprint {
45- log .InfoContext (ctx , "fingerprint match, skipping" )
46- continue Update
47- }
43+ for e , seq := range ld .All () {
44+ l := slog .With ("updater" , e .Updater )
45+ var check []driver.UpdateOperation
46+ switch e .Kind {
47+ case driver .VulnerabilityKind :
48+ check = vulns [e .Updater ]
49+ case driver .EnrichmentKind :
50+ check = enrichers [e .Updater ]
4851 }
52+ seen := slices .ContainsFunc (check , func (op driver.UpdateOperation ) bool {
53+ return op .Fingerprint == e .Fingerprint
54+ })
55+ if seen {
56+ l .InfoContext (ctx , "fingerprint match, skipping" )
57+ continue
58+ }
59+
60+ l .InfoContext (ctx , "new update" )
4961 var ref uuid.UUID
50- if e .Enrichment != nil {
51- if ref , err = s .UpdateEnrichments (ctx , e .Updater , e .Fingerprint , e .Enrichment ); err != nil {
52- return fmt .Errorf ("updating enrichements: %w" , err )
62+ var vulnCt , enrichCt int
63+ switch e .Kind {
64+ case driver .VulnerabilityKind :
65+ wrap := func (yield func (* claircore.Vulnerability , error ) bool ) {
66+ for v := range seq {
67+ if v == nil {
68+ if ! yield (nil , ld .Err ()) {
69+ return
70+ }
71+ continue
72+ }
73+ vulnCt ++
74+ if ! yield (v , nil ) {
75+ return
76+ }
77+ jsonblob .ReturnVulnerability (v )
78+ }
5379 }
54- }
55- if e .Vuln != nil {
56- if ref , err = s .UpdateVulnerabilities (ctx , e .Updater , e .Fingerprint , e .Vuln ); err != nil {
57- return fmt .Errorf ("updating vulnerabilities: %w" , err )
80+ ref , err = s .UpdateVulnerabilitiesIter (ctx , e .Updater , e .Fingerprint , wrap )
81+ case driver .EnrichmentKind :
82+ wrap := func (yield func (* driver.EnrichmentRecord , error ) bool ) {
83+ for _ , e := range seq {
84+ if e == nil {
85+ if ! yield (nil , ld .Err ()) {
86+ return
87+ }
88+ continue
89+ }
90+ enrichCt ++
91+ if ! yield (e , nil ) {
92+ return
93+ }
94+ jsonblob .ReturnEnrichment (e )
95+ }
5896 }
97+ ref , err = s .UpdateEnrichmentsIter (ctx , e .Updater , e .Fingerprint , wrap )
98+ default :
99+ panic ("unreachable" )
100+ }
101+ if err == nil {
102+ l .InfoContext (
103+ ctx , "update imported" ,
104+ "ref" , ref ,
105+ "vuln_count" , vulnCt ,
106+ "enrichment_count" , enrichCt ,
107+ )
108+ } else {
109+ l .InfoContext (ctx , "update failed" , "reason" , err )
110+ break
59111 }
60- log .InfoContext (ctx , "update imported" ,
61- "ref" , ref ,
62- "vuln_count" , len (e .Vuln ),
63- "enrichment_count" , len (e .Enrichment ))
64112 }
65- if err := l .Err (); err != nil {
113+
114+ if err := errors .Join (err , ld .Err ()); err != nil {
66115 return err
67116 }
68117 return nil
0 commit comments