def test_run_skips_disabled_yara_rules(self): assert len(ScannerResult.objects.all()) == 0 # This rule should match for all files in the xpi but it is disabled. ScannerRule.objects.create( name='always_true', scanner=YARA, definition='rule always_true { condition: true }', is_active=False, ) run_yara(self.results, self.upload.pk) yara_result = ScannerResult.objects.all()[0] assert yara_result.upload == self.upload assert len(yara_result.results) == 0
def test_does_not_run_when_results_contain_errors(self, yara_compile_mock): self.results.update({'errors': 1}) received_results = run_yara(self.results, self.upload.pk) assert not yara_compile_mock.called # The task should always return the results. assert received_results == self.results
def test_run_with_mocks(self, incr_mock): assert len(ScannerResult.objects.all()) == 0 # This compiled rule will match for all files in the xpi. rules = yara.compile(source='rule always_true { condition: true }') with mock.patch('yara.compile') as yara_compile_mock: yara_compile_mock.return_value = rules received_results = run_yara(self.results, self.upload.pk) assert yara_compile_mock.called yara_results = ScannerResult.objects.all() assert len(yara_results) == 1 yara_result = yara_results[0] assert yara_result.upload == self.upload assert len(yara_result.matches) == 2 assert yara_result.matches[0] == { 'rule': 'always_true', 'tags': [], 'meta': {'filename': 'index.js'}, } assert yara_result.matches[1] == { 'rule': 'always_true', 'tags': [], 'meta': {'filename': 'manifest.json'}, } assert incr_mock.called assert incr_mock.call_count == 2 incr_mock.assert_has_calls( [ mock.call('devhub.yara.has_matches'), mock.call('devhub.yara.success'), ] ) # The task should always return the results. assert received_results == self.results
def test_run_in_binary_mode(self): self.upload = self.get_upload('webextension_with_image.zip') assert len(ScannerResult.objects.all()) == 0 # This rule will match for all PNG files in the xpi. rule = ScannerRule.objects.create( name='match_png', scanner=YARA, definition='rule match_png { ' 'strings: $png = { 89 50 4E 47 0D 0A 1A 0A } ' 'condition: $png at 0 }', ) received_results = run_yara(self.results, self.upload.pk) yara_results = ScannerResult.objects.all() assert len(yara_results) == 1 yara_result = yara_results[0] assert yara_result.upload == self.upload assert len(yara_result.results) == 1 assert yara_result.results[0] == { 'rule': rule.name, 'tags': [], 'meta': {'filename': 'img.png'}, } # The task should always return the results. assert received_results == self.results
def test_run_is_manifest(self, incr_mock): assert len(ScannerResult.objects.all()) == 0 # This rule will match for just the manifest.json rule = ScannerRule.objects.create( name='is_manifest_true', scanner=YARA, # 'is_manifest_file' is an external variable we automatically # provide. definition='rule is_manifest_true { condition: is_manifest_file }', ) received_results = run_yara(self.results, self.upload.pk) yara_results = ScannerResult.objects.all() assert len(yara_results) == 1 yara_result = yara_results[0] assert yara_result.upload == self.upload assert len(yara_result.results) == 1 assert yara_result.results[0] == { 'rule': rule.name, 'tags': [], 'meta': {'filename': 'manifest.json'}, } assert incr_mock.called assert incr_mock.call_count == 3 incr_mock.assert_has_calls( [ mock.call('devhub.yara.has_matches'), mock.call(f'devhub.yara.rule.{rule.id}.match'), mock.call('devhub.yara.success'), ] ) # The task should always return the results. assert received_results == self.results
def test_run_with_invalid_filename(self, incr_mock): assert len(ScannerResult.objects.all()) == 0 # This rule will match for all files in the xpi. rule = ScannerRule.objects.create( name='always_true', scanner=YARA, definition='rule always_true { condition: true }', ) self.upload = self.get_upload('archive-with-invalid-chars-in-filenames.zip') received_results = run_yara(self.results, self.upload.pk) yara_results = ScannerResult.objects.all() assert len(yara_results) == 1 yara_result = yara_results[0] assert yara_result.upload == self.upload assert len(yara_result.results) == 1 print(yara_result.results[0]) assert yara_result.results[0] == { 'rule': rule.name, 'tags': [], 'meta': {'filename': 'path\\to\\file.txt'}, } # The task should always return the results. assert received_results == self.results
def test_run_does_not_raise(self, incr_mock, yara_compile_mock): yara_compile_mock.side_effect = Exception() received_results = run_yara(self.results, self.upload.pk) assert incr_mock.called incr_mock.assert_called_with('devhub.yara.failure') # The task should always return the results. assert received_results == self.results
def test_run_does_not_raise(self, incr_mock): # This call should not raise even though there will be an error because # YARA_RULES_FILEPATH is configured with a wrong path. received_results = run_yara(self.results, self.upload.pk) assert incr_mock.called incr_mock.assert_called_with('devhub.yara.failure') # The task should always return the results. assert received_results == self.results
def test_skip_non_webextensions_with_mocks(self, yara_compile_mock): upload = self.get_upload('search.xml') results = { **amo.VALIDATOR_SKELETON_RESULTS, 'metadata': {'is_webextension': False}, } received_results = run_yara(results, upload.pk) assert not yara_compile_mock.called # The task should always return the results. assert received_results == results
def test_run_no_matches_with_mocks(self, incr_mock): assert len(ScannerResult.objects.all()) == 0 # This compiled rule will never match. rules = yara.compile(source='rule always_false { condition: false }') with mock.patch('yara.compile') as yara_compile_mock: yara_compile_mock.return_value = rules received_results = run_yara(self.results, self.upload.pk) yara_result = ScannerResult.objects.all()[0] assert yara_result.results == [] # The task should always return the results. assert received_results == self.results assert incr_mock.called assert incr_mock.call_count == 1 incr_mock.assert_called_with('devhub.yara.success')
def test_run_no_matches(self, incr_mock): assert len(ScannerResult.objects.all()) == 0 # This compiled rule will never match. ScannerRule.objects.create( name='always_false', scanner=YARA, definition='rule always_false { condition: false }', ) received_results = run_yara(self.results, self.upload.pk) yara_result = ScannerResult.objects.all()[0] assert yara_result.results == [] # The task should always return the results. assert received_results == self.results assert incr_mock.called assert incr_mock.call_count == 1 incr_mock.assert_called_with('devhub.yara.success')
def test_run_ignores_directories(self): upload = self.get_upload('webextension_signed_already.xpi') results = { **amo.VALIDATOR_SKELETON_RESULTS, 'metadata': {'is_webextension': True}, } # This compiled rule will match for all files in the xpi. rules = yara.compile(source='rule always_true { condition: true }') with mock.patch('yara.compile') as yara_compile_mock: yara_compile_mock.return_value = rules received_results = run_yara(results, upload.pk) yara_result = ScannerResult.objects.all()[0] assert yara_result.upload == upload # The `webextension_signed_already.xpi` fixture file has 1 directory # and 3 files. assert len(yara_result.results) == 3 # The task should always return the results. assert received_results == results
def test_run_ignores_directories(self): upload = self.get_upload('webextension_signed_already.xpi') results = { **amo.VALIDATOR_SKELETON_RESULTS, } # This rule will match for all files in the xpi. ScannerRule.objects.create( name='always_true', scanner=YARA, definition='rule always_true { condition: true }', ) received_results = run_yara(results, upload.pk) yara_result = ScannerResult.objects.all()[0] assert yara_result.upload == upload # The `webextension_signed_already.xpi` fixture file has 1 directory # and 3 files. assert len(yara_result.results) == 3 # The task should always return the results. assert received_results == results
def test_run_in_non_binary_mode_with_binary(self): self.upload = self.get_upload('webextension_with_image.zip') assert len(ScannerResult.objects.all()) == 0 # This rule will match for all PNG files in the xpi. ScannerRule.objects.create( name='match_png', scanner=YARA, definition='rule match_png { ' 'strings: $png = { 89 50 4E 47 0D 0A 1A 0A } ' 'condition: $png at 0 }', ) received_results = run_yara(self.results, self.upload.pk) yara_result = ScannerResult.objects.all()[0] # We don't match here, as decoding the bytes leads to missing the rule. assert yara_result.results == [] # The task should always return the results. assert received_results == self.results
def test_run(self, incr_mock): assert len(ScannerResult.objects.all()) == 0 # This rule will match for all files in the xpi. rule = ScannerRule.objects.create( name='always_true', scanner=YARA, definition='rule always_true { condition: true }', ) received_results = run_yara(self.results, self.upload.pk) yara_results = ScannerResult.objects.all() assert len(yara_results) == 1 yara_result = yara_results[0] assert yara_result.upload == self.upload assert len(yara_result.results) == 2 assert yara_result.results[0] == { 'rule': rule.name, 'tags': [], 'meta': { 'filename': 'index.js' }, } assert yara_result.results[1] == { 'rule': rule.name, 'tags': [], 'meta': { 'filename': 'manifest.json' }, } assert incr_mock.called assert incr_mock.call_count == 3 incr_mock.assert_has_calls([ mock.call('devhub.yara.has_matches'), mock.call(f'devhub.yara.rule.{rule.id}.match'), mock.call('devhub.yara.success'), ]) # The task should always return the results. assert received_results == self.results
def test_run_is_locale_file(self, incr_mock): self.upload = self.get_upload('notify-link-clicks-i18n.xpi') assert len(ScannerResult.objects.all()) == 0 # This rule will match for all _locales/*/messages.json files rule = ScannerRule.objects.create( name='is_locale_true', scanner=YARA, # 'is_locale_file' is an external variable we automatically # provide. definition='rule is_locale_true { condition: is_locale_file }', ) received_results = run_yara(self.results, self.upload.pk) yara_results = ScannerResult.objects.all() assert len(yara_results) == 1 yara_result = yara_results[0] assert yara_result.upload == self.upload assert len(yara_result.results) == 7 assert yara_result.results[0] == { 'rule': rule.name, 'tags': [], 'meta': {'filename': '_locales/de/messages.json'}, } assert yara_result.results[1] == { 'rule': rule.name, 'tags': [], 'meta': {'filename': '_locales/en/messages.json'}, } assert yara_result.results[2] == { 'rule': rule.name, 'tags': [], 'meta': {'filename': '_locales/ja/messages.json'}, } assert yara_result.results[3] == { 'rule': rule.name, 'tags': [], 'meta': {'filename': '_locales/nb_NO/messages.json'}, } assert yara_result.results[4] == { 'rule': rule.name, 'tags': [], 'meta': {'filename': '_locales/nl/messages.json'}, } assert yara_result.results[5] == { 'rule': rule.name, 'tags': [], 'meta': {'filename': '_locales/ru/messages.json'}, } assert yara_result.results[6] == { 'rule': rule.name, 'tags': [], 'meta': {'filename': '_locales/sv/messages.json'}, } assert incr_mock.called assert incr_mock.call_count == 3 incr_mock.assert_has_calls( [ mock.call('devhub.yara.has_matches'), mock.call(f'devhub.yara.rule.{rule.id}.match'), mock.call('devhub.yara.success'), ] ) # The task should always return the results. assert received_results == self.results
def test_calls_statsd_timer(self, timer_mock): run_yara(self.results, self.upload.pk) assert timer_mock.called timer_mock.assert_called_with('devhub.yara')