Exemple #1
0
 def _run(self, args: argparse.Namespace) -> int:
     """Execute and process the args."""
     try:
         log.set_log_level_from_args(args)
         return self.replicate_object(args.model, args)
     except Exception as e:  # pragma: no cover
         return handle_generic_command_exception(e, logger, 'Error while replicating model')
Exemple #2
0
    def _run(self, args: argparse.Namespace) -> int:
        try:
            if self._initialize(args):
                raise TrestleError(
                    f'Error when initializing trestle folders command with args: {args}'
                )
            if args.mode == 'create-sample':
                status = self.create_sample()

            elif args.mode == 'template-validate':
                status = self.template_validate(args.header_validate,
                                                args.header_only_validate,
                                                args.governed_heading,
                                                args.readme_validate)
            elif args.mode == 'setup':
                status = self.setup_template(args.template_version)
            elif args.mode == 'validate':
                # mode is validate
                status = self.validate(args.header_validate,
                                       args.header_only_validate,
                                       args.governed_heading,
                                       args.readme_validate,
                                       args.template_version, args.ignore)
            else:
                raise TrestleIncorrectArgsError(
                    f'Unsupported mode: {args.mode} for folders command.')

            return status

        except Exception as e:  # pragma: no cover
            return handle_generic_command_exception(
                e, logger,
                'Error occurred when running trestle author folders')
Exemple #3
0
    def _run(self, args: argparse.Namespace) -> int:
        """
        Execute the create command.

        Notes
            Either a new model will be created of the specified type,
            or an existing file will have new elements added within it.
        """
        try:
            # Normal create path
            if args.type and args.output:
                object_type = ElementPath(args.type).get_type()
                return self.create_object(args.type, object_type, args)
            # Add path
            elif args.file and args.element:
                add = Add()
                return add.add_from_args(args)

            raise err.TrestleIncorrectArgsError(
                'Create requires either a model type and output name, or a file and element path.'
            )

        except Exception as e:  # pragma: no cover
            return err.handle_generic_command_exception(
                e, logger, 'Error while creating a sample OSCAL model')
Exemple #4
0
    def _run(self, args: argparse.Namespace) -> int:
        try:
            status = 1
            if self._initialize(args):
                return status

            if args.mode == 'create-sample':
                status = self.create_sample()

            elif args.mode == 'template-validate':
                status = self.template_validate(
                    args.governed_heading,
                    args.header_validate,
                    args.header_only_validate,
                )
            elif args.mode == 'setup':
                status = self.setup_template_governed_docs(
                    args.template_version)
            elif args.mode == 'validate':
                # mode is validate
                status = self.validate(args.governed_heading,
                                       args.header_validate,
                                       args.header_only_validate, args.recurse,
                                       args.readme_validate,
                                       args.template_version, args.ignore)

            return status

        except Exception as e:  # pragma: no cover
            return handle_generic_command_exception(
                e, logger, 'Error occurred when running trestle author docs')
Exemple #5
0
    def _run(self, args: argparse.Namespace) -> int:
        try:
            log.set_log_level_from_args(args)
            trestle_root = pathlib.Path(args.trestle_root)

            return self.filter_ssp(trestle_root, args.name, args.profile,
                                   args.output, args.regenerate, args.version)
        except Exception as e:  # pragma: no cover
            return handle_generic_command_exception(
                e, logger, 'Error generating the filtered ssp')
Exemple #6
0
    def _run(self, args: argparse.Namespace) -> int:
        try:
            log.set_log_level_from_args(args)

            mode_args = argparse.Namespace(mode=VAL_MODE_ALL)
            validator = vfact.validator_factory.get(mode_args)

            return validator.validate(args)
        except Exception as e:  # pragma: no cover
            return handle_generic_command_exception(e, logger, 'Error while validating contents of a trestle model')
    def _run(self, args: argparse.Namespace) -> int:
        try:
            log.set_log_level_from_args(args)
            file_path: pathlib.Path = args.file.resolve()
            if not file_path.exists() or not file_path.is_file():
                raise TrestleError(
                    'File path provided does not exist or is a directory')

            element_str: str = args.element
            if ',' in element_str:
                logger.warning('Only a single element path is allowed.')

            return self.partial_object_validate(file_path, element_str)
        except Exception as e:  # pragma: no cover
            return handle_generic_command_exception(
                e, logger, 'Error while validating OSCAL file')
