diff --git a/README.md b/README.md index a9d5f7973..42f46b8dd 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,8 @@ # Cerberus Framework +![Main View](doc/images/CerberusView.png) + + Cerberus is a program repair framework that provides the interface to multiple state-of-the art program analysis tools such as Infer and Pulse, as well as program repair tools such as Prophet, Darjeeling, Angelix, F1X etc. Encapsulating the difficulties to setup the infrastructure for program analysis/repair technology, this platform provides @@ -48,6 +51,7 @@ Cerberus should be considered alpha-quality software. Bugs can be reported here: * [Manual](doc/Manual.md) * [Extending](doc/Extending.md) * [Project Architecture](doc/ProjectArchitecture.md) +* [Notifications](doc/Notifications.md) diff --git a/app/core/configuration.py b/app/core/configuration.py index 58e4aff79..df49dcb83 100644 --- a/app/core/configuration.py +++ b/app/core/configuration.py @@ -16,7 +16,7 @@ def load_configuration_details(config_file_path: str): - emitter.normal("Loading profile setup") + emitter.normal("\tLoading profile setup") json_data = None if os.path.isfile(config_file_path): with open(config_file_path, "r") as conf_file: @@ -36,7 +36,7 @@ def load_class(class_name: str): def load_tool(tool_name: str) -> AbstractTool: tool_type = values.task_type - emitter.normal(f"Loading {tool_type} tool {tool_name}") + emitter.normal(f"\tLoading {tool_type} tool {tool_name}") tool_directory = f"{values.dir_tool_drivers}/{tool_type}" existing_tool_list = [ (str(x).split("/")[-1], str(x).split("/")[-2]) @@ -58,11 +58,10 @@ def load_tool(tool_name: str) -> AbstractTool: tool_class = getattr(mod, tool_class_name) initializer = getattr(tool_class, tool_class_name) return initializer() - raise Exception("Should not be reached") def load_benchmark(benchmark_name: str) -> AbstractBenchmark: - emitter.normal("Loading benchmark {}".format(benchmark_name)) + emitter.normal("\tLoading benchmark {}".format(benchmark_name)) # class_file_path = values.dir_benchmark_drivers + benchmark_name + ".py" existing_benchmark_list = [ @@ -139,8 +138,8 @@ def convert_range(self, x): return range(start, end + 1) def read_arg_list(self, arg_list: Namespace): - emitter.normal("Reading profile values") - emitter.normal("Reading configuration values from arguments") + emitter.normal("\tReading profile values") + emitter.normal("\tReading configuration values from arguments") flat_map = lambda f, xs: (y for ys in xs for y in f(ys)) self.__runtime_config_values["task-type"] = arg_list.task_type if arg_list.config: @@ -317,7 +316,7 @@ def print_configuration(self): emitter.configuration(config_key, config_value) def update_configuration(self): - emitter.normal("Updating configuration values") + emitter.normal("\tUpdating configuration values") values.task_type = self.__runtime_config_values["task-type"] values.only_setup = self.__runtime_config_values["only-setup"] if values.task_type == "prepare": diff --git a/app/core/container.py b/app/core/container.py index 09a7adff0..ef68423de 100644 --- a/app/core/container.py +++ b/app/core/container.py @@ -62,7 +62,7 @@ def get_image(image_name: str, tag_name="latest"): def pull_image(image_name: str, tag_name: str): client = get_client() - emitter.normal("pulling docker image") + emitter.normal("\tPulling docker image {}:{}".format(image_name, tag_name)) image = None try: for line in client.api.pull( @@ -82,7 +82,7 @@ def pull_image(image_name: str, tag_name: str): def build_image(dockerfile_path: str, image_name: str): client = get_client() - emitter.normal("\t\t[benchmark] building docker image") + emitter.normal("\t[benchmark] Building docker image {}".format(image_name)) context_dir = os.path.abspath(os.path.dirname(dockerfile_path)) if os.path.isfile(dockerfile_path): dockerfilename = dockerfile_path.split("/")[-1] @@ -169,7 +169,11 @@ def build_container( container_name: str, volume_list, image_name: str, cpu: str ) -> Optional[str]: client = get_client() - emitter.normal("\t\t\t[benchmark] building docker container") + emitter.normal( + "\t\t\t[benchmark] Building docker container based on image {} with name {}".format( + image_name, container_name + ) + ) try: for local_dir_path in volume_list: if local_dir_path == "/var/run/docker.sock": diff --git a/app/core/emitter.py b/app/core/emitter.py index 85cb0e11d..5c229969f 100644 --- a/app/core/emitter.py +++ b/app/core/emitter.py @@ -102,14 +102,14 @@ def sub_sub_title(text): def command(message): if values.debug: - prefix = "\t\t(command) " + prefix = "\t\t[command] " write(message, COLOR.ROSE, prefix=prefix, indent_level=2) logger.command(message) def docker_command(message): if values.debug: - prefix = "\t\t(docker-command) " + prefix = "\t\t[docker-command] " write(message, COLOR.ROSE, prefix=prefix, indent_level=2) logger.docker_command(message) @@ -123,14 +123,14 @@ def debug(message): def build(message): if values.debug: - prefix = "\t\t(build) " + prefix = "\t\t[build] " write(message, COLOR.GREY, prefix=prefix, indent_level=2) logger.build(message) def data(message, info=None): if values.debug: - prefix = "\t\t(data) " + prefix = "\t\t[data] " write(message, COLOR.GREY, prefix=prefix, indent_level=2) if info: write(info, COLOR.GREY, prefix=prefix, indent_level=2) @@ -203,7 +203,7 @@ def note(message): def configuration(setting, value): - message = "\t(config) " + setting + ": " + str(value) + message = "\t[config] " + setting + ": " + str(value) write(message, COLOR.WHITE, True) logger.configuration(setting + ":" + str(value)) diff --git a/app/core/main.py b/app/core/main.py index f54d0db68..f3c06af7f 100644 --- a/app/core/main.py +++ b/app/core/main.py @@ -318,7 +318,7 @@ def get_setup() -> Any: setup = configuration.load_configuration_details(values.file_configuration) for profile_id in values.profile_id_list: if profile_id not in setup: - utilities.error_exit("invalid profile id " + profile_id) + utilities.error_exit("Invalid profile id {}".format(profile_id)) return setup @@ -332,7 +332,7 @@ def get_tools() -> List[AbstractTool]: tool.check_tool_exists() tool_list.append(tool) emitter.highlight( - f"[profile] {values.task_type}-tool(s): " + f"\t[profile] {values.task_type}-tool(s): " + " ".join([x.name for x in tool_list]) ) return tool_list @@ -340,7 +340,7 @@ def get_tools() -> List[AbstractTool]: def get_benchmark() -> AbstractBenchmark: benchmark = configuration.load_benchmark(values.benchmark_name.lower()) - emitter.highlight(f"[profile] {values.task_type}-benchmark: {benchmark.name}") + emitter.highlight(f"\t[profile] {values.task_type}-benchmark: {benchmark.name}") return benchmark diff --git a/app/core/task/task.py b/app/core/task/task.py index 97fbb3ad5..ac5f3ac66 100644 --- a/app/core/task/task.py +++ b/app/core/task/task.py @@ -299,7 +299,7 @@ def run( # emitter.information("directory is {}".format(dir_instr_local)) if os.path.isdir(dir_instr_local): emitter.warning( - "\t\t[note] there is custom instrumentation for {}".format(tool.name) + "\t\t[note] There is custom instrumentation for {}".format(tool.name) ) if values.only_analyse: can_analyse_results = True diff --git a/app/drivers/benchmarks/AbstractBenchmark.py b/app/drivers/benchmarks/AbstractBenchmark.py index e8586100f..2c5f6b367 100644 --- a/app/drivers/benchmarks/AbstractBenchmark.py +++ b/app/drivers/benchmarks/AbstractBenchmark.py @@ -92,7 +92,7 @@ def get_list(self): return self.experiment_subjects def load_meta_file(self): - emitter.normal("loading experiment meta-data") + emitter.normal("\t[benchmark] Loading experiment meta-data") if not self.meta_file: utilities.error_exit("Meta file path not set") if not os.path.isfile(cast(str, self.meta_file)): @@ -104,7 +104,7 @@ def load_meta_file(self): self.size = len(json_data) else: values.experiment_status.set(TaskStatus.FAIL_IN_SETUP) - utilities.error_exit("could not load meta-data from ", self.meta_file) + utilities.error_exit("Could not load meta-data from ", self.meta_file) return def run_command( diff --git a/doc/GetStart.md b/doc/GetStart.md index c5ef65b4c..e3374a056 100644 --- a/doc/GetStart.md +++ b/doc/GetStart.md @@ -9,7 +9,7 @@ Cerberus will do the following actions in order when given a tool list and exper * Prepare an image for each subject, if one was not already created. * If sequentially running (by default), each experiment is ran on each tool in an isolated container (or locally if selected). -## Sequential +## Sequential execution We consider the [libtiff project](https://github.com/vadz/libtiff/) from the VulnLoc benchmark as a medium-sized example. @@ -21,7 +21,7 @@ We consider the [libtiff project](https://github.com/vadz/libtiff/) from the Vul We have selected to run the vulnfix tool on the 22nd bug of the vulnloc benchmark. Cerberus will prepare everything needed and run the tool on the selected subject. -## Parallel +## Parallel execution The becnhark has instrumentation setup for most of the C program repair tools currently integrated, thus we can test multiple tools and bugs in parallel and examine their results. @@ -34,14 +34,15 @@ Let us run some of them - vulnfix, extractfix, f1x and fix2fit and 4 of the bugs Cerberus will allocate 4*4 = 16 tasks and display 2 windows - the first one is the log of the currently selected task, this by default is the first allocated, and the second window is a table showing all tasks. If the `--debug` flag is passed there will is a third window collecting all textual messages from all tasks, showing the messages in chronological order. -![Tool Preparation Stage](images/UIPrepareTools.png) - -![Text log](images/TextLog.png) +![Tool Preparation Stage](images/ToolPreparation.png) ![UI Running](images/TaskList.png) Now Cerberus is running, one can easily filter the table by clicking on the buttons in the footer or click the accelerators or clicking on the different rows of the table to select the different text logs. By default Cerberus uses 2 less than the maximum amount of cores for task allocation to ensure that the system is not overloaded. One can easily change this amount with the `--cpus` flag and achieve sequential execution with the UI active by setting the cpus to 1. +The Status column can have various values and the common ones are "Allocated", "Running", "Waiting for CPU", "Successful", "Failed". Cerberus has a CPU allocation scheduling, which ensures that an experiment gets a cpu core. + + ## When complete When running each tool, the output from the run of the tool is stored in the `output/artifacts` folder and the logs in the `output/logs`. Each experiment run has a unique identifier, which can be seen from the first lines of the output of Cerberus. The folder of the artifact contains patches, output of the tool and extra files if defined by the driver. One can also use the symbolic link `TOOL-vulnloc-bugzilla-2633-last` where `TOOL` is the respective name of the tool to more easily access the run. This is a concrete instance of the patern pattern `TOOL-BENCHMARK-EXPERIMENT-last`. diff --git a/doc/Notifications.md b/doc/Notifications.md new file mode 100644 index 000000000..760e02fba --- /dev/null +++ b/doc/Notifications.md @@ -0,0 +1,3 @@ +# Getting notifications + +Currently Cerberus supports two types of notification systems - emails and Slack comments. The only requirement for setup is to provide proper configuration data. The config folder contains json files, which show the required fields. \ No newline at end of file diff --git a/doc/images/CerberusView.png b/doc/images/CerberusView.png new file mode 100644 index 000000000..715dcf40b Binary files /dev/null and b/doc/images/CerberusView.png differ diff --git a/doc/images/SequentialUI.png b/doc/images/SequentialUI.png index ac910e78c..a5fd78b8b 100644 Binary files a/doc/images/SequentialUI.png and b/doc/images/SequentialUI.png differ diff --git a/doc/images/TaskList.png b/doc/images/TaskList.png index ca144d213..ab2b1831c 100644 Binary files a/doc/images/TaskList.png and b/doc/images/TaskList.png differ diff --git a/doc/images/TextLog.png b/doc/images/TextLog.png deleted file mode 100644 index 197a4da03..000000000 Binary files a/doc/images/TextLog.png and /dev/null differ diff --git a/doc/images/ToolPreparation.png b/doc/images/ToolPreparation.png new file mode 100644 index 000000000..a2b1812f3 Binary files /dev/null and b/doc/images/ToolPreparation.png differ diff --git a/doc/images/UIPrepareTools.png b/doc/images/UIPrepareTools.png deleted file mode 100644 index 2f5cb1aee..000000000 Binary files a/doc/images/UIPrepareTools.png and /dev/null differ