Example #1
0
 def test_create_web3_client_private_key(self, method_call_mock):
     """
     Test that private key is instantiated correctly when creating web3 client
     """
     eth_provider = self.config_utils.create_eth_provider(
         "EthereumTesterProvider", {})
     private_key = "0xc2fd94c5216e754d3eb8f4f34017120fef318c50780ce408b54db575b120229f"
     passphrase = "abc123ropsten"
     client, new_account, new_private_key = self.config_utils.create_web3_client(
         eth_provider, passphrase,
         io_utils.fetch_file(resource_uri("mykey.json")), 2)
     self.assertEqual(private_key, Web3.toHex(new_private_key),
                      "Private key was not decrypted correctly")
     # None ETH provider will make this fail
     try:
         client, new_account, new_private_key = self.config_utils.create_web3_client(
             eth_provider, "incorrect-passphrase",
             io_utils.fetch_file(resource_uri("mykey.json")), 2)
         self.fail(
             "No exception was thrown even though the private key isn't correct"
         )
     except ConfigurationException as e:
         self.assertTrue("MAC mismatch" in str(e),
                         "Expected the MAC mismatch exception")
         # Expected
         pass
    def test_compress_and_decode_full_report(self):
        """
        Ensures that a typical, complete report is compressed properly.
        """
        report = load_json(fetch_file(resource_uri("reports/DAOBug.json")))
        hexstring = self.compress_report(report)
        decoded_report = self.decode_report(hexstring)

        expected_report = load_json(
            fetch_file(resource_uri("reports/DAOBugDecompressed.json")))
        self.__compare_json(decoded_report, expected_report)
 def setUp(self):
     """
     Sets up fresh database for each test.
     """
     self.worker = Sqlite3Worker(TestSqlLite3Worker.db_file)
     self.worker.execute_script(
         fetch_file(resource_uri('evt/createdb.sql', is_main=True)))
Example #4
0
 def load_config(cls, config_file_uri, environment):
     """
     Loads config from file and returns.
     """
     config_file_path = io_utils.fetch_file(config_file_uri)
     config_file = io_utils.load_yaml(config_file_path)
     return config_file[environment]
Example #5
0
def __load_audit_contract_from_src(web3_client, contract_src_uri,
                                   contract_name, constructor_from):
    """
    Loads the QuantstampAuditMock contract from source code returning the (address, contract)
    pair.
    """
    audit_contract_src = fetch_file(contract_src_uri)
    contract_dict = compile_files([audit_contract_src])
    contract_id = "{0}:{1}".format(
        contract_src_uri,
        contract_name,
    )
    contract_interface = contract_dict[contract_id]

    # deploy the audit contract
    audit_contract = web3_client.eth.contract(
        abi=contract_interface['abi'], bytecode=contract_interface['bin'])
    tx_hash = safe_transact(audit_contract.constructor(), {
        'from': constructor_from,
        'gasPrice': 0
    })
    receipt = web3_client.eth.getTransactionReceipt(tx_hash)
    address = receipt['contractAddress']
    audit_contract = web3_client.eth.contract(
        abi=contract_interface['abi'],
        address=address,
    )
    return address, audit_contract
Example #6
0
    def __copy_yaml_setup(self):
        test_config = fetch_file(resource_uri('test_config.yaml'))
        with open(test_config) as yaml_file:
            cfg = yaml.load(yaml_file)
        tmp = NamedTemporaryFile(mode='w+t', delete=False)
        yaml.dump(cfg, tmp, default_flow_style=False)

        return tmp, cfg
 def test_encode_decode_idempotence(self):
     """
     Ensures that encode(decode(report)) == encode(decode(encode(decode(report))))
     """
     report = load_json(fetch_file(resource_uri("reports/DAOBug.json")))
     decoded_report = self.decode_report(self.compress_report(report))
     twice_decoded_report = self.decode_report(
         self.compress_report(decoded_report))
     self.__compare_json(decoded_report, twice_decoded_report)
