def _execute(self) -> TaskOutcome: """Execute path core.""" if not self.xlsx_helper.configure(self): return TaskOutcome('failure') # config output odir = self._config.get('output-dir') opth = pathlib.Path(odir) self._overwrite = self._config.getboolean('output-overwrite', True) # insure output dir exists opth.mkdir(exist_ok=True, parents=True) # calculate output file name & check writability oname = 'component-definition.json' ofile = opth / oname if not self._overwrite and pathlib.Path(ofile).exists(): logger.error(f'output: {ofile} already exists') return TaskOutcome('failure') # initialize self.component_names = [] self.defined_components = [] self.parameters = {} self.parameter_helper = None # roles, responsible_roles, parties, responsible parties party_uuid_01 = str(uuid.uuid4()) party_uuid_02 = str(uuid.uuid4()) party_uuid_03 = str(uuid.uuid4()) roles = self._build_roles() responsible_roles = self._build_responsible_roles( party_uuid_01, party_uuid_02, party_uuid_03) parties = self._build_parties(party_uuid_01, party_uuid_02, party_uuid_03) responsible_parties = self._build_responsible_parties( party_uuid_01, party_uuid_02, party_uuid_03) # process each row of spread sheet self._process_rows(responsible_roles) # create OSCAL ComponentDefinition metadata = Metadata(title='Component definition for ' + self._get_catalog_title() + ' profiles', last_modified=self._timestamp, oscal_version=OSCAL_VERSION, version=get_trestle_version(), roles=roles, parties=parties, responsible_parties=responsible_parties) component_definition = ComponentDefinition( uuid=str(uuid.uuid4()), metadata=metadata, components=self.defined_components, ) # write OSCAL ComponentDefinition to file if self._verbose: logger.info(f'output: {ofile}') component_definition.oscal_write(pathlib.Path(ofile)) # issues self._report_issues() # <hack> # create a catalog containing the parameters, # since parameters are not supported in OSCAL 1.0.0 component definition self._write_catalog() # </hack> return TaskOutcome('success')
def _transform_work(self) -> TaskOutcome: """ Perform the transformation work. Transformation work steps: read input, process, write output, display analysis. """ mode = '' if self._simulate: mode = 'simulated-' if not self._config: logger.error('Config missing') return TaskOutcome(mode + 'failure') # config required input & output dirs try: idir = self._config['input-dir'] ipth = pathlib.Path(idir) odir = self._config['output-dir'] opth = pathlib.Path(odir) except KeyError as e: logger.debug(f'key {e.args[0]} missing') return TaskOutcome(mode + 'failure') # config optional overwrite & quiet self._overwrite = self._config.getboolean('output-overwrite', True) quiet = self._config.get('quiet', False) self._verbose = not self._simulate and not quiet # config optional timestamp timestamp = self._config.get('timestamp') if timestamp is not None: try: TaniumTransformer.set_timestamp(timestamp) except Exception: logger.error('config invalid "timestamp"') return TaskOutcome(mode + 'failure') # config optional performance modes = { 'blocksize': self._config.getint('blocksize', 10000), 'cpus_max': self._config.getint('cpus-max', 1), 'cpus_min': self._config.getint('cpus-min', 1), 'checking': self._config.getboolean('checking', False), } # insure output dir exists opth.mkdir(exist_ok=True, parents=True) # process for ifile in sorted(ipth.iterdir()): blob = self._read_file(ifile) tanium_transformer = TaniumTransformer() tanium_transformer.set_modes(modes) results = tanium_transformer.transform(blob) oname = ifile.stem + '.oscal' + '.json' ofile = opth / oname if not self._overwrite and pathlib.Path(ofile).exists(): logger.error(f'output: {ofile} already exists') return TaskOutcome(mode + 'failure') self._write_file(results, ofile) self._show_analysis(tanium_transformer) return TaskOutcome(mode + 'success')
def execute(self) -> TaskOutcome: """Provide an executed outcome.""" try: return self._execute() except Exception: logger.info(traceback.format_exc()) return TaskOutcome('failure')
def _transform(self) -> TaskOutcome: """Perform transformation.""" try: return self._transform_work() except Exception: logger.info(traceback.format_exc()) mode = '' if self._simulate: mode = 'simulated-' return TaskOutcome(mode + 'failure')
def _execute(self) -> TaskOutcome: """Execute path core.""" if not self.xlsx_helper.configure(self): return TaskOutcome('failure') # config output odir = self._config.get('output-dir') opth = pathlib.Path(odir) self._overwrite = self._config.getboolean('output-overwrite', True) # insure output dir exists opth.mkdir(exist_ok=True, parents=True) # calculate output file name & check writability oname = 'profile.json' ofile = opth / oname if not self._overwrite and pathlib.Path(ofile).exists(): logger.error(f'output: {ofile} already exists') return TaskOutcome('failure') # create OSCAL Profile metadata = Metadata( title='Profile for ' + self._get_profile_title(), last_modified=self._timestamp, oscal_version=OSCAL_VERSION, version=get_trestle_version(), ) import_ = Import( href=self._get_spread_sheet_url(), include_controls=self._get_include_controls(), ) imports = [import_] set_parameters = self._get_set_parameters() modify = Modify(set_parameters=set_parameters) profile = Profile( uuid=str(uuid.uuid4()), metadata=metadata, imports=imports, modify=modify, ) # write OSCAL Profile to file if self._verbose: logger.info(f'output: {ofile}') profile.oscal_write(pathlib.Path(ofile)) # issues self._report_issues() return TaskOutcome('success')
def _execute(self) -> TaskOutcome: """Perform transformation.""" # check config if not self._config: logger.error('config missing') return TaskOutcome('failure') # input-file input_file = self._config.get('input-file') if input_file is None: logger.error('config missing "input-file"') return TaskOutcome('failure') logger.info(f'input-file: {input_file}') input_path = pathlib.Path(input_file) # output-dir output_dir = self._config.get('output-dir') if output_dir is None: logger.error('config missing "output-dir"') return TaskOutcome('failure') output_path = pathlib.Path(output_dir) # insure output dir exists output_path.mkdir(exist_ok=True, parents=True) # output file path output_name = self._config.get('output-name', 'osco-profile.yaml') output_filepath = pathlib.Path(output_dir, output_name) logger.info(f'output-file: {output_filepath}') # overwrite overwrite = self._config.getboolean('output-overwrite', True) if not overwrite and pathlib.Path(output_filepath).exists(): logger.error(f'output-file: {output_filepath} already exists') return TaskOutcome('failure') # read input profile = Profile.oscal_read(input_path) # transform transformer = ProfileToOscoTransformer() ydata = json.loads(transformer.transform(profile)) # write output yaml = YAML(typ='safe') yaml.default_flow_style = False with open(output_filepath, 'w') as outfile: yaml.dump(ydata, outfile) # success return TaskOutcome('success')
def simulate(self) -> TaskOutcome: """Provide a simulated outcome.""" return TaskOutcome('simulated-success')
def execute(self) -> TaskOutcome: """Provide an actual outcome.""" if self._config: # initialize default_metadata = {} # process config idir = self._config.get('input-dir') if idir is None: logger.error(f'config missing "input-dir"') return TaskOutcome('failure') ipth = pathlib.Path(idir) odir = self._config.get('output-dir') if odir is None: logger.error(f'config missing "output-dir"') return TaskOutcome('failure') imeta = self._config.get('input-metadata', 'oscal-metadata.yaml') opth = pathlib.Path(odir) overwrite = self._config.getboolean('output-overwrite', True) quiet = self._config.getboolean('quiet', False) # insure output folder exists opth.mkdir(exist_ok=True, parents=True) # fetch enhancing oscal metadata mfile = ipth / imeta metadata = self._get_metadata(mfile, default_metadata) if len(metadata) == 0: logger.info(f'no metadata: {imeta}.') # examine each file in the input folder for ifile in sorted(ipth.iterdir()): # skip enhancing oscal metadata if ifile.name == imeta: continue # assemble collection comprising output file name to unprocessed content collection = self._assemble(ifile) # formulate each output OSCAL partial results file for oname in collection.keys(): ofile = opth / pathlib.Path(oname) # only allow writing output file if either: # a) it does not already exist, or # b) output-overwrite flag is True if not overwrite: if ofile.exists(): logger.error(f'file exists: {ofile}') return TaskOutcome('failure') if not quiet: logger.info(f'create: {ofile}') # create the OSCAL .json file from the OSCO and the optional osco-metadata files observations, analysis = osco.get_observations( collection[oname], metadata) # write the OSCAL to the output file self._write_content(ofile, observations) # display analysis if not quiet: logger.info(f'Rules Analysis:') logger.info(f'config_maps: {analysis["config_maps"]}') logger.info( f'dispatched rules: {analysis["dispatched_rules"]}' ) logger.info( f'result types: {analysis["result_types"]}') return TaskOutcome('success') logger.error(f'config missing') return TaskOutcome('failure')
def _execute(self) -> TaskOutcome: if not self._config: logger.error('config missing') return TaskOutcome('failure') try: component_name = self._config['component-name'] org_name = self._config['org-name'] org_remarks = self._config['org-remarks'] self._folder_cac = self._config['folder-cac'] profile_check_version = self._config['profile-check-version'] profile_type = self._config['profile-type'] profile_mnemonic = self._config['profile-mnemonic'] profile_name = self._config['profile-name'] profile_ns = self._config['profile-ns'] profile_version = self._config['profile-version'] profile_sets = {} profile_list = self._config['profile-list'].split() for profile in profile_list: profile_sets[profile] = {} profile_sets[profile]['profile-file'] = self._config[ f'profile-file.{profile}'] profile_sets[profile]['profile-url'] = self._config[ f'profile-url.{profile}'] profile_sets[profile]['profile-title'] = self._config[ f'profile-title.{profile}'] profile_sets[profile]['profile-ns'] = profile_ns profile_sets[profile]['component-name'] = component_name odir = self._config['output-dir'] except KeyError as e: logger.info(f'key {e.args[0]} missing') return TaskOutcome('failure') # selected rules self._selected_rules = self._get_filter_rules('selected-rules', 'selected') # enabled rules self._enabled_rules = self._get_filter_rules('enabled-rules', 'enabled') # verbosity quiet = self._config.get('quiet', False) verbose = not quiet # output overwrite = self._config.getboolean('output-overwrite', True) opth = pathlib.Path(odir) # insure output dir exists opth.mkdir(exist_ok=True, parents=True) # calculate output file name & check writability oname = 'component-definition.json' ofile = opth / oname if not overwrite and pathlib.Path(ofile).exists(): logger.error(f'output: {ofile} already exists') return TaskOutcome('failure') # fetch rule to parameters map self._rule_to_parm_map = self._get_parameters_map( 'rule-to-parameters-map') # roles, responsible_roles, parties, responsible parties party_uuid_01 = str(uuid.uuid4()) party_uuid_02 = str(uuid.uuid4()) party_uuid_03 = str(uuid.uuid4()) roles = self._build_roles() responsible_roles = self._build_responsible_roles( party_uuid_01, party_uuid_02, party_uuid_03) parties = self._build_parties(org_name, org_remarks, party_uuid_01, party_uuid_02, party_uuid_03) responsible_parties = self._build_responsible_parties( party_uuid_01, party_uuid_02, party_uuid_03) # metadata metadata = Metadata( title=f'Component definition for {profile_type} profiles', last_modified=self._timestamp, oscal_version=OSCAL_VERSION, version=trestle.__version__, roles=roles, parties=parties, responsible_parties=responsible_parties) # defined component component_title = component_name component_description = component_name defined_component = DefinedComponent( uuid=str(uuid.uuid4()), description=component_description, title=component_title, type='Service', ) # add control implementation per profile prop1 = Property( name='profile_name', value=profile_name, class_='scc_profile_name', ns=profile_ns, ) prop2 = Property( name='profile_mnemonic', value=profile_mnemonic, class_='scc_profile_mnemonic', ns=profile_ns, ) prop3 = Property( name='profile_version', value=profile_version, class_='scc_profile_version', ns=profile_ns, ) prop4 = Property( name='profile_check_version', value=profile_check_version, ) props = [prop1, prop2, prop3, prop4] for profile in profile_list: profile_set = profile_sets[profile] control_implementation = self._build_control_implementation( profile_set, responsible_roles, props) if control_implementation is not None: if defined_component.control_implementations is None: defined_component.control_implementations = [ control_implementation ] else: defined_component.control_implementations.append( control_implementation) # defined components defined_components = [defined_component] # component definition component_definition = ComponentDefinition( uuid=str(uuid.uuid4()), metadata=metadata, components=defined_components, ) # write OSCAL ComponentDefinition to file if verbose: logger.info(f'output: {ofile}') component_definition.oscal_write(pathlib.Path(ofile)) return TaskOutcome('success')
def _execute(self) -> TaskOutcome: """Wrap the execute for exception handling.""" if not self._config: logger.error('config missing') return TaskOutcome('failure') try: idir = self._config['input-dir'] odir = self._config['output-dir'] except KeyError as e: logger.info(f'key {e.args[0]} missing') return TaskOutcome('failure') # verbosity quiet = self._config.get('quiet', False) verbose = not quiet # output overwrite = self._config.getboolean('output-overwrite', True) opth = pathlib.Path(odir) # insure output dir exists opth.mkdir(exist_ok=True, parents=True) # calculate output file name & check writability oname = 'catalog.json' ofile = opth / oname if not overwrite and pathlib.Path(ofile).exists(): logger.error(f'output: {ofile} already exists') return TaskOutcome('failure') # metadata links (optional) metadata_links = self._config.get('metadata-links') # get list or <name>.profile files filelist = self._get_filelist(idir) if len(filelist) < 1: logger.error(f'input: {idir} no .profile file found') return TaskOutcome('failure') # initialize node list self._node_map = {} # process files for fp in filelist: lines = self._get_content(fp) self._parse(lines) # get root nodes root_nodes = self._get_root_nodes() # groups and controls root = Group(title='root', groups=[]) for node in root_nodes: group = Group(title=f'{node.name} {node.description}') root.groups.append(group) depth = self._depth(node.name) if depth == 3: self._add_groups(group, node.name, depth) if depth == 2: self._add_controls(group, node.name, depth) # metadata metadata = Metadata( title=self._title, last_modified=self._timestamp, oscal_version=OSCAL_VERSION, version=trestle.__version__ ) # metadata links if metadata_links is not None: metadata.links = [] for item in metadata_links.split(): link = Link(href=item) metadata.links.append(link) # catalog catalog = Catalog(uuid=_uuid(), metadata=metadata, groups=root.groups) # write OSCAL ComponentDefinition to file if verbose: logger.info(f'output: {ofile}') catalog.oscal_write(pathlib.Path(ofile)) return TaskOutcome('success')