bitbucket.org/Aishee/synsec@v0.0.0-20210414005726-236fc01a153d/pkg/cwhub/cwhub_test.go (about) 1 package cwhub 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "net/http" 7 "os" 8 "path/filepath" 9 "strings" 10 "testing" 11 12 "bitbucket.org/Aishee/synsec/pkg/csconfig" 13 log "github.com/sirupsen/logrus" 14 ) 15 16 /* 17 To test : 18 - Download 'first' hub index 19 - Update hub index 20 - Install collection + list content 21 - Taint existing parser + list 22 - Upgrade collection 23 */ 24 25 var testDataFolder = "." 26 27 func TestItemStatus(t *testing.T) { 28 cfg := test_prepenv() 29 30 err := UpdateHubIdx(cfg.Hub) 31 //DownloadHubIdx() 32 if err != nil { 33 t.Fatalf("failed to download index : %s", err) 34 } 35 if err := GetHubIdx(cfg.Hub); err != nil { 36 t.Fatalf("failed to load hub index : %s", err) 37 } 38 39 //get existing map 40 x := GetItemMap(COLLECTIONS) 41 if len(x) == 0 { 42 t.Fatalf("expected non empty result") 43 } 44 45 //Get item : good and bad 46 for k, _ := range x { 47 item := GetItem(COLLECTIONS, k) 48 if item == nil { 49 t.Fatalf("expected item") 50 } 51 item.Installed = true 52 item.UpToDate = false 53 item.Local = false 54 item.Tainted = false 55 txt, _, _, _ := ItemStatus(*item) 56 if txt != "enabled,update-available" { 57 log.Fatalf("got '%s'", txt) 58 } 59 60 item.Installed = false 61 item.UpToDate = false 62 item.Local = true 63 item.Tainted = false 64 txt, _, _, _ = ItemStatus(*item) 65 if txt != "disabled,local" { 66 log.Fatalf("got '%s'", txt) 67 } 68 69 break 70 } 71 DisplaySummary() 72 } 73 74 func TestGetters(t *testing.T) { 75 cfg := test_prepenv() 76 77 err := UpdateHubIdx(cfg.Hub) 78 //DownloadHubIdx() 79 if err != nil { 80 t.Fatalf("failed to download index : %s", err) 81 } 82 if err := GetHubIdx(cfg.Hub); err != nil { 83 t.Fatalf("failed to load hub index : %s", err) 84 } 85 86 //get non existing map 87 empty := GetItemMap("ratata") 88 if empty != nil { 89 t.Fatalf("expected nil result") 90 } 91 //get existing map 92 x := GetItemMap(COLLECTIONS) 93 if len(x) == 0 { 94 t.Fatalf("expected non empty result") 95 } 96 97 //Get item : good and bad 98 for k, _ := range x { 99 empty := GetItem(COLLECTIONS, k+"nope") 100 if empty != nil { 101 t.Fatalf("expected empty item") 102 } 103 104 item := GetItem(COLLECTIONS, k) 105 if item == nil { 106 t.Fatalf("expected non empty item") 107 } 108 109 //Add item and get it 110 item.Name += "nope" 111 if err := AddItem(COLLECTIONS, *item); err != nil { 112 t.Fatalf("didn't expect error : %s", err) 113 } 114 115 newitem := GetItem(COLLECTIONS, item.Name) 116 if newitem == nil { 117 t.Fatalf("expected non empty item") 118 } 119 120 //Add bad item 121 if err := AddItem("ratata", *item); err != nil { 122 if fmt.Sprintf("%s", err) != "ItemType ratata is unknown" { 123 t.Fatalf("unexpected error") 124 } 125 } else { 126 t.Fatalf("Expected error") 127 } 128 129 break 130 } 131 132 } 133 134 func TestIndexDownload(t *testing.T) { 135 136 cfg := test_prepenv() 137 138 err := UpdateHubIdx(cfg.Hub) 139 //DownloadHubIdx() 140 if err != nil { 141 t.Fatalf("failed to download index : %s", err) 142 } 143 if err := GetHubIdx(cfg.Hub); err != nil { 144 t.Fatalf("failed to load hub index : %s", err) 145 } 146 } 147 148 func test_prepenv() *csconfig.Config { 149 log.SetLevel(log.DebugLevel) 150 151 var cfg = &csconfig.Config{} 152 cfg.Hub = &csconfig.Hub{} 153 cfg.Hub.ConfigDir, _ = filepath.Abs("./install") 154 cfg.Hub.HubDir, _ = filepath.Abs("./hubdir") 155 cfg.Hub.HubIndexFile = filepath.Clean("./hubdir/.index.json") 156 157 //Mock the http client 158 http.DefaultClient.Transport = newMockTransport() 159 160 if err := os.RemoveAll(cfg.Hub.ConfigDir); err != nil { 161 log.Fatalf("failed to remove %s : %s", cfg.Hub.ConfigDir, err) 162 } 163 164 if err := os.MkdirAll(cfg.Hub.ConfigDir, 0700); err != nil { 165 log.Fatalf("mkdir : %s", err) 166 } 167 168 if err := os.RemoveAll(cfg.Hub.HubDir); err != nil { 169 log.Fatalf("failed to remove %s : %s", cfg.Hub.HubDir, err) 170 } 171 if err := os.MkdirAll(cfg.Hub.HubDir, 0700); err != nil { 172 log.Fatalf("failed to mkdir %s : %s", cfg.Hub.HubDir, err) 173 } 174 175 if err := UpdateHubIdx(cfg.Hub); err != nil { 176 log.Fatalf("failed to download index : %s", err) 177 } 178 179 // if err := os.RemoveAll(cfg.Hub.InstallDir); err != nil { 180 // log.Fatalf("failed to remove %s : %s", cfg.Hub.InstallDir, err) 181 // } 182 // if err := os.MkdirAll(cfg.Hub.InstallDir, 0700); err != nil { 183 // log.Fatalf("failed to mkdir %s : %s", cfg.Hub.InstallDir, err) 184 // } 185 return cfg 186 187 } 188 189 func testInstallItem(cfg *csconfig.Hub, t *testing.T, item Item) { 190 191 //Install the parser 192 item, err := DownloadLatest(cfg, item, false) 193 if err != nil { 194 t.Fatalf("error while downloading %s : %v", item.Name, err) 195 } 196 if err, _ := LocalSync(cfg); err != nil { 197 t.Fatalf("taint: failed to run localSync : %s", err) 198 } 199 if !hubIdx[item.Type][item.Name].UpToDate { 200 t.Fatalf("download: %s should be up-to-date", item.Name) 201 } 202 if hubIdx[item.Type][item.Name].Installed { 203 t.Fatalf("download: %s should not be install", item.Name) 204 } 205 if hubIdx[item.Type][item.Name].Tainted { 206 t.Fatalf("download: %s should not be tainted", item.Name) 207 } 208 209 item, err = EnableItem(cfg, item) 210 if err != nil { 211 t.Fatalf("error while enabled %s : %v.", item.Name, err) 212 } 213 if err, _ := LocalSync(cfg); err != nil { 214 t.Fatalf("taint: failed to run localSync : %s", err) 215 } 216 if !hubIdx[item.Type][item.Name].Installed { 217 t.Fatalf("install: %s should be install", item.Name) 218 } 219 } 220 221 func testTaintItem(cfg *csconfig.Hub, t *testing.T, item Item) { 222 if hubIdx[item.Type][item.Name].Tainted { 223 t.Fatalf("pre-taint: %s should not be tainted", item.Name) 224 } 225 f, err := os.OpenFile(item.LocalPath, os.O_APPEND|os.O_WRONLY, 0600) 226 if err != nil { 227 t.Fatalf("(taint) opening %s (%s) : %s", item.LocalPath, item.Name, err) 228 } 229 230 if _, err = f.WriteString("tainted"); err != nil { 231 t.Fatalf("tainting %s : %s", item.Name, err) 232 } 233 f.Close() 234 //Local sync and check status 235 if err, _ := LocalSync(cfg); err != nil { 236 t.Fatalf("taint: failed to run localSync : %s", err) 237 } 238 if !hubIdx[item.Type][item.Name].Tainted { 239 t.Fatalf("taint: %s should be tainted", item.Name) 240 } 241 } 242 243 func testUpdateItem(cfg *csconfig.Hub, t *testing.T, item Item) { 244 245 if hubIdx[item.Type][item.Name].UpToDate { 246 t.Fatalf("update: %s should NOT be up-to-date", item.Name) 247 } 248 //Update it + check status 249 item, err := DownloadLatest(cfg, item, true) 250 if err != nil { 251 t.Fatalf("failed to update %s : %s", item.Name, err) 252 } 253 //Local sync and check status 254 if err, _ := LocalSync(cfg); err != nil { 255 t.Fatalf("failed to run localSync : %s", err) 256 } 257 if !hubIdx[item.Type][item.Name].UpToDate { 258 t.Fatalf("update: %s should be up-to-date", item.Name) 259 } 260 if hubIdx[item.Type][item.Name].Tainted { 261 t.Fatalf("update: %s should not be tainted anymore", item.Name) 262 } 263 } 264 265 func testDisableItem(cfg *csconfig.Hub, t *testing.T, item Item) { 266 if !item.Installed { 267 t.Fatalf("disable: %s should be installed", item.Name) 268 } 269 //Remove 270 item, err := DisableItem(cfg, item, false, false) 271 if err != nil { 272 t.Fatalf("failed to disable item : %v", err) 273 } 274 //Local sync and check status 275 if err, warns := LocalSync(cfg); err != nil || len(warns) > 0 { 276 t.Fatalf("failed to run localSync : %s (%+v)", err, warns) 277 } 278 if hubIdx[item.Type][item.Name].Tainted { 279 t.Fatalf("disable: %s should not be tainted anymore", item.Name) 280 } 281 if hubIdx[item.Type][item.Name].Installed { 282 t.Fatalf("disable: %s should not be installed anymore", item.Name) 283 } 284 if !hubIdx[item.Type][item.Name].Downloaded { 285 t.Fatalf("disable: %s should still be downloaded", item.Name) 286 } 287 //Purge 288 item, err = DisableItem(cfg, item, true, false) 289 if err != nil { 290 t.Fatalf("failed to purge item : %v", err) 291 } 292 //Local sync and check status 293 if err, warns := LocalSync(cfg); err != nil || len(warns) > 0 { 294 t.Fatalf("failed to run localSync : %s (%+v)", err, warns) 295 } 296 if hubIdx[item.Type][item.Name].Installed { 297 t.Fatalf("disable: %s should not be installed anymore", item.Name) 298 } 299 if hubIdx[item.Type][item.Name].Downloaded { 300 t.Fatalf("disable: %s should not be downloaded", item.Name) 301 } 302 } 303 304 func TestInstallParser(t *testing.T) { 305 306 /* 307 - install a random parser 308 - check its status 309 - taint it 310 - check its status 311 - force update it 312 - check its status 313 - remove it 314 */ 315 cfg := test_prepenv() 316 317 if err := GetHubIdx(cfg.Hub); err != nil { 318 t.Fatalf("failed to load hub index") 319 } 320 //map iteration is random by itself 321 for _, it := range hubIdx[PARSERS] { 322 testInstallItem(cfg.Hub, t, it) 323 it = hubIdx[PARSERS][it.Name] 324 _ = HubStatus(PARSERS, it.Name, false) 325 testTaintItem(cfg.Hub, t, it) 326 it = hubIdx[PARSERS][it.Name] 327 _ = HubStatus(PARSERS, it.Name, false) 328 testUpdateItem(cfg.Hub, t, it) 329 it = hubIdx[PARSERS][it.Name] 330 testDisableItem(cfg.Hub, t, it) 331 it = hubIdx[PARSERS][it.Name] 332 333 break 334 } 335 } 336 337 func TestInstallCollection(t *testing.T) { 338 339 /* 340 - install a random parser 341 - check its status 342 - taint it 343 - check its status 344 - force update it 345 - check its status 346 - remove it 347 */ 348 cfg := test_prepenv() 349 350 if err := GetHubIdx(cfg.Hub); err != nil { 351 t.Fatalf("failed to load hub index") 352 } 353 //map iteration is random by itself 354 for _, it := range hubIdx[COLLECTIONS] { 355 testInstallItem(cfg.Hub, t, it) 356 it = hubIdx[COLLECTIONS][it.Name] 357 testTaintItem(cfg.Hub, t, it) 358 it = hubIdx[COLLECTIONS][it.Name] 359 testUpdateItem(cfg.Hub, t, it) 360 it = hubIdx[COLLECTIONS][it.Name] 361 testDisableItem(cfg.Hub, t, it) 362 363 it = hubIdx[COLLECTIONS][it.Name] 364 x := HubStatus(COLLECTIONS, it.Name, false) 365 log.Printf("%+v", x) 366 break 367 } 368 } 369 370 type mockTransport struct{} 371 372 func newMockTransport() http.RoundTripper { 373 return &mockTransport{} 374 } 375 376 // Implement http.RoundTripper 377 func (t *mockTransport) RoundTrip(req *http.Request) (*http.Response, error) { 378 // Create mocked http.Response 379 response := &http.Response{ 380 Header: make(http.Header), 381 Request: req, 382 StatusCode: http.StatusOK, 383 } 384 response.Header.Set("Content-Type", "application/json") 385 responseBody := "" 386 log.Printf("---> %s", req.URL.Path) 387 388 /*FAKE PARSER*/ 389 if req.URL.Path == "/breakteam/hub/master/parsers/s01-parse/breakteam/foobar_parser.yaml" { 390 responseBody = `onsuccess: next_stage 391 filter: evt.Parsed.program == 'foobar_parser' 392 name: breakteam/foobar_parser 393 #debug: true 394 description: A parser for foobar_parser WAF 395 grok: 396 name: foobar_parser 397 apply_on: message 398 ` 399 400 } else if req.URL.Path == "/breakteam/hub/master/parsers/s01-parse/breakteam/foobar_subparser.yaml" { 401 responseBody = `onsuccess: next_stage 402 filter: evt.Parsed.program == 'foobar_parser' 403 name: breakteam/foobar_parser 404 #debug: true 405 description: A parser for foobar_parser WAF 406 grok: 407 name: foobar_parser 408 apply_on: message 409 ` 410 /*FAKE SCENARIO*/ 411 412 } else if req.URL.Path == "/breakteam/hub/master/scenarios/breakteam/foobar_scenario.yaml" { 413 responseBody = `filter: true 414 name: breakteam/foobar_scenario` 415 /*FAKE COLLECTIONS*/ 416 } else if req.URL.Path == "/breakteam/hub/master/collections/breakteam/foobar.yaml" { 417 responseBody = ` 418 blah: blalala 419 qwe: jejwejejw` 420 } else if req.URL.Path == "/breakteam/hub/master/collections/breakteam/foobar_subcollection.yaml" { 421 responseBody = ` 422 blah: blalala 423 qwe: jejwejejw` 424 } else if req.URL.Path == "/breakteam/hub/master/.index.json" { 425 responseBody = 426 `{ 427 "collections": { 428 "breakteam/foobar": { 429 "path": "collections/breakteam/foobar.yaml", 430 "version": "0.1", 431 "versions": { 432 "0.1": { 433 "digest": "786c9490e4dd234453e53aa9bb7d28c60668e31c3c0c71a7dd6d0abbfa60261a", 434 "deprecated": false 435 } 436 }, 437 "long_description": "bG9uZyBkZXNjcmlwdGlvbgo=", 438 "content": "bG9uZyBkZXNjcmlwdGlvbgo=", 439 "description": "foobar collection : foobar", 440 "author": "breakteam", 441 "labels": null, 442 "collections" : ["breakteam/foobar_subcollection"], 443 "parsers": [ 444 "breakteam/foobar_parser" 445 ], 446 "scenarios": [ 447 "breakteam/foobar_scenario" 448 ] 449 }, 450 "breakteam/foobar_subcollection": { 451 "path": "collections/breakteam/foobar_subcollection.yaml", 452 "version": "0.1", 453 "versions": { 454 "0.1": { 455 "digest": "786c9490e4dd234453e53aa9bb7d28c60668e31c3c0c71a7dd6d0abbfa60261a", 456 "deprecated": false 457 } 458 }, 459 "long_description": "bG9uZyBkZXNjcmlwdGlvbgo=", 460 "content": "bG9uZyBkZXNjcmlwdGlvbgo=", 461 "description": "foobar collection : foobar", 462 "author": "breakteam", 463 "labels": null, 464 "parsers": [ 465 "breakteam/foobar_subparser" 466 ] 467 } 468 }, 469 "parsers": { 470 "breakteam/foobar_parser": { 471 "path": "parsers/s01-parse/breakteam/foobar_parser.yaml", 472 "stage": "s01-parse", 473 "version": "0.1", 474 "versions": { 475 "0.1": { 476 "digest": "7d72765baa7227095d8e83803d81f2a8f383e5808f1a4d72deb425352afd59ae", 477 "deprecated": false 478 } 479 }, 480 "long_description": "bG9uZyBkZXNjcmlwdGlvbgo=", 481 "content": "bG9uZyBkZXNjcmlwdGlvbgo=", 482 "description": "A foobar parser", 483 "author": "breakteam", 484 "labels": null 485 }, 486 "breakteam/foobar_subparser": { 487 "path": "parsers/s01-parse/breakteam/foobar_subparser.yaml", 488 "stage": "s01-parse", 489 "version": "0.1", 490 "versions": { 491 "0.1": { 492 "digest": "7d72765baa7227095d8e83803d81f2a8f383e5808f1a4d72deb425352afd59ae", 493 "deprecated": false 494 } 495 }, 496 "long_description": "bG9uZyBkZXNjcmlwdGlvbgo=", 497 "content": "bG9uZyBkZXNjcmlwdGlvbgo=", 498 "description": "A foobar parser", 499 "author": "breakteam", 500 "labels": null 501 } 502 }, 503 "postoverflows": { 504 }, 505 "scenarios": { 506 "breakteam/foobar_scenario": { 507 "path": "scenarios/breakteam/foobar_scenario.yaml", 508 "version": "0.1", 509 "versions": { 510 "0.1": { 511 "digest": "a76b389db944ca7a9e5a3f3ae61ee2d4ee98167164ec9b971174b1d44f5a01c6", 512 "deprecated": false 513 } 514 }, 515 "long_description": "bG9uZyBkZXNjcmlwdGlvbgo=", 516 "content": "bG9uZyBkZXNjcmlwdGlvbgo=", 517 "description": "a foobar scenario", 518 "author": "breakteam", 519 "labels": { 520 "remediation": "true", 521 "scope": "ip", 522 "service": "http", 523 "type": "web_attack" 524 } 525 } 526 } 527 } 528 ` 529 } else { 530 log.Fatalf("unexpected url :/") 531 } 532 533 response.Body = ioutil.NopCloser(strings.NewReader(responseBody)) 534 return response, nil 535 }