Example #8
0
    def create_contract(self, web3_client, contract_abi_uri, contract_address):
        """
        Creates the audit contract from ABI.
        """
        abi_file = io_utils.fetch_file(contract_abi_uri)
        abi_json = io_utils.load_json(abi_file)

        return web3_client.eth.contract(
            address=contract_address,
            abi=abi_json,
        )
 def __assert_audit_request_report(self,
                                   request_id,
                                   report_file_path=None,
                                   ignore_id=False):
     audit = self.__fetch_audit_from_db(request_id)
     if report_file_path is not None:
         audit_file = fetch_file(audit['audit_uri'])
         self.assertEqual(digest_file(audit_file), audit['audit_hash'])
         self.compare_json(audit_file,
                           report_file_path,
                           ignore_id=ignore_id)
    def test_create_set_from_compressed_report(self):
        # Tests whether vulnerability sets for compressed reports match those from
        # their corresponding uncompressed ones.
        for report in os.listdir(fetch_file(resource_uri("reports/"))):
            uncompressed_report = load_json(
                fetch_file(resource_uri("reports/DAOBug.json")))
            expected_set = VulnerabilitiesSet.from_uncompressed_report(
                uncompressed_report)

            request_id = uncompressed_report['request_id']

            encoder = ReportEncoder()
            compressed_report = encoder.compress_report(
                uncompressed_report, request_id)
            decompressed_report = encoder.decode_report(
                compressed_report, request_id)
            found_set = VulnerabilitiesSet.from_uncompressed_report(
                decompressed_report)

            self.assertEquals(expected_set, found_set)
    def test_inserting_duplicates_events(self):
        """
        Tests that the worker does not propagate raised exception when two records with the same
        primary key are inserted in the database. Also tests that if such an insert is invoked, the
        existing values remain the same.
        """
        with mock.patch.object(self.worker,
                               'logger') as sql3liteworker_logger_mock:
            with mock.patch('evt.evt_pool_manager.logger'
                            ) as evt_pool_manager_logger_mock:
                self.assertFalse(sql3liteworker_logger_mock.warning.called)

                self.worker.execute_script(
                    fetch_file(
                        resource_uri('evt/add_evt_to_be_assigned.sql',
                                     is_main=True)),
                    values=(1, 'x', 'x', 'x', 10, 'x', 'x', 12),
                    error_handler=EventPoolManager.insert_error_handler)

                self.assertFalse(sql3liteworker_logger_mock.warning.called)
                self.assertFalse(evt_pool_manager_logger_mock.warning.called)

        with mock.patch.object(self.worker,
                               'logger') as sql3liteworker_logger_mock:
            with mock.patch('evt.evt_pool_manager.logger'
                            ) as evt_pool_manager_logger_mock:
                self.worker.execute_script(
                    fetch_file(
                        resource_uri('evt/add_evt_to_be_assigned.sql',
                                     is_main=True)),
                    values=(1, 'x', 'x', 'x', 10, 'x', 'x', 12),
                    error_handler=EventPoolManager.insert_error_handler)
                # Ensure that threads were merged before assertions
                self.worker.close()

                self.assertFalse(sql3liteworker_logger_mock.error.called)
                self.assertFalse(evt_pool_manager_logger_mock.error.called)

                self.assertTrue(evt_pool_manager_logger_mock.warning.called)
                args, _ = evt_pool_manager_logger_mock.warning.call_args
                self.assertTrue(isinstance(args[3], apsw.ConstraintError))
Example #12
0
    def __assert_all_analyzers(self, request_id):
        """
        Asserts that all configured analyzers were executed and are included in the report.
        """
        row = self.__fetch_audit_from_db(request_id)

        audit_uri = row['audit_uri']
        audit_file = fetch_file(audit_uri)
        actual_json = load_json(audit_file)
        executed_analyzers = [x['analyzer']['name'] for x in actual_json['analyzers_reports']]
        for analyzer in self.__config.analyzers_config:
            name, conf = list(analyzer.items())[0]
            self.assertTrue(name in executed_analyzers)
    def test_old_pragma_with_caret(self):
        """
        Tests whether no exception is raised upon calling the analyzer
        with a contract locking an old version of Solidity with caret.
        """

        old_contract = fetch_file(resource_uri("DAOBugOld-Caret.sol"))
        analyzer = TestAnalyzerSecurify.__new_analyzer()
        request_id = 15
        report = analyzer.check(old_contract, request_id,
                                "DAOBugOld-Caret.sol")

        self.assertTrue(report['status'], 'success')
        self.assertEquals(6, len(report['potential_vulnerabilities']))