Exemple #8
0
    def _run(self, args: argparse.Namespace) -> int:
        """Remove an OSCAL component/subcomponent to the specified component.

        This method takes input a filename and a list of comma-seperated element path. Element paths are field aliases.
        The method first finds the parent model from the file and loads the file into the model.
        Then the method executes 'remove' for each of the element paths specified.
        """
        try:
            log.set_log_level_from_args(args)
            args_dict = args.__dict__

            file_path = pathlib.Path(args_dict[const.ARG_FILE]).resolve()
            relative_path = file_path.relative_to(args.trestle_root)
            # Get parent model and then load json into parent model
            parent_model, parent_alias = ModelUtils.get_relative_model_type(
                relative_path)

            parent_object = parent_model.oscal_read(file_path)
            parent_element = Element(parent_object, parent_alias)

            add_plan = Plan()

            # Do _remove for each element_path specified in args
            element_paths: List[str] = str(
                args_dict[const.ARG_ELEMENT]).split(',')
            for elm_path_str in element_paths:
                element_path = ElementPath(elm_path_str)
                remove_action, parent_element = self.remove(
                    element_path, parent_element)
                add_plan.add_action(remove_action)

            create_action = CreatePathAction(file_path, True)
            write_action = WriteFileAction(
                file_path, parent_element,
                FileContentType.to_content_type(file_path.suffix))
            add_plan.add_action(remove_action)
            add_plan.add_action(create_action)
            add_plan.add_action(write_action)

            add_plan.execute()

            return CmdReturnCodes.SUCCESS.value

        except Exception as e:
            return err.handle_generic_command_exception(
                e, logger, 'Error while removing OSCAL component')
Exemple #9
0
    def _run(self, args: argparse.Namespace) -> int:
        try:
            logger.debug('Entering trestle href.')

            log.set_log_level_from_args(args)

            profile_name: str = args.name

            new_href: str = args.href.strip("'")

            item_num = args.item

            return self.change_import_href(args.trestle_root, profile_name,
                                           new_href, item_num)
        except Exception as e:  # pragma: no cover
            return handle_generic_command_exception(
                e, logger,
                f'Error while changing href or import in profile: {e}')
Exemple #10
0
    def _run(self, args: argparse.Namespace) -> int:
        try:
            logger.debug('Entering trestle describe.')

            log.set_log_level_from_args(args)

            if args.file:
                model_file = pathlib.Path(args.file)

                element = '' if not args.element else args.element.strip("'")
                results = self.describe(model_file.resolve(), element, args.trestle_root)

                return CmdReturnCodes.SUCCESS.value if len(results) > 0 else CmdReturnCodes.COMMAND_ERROR.value
            else:
                raise TrestleIncorrectArgsError('No file specified for command describe.')

        except Exception as e:  # pragma: no cover
            return handle_generic_command_exception(e, logger, 'Error while describing contents of a model')
Exemple #11
0
 def _run(self, args: argparse.Namespace) -> int:
     try:
         log.set_log_level_from_args(args)
         trestle_root = pathlib.Path(args.trestle_root)
         # the original profile model name defaults to being the same as the new one
         prof_name = args.output if not args.name else args.name
         return self.assemble_profile(
             trestle_root=trestle_root,
             orig_profile_name=prof_name,
             md_name=args.markdown,
             new_profile_name=args.output,
             set_parameters=args.set_parameters,
             regenerate=args.regenerate,
             version=args.version,
             required_sections=args.required_sections,
             allowed_sections=args.allowed_sections)
     except Exception as e:  # pragma: no cover
         return handle_generic_command_exception(
             e, logger, 'Assembly of markdown to profile failed')
Exemple #12
0
    def _run(self, args: argparse.Namespace) -> int:
        """Split an OSCAL file into elements."""
        try:
            log.set_log_level_from_args(args)
            trace.log('Entering trestle split.')
            # get the Model
            args_raw: Dict[str, str] = args.__dict__

            # remove any quotes passed in as on windows platforms
            elements_clean: str = args_raw[const.ARG_ELEMENT].strip("'")

            file_name = ''
            file_name = '' if not args_raw[const.ARG_FILE] else args_raw[const.ARG_FILE]
            # cwd must be in the model directory if file to split is not specified
            effective_cwd = pathlib.Path.cwd()

            return self.perform_split(effective_cwd, file_name, elements_clean, args.trestle_root)
        except Exception as e:  # pragma: no cover
            return handle_generic_command_exception(e, logger, 'Error while performing a split operation')
