github.com/quay/claircore@v1.5.28/rhel/rhcc/matcher_integration_test.go (about)

     1  package rhcc
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"io"
     8  	"net/http"
     9  	"net/http/httptest"
    10  	"os"
    11  	"path/filepath"
    12  	"testing"
    13  
    14  	"github.com/quay/zlog"
    15  
    16  	"github.com/quay/claircore"
    17  	"github.com/quay/claircore/datastore/postgres"
    18  	match_engine "github.com/quay/claircore/internal/matcher"
    19  	"github.com/quay/claircore/libvuln/driver"
    20  	"github.com/quay/claircore/libvuln/updates"
    21  	"github.com/quay/claircore/pkg/ctxlock"
    22  	"github.com/quay/claircore/test/integration"
    23  	testpostgres "github.com/quay/claircore/test/postgres"
    24  )
    25  
    26  func TestMain(m *testing.M) {
    27  	var c int
    28  	defer func() { os.Exit(c) }()
    29  	defer integration.DBSetup()()
    30  	c = m.Run()
    31  }
    32  
    33  func TestMatcherIntegration(t *testing.T) {
    34  	t.Parallel()
    35  
    36  	type testcase struct {
    37  		Name        string
    38  		cvemap      string
    39  		indexReport string
    40  		cveID       string
    41  		match       bool
    42  	}
    43  	table := []testcase{
    44  		{
    45  			Name:        "Clair",
    46  			cvemap:      "cve-2021-3762",
    47  			indexReport: "clair-rhel8-v3.5.5-4",
    48  			cveID:       "RHSA-2021:3665",
    49  			match:       true,
    50  		},
    51  		{
    52  			Name:        "Rook4.6",
    53  			cvemap:      "cve-2020-8565",
    54  			indexReport: "rook-ceph-operator-container-4.6-115.d1788e1.release_4.6",
    55  			cveID:       "RHSA-2021:2041",
    56  			match:       true,
    57  		},
    58  		{
    59  			Name:        "Rook4.7",
    60  			cvemap:      "cve-2020-8565",
    61  			indexReport: "rook-ceph-operator-container-4.7-159.76b9b11.release_4.7",
    62  			cveID:       "RHSA-2021:2041",
    63  			match:       false,
    64  		},
    65  	}
    66  
    67  	for i := range table {
    68  		tt := &table[i]
    69  		t.Run(tt.Name, func(t *testing.T) {
    70  			t.Parallel()
    71  			integration.NeedDB(t)
    72  			ctx := zlog.Test(context.Background(), t)
    73  			pool := testpostgres.TestMatcherDB(ctx, t)
    74  			store := postgres.NewMatcherStore(pool)
    75  			m := &matcher{}
    76  
    77  			serveFile := filepath.Join("testdata", tt.cvemap+".xml")
    78  			fi, err := os.Stat(serveFile)
    79  			if err != nil {
    80  				t.Fatal(err)
    81  			}
    82  			tag := fmt.Sprintf(`"%d"`, fi.ModTime().UnixNano())
    83  			srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    84  				switch r.URL.Path {
    85  				case "/cvemap.xml":
    86  					w.Header().Set("etag", tag)
    87  					http.ServeFile(w, r, serveFile)
    88  				case "/cvemap.xml.bz2":
    89  					http.Error(w, "no bz2", http.StatusNotFound)
    90  				default:
    91  					t.Errorf("unexpected request: %s", r.URL)
    92  					http.Error(w, "???", http.StatusNotImplemented)
    93  				}
    94  			}))
    95  			defer srv.Close()
    96  			s := driver.NewUpdaterSet()
    97  			if err := s.Add(new(updater)); err != nil {
    98  				t.Error(err)
    99  			}
   100  			cfg := updates.Configs{
   101  				updaterName: func(v any) error {
   102  					cfg := v.(*UpdaterConfig)
   103  					cfg.URL = srv.URL + "/cvemap.xml"
   104  					return nil
   105  				},
   106  			}
   107  
   108  			locks, err := ctxlock.New(ctx, pool)
   109  			if err != nil {
   110  				t.Error(err)
   111  			}
   112  			defer locks.Close(ctx)
   113  
   114  			facs := make(map[string]driver.UpdaterSetFactory, 1)
   115  			facs[updaterName] = driver.StaticSet(s)
   116  			mgr, err := updates.NewManager(ctx, store, locks, srv.Client(), updates.WithFactories(facs), updates.WithConfigs(cfg))
   117  			if err != nil {
   118  				t.Error(err)
   119  			}
   120  
   121  			// force update
   122  			if err := mgr.Run(ctx); err != nil {
   123  				t.Error(err)
   124  			}
   125  
   126  			f, err := os.Open(filepath.Join("testdata", fmt.Sprintf("%s-indexreport.json", tt.indexReport)))
   127  			if err != nil {
   128  				t.Fatalf("%v", err)
   129  			}
   130  			defer f.Close()
   131  			var ir claircore.IndexReport
   132  			if err := json.NewDecoder(f).Decode(&ir); err != nil {
   133  				t.Fatalf("failed to decode IndexReport: %v", err)
   134  			}
   135  			vr, err := match_engine.Match(ctx, &ir, []driver.Matcher{m}, store)
   136  			if err != nil {
   137  				t.Fatal(err)
   138  			}
   139  			found := false
   140  			vulns := vr.Vulnerabilities
   141  			for _, vuln := range vulns {
   142  				t.Log(vuln.Name)
   143  				if vuln.Name == tt.cveID {
   144  					found = true
   145  				}
   146  			}
   147  			if found != tt.match {
   148  				t.Fatalf("Expected to find %s in vulnerability report", tt.cveID)
   149  			}
   150  			if err := json.NewEncoder(io.Discard).Encode(&vr); err != nil {
   151  				t.Fatalf("failed to marshal VR: %v", err)
   152  			}
   153  		})
   154  	}
   155  }