def report(self): logger.info("Generating report...") logger.debug("Validating configuration") (valid, error) = data.validate_yaml_file( "threatspec.yaml", os.path.join("data", "config_schema.json")) if not valid: logger.error( "Couldn't validate the configation file {}: {}".format( "threatspec.yaml", error)) sys.exit(0) logger.debug("Loading configuration from threatspec.yaml") self.config.load(data.read_yaml("threatspec.yaml")) self.load_threat_library_data() self.load_threat_model_data() self.generate_report() logger.info(""" The following threat model markdown report has been created: ThreatModel.md The following visualisation image used in the report has also been created: ThreatModel.gv.png """)
def run(self): logger.info("Running threatspec...") config_path = data.abs_path(data.cwd(), "threatspec.yaml") (valid, error) = data.validate_yaml_file( config_path, os.path.join("data", "config_schema.json")) if not valid: logger.error( "Couldn't validate the configation file {}: {}".format( "threatspec.yaml", error)) sys.exit(0) self.config.load(data.read_yaml(config_path)) self.load_threat_library_data() self.parse_source(self.config.paths, data.cwd()) self.save_threat_library_data() self.save_threat_model_data() logger.info(""" Threatspec has been run against the source files. The following threat mode file has been created and contains the mitigations, acceptances, connections etc. for the project: threatmodel/threatmodel.json The following library files have also been create: threatmodel/threats.json threatmodel/controls.json threatmodel/components.json """)
def load_threat_library_data_from_path(self, paths, parent): for config_path in paths: abs_path = data.abs_path(parent, config_path.path) if abs_path == data.cwd(): continue # Skip current directory as this was handled earlier if abs_path in self.loaded_library_paths: logger.debug( "Skipping library path {} as we've processed it before". format(abs_path)) continue # Skip as we've seen this path before self.loaded_library_paths[abs_path] = True # We've seen it now if data.is_threatspec_path(abs_path): logger.debug( "Found threatspec.yaml, loading library from {}".format( abs_path)) self.load_threat_library(abs_path) self.load_control_library(abs_path) self.load_component_library(abs_path) new_config_file = data.abs_path(abs_path, "threatspec.yaml") new_config = config.Config() logger.debug("Validating {}".format(new_config_file)) (valid, error) = data.validate_yaml_file( new_config_file, os.path.join("data", "config_schema.json")) if not valid: logger.error( "Couldn't validate the configation file {}: {}".format( "threatspec.yaml", error)) sys.exit(0) new_config.load(data.read_yaml(new_config_file)) self.load_threat_library_data_from_path( new_config.paths, abs_path)
def load_local_config(self): logger.debug("Loading local threatspec.yaml configuration file") config_path = data.abs_path(data.cwd(), "threatspec.yaml") (valid, error) = data.validate_yaml_file( config_path, os.path.join("data", "config_schema.json")) if not valid: logger.error( "Couldn't validate the configation file {}: {}".format( "threatspec.yaml", error)) sys.exit(1) self.config.load(data.read_yaml(config_path))
def parse_source(self, paths, parent): for config_path in paths: abs_path = data.abs_path(parent, config_path.path) if data.blacklisted_path(abs_path): logger.debug( "Skipping path {} as it is blacklisted".format(abs_path)) continue logger.debug("Processing source path {}".format(abs_path)) if abs_path in self.loaded_source_paths: logger.debug( "Skipping source path {} as it has already been processed". format(abs_path)) continue self.loaded_source_paths[abs_path] = True # We've seen it now if data.is_threatspec_path(abs_path): logger.debug( "Found threatspec.yaml, loading source configuration from {}" .format(abs_path)) new_config = config.Config() new_config_file = data.abs_path(abs_path, "threatspec.yaml") (valid, error) = data.validate_yaml_file( new_config_file, os.path.join("data", "config_schema.json")) if not valid: logger.error( "Couldn't validate the configation file {}: {}".format( abs_path, error)) sys.exit(1) new_config.load(data.read_yaml(new_config_file)) self.parse_source(new_config.paths, abs_path) for path in data.recurse_path(abs_path): if data.path_ignored(path, config_path.ignore): logger.debug("Skipping ignored file path: {}".format(path)) continue logger.debug("Parsing source files in path {}".format(path)) if os.path.isfile(path): self.parser = self.get_parser_for_path(path, config_path) if self.parser: self.parser.parse_file(path)
def init(self): logger.info("Initialising threatspec...") logger.debug("Creating default configuration file") try: data.copy_pkg_file(os.path.join("data", "default_config.yaml"), "threatspec.yaml") except FileExistsError as e: logger.error( "Configuration file already exists, it looks like threatspec has already been initiated here." ) sys.exit(0) config_file = data.abs_path(data.cwd(), "threatspec.yaml") logger.debug("Validating {}".format(config_file)) (valid, error) = data.validate_yaml_file( config_file, os.path.join("data", "config_schema.json")) if not valid: logger.error( "Couldn't validate the configation file {}: {}".format( config_file, error)) sys.exit(0) logger.debug("Loading configuration") self.config.load(data.read_yaml(config_file)) logger.debug("Creating directories") try: data.create_directories(["threatmodel"]) except IOError as e: logger.error("Failed to create directories: {}".format(str(e))) raise logger.info(""" Threatspec has been initialised. You can now configure the project in this repository by editing the following file: threatspec.yaml. """)