Exemple #13
0
    def _run(self, args: argparse.Namespace) -> int:
        try:
            log.set_log_level_from_args(args)
            trestle_root: pathlib.Path = args.trestle_root
            if not file_utils.is_directory_name_allowed(args.output):
                raise TrestleError(
                    f'{args.output} is not an allowed directory name')

            yaml_header: dict = {}
            if args.yaml_header:
                try:
                    logging.debug(
                        f'Loading yaml header file {args.yaml_header}')
                    yaml = YAML()
                    yaml_header = yaml.load(
                        pathlib.Path(args.yaml_header).open('r'))
                except YAMLError as e:
                    raise TrestleError(
                        f'YAML error loading yaml header for ssp generation: {e}'
                    )

            # combine command line sections with any in the yaml header, with priority to command line
            sections_dict: Optional[Dict[str, str]] = None
            if args.sections:
                sections_dict = sections_to_dict(args.sections)

            profile_path = trestle_root / f'profiles/{args.name}/profile.json'

            markdown_path = trestle_root / args.output

            return self.generate_markdown(trestle_root, profile_path,
                                          markdown_path, yaml_header,
                                          args.overwrite_header_values,
                                          sections_dict,
                                          args.required_sections)
        except Exception as e:  # pragma: no cover
            return handle_generic_command_exception(
                e, logger, 'Generation of the profile markdown failed')
Exemple #14
0
    def _run(self, args: argparse.Namespace) -> int:
        try:
            status = 1
            if self._initialize(args):
                return status
            # Handle conditional requirement of args.task_name
            # global is special so we need to use get attribute.
            if not self.global_ and not self.task_name:
                logger.warning(
                    'Task name (-tn) argument is required when global is not specified'
                )
                return status

            if args.exclude:
                logger.warning(
                    '--exclude or -e is deprecated, use --ignore instead.')

            if args.mode == 'create-sample':
                status = self.create_sample()

            elif args.mode == 'template-validate':
                status = self.template_validate()
            elif args.mode == 'setup':
                status = self.setup(args.template_version)
            elif args.mode == 'validate':
                exclusions = []
                if args.exclude:
                    exclusions = args.exclude
                # mode is validate
                status = self.validate(args.recurse, args.readme_validate,
                                       exclusions, args.template_version,
                                       args.ignore)
            return status

        except Exception as e:  # pragma: no cover
            return handle_generic_command_exception(
                e, logger,
                'Error occurred when running trestle author headers')
Exemple #15
0
    def _run(self, args: argparse.Namespace):
        try:
            log.set_log_level_from_args(args)
            logger.debug(f'Starting {self.name} command')
            input_path = pathlib.Path(args.input)
            output_path = pathlib.Path(args.output)

            if args.look_up_table:
                lut_table = pathlib.Path(args.look_up_table)
                lookup_table_path = pathlib.Path.cwd() / lut_table
                lut = JinjaCmd.load_LUT(lookup_table_path, args.external_lut_prefix)
                status = JinjaCmd.jinja_ify(
                    pathlib.Path(args.trestle_root),
                    input_path,
                    output_path,
                    args.system_security_plan,
                    args.profile,
                    lut,
                    number_captions=args.number_captions,
                    parameters_formatting=args.param_formatting
                )
            else:
                status = JinjaCmd.jinja_ify(
                    pathlib.Path(args.trestle_root),
                    input_path,
                    output_path,
                    args.system_security_plan,
                    args.profile,
                    number_captions=args.number_captions,
                    parameters_formatting=args.param_formatting
                )
            logger.debug(f'Done {self.name} command')
            return status

        except Exception as e:  # pragma: no cover
            return handle_generic_command_exception(e, logger, 'Error while generating markdown via Jinja template')
Exemple #16
0
    def _run(self, args: argparse.Namespace) -> int:
        """Create a trestle project in the current directory."""
        try:
            log.set_log_level_from_args(args)
            dir_path: pathlib.Path = args.trestle_root
            if not dir_path.exists() or not dir_path.is_dir():
                raise TrestleRootError(
                    f'Initialization failed. Given directory {dir_path} does not exist or is not a directory.'
                )

            # Create directories
            self._create_directories(dir_path)

            # Create config file
            self._copy_config_file(dir_path)

            logger.info(
                f'Initialized trestle project successfully in {dir_path}')

            return CmdReturnCodes.SUCCESS.value

        except Exception as e:  # pragma: no cover
            return handle_generic_command_exception(
                e, logger, 'Failed to initialize Trestle working directory.')
