def get_mythx_client() -> Client: """Generate a MythX client instance. This method will look for an API key passed as a parameter, and if none is found, look for a key in the environment variable :code:`MYTHX_API_KEY`. If a key is detected, a PythX client instance is returned, otherwise a :code:`ValidationError` is raised. :raises: ValidationError if no valid API key is provided :return: A PythX client instance """ if CONFIG.argv["api-key"]: auth_args = {"api_key": CONFIG.argv["api-key"]} elif environ.get("MYTHX_API_KEY"): auth_args = {"api_key": environ.get("MYTHX_API_KEY")} else: raise ValidationError( "You must provide a MythX API key via environment variable or the command line" ) return Client(**auth_args, middlewares=[ ClientToolNameMiddleware( name=f"brownie-{__version__}") ])
def main(): """The main entry point of the MythX plugin for Brownie.""" args = docopt(__doc__) _update_argv_from_docopt(args) if CONFIG.argv["mode"] not in ANALYSIS_MODES: raise ValidationError( "Invalid analysis mode: Must be one of [{}]".format( ", ".join(ANALYSIS_MODES))) project_path = project.check_for_project(".") if project_path is None: raise ProjectNotFound build = project.load()._build submission = SubmissionPipeline(build) print("Preparing project data for submission to MythX...") submission.prepare_requests() print("Sending analysis requests to MythX...") submission.send_requests() # exit if user wants an async analysis run if CONFIG.argv["async"]: print( "\nAll contracts were submitted successfully. Check the dashboard at " "https://dashboard.mythx.io/ for the progress and results of your analyses" ) return print("\nWaiting for results...") submission.wait_for_jobs() submission.generate_stdout_report() submission.generate_highlighting_report() # erase previous report report_path = project_path.joinpath( _load_project_structure_config(project_path)["reports"]) report_path = report_path.joinpath("security.json") if report_path.exists(): report_path.unlink() print_console_report(submission.stdout_report) # Write report to Brownie directory with report_path.open("w+") as fp: json.dump(submission.highlight_report, fp, indent=2, sort_keys=True) # Launch GUI if user requested it if CONFIG.argv["gui"]: print("Launching the Brownie GUI") gui = importlib.import_module("brownie._gui").Gui gui().mainloop()
def wait_for_jobs(self) -> None: """Poll the MythX API and returns once all requests have been processed. This will wait for all analysis requests in the internal :code:`responses` dict to finish. If a user passes the :code:`--interval` option, the plugin will poll the MythX API in the user-specified interval (in seconds) to see whether the analysis request is done processing. If the internal responses dict is empty, a :code:`ValidationError` is raised. :raise: :code:`ValidationError` :return: None """ if not self.responses: raise ValidationError("No requests given") for contract_name, response in self.responses.items(): while not self.client.analysis_ready(response.uuid): time.sleep(int(CONFIG.argv["interval"])) self.reports[contract_name] = self.client.report(response.uuid)