github.com/quay/claircore@v1.5.28/updater/osv/osv_test.go (about) 1 package osv 2 3 import ( 4 "archive/zip" 5 "bufio" 6 "bytes" 7 "context" 8 "encoding/json" 9 "errors" 10 "fmt" 11 "io" 12 "io/fs" 13 "net/http" 14 "net/http/httptest" 15 "os" 16 "path" 17 "path/filepath" 18 "strings" 19 "testing" 20 21 "github.com/quay/zlog" 22 23 "github.com/quay/claircore" 24 "github.com/quay/claircore/libvuln/driver" 25 ) 26 27 func TestFetch(t *testing.T) { 28 srv := httptest.NewServer(&apiStub{t, ""}) 29 defer srv.Close() 30 ctx := zlog.Test(context.Background(), t) 31 32 f := Factory{} 33 cfgFunc := func(v interface{}) error { 34 cfg := v.(*FactoryConfig) 35 cfg.URL = srv.URL 36 return nil 37 } 38 if err := f.Configure(ctx, cfgFunc, srv.Client()); err != nil { 39 t.Error(err) 40 } 41 42 s, err := f.UpdaterSet(ctx) 43 if err != nil { 44 t.Error(err) 45 } 46 if len(s.Updaters()) == 0 { 47 t.Errorf("expected more than 0 updaters") 48 } 49 50 for _, u := range s.Updaters() { 51 rc, fp, err := u.Fetch(ctx, driver.Fingerprint("")) 52 if err != nil { 53 t.Error(err) 54 } 55 _ = fp 56 if rc != nil { 57 rc.Close() 58 } 59 60 } 61 } 62 63 type apiStub struct { 64 *testing.T 65 path string 66 } 67 68 func (a *apiStub) ServeHTTP(w http.ResponseWriter, r *http.Request) { 69 a.Logf("req: %s", r.RequestURI) 70 sys := os.DirFS(filepath.Join("testdata", a.path)) 71 p := r.URL.Path 72 switch { 73 case p == "/ecosystems.txt": 74 out := bufio.NewWriter(w) 75 defer out.Flush() 76 fmt.Fprintln(out, "testing_ecosystem") 77 ms, err := fs.Glob(sys, "*.zip") 78 if err != nil { 79 panic(err) // can only ever be ErrBadPatern 80 } 81 for _, m := range ms { 82 fmt.Fprintln(out, strings.TrimSuffix(m, ".zip")) 83 } 84 case strings.HasSuffix(p, "all.zip"): 85 w.WriteHeader(http.StatusOK) 86 n := strings.ToLower(path.Dir(p)[1:]) + ".zip" 87 a.Logf("serving %q", n) 88 if f, err := sys.Open(n); errors.Is(err, nil) { 89 defer f.Close() 90 if _, err := io.Copy(w, f); err != nil { 91 a.Error(err) 92 } 93 return 94 } 95 z := zip.NewWriter(w) 96 if err := z.SetComment("empty zip"); err != nil { 97 a.Error(err) 98 } 99 if err := z.Close(); err != nil { 100 a.Error(err) 101 } 102 default: 103 w.WriteHeader(http.StatusNotFound) 104 } 105 } 106 107 func TestParse(t *testing.T) { 108 srv := httptest.NewServer(&apiStub{t, ""}) 109 defer srv.Close() 110 ctx := zlog.Test(context.Background(), t) 111 112 f := Factory{} 113 cfgFunc := func(v interface{}) error { 114 cfg := v.(*FactoryConfig) 115 cfg.URL = srv.URL 116 return nil 117 } 118 if err := f.Configure(ctx, cfgFunc, srv.Client()); err != nil { 119 t.Error(err) 120 } 121 s, err := f.UpdaterSet(ctx) 122 if err != nil { 123 t.Error(err) 124 } 125 if len(s.Updaters()) == 0 { 126 t.Errorf("expected more than 0 updaters") 127 } 128 129 for _, u := range s.Updaters() { 130 rc, _, err := u.Fetch(ctx, driver.Fingerprint("")) 131 if err != nil { 132 t.Error(err) 133 } 134 defer rc.Close() 135 vs, err := u.Parse(ctx, rc) 136 if err != nil { 137 t.Error(err) 138 } 139 t.Logf("parsed %d vulnerabilities", len(vs)) 140 if len(vs) != 0 { 141 t.Log("first one:") 142 var buf bytes.Buffer 143 enc := json.NewEncoder(&buf) 144 enc.SetIndent("", "\t") 145 if err := enc.Encode(vs[0]); err != nil { 146 t.Error(err) 147 } 148 t.Log(buf.String()) 149 } 150 } 151 } 152 153 var severityTestCases = []struct { 154 name string 155 a *advisory 156 expectedNormalizedSeverity claircore.Severity 157 expectedSeverity string 158 }{ 159 { 160 name: "CVSS V3 HIGH", 161 a: &advisory{ 162 ID: "test1", 163 Severity: []severity{ 164 { 165 Type: "CVSS_V3", 166 Score: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N", 167 }, 168 }, 169 Affected: []affected{ 170 { 171 Package: _package{ 172 Ecosystem: "go", 173 Name: "something", 174 }, 175 Ranges: []_range{ 176 { 177 Type: "ECOSYSTEM", 178 Events: []rangeEvent{ 179 { 180 Introduced: "0.1", 181 Fixed: "0.4", 182 }, 183 }, 184 }, 185 }, 186 }, 187 }, 188 }, 189 expectedNormalizedSeverity: claircore.High, 190 expectedSeverity: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N", 191 }, 192 { 193 name: "CVSS V2 MEDIUM", 194 a: &advisory{ 195 ID: "test2", 196 Severity: []severity{ 197 { 198 Type: "CVSS_V2", 199 Score: "AV:L/AC:H/Au:N/C:C/I:C/A:C", 200 }, 201 }, 202 Affected: []affected{ 203 { 204 Package: _package{ 205 Ecosystem: "go", 206 Name: "something", 207 }, 208 Ranges: []_range{ 209 { 210 Type: "ECOSYSTEM", 211 Events: []rangeEvent{ 212 { 213 Introduced: "0.1", 214 Fixed: "0.4", 215 }, 216 }, 217 }, 218 }, 219 }, 220 }, 221 }, 222 expectedNormalizedSeverity: claircore.Medium, 223 expectedSeverity: "AV:L/AC:H/Au:N/C:C/I:C/A:C", 224 }, 225 { 226 name: "database_specific moderate", 227 a: &advisory{ 228 ID: "test2", 229 Affected: []affected{ 230 { 231 Package: _package{ 232 Ecosystem: "go", 233 Name: "something", 234 }, 235 Ranges: []_range{ 236 { 237 Type: "ECOSYSTEM", 238 Events: []rangeEvent{ 239 { 240 Introduced: "0.1", 241 Fixed: "0.4", 242 }, 243 }, 244 }, 245 }, 246 }, 247 }, 248 Database: json.RawMessage([]byte(`{"severity":"moderate"}`)), 249 }, 250 expectedNormalizedSeverity: claircore.Medium, 251 expectedSeverity: "moderate", 252 }, 253 { 254 name: "CVSS V3 HIGH and database_specific moderate", 255 a: &advisory{ 256 ID: "test2", 257 Severity: []severity{ 258 { 259 Type: "CVSS_V3", 260 Score: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N", 261 }, 262 }, 263 Affected: []affected{ 264 { 265 Package: _package{ 266 Ecosystem: "go", 267 Name: "something", 268 }, 269 Ranges: []_range{ 270 { 271 Type: "ECOSYSTEM", 272 Events: []rangeEvent{ 273 { 274 Introduced: "0.1", 275 Fixed: "0.4", 276 }, 277 }, 278 }, 279 }, 280 }, 281 }, 282 Database: json.RawMessage([]byte(`{"severity":"moderate"}`)), 283 }, 284 expectedNormalizedSeverity: claircore.High, 285 expectedSeverity: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N", 286 }, 287 } 288 289 func TestSeverityParsing(t *testing.T) { 290 ctx := zlog.Test(context.Background(), t) 291 292 for _, tt := range severityTestCases { 293 t.Run(tt.name, func(t *testing.T) { 294 ecs := newECS("test") 295 296 err := ecs.Insert(ctx, nil, "", tt.a) 297 if err != nil { 298 t.Error("got error Inserting advisory", err) 299 } 300 if len(ecs.Vulnerability) != 1 { 301 t.Errorf("should have one vulnerability but got %d", len(ecs.Vulnerability)) 302 } 303 v := ecs.Vulnerability[0] 304 if v.NormalizedSeverity != tt.expectedNormalizedSeverity { 305 t.Errorf("expected severity %q but got %q", tt.expectedNormalizedSeverity, v.NormalizedSeverity) 306 } 307 if v.Severity != tt.expectedSeverity { 308 t.Errorf("expected severity %q but got %q", tt.expectedSeverity, v.Severity) 309 } 310 311 }) 312 } 313 }