Exemple #17
0
 def _run(self, args: argparse.Namespace) -> int:
     try:
         return self.assemble_model(args.model, args)
     except Exception as e:  # pragma: no cover
         return handle_generic_command_exception(
             e, logger, 'Error while assembling OSCAL model')
Exemple #18
0
    def _run(self, args: argparse.Namespace) -> int:
        try:
            logger.debug('Entering trestle task.')
            log.set_log_level_from_args(args)
            # Initial logic for conflicting args
            if args.task and args.list:
                raise TrestleIncorrectArgsError(
                    'Task name or -l can be provided not both.')

            if not args.task and not args.list:
                raise TrestleIncorrectArgsError(
                    'Either a trestle task or "-l/--list" shoudl be passed as input arguments.'
                )

            # Ensure trestle directory (must be true)
            trestle_root = args.trestle_root  # trestle root is set via command line in args. Default is cwd.
            if not trestle_root or not file_utils.is_valid_project_root(
                    args.trestle_root):
                raise TrestleError(
                    f'Given directory: {trestle_root} is not a trestle project.'
                )

            config_path = trestle_root / const.TRESTLE_CONFIG_DIR / const.TRESTLE_CONFIG_FILE

            if args.config:
                config_path = pathlib.Path(args.config)
            if not config_path.exists():
                raise TrestleError(
                    f'Config file at {config_path} does not exist.')

            # permit ${name} in config definitions
            global_config = configparser.ConfigParser(
                interpolation=configparser.ExtendedInterpolation())
            global_config.read_file(
                config_path.open('r', encoding=const.FILE_ENCODING))
            # run setup
            task_index = self._build_task_index()

            # Clean to run
            if args.list:
                self._list_tasks(task_index)
                return CmdReturnCodes.SUCCESS.value
            # run the task
            if args.task not in task_index.keys():
                raise TrestleIncorrectArgsError(
                    f'Unknown trestle task: {args.task}')

            logger.debug(f'Loading task: {args.task}')
            section_label = 'task.' + args.task
            config_section: Optional[configparser.SectionProxy] = None
            if section_label in global_config.sections():
                config_section = global_config[section_label]
            else:
                logger.warning(
                    f'Config file was not configured with the appropriate section for the task: "[{section_label}]"'
                )

            task = task_index[args.task](config_section)
            if args.info:
                task.print_info()
                return CmdReturnCodes.SUCCESS.value

            simulate_result = task.simulate()
            if not (simulate_result == TaskOutcome.SIM_SUCCESS):
                raise TrestleError(
                    f'Task {args.task} reported a {simulate_result}')

            actual_result = task.execute()
            if not (actual_result == TaskOutcome.SUCCESS):
                raise TrestleError(
                    f'Task {args.task} reported a {actual_result}')

            logger.info(f'Task: {args.task} executed successfully.')
            return CmdReturnCodes.SUCCESS.value

        except Exception as e:  # pragma: no cover
            return handle_generic_command_exception(
                e, logger, 'Error while executing Trestle task')
