github.com/khulnasoft-lab/defsec@v1.0.5-0.20230827010352-5e9f46893d95/pkg/rego/scanner_test.go (about) 1 package rego 2 3 import ( 4 "bytes" 5 "context" 6 "os" 7 "path/filepath" 8 "testing" 9 10 "github.com/khulnasoft-lab/defsec/pkg/types" 11 12 "github.com/khulnasoft-lab/defsec/pkg/scanners/options" 13 14 "github.com/khulnasoft-lab/defsec/pkg/severity" 15 16 "github.com/khulnasoft-lab/defsec/test/testutil" 17 18 "github.com/stretchr/testify/assert" 19 20 "github.com/stretchr/testify/require" 21 ) 22 23 func Test_RegoScanning_Deny(t *testing.T) { 24 25 srcFS := testutil.CreateFS(t, map[string]string{ 26 "policies/test.rego": ` 27 package defsec.test 28 29 deny { 30 input.evil 31 } 32 `, 33 }) 34 35 scanner := NewScanner(types.SourceJSON) 36 require.NoError( 37 t, 38 scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), 39 ) 40 41 results, err := scanner.ScanInput(context.TODO(), Input{ 42 Path: "/evil.lol", 43 Contents: map[string]interface{}{ 44 "evil": true, 45 }, 46 FS: srcFS, 47 }) 48 require.NoError(t, err) 49 50 require.Equal(t, 1, len(results.GetFailed())) 51 assert.Equal(t, 0, len(results.GetPassed())) 52 assert.Equal(t, 0, len(results.GetIgnored())) 53 54 assert.Equal(t, "/evil.lol", results.GetFailed()[0].Metadata().Range().GetFilename()) 55 assert.False(t, results.GetFailed()[0].IsWarning()) 56 } 57 58 func Test_RegoScanning_AbsolutePolicyPath_Deny(t *testing.T) { 59 60 tmp := t.TempDir() 61 require.NoError(t, os.Mkdir(filepath.Join(tmp, "policies"), 0755)) 62 require.NoError(t, os.WriteFile(filepath.Join(tmp, "policies", "test.rego"), []byte(`package defsec.test 63 64 deny { 65 input.evil 66 }`), 0600)) 67 68 srcFS := os.DirFS(tmp) 69 70 scanner := NewScanner(types.SourceJSON) 71 require.NoError( 72 t, 73 scanner.LoadPolicies(false, false, srcFS, []string{"/policies"}, nil), 74 ) 75 76 results, err := scanner.ScanInput(context.TODO(), Input{ 77 Path: "/evil.lol", 78 Contents: map[string]interface{}{ 79 "evil": true, 80 }, 81 FS: srcFS, 82 }) 83 require.NoError(t, err) 84 85 require.Equal(t, 1, len(results.GetFailed())) 86 assert.Equal(t, 0, len(results.GetPassed())) 87 assert.Equal(t, 0, len(results.GetIgnored())) 88 89 assert.Equal(t, "/evil.lol", results.GetFailed()[0].Metadata().Range().GetFilename()) 90 assert.False(t, results.GetFailed()[0].IsWarning()) 91 } 92 93 func Test_RegoScanning_Warn(t *testing.T) { 94 95 srcFS := testutil.CreateFS(t, map[string]string{ 96 "policies/test.rego": ` 97 package defsec.test 98 99 warn { 100 input.evil 101 } 102 `, 103 }) 104 105 scanner := NewScanner(types.SourceJSON) 106 require.NoError( 107 t, 108 scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), 109 ) 110 111 results, err := scanner.ScanInput(context.TODO(), Input{ 112 Path: "/evil.lol", 113 Contents: map[string]interface{}{ 114 "evil": true, 115 }, 116 }) 117 require.NoError(t, err) 118 119 require.Equal(t, 1, len(results.GetFailed())) 120 require.Equal(t, 0, len(results.GetPassed())) 121 require.Equal(t, 0, len(results.GetIgnored())) 122 123 assert.True(t, results.GetFailed()[0].IsWarning()) 124 } 125 126 func Test_RegoScanning_Allow(t *testing.T) { 127 srcFS := testutil.CreateFS(t, map[string]string{ 128 "policies/test.rego": ` 129 package defsec.test 130 131 deny { 132 input.evil 133 } 134 `, 135 }) 136 137 scanner := NewScanner(types.SourceJSON) 138 require.NoError( 139 t, 140 scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), 141 ) 142 143 results, err := scanner.ScanInput(context.TODO(), Input{ 144 Path: "/evil.lol", 145 Contents: map[string]interface{}{ 146 "evil": false, 147 }, 148 }) 149 require.NoError(t, err) 150 151 assert.Equal(t, 0, len(results.GetFailed())) 152 require.Equal(t, 1, len(results.GetPassed())) 153 assert.Equal(t, 0, len(results.GetIgnored())) 154 155 assert.Equal(t, "/evil.lol", results.GetPassed()[0].Metadata().Range().GetFilename()) 156 } 157 158 func Test_RegoScanning_Namespace_Exception(t *testing.T) { 159 160 srcFS := testutil.CreateFS(t, map[string]string{ 161 "policies/test.rego": ` 162 package defsec.test 163 164 deny { 165 input.evil 166 } 167 `, 168 "policies/exceptions.rego": ` 169 package namespace.exceptions 170 171 import data.namespaces 172 173 exception[ns] { 174 ns := data.namespaces[_] 175 startswith(ns, "defsec") 176 } 177 `, 178 }) 179 180 scanner := NewScanner(types.SourceJSON) 181 require.NoError( 182 t, 183 scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), 184 ) 185 186 results, err := scanner.ScanInput(context.TODO(), Input{ 187 Path: "/evil.lol", 188 Contents: map[string]interface{}{ 189 "evil": true, 190 }, 191 }) 192 require.NoError(t, err) 193 194 assert.Equal(t, 0, len(results.GetFailed())) 195 assert.Equal(t, 0, len(results.GetPassed())) 196 assert.Equal(t, 1, len(results.GetIgnored())) 197 198 } 199 200 func Test_RegoScanning_Namespace_Exception_WithoutMatch(t *testing.T) { 201 202 srcFS := testutil.CreateFS(t, map[string]string{ 203 "policies/test.rego": ` 204 package defsec.test 205 206 deny { 207 input.evil 208 } 209 `, "policies/something.rego": ` 210 package builtin.test 211 212 deny_something { 213 input.something 214 } 215 `, 216 "policies/exceptions.rego": ` 217 package namespace.exceptions 218 219 import data.namespaces 220 221 exception[ns] { 222 ns := data.namespaces[_] 223 startswith(ns, "builtin") 224 } 225 `, 226 }) 227 228 scanner := NewScanner(types.SourceJSON) 229 require.NoError( 230 t, 231 scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), 232 ) 233 234 results, err := scanner.ScanInput(context.TODO(), Input{ 235 Path: "/evil.lol", 236 Contents: map[string]interface{}{ 237 "evil": true, 238 }, 239 }) 240 require.NoError(t, err) 241 242 assert.Equal(t, 1, len(results.GetFailed())) 243 assert.Equal(t, 0, len(results.GetPassed())) 244 assert.Equal(t, 1, len(results.GetIgnored())) 245 246 } 247 248 func Test_RegoScanning_Rule_Exception(t *testing.T) { 249 srcFS := testutil.CreateFS(t, map[string]string{ 250 "policies/test.rego": ` 251 package defsec.test 252 deny_evil { 253 input.evil 254 } 255 `, 256 "policies/exceptions.rego": ` 257 package defsec.test 258 259 exception[rules] { 260 rules := ["evil"] 261 } 262 `, 263 }) 264 265 scanner := NewScanner(types.SourceJSON) 266 require.NoError( 267 t, 268 scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), 269 ) 270 271 results, err := scanner.ScanInput(context.TODO(), Input{ 272 Path: "/evil.lol", 273 Contents: map[string]interface{}{ 274 "evil": true, 275 }, 276 }) 277 require.NoError(t, err) 278 279 assert.Equal(t, 0, len(results.GetFailed())) 280 assert.Equal(t, 0, len(results.GetPassed())) 281 assert.Equal(t, 1, len(results.GetIgnored())) 282 } 283 284 func Test_RegoScanning_Rule_Exception_WithoutMatch(t *testing.T) { 285 srcFS := testutil.CreateFS(t, map[string]string{ 286 "policies/test.rego": ` 287 package defsec.test 288 deny_evil { 289 input.evil 290 } 291 `, 292 "policies/exceptions.rego": ` 293 package defsec.test 294 295 exception[rules] { 296 rules := ["good"] 297 } 298 `, 299 }) 300 301 scanner := NewScanner(types.SourceJSON) 302 require.NoError( 303 t, 304 scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), 305 ) 306 307 results, err := scanner.ScanInput(context.TODO(), Input{ 308 Path: "/evil.lol", 309 Contents: map[string]interface{}{ 310 "evil": true, 311 }, 312 }) 313 require.NoError(t, err) 314 315 assert.Equal(t, 1, len(results.GetFailed())) 316 assert.Equal(t, 0, len(results.GetPassed())) 317 assert.Equal(t, 0, len(results.GetIgnored())) 318 } 319 320 func Test_RegoScanning_WithRuntimeValues(t *testing.T) { 321 322 _ = os.Setenv("DEFSEC_RUNTIME_VAL", "AOK") 323 324 srcFS := testutil.CreateFS(t, map[string]string{ 325 "policies/test.rego": ` 326 package defsec.test 327 328 deny_evil { 329 output := opa.runtime() 330 output.env.DEFSEC_RUNTIME_VAL == "AOK" 331 } 332 `, 333 }) 334 335 scanner := NewScanner(types.SourceJSON) 336 require.NoError( 337 t, 338 scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), 339 ) 340 341 results, err := scanner.ScanInput(context.TODO(), Input{ 342 Path: "/evil.lol", 343 Contents: map[string]interface{}{ 344 "evil": true, 345 }, 346 }) 347 require.NoError(t, err) 348 349 assert.Equal(t, 1, len(results.GetFailed())) 350 assert.Equal(t, 0, len(results.GetPassed())) 351 assert.Equal(t, 0, len(results.GetIgnored())) 352 } 353 354 func Test_RegoScanning_WithDenyMessage(t *testing.T) { 355 srcFS := testutil.CreateFS(t, map[string]string{ 356 "policies/test.rego": ` 357 package defsec.test 358 359 deny[msg] { 360 input.evil 361 msg := "oh no" 362 } 363 `, 364 }) 365 366 scanner := NewScanner(types.SourceJSON) 367 require.NoError( 368 t, 369 scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), 370 ) 371 372 results, err := scanner.ScanInput(context.TODO(), Input{ 373 Path: "/evil.lol", 374 Contents: map[string]interface{}{ 375 "evil": true, 376 }, 377 }) 378 require.NoError(t, err) 379 380 require.Equal(t, 1, len(results.GetFailed())) 381 assert.Equal(t, 0, len(results.GetPassed())) 382 assert.Equal(t, 0, len(results.GetIgnored())) 383 384 assert.Equal(t, "oh no", results.GetFailed()[0].Description()) 385 assert.Equal(t, "/evil.lol", results.GetFailed()[0].Metadata().Range().GetFilename()) 386 } 387 388 func Test_RegoScanning_WithDenyMetadata_ImpliedPath(t *testing.T) { 389 srcFS := testutil.CreateFS(t, map[string]string{ 390 "policies/test.rego": ` 391 package defsec.test 392 393 deny[res] { 394 input.evil 395 res := { 396 "msg": "oh no", 397 "startline": 123, 398 "endline": 456, 399 } 400 } 401 `, 402 }) 403 404 scanner := NewScanner(types.SourceJSON) 405 require.NoError( 406 t, 407 scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), 408 ) 409 410 results, err := scanner.ScanInput(context.TODO(), Input{ 411 Path: "/evil.lol", 412 Contents: map[string]interface{}{ 413 "evil": true, 414 }, 415 }) 416 require.NoError(t, err) 417 418 require.Equal(t, 1, len(results.GetFailed())) 419 assert.Equal(t, 0, len(results.GetPassed())) 420 assert.Equal(t, 0, len(results.GetIgnored())) 421 422 assert.Equal(t, "oh no", results.GetFailed()[0].Description()) 423 assert.Equal(t, "/evil.lol", results.GetFailed()[0].Metadata().Range().GetFilename()) 424 assert.Equal(t, 123, results.GetFailed()[0].Metadata().Range().GetStartLine()) 425 assert.Equal(t, 456, results.GetFailed()[0].Metadata().Range().GetEndLine()) 426 427 } 428 429 func Test_RegoScanning_WithDenyMetadata_PersistedPath(t *testing.T) { 430 srcFS := testutil.CreateFS(t, map[string]string{ 431 "policies/test.rego": ` 432 package defsec.test 433 434 deny[res] { 435 input.evil 436 res := { 437 "msg": "oh no", 438 "startline": 123, 439 "endline": 456, 440 "filepath": "/blah.txt", 441 } 442 } 443 `, 444 }) 445 446 scanner := NewScanner(types.SourceJSON) 447 require.NoError( 448 t, 449 scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), 450 ) 451 452 results, err := scanner.ScanInput(context.TODO(), Input{ 453 Path: "/evil.lol", 454 Contents: map[string]interface{}{ 455 "evil": true, 456 }, 457 }) 458 require.NoError(t, err) 459 460 require.Equal(t, 1, len(results.GetFailed())) 461 assert.Equal(t, 0, len(results.GetPassed())) 462 assert.Equal(t, 0, len(results.GetIgnored())) 463 464 assert.Equal(t, "oh no", results.GetFailed()[0].Description()) 465 assert.Equal(t, "/blah.txt", results.GetFailed()[0].Metadata().Range().GetFilename()) 466 assert.Equal(t, 123, results.GetFailed()[0].Metadata().Range().GetStartLine()) 467 assert.Equal(t, 456, results.GetFailed()[0].Metadata().Range().GetEndLine()) 468 469 } 470 471 func Test_RegoScanning_WithStaticMetadata(t *testing.T) { 472 srcFS := testutil.CreateFS(t, map[string]string{ 473 "policies/test.rego": ` 474 package defsec.test 475 476 __rego_metadata__ := { 477 "id": "AA001", 478 "avd_id": "AVD-XX-9999", 479 "title": "This is a title", 480 "short_code": "short-code", 481 "severity": "LOW", 482 "type": "Dockerfile Security Check", 483 "description": "This is a description", 484 "recommended_actions": "This is a recommendation", 485 "url": "https://google.com", 486 } 487 488 deny[res] { 489 input.evil 490 res := { 491 "msg": "oh no", 492 "startline": 123, 493 "endline": 456, 494 "filepath": "/blah.txt", 495 } 496 } 497 `, 498 }) 499 500 scanner := NewScanner(types.SourceJSON) 501 require.NoError( 502 t, 503 scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), 504 ) 505 506 results, err := scanner.ScanInput(context.TODO(), Input{ 507 Path: "/evil.lol", 508 Contents: map[string]interface{}{ 509 "evil": true, 510 }, 511 }) 512 require.NoError(t, err) 513 514 require.Equal(t, 1, len(results.GetFailed())) 515 assert.Equal(t, 0, len(results.GetPassed())) 516 assert.Equal(t, 0, len(results.GetIgnored())) 517 518 failure := results.GetFailed()[0] 519 520 assert.Equal(t, "oh no", failure.Description()) 521 assert.Equal(t, "/blah.txt", failure.Metadata().Range().GetFilename()) 522 assert.Equal(t, 123, failure.Metadata().Range().GetStartLine()) 523 assert.Equal(t, 456, failure.Metadata().Range().GetEndLine()) 524 assert.Equal(t, "AVD-XX-9999", failure.Rule().AVDID) 525 assert.True(t, failure.Rule().HasID("AA001")) 526 assert.Equal(t, "This is a title", failure.Rule().Summary) 527 assert.Equal(t, severity.Low, failure.Rule().Severity) 528 assert.Equal(t, "This is a recommendation", failure.Rule().Resolution) 529 assert.Equal(t, "https://google.com", failure.Rule().Links[0]) 530 531 } 532 533 func Test_RegoScanning_WithMatchingInputSelector(t *testing.T) { 534 srcFS := testutil.CreateFS(t, map[string]string{ 535 "policies/test.rego": ` 536 package defsec.test 537 538 __rego_input__ := { 539 "selector": [{"type": "json"}], 540 } 541 542 deny { 543 input.evil 544 } 545 546 `, 547 }) 548 549 scanner := NewScanner(types.SourceJSON) 550 require.NoError( 551 t, 552 scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), 553 ) 554 555 results, err := scanner.ScanInput(context.TODO(), Input{ 556 Path: "/evil.lol", 557 Contents: map[string]interface{}{ 558 "evil": true, 559 }, 560 }) 561 require.NoError(t, err) 562 563 assert.Equal(t, 1, len(results.GetFailed())) 564 assert.Equal(t, 0, len(results.GetPassed())) 565 assert.Equal(t, 0, len(results.GetIgnored())) 566 } 567 568 func Test_RegoScanning_WithNonMatchingInputSelector(t *testing.T) { 569 srcFS := testutil.CreateFS(t, map[string]string{ 570 "policies/test.rego": ` 571 package defsec.test 572 573 __rego_input__ := { 574 "selector": [{"type": "testing"}], 575 } 576 577 deny { 578 input.evil 579 } 580 `, 581 }) 582 583 scanner := NewScanner(types.SourceJSON) 584 require.NoError( 585 t, 586 scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), 587 ) 588 589 results, err := scanner.ScanInput(context.TODO(), Input{ 590 Path: "/evil.lol", 591 Contents: map[string]interface{}{ 592 "evil": true, 593 }, 594 }) 595 require.NoError(t, err) 596 597 assert.Equal(t, 0, len(results.GetFailed())) 598 assert.Equal(t, 0, len(results.GetPassed())) 599 assert.Equal(t, 0, len(results.GetIgnored())) 600 } 601 602 func Test_RegoScanning_NoTracingByDefault(t *testing.T) { 603 604 srcFS := testutil.CreateFS(t, map[string]string{ 605 "policies/test.rego": ` 606 package defsec.test 607 608 deny { 609 input.evil 610 } 611 `, 612 }) 613 614 scanner := NewScanner(types.SourceJSON) 615 require.NoError( 616 t, 617 scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), 618 ) 619 620 results, err := scanner.ScanInput(context.TODO(), Input{ 621 Path: "/evil.lol", 622 Contents: map[string]interface{}{ 623 "evil": true, 624 }, 625 }) 626 require.NoError(t, err) 627 628 assert.Equal(t, 1, len(results.GetFailed())) 629 assert.Equal(t, 0, len(results.GetPassed())) 630 assert.Equal(t, 0, len(results.GetIgnored())) 631 632 assert.Len(t, results.GetFailed()[0].Traces(), 0) 633 } 634 635 func Test_RegoScanning_GlobalTracingEnabled(t *testing.T) { 636 637 srcFS := testutil.CreateFS(t, map[string]string{ 638 "policies/test.rego": ` 639 package defsec.test 640 641 deny { 642 input.evil 643 } 644 `, 645 }) 646 647 traceBuffer := bytes.NewBuffer([]byte{}) 648 649 scanner := NewScanner(types.SourceJSON, options.ScannerWithTrace(traceBuffer)) 650 require.NoError( 651 t, 652 scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), 653 ) 654 655 results, err := scanner.ScanInput(context.TODO(), Input{ 656 Path: "/evil.lol", 657 Contents: map[string]interface{}{ 658 "evil": true, 659 }, 660 }) 661 require.NoError(t, err) 662 663 assert.Equal(t, 1, len(results.GetFailed())) 664 assert.Equal(t, 0, len(results.GetPassed())) 665 assert.Equal(t, 0, len(results.GetIgnored())) 666 667 assert.Len(t, results.GetFailed()[0].Traces(), 0) 668 assert.Greater(t, len(traceBuffer.Bytes()), 0) 669 } 670 671 func Test_RegoScanning_PerResultTracingEnabled(t *testing.T) { 672 673 srcFS := testutil.CreateFS(t, map[string]string{ 674 "policies/test.rego": ` 675 package defsec.test 676 677 deny { 678 input.evil 679 } 680 `, 681 }) 682 683 scanner := NewScanner(types.SourceJSON, options.ScannerWithPerResultTracing(true)) 684 require.NoError( 685 t, 686 scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), 687 ) 688 689 results, err := scanner.ScanInput(context.TODO(), Input{ 690 Path: "/evil.lol", 691 Contents: map[string]interface{}{ 692 "evil": true, 693 }, 694 }) 695 require.NoError(t, err) 696 697 assert.Equal(t, 1, len(results.GetFailed())) 698 assert.Equal(t, 0, len(results.GetPassed())) 699 assert.Equal(t, 0, len(results.GetIgnored())) 700 701 assert.Greater(t, len(results.GetFailed()[0].Traces()), 0) 702 } 703 704 func Test_dynamicMetadata(t *testing.T) { 705 706 srcFS := testutil.CreateFS(t, map[string]string{ 707 "policies/test.rego": ` 708 package defsec.test 709 710 __rego_metadata__ := { 711 "title" : sprintf("i am %s",[input.text]) 712 } 713 714 deny { 715 input.text 716 } 717 718 `, 719 }) 720 721 scanner := NewScanner(types.SourceJSON) 722 require.NoError( 723 t, 724 scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), 725 ) 726 727 results, err := scanner.ScanInput(context.TODO(), Input{ 728 Path: "/evil.lol", 729 Contents: map[string]interface{}{ 730 "text": "dynamic", 731 }, 732 }) 733 require.NoError(t, err) 734 assert.Equal(t, results[0].Rule().Summary, "i am dynamic") 735 } 736 737 func Test_staticMetadata(t *testing.T) { 738 739 srcFS := testutil.CreateFS(t, map[string]string{ 740 "policies/test.rego": ` 741 package defsec.test 742 743 __rego_metadata__ := { 744 "title" : "i am static" 745 } 746 747 deny { 748 input.text 749 } 750 751 `, 752 }) 753 754 scanner := NewScanner(types.SourceJSON) 755 require.NoError( 756 t, 757 scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), 758 ) 759 760 results, err := scanner.ScanInput(context.TODO(), Input{ 761 Path: "/evil.lol", 762 Contents: map[string]interface{}{ 763 "text": "test", 764 }, 765 }) 766 require.NoError(t, err) 767 assert.Equal(t, results[0].Rule().Summary, "i am static") 768 } 769 770 func Test_annotationMetadata(t *testing.T) { 771 772 srcFS := testutil.CreateFS(t, map[string]string{ 773 "policies/test.rego": `# METADATA 774 # title: i am a title 775 # description: i am a description 776 # related_resources: 777 # - https://google.com 778 # custom: 779 # id: EG123 780 # avd_id: AVD-EG-0123 781 # severity: LOW 782 # recommended_action: have a cup of tea 783 package defsec.test 784 785 deny { 786 input.text 787 } 788 789 `, 790 "policies/test2.rego": `# METADATA 791 # title: i am another title 792 package defsec.test2 793 794 deny { 795 input.blah 796 } 797 798 `, 799 }) 800 801 scanner := NewScanner(types.SourceJSON) 802 require.NoError( 803 t, 804 scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), 805 ) 806 807 results, err := scanner.ScanInput(context.TODO(), Input{ 808 Path: "/evil.lol", 809 Contents: map[string]interface{}{ 810 "text": "test", 811 }, 812 }) 813 require.NoError(t, err) 814 require.Len(t, results.GetFailed(), 1) 815 failure := results.GetFailed()[0].Rule() 816 assert.Equal(t, "i am a title", failure.Summary) 817 assert.Equal(t, "i am a description", failure.Explanation) 818 require.Len(t, failure.Links, 1) 819 assert.Equal(t, "https://google.com", failure.Links[0]) 820 assert.Equal(t, "AVD-EG-0123", failure.AVDID) 821 assert.Equal(t, severity.Low, failure.Severity) 822 assert.Equal(t, "have a cup of tea", failure.Resolution) 823 } 824 825 func Test_RegoScanning_WithInvalidInputSchema(t *testing.T) { 826 827 srcFS := testutil.CreateFS(t, map[string]string{ 828 "policies/test.rego": `# METADATA 829 # schemas: 830 # - input: schema["input"] 831 package defsec.test 832 833 deny { 834 input.evil == "lol" 835 } 836 `, 837 }) 838 839 scanner := NewScanner(types.SourceDockerfile) 840 scanner.SetRegoErrorLimit(0) // override to not allow any errors 841 assert.ErrorContains( 842 t, 843 scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), 844 "undefined ref: input.evil", 845 ) 846 } 847 848 func Test_RegoScanning_WithValidInputSchema(t *testing.T) { 849 850 srcFS := testutil.CreateFS(t, map[string]string{ 851 "policies/test.rego": `# METADATA 852 # schemas: 853 # - input: schema["input"] 854 package defsec.test 855 856 deny { 857 input.Stages[0].Commands[0].Cmd == "lol" 858 } 859 `, 860 }) 861 862 scanner := NewScanner(types.SourceDockerfile) 863 assert.NoError( 864 t, 865 scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), 866 ) 867 } 868 869 func Test_RegoScanning_WithFilepathToSchema(t *testing.T) { 870 srcFS := testutil.CreateFS(t, map[string]string{ 871 "policies/test.rego": `# METADATA 872 # schemas: 873 # - input: schema["dockerfile"] 874 package defsec.test 875 876 deny { 877 input.evil == "lol" 878 } 879 `, 880 }) 881 scanner := NewScanner(types.SourceJSON) 882 scanner.SetRegoErrorLimit(0) // override to not allow any errors 883 assert.ErrorContains( 884 t, 885 scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), 886 "undefined ref: input.evil", 887 ) 888 } 889 890 func Test_RegoScanning_CustomData(t *testing.T) { 891 srcFS := testutil.CreateFS(t, map[string]string{ 892 "policies/test.rego": ` 893 package defsec.test 894 import data.settings.DS123.foo_bar_baz 895 896 deny { 897 not foo_bar_baz 898 } 899 `, 900 }) 901 902 dataFS := testutil.CreateFS(t, map[string]string{ 903 "data/data.json": `{ 904 "settings": { 905 "DS123":{ 906 "foo_bar_baz":false 907 } 908 } 909 }`, 910 "data/junk.txt": "this file should be ignored", 911 }) 912 913 scanner := NewScanner(types.SourceJSON) 914 scanner.SetDataFilesystem(dataFS) 915 scanner.SetDataDirs(".") 916 917 require.NoError( 918 t, 919 scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), 920 ) 921 922 results, err := scanner.ScanInput(context.TODO(), Input{}) 923 require.NoError(t, err) 924 925 assert.Equal(t, 1, len(results.GetFailed())) 926 assert.Equal(t, 0, len(results.GetPassed())) 927 assert.Equal(t, 0, len(results.GetIgnored())) 928 } 929 930 func Test_RegoScanning_InvalidFS(t *testing.T) { 931 srcFS := testutil.CreateFS(t, map[string]string{ 932 "policies/test.rego": ` 933 package defsec.test 934 import data.settings.DS123.foo_bar_baz 935 936 deny { 937 not foo_bar_baz 938 } 939 `, 940 }) 941 942 dataFS := testutil.CreateFS(t, map[string]string{ 943 "data/data.json": `{ 944 "settings": { 945 "DS123":{ 946 "foo_bar_baz":false 947 } 948 } 949 }`, 950 "data/junk.txt": "this file should be ignored", 951 }) 952 953 scanner := NewScanner(types.SourceJSON) 954 scanner.SetDataFilesystem(dataFS) 955 scanner.SetDataDirs("X://") 956 957 require.NoError( 958 t, 959 scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), 960 ) 961 962 results, err := scanner.ScanInput(context.TODO(), Input{}) 963 require.NoError(t, err) 964 965 assert.Equal(t, 1, len(results.GetFailed())) 966 assert.Equal(t, 0, len(results.GetPassed())) 967 assert.Equal(t, 0, len(results.GetIgnored())) 968 }