Example #14
0
 def compare_json(self,
                  audit_file,
                  report_file_path,
                  json_loaded=False,
                  ignore_id=False):
     if not json_loaded:
         actual_json = load_json(audit_file)
     else:
         actual_json = audit_file
     expected_json = load_json(fetch_file(resource_uri(report_file_path)))
     if ignore_id:
         expected_json['request_id'] = actual_json['request_id']
     diff = DeepDiff(
         actual_json,
         expected_json,
         exclude_paths={
             "root['contract_uri']",
             "root['version']",
             # There is no keystore used for testing. Accounts
             # are dynamic and therefore cannot be compared
             "root['auditor']",
             "root['requestor']",
             # Path is different depending on whether running inside Docker
             "root['timestamp']",
             "root['start_time']",
             "root['end_time']",
             "root['analyzers_reports'][0]['analyzer']['command']",
             "root['analyzers_reports'][0]['coverages'][0]['file']",
             "root['analyzers_reports'][0]['potential_vulnerabilities'][0]['file']",
             "root['analyzers_reports'][0]['start_time']",
             "root['analyzers_reports'][0]['end_time']",
             "root['analyzers_reports'][1]['analyzer']['command']",
             "root['analyzers_reports'][1]['coverages'][0]['file']",
             "root['analyzers_reports'][1]['potential_vulnerabilities'][0]['file']",
             "root['analyzers_reports'][1]['start_time']",
             "root['analyzers_reports'][1]['end_time']",
             "root['analyzers_reports'][2]['analyzer']['command']",
             "root['analyzers_reports'][2]['coverages'][0]['file']",
             "root['analyzers_reports'][2]['potential_vulnerabilities'][0]['file']",
             "root['analyzers_reports'][2]['start_time']",
             "root['analyzers_reports'][2]['end_time']",
             # Once scripts are either executed or skipped. The traces at position 1 differ.
             "root['analyzers_reports'][0]['trace']",
             "root['analyzers_reports'][1]['trace']",
             "root['analyzers_reports'][2]['trace']"
         })
     pprint(diff)
     self.assertEqual(diff, {})
     self.assertEqual(ntpath.basename(actual_json['contract_uri']),
                      ntpath.basename(expected_json['contract_uri']))
Example #15
0
 def test_analyzer_produces_metadata_for_errors(self):
     """
     Tests that analyzers produce their metadata even when failure occurs
     """
     buggy_contract = resource_uri("BasicToken.sol")
     buggy_contract_file = fetch_file(buggy_contract)
     # directly calling this function to avoid compilation checks;
     # this will cause error states for the analyzers
     report = self.__thread.get_audit_report_from_analyzers(
         buggy_contract_file, "0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf",
         buggy_contract, 1)
     self.compare_json(report,
                       "reports/BasicTokenErrorWithMetadata.json",
                       json_loaded=True)
Example #16
0
    def test_old_pragma(self):
        """
        Tests whether an exception is raised upon calling the analyzer
        with a contract locking an old version of Solidity.
        """

        old_contract = fetch_file(resource_uri("DAOBugOld.sol"))
        analyzer = TestAnalyzerOyente.__new_analyzer()
        request_id = 15
        report = analyzer.check(old_contract, request_id, "DAOBugOld.sol")

        self.assertTrue(report['status'], 'error')
        self.assertTrue(1, len(report['errors']))
        self.assertTrue("Source file requires different compiler version" in
                        report['errors'][0])
Example #17
0
    def test_old_pragma(self):
        """
        Tests whether an exception is raised upon calling the analyzer
        with a contract locking an old version of Solidity.
        """

        old_contract = fetch_file(resource_uri("DAOBugOld.sol"))
        analyzer = TestAnalyzerMythril.__new_analyzer()
        request_id = 15
        report = analyzer.check(old_contract, request_id, "DAOBugOld.sol")
        self.assertTrue(report['status'], 'error')

        self.assertTrue(len(report['errors']) > 0)
        self.assertEquals(12, len(report['trace']))
        self.assertTrue(
            "Error: Source file requires different compiler version" in
            ''.join(err + '\n' for err in report['errors']))
    def test_old_pragma(self):
        """
        Tests whether an exception is raised upon calling the analyzer
        with a contract locking an old version of Solidity.
        """

        old_contract = fetch_file(resource_uri("DAOBugOld.sol"))
        analyzer = TestAnalyzerSecurify.__new_analyzer()
        request_id = 15
        report = analyzer.check(old_contract, request_id, "DAOBugOld.sol")
        self.assertTrue(report['status'], 'error')

        self.assertTrue(len(report['errors']) > 0)
        self.assertEquals(11, len(report['trace']))
        self.assertTrue(
            "ch.securify.CompilationHelpers.compileContracts" in ''.join(
                err + '\n' for err in report['errors']))