Exemple #19
0
    def _run(self, args: argparse.Namespace) -> int:
        """Top level import run command."""
        try:
            log.set_log_level_from_args(args)
            trestle_root = args.trestle_root
            if not file_utils.is_valid_project_root(trestle_root):
                raise TrestleRootError(
                    f'Attempt to import from non-valid trestle project root {trestle_root}'
                )

            input_uri = args.file
            if cache.FetcherFactory.in_trestle_directory(
                    trestle_root, input_uri):
                raise TrestleError(
                    f'Imported file {input_uri} cannot be from current trestle project. Use duplicate instead.'
                )

            content_type = FileContentType.to_content_type(
                '.' + input_uri.split('.')[-1])

            fetcher = cache.FetcherFactory.get_fetcher(trestle_root,
                                                       str(input_uri))

            model_read, parent_alias = fetcher.get_oscal(True)

            plural_path = ModelUtils.model_type_to_model_dir(parent_alias)

            output_name = args.output

            desired_model_dir = trestle_root / plural_path
            desired_model_path: pathlib.Path = desired_model_dir / output_name / parent_alias
            desired_model_path = desired_model_path.with_suffix(
                FileContentType.to_file_extension(content_type)).resolve()

            if desired_model_path.exists():
                raise TrestleError(
                    f'Cannot import because file to be imported here: {desired_model_path} already exists.'
                )

            if args.regenerate:
                logger.debug(
                    f'regenerating uuids in imported file {input_uri}')
                model_read, lut, nchanged = ModelUtils.regenerate_uuids(
                    model_read)
                logger.debug(
                    f'uuid lut has {len(lut.items())} entries and {nchanged} refs were updated'
                )

            top_element = Element(model_read)
            create_action = CreatePathAction(desired_model_path, True)
            write_action = WriteFileAction(desired_model_path, top_element,
                                           content_type)

            # create a plan to create the directory and write the imported file.
            import_plan = Plan()
            import_plan.add_action(create_action)
            import_plan.add_action(write_action)

            import_plan.execute()

            args = argparse.Namespace(file=desired_model_path,
                                      verbose=args.verbose,
                                      trestle_root=args.trestle_root,
                                      type=None,
                                      all=None)
            rollback = False
            try:
                rc = validatecmd.ValidateCmd()._run(args)
                if rc > 0:
                    logger.warning(
                        f'Validation of imported file {desired_model_path} did not pass'
                    )
                    rollback = True
            except TrestleError as err:
                logger.warning(
                    f'Import of {str(input_uri)} failed with validation error: {err}'
                )
                rollback = True

            if rollback:
                logger.debug(
                    f'Rolling back import of {str(input_uri)} to {desired_model_path}'
                )
                try:
                    import_plan.rollback()
                except TrestleError as err:
                    raise TrestleError(
                        f'Import failed in plan rollback: {err}. Manually remove {desired_model_path} to recover.'
                    )
                logger.debug(
                    f'Successful rollback of import to {desired_model_path}')
                return CmdReturnCodes.COMMAND_ERROR.value

            return CmdReturnCodes.SUCCESS.value

        except Exception as e:  # pragma: no cover
            return handle_generic_command_exception(
                e, logger, 'Error while importing OSCAL file')
Exemple #20
0
    def _run(self, args: argparse.Namespace) -> int:
        try:
            log.set_log_level_from_args(args)
            trestle_root = args.trestle_root
            if not file_utils.is_directory_name_allowed(args.output):
                raise TrestleError(
                    f'{args.output} is not an allowed directory name')

            profile_path = trestle_root / f'profiles/{args.profile}/profile.json'

            yaml_header: dict = {}
            if args.yaml_header:
                try:
                    logging.debug(
                        f'Loading yaml header file {args.yaml_header}')
                    yaml = YAML()
                    yaml_header = yaml.load(
                        pathlib.Path(args.yaml_header).open('r'))
                except YAMLError as e:
                    raise TrestleError(
                        f'YAML error loading yaml header for ssp generation: {e}'
                    )

            markdown_path = trestle_root / args.output

            profile_resolver = ProfileResolver()

            resolved_catalog = profile_resolver.get_resolved_profile_catalog(
                trestle_root, profile_path)
            catalog_interface = CatalogInterface(resolved_catalog)

            sections_dict: Dict[str, str] = {}
            if args.sections:
                sections_dict = sections_to_dict(args.sections)
                if 'statement' in sections_dict:
                    raise TrestleError(
                        'Statement is not allowed as a section name.')
                # add any existing sections from the controls but only have short names
                control_section_short_names = catalog_interface.get_sections()
                for short_name in control_section_short_names:
                    if short_name not in sections_dict:
                        sections_dict[short_name] = short_name
                logger.debug(f'ssp sections dict: {sections_dict}')

            catalog_interface.write_catalog_as_markdown(
                md_path=markdown_path,
                yaml_header=yaml_header,
                sections_dict=sections_dict,
                prompt_responses=True,
                additional_content=False,
                profile=None,
                overwrite_header_values=args.overwrite_header_values,
                set_parameters=False,
                required_sections=None,
                allowed_sections=args.allowed_sections)

            return CmdReturnCodes.SUCCESS.value

        except Exception as e:  # pragma: no cover
            return handle_generic_command_exception(
                e, logger, 'Error while writing markdown from catalog')
Exemple #21
0
    def _run(self, args: argparse.Namespace) -> int:
        try:
            log.set_log_level_from_args(args)
            trestle_root = pathlib.Path(args.trestle_root)

            md_path = trestle_root / args.markdown

            # the original, reference ssp name defaults to same as output if name not specified
            # thus in cyclic editing you are reading and writing same json ssp
            orig_ssp_name = args.output
            if args.name:
                orig_ssp_name = args.name
            new_ssp_name = args.output
            # if orig ssp exists - need to load it rather than instantiate new one
            orig_ssp_path = ModelUtils.path_for_top_level_model(
                trestle_root, orig_ssp_name, ossp.SystemSecurityPlan,
                FileContentType.JSON)

            # if output ssp already exists, load it to see if new one is different
            existing_ssp: Optional[ossp.SystemSecurityPlan] = None
            new_ssp_path = ModelUtils.path_for_top_level_model(
                trestle_root, new_ssp_name, ossp.SystemSecurityPlan,
                FileContentType.JSON)
            if new_ssp_path.exists():
                _, _, existing_ssp = ModelUtils.load_distributed(
                    new_ssp_path, trestle_root)

            ssp: ossp.SystemSecurityPlan
            comp_dict: Dict[str, ossp.SystemComponent] = {}

            # need to load imp_reqs from markdown but need component first
            if orig_ssp_path.exists():
                # load the existing json ssp
                _, _, ssp = ModelUtils.load_distributed(
                    orig_ssp_path, trestle_root)
                for component in ssp.system_implementation.components:
                    comp_dict[component.title] = component
                # read the new imp reqs from markdown and have them reference existing components
                imp_reqs = CatalogInterface.read_catalog_imp_reqs(
                    md_path, comp_dict)
                self._merge_imp_reqs(ssp, imp_reqs)
            else:
                # create a sample ssp to hold all the parts
                ssp = gens.generate_sample_model(ossp.SystemSecurityPlan)
                # load the imp_reqs from markdown and create components as needed, referenced by ### headers
                imp_reqs = CatalogInterface.read_catalog_imp_reqs(
                    md_path, comp_dict)

                # create system implementation
                system_imp: ossp.SystemImplementation = gens.generate_sample_model(
                    ossp.SystemImplementation)
                ssp.system_implementation = system_imp

                # create a control implementation to hold the implementated requirements
                control_imp: ossp.ControlImplementation = gens.generate_sample_model(
                    ossp.ControlImplementation)
                control_imp.implemented_requirements = imp_reqs
                control_imp.description = const.SSP_SYSTEM_CONTROL_IMPLEMENTATION_TEXT

                # insert the parts into the ssp
                ssp.control_implementation = control_imp
                ssp.system_implementation = system_imp

                # we don't have access to the original profile so we don't know the href
                import_profile: ossp.ImportProfile = gens.generate_sample_model(
                    ossp.ImportProfile)
                import_profile.href = 'REPLACE_ME'
                ssp.import_profile = import_profile

            # now that we know the complete list of needed components, add them to the sys_imp
            # TODO if the ssp already existed then components may need to be removed if not ref'd by imp_reqs
            component_list: List[ossp.SystemComponent] = []
            for comp in comp_dict.values():
                component_list.append(comp)
            if ssp.system_implementation.components:
                # reconstruct list with same order as existing, but add/remove components as needed
                new_list: List[ossp.SystemComponent] = []
                for comp in ssp.system_implementation.components:
                    if comp in component_list:
                        new_list.append(comp)
                for comp in component_list:
                    if comp not in new_list:
                        new_list.append(comp)
                ssp.system_implementation.components = new_list
            elif component_list:
                ssp.system_implementation.components = component_list
            self._generate_roles_in_metadata(ssp)

            if args.version:
                ssp.metadata.version = com.Version(__root__=args.version)

            if existing_ssp == ssp:
                logger.info(
                    'No changes to assembled ssp so ssp not written out.')
                return CmdReturnCodes.SUCCESS.value

            if args.regenerate:
                ssp, _, _ = ModelUtils.regenerate_uuids(ssp)
            ModelUtils.update_last_modified(ssp)

            # write out the ssp as json
            ModelUtils.save_top_level_model(ssp, trestle_root, new_ssp_name,
                                            FileContentType.JSON)

            return CmdReturnCodes.SUCCESS.value

        except Exception as e:  # pragma: no cover
            return handle_generic_command_exception(
                e, logger, 'Error while assembling SSP')