Example #19
0
    def test_old_pragma_with_caret(self):
        """
        Tests whether an exception is raised upon calling the analyzer with a contract locking an
        old version of Solidity. This SHOULD invoke dockerhub fail.
        """

        old_contract = fetch_file(resource_uri("DAOBugOld-Caret.sol"))

        analyzer = TestAnalyzerDockerhubFail.__new_analyzer()
        request_id = 15
        report = analyzer.check(old_contract, request_id,
                                "DAOBugOld-Caret.sol")

        self.assertTrue(report['status'], 'error')
        self.assertEquals(2, len(report['trace']))
        self.assertEquals(1, len(report['errors']))
        msg = "Error response from daemon: pull access denied for qspprotocol/" \
              "does-not-exist-0.4.25, repository does not exist or may require 'docker login'\n"
        self.assertEquals(msg, report['errors'][0])
Example #20
0
    def test_inject_token_auth(self):
        auth_token = "abc123456"
        endpoint = "https://test.com/?token={0}".format(auth_token)
        target_env = "dev"

        # Sets the dictionary to be returned by a call to load_config
        config_file = fetch_file(resource_uri("test_config_with_auth_token.yaml"))
        config_yaml = load_yaml(config_file)
        dummy_utils = ConfigUtilsDummy({'load_config': config_yaml[target_env]})

        config = ConfigFactory.create_from_file(
            environment=target_env,
            config_file_uri="some dummy uri",
            auth_token=auth_token,
            validate_contract_settings=False,
            config_utils=dummy_utils,
        )
        self.assertEqual(config.auth_token, auth_token)
        self.assertEqual(config.eth_provider_args['endpoint_uri'], endpoint)
    def test_report_creation(self):
        """
        Tests whether a report is created upon calling the analyzer
        on a buggy contract
        """
        analyzer = TestAnalyzerSecurify.__new_analyzer()

        buggy_contract = fetch_file(resource_uri("DAOBug.sol"))
        request_id = 15
        report = analyzer.check(buggy_contract, request_id, "DAOBug.sol")

        # Asserts some result produced
        self.assertTrue(report)

        print(json.dumps(report, indent=2))

        # Asserts result is success
        self.assertTrue(report['status'], 'success')
        self.assertIsNotNone(report['potential_vulnerabilities'])
        self.assertEquals(6, len(report['potential_vulnerabilities']))
Example #22
0
    def test_report_creation(self):
        """
        Tests whether a report is created upon calling the analyzer on a buggy contract. This SHOULD
        invoke dockerhub fail.
        """
        analyzer = TestAnalyzerDockerhubFail.__new_analyzer()

        buggy_contract = fetch_file(resource_uri("DAOBug.sol"))
        request_id = 15
        report = analyzer.check(buggy_contract, request_id, "DAOBug.sol")

        # Asserts some result produced
        self.assertTrue(report)

        self.assertTrue(report['status'], 'error')

        self.assertEquals(2, len(report['trace']))
        self.assertEquals(1, len(report['errors']))
        msg = "Error response from daemon: pull access denied for qspprotocol/" \
              "does-not-exist-0.4.25, repository does not exist or may require 'docker login'\n"
        self.assertEquals(msg, report['errors'][0])
Example #23
0
def fetch_config(inject_contract=False):
    # create config from file, the contract is not provided and will be injected separately
    config_file_uri = resource_uri("test_config.yaml")
    config = ConfigFactory.create_from_file(config_file_uri,
                                            os.getenv("QSP_ENV",
                                                      default="dev"),
                                            validate_contract_settings=False)
    if inject_contract:
        contract_source_uri = "./tests/resources/QuantstampAuditMock.sol"
        contract_metadata_uri = "./tests/resources/QuantstampAudit-metadata.json"
        audit_contract_metadata = load_json(fetch_file(contract_metadata_uri))
        audit_contract_name = get(audit_contract_metadata, '/contractName')

        addr, contract = __load_audit_contract_from_src(
            config.web3_client, contract_source_uri, audit_contract_name,
            config.account)

        config._Config__audit_contract_address = addr
        config._Config__audit_contract = contract

        config_utils = ConfigUtils(config.node_version)
        config_utils.check_configuration_settings(config)

    return config
 def __load_report(self, report_file_path):
     return load_json(fetch_file(resource_uri(report_file_path)))
Example #25
0
 def __fetch_contract_metadata(self, cfg, config_utils, contract_abi):
     metadata_uri = config_utils.resolve_version(
         config_value(cfg, '/' + contract_abi + '/metadata'))
     if metadata_uri is not None:
         return io_utils.load_json(io_utils.fetch_file(metadata_uri))
Example #26
0
    def test_successful_police_audit(self):
        uncompressed_report = load_json(
            fetch_file(resource_uri("reports/DAOBug.json")))
        request_id = uncompressed_report['request_id']

        encoder = ReportEncoder()
        compressed_report = encoder.compress_report(uncompressed_report,
                                                    request_id)

        # Creates a mocked method for retrieving the audit result from the blockchain.
        submit_report_instance = SubmitReportThread(self.__config)
        submit_report_instance._SubmitReportThread__get_report_in_blockchain = MagicMock(
        )
        submit_report_instance._SubmitReportThread__get_report_in_blockchain.return_value = \
            compressed_report
        replace_thread(self.__audit_node, SubmitReportThread,
                       submit_report_instance)

        # Adds a police event to the database to trigger the flow of a police
        # check. Since no other thread should be writing to the DB at this
        # point, the write can be performed without a lock.
        poll_requests_instance = PollRequestsThread(
            self.__config, self.__block_mined_polling_thread)
        poll_requests_instance._PollRequestsThread__add_evt_to_db(
            request_id=request_id,
            requestor=self.__audit_node.config.audit_contract_address,
            price=100,
            uri=resource_uri("reports/DAOBug.json"),
            assigned_block_nbr=100,
            is_audit=False)
        replace_thread(self.__audit_node, PollRequestsThread,
                       poll_requests_instance)

        # Disables the claim rewards threading from continuously running ahead;
        # negate the default mocking behaviour of always having rewards
        # available
        claim_rewards_instance = ClaimRewardsThread(self.__config)
        claim_rewards_instance._ClaimRewardsThread__has_available_rewards = MagicMock(
        )
        claim_rewards_instance._ClaimRewardsThread__has_available_rewards.return_value = False
        replace_thread(self.__audit_node, ClaimRewardsThread,
                       claim_rewards_instance)

        # Sets the node as a police officer.
        self.__audit_node.is_police_officer = MagicMock()
        self.__audit_node.is_police_officer.return_value = True

        # Sets the audit report value itself to be returned by the audit node.
        self.__audit_node.audit = MagicMock()
        self.__audit_node.audit.return_value = {
            'audit_state': uncompressed_report['audit_state'],
            'audit_uri': 'http://some-url.com',
            'audit_hash': 'some-hash',
            'full_report': json.dumps(uncompressed_report),
            'compressed_report': compressed_report
        }

        self.__run_audit_node()

        sql3lite_worker = self.__audit_node.config.event_pool_manager.sql3lite_worker
        result_found = False

        # Waits till the record moves from assigned status to submitted.
        sql = "select * from audit_evt where request_id = {0} and fk_status == 'SB' and fk_type='PC'"
        while not result_found:
            rows = sql3lite_worker.execute(sql.format(request_id))
            if len(rows) == 0:
                sleep(0.1)
                continue

            self.assertTrue(len(rows), 1)
            result_found = True
Example #27
0
 def __compress_report(self, report_path_uri):
     full_report = load_json(fetch_file(resource_uri(report_path_uri)))
     full_report['version'] = self.__config.node_version
     encoder = ReportEncoder()
     return encoder.compress_report(full_report, full_report['request_id'])
 def __compress_report(report_path_uri):
     full_report = load_json(fetch_file(resource_uri(report_path_uri)))
     encoder = ReportEncoder()
     return encoder.compress_report(full_report, full_report['request_id'])
Example #29
0
 def setUpClass(cls):
     cfg = load_yaml(fetch_file(resource_uri("test_config.yaml")))
     TestEvtPoolManager.db_file = config_value(cfg, '/dev/evt_db_path')
     remove(TestEvtPoolManager.db_file)
 def validate_report(self, report_path):
     report = load_json(fetch_file(resource_uri(report_path)))
     validate(report, self.schema)