def __simplify_graph(self, graph: Subgraph) -> Subgraph: # List edges edge_dict = dict() edge_deny = dict() for edge in graph.relationships(): source = edge.start_node()['name'] target = edge.end_node()['name'] edge_dict.setdefault(source + target, []) if not edge.type() in edge_dict[source + target]: edge_dict[source + target].append(edge.type()) else: edge['__drop__'] = 1 edge_deny.setdefault(source + target, False) edge_deny[source + target] |= bool(edge['DENY']) # Group edges new_edges = [] for edge in graph.relationships(): source = edge.start_node()['name'] target = edge.end_node()['name'] tags = edge_dict.get(source + target, []) if len(tags) > 1: edge['__drop__'] = 1 if '__done__' not in tags: new_rel = Relationship(edge.start_node(), ','.join(tags), edge.end_node()) if edge_deny.get(source + target): new_rel['DENY'] = 1 edge_dict[source + target].append('__done__') new_edges.append(new_rel) # Build the simplified graph new_graph = Subgraph( nodes=[x for x in graph.nodes()], relationships=[ x for x in graph.relationships() if not x['__drop__'] ] + new_edges) return new_graph
def __denyace(self, graph: Subgraph, graph_target: str) -> Subgraph: if not self.__workdir: self.logger.warning( 'No denyace applied - dump directory not provided') return graph rels = dict() # Load DENY Ace from Relation folder if not self.__denied_ace: for deny_file in (self.__workdir / 'Relations').glob('*.deny.csv'): with deny_file.open('r', encoding='utf-16-le') as ifile: self.logger.debug('Parsing denied ACE from %s', deny_file) reader = DictReader(ifile) for row in reader: self.__denied_ace.append(row) self.logger.debug('Denied ACE : %d', len(self.__denied_ace)) nodes = dict() # Step 1 : cut all direct relationships for edge in graph.relationships(): source = edge.start_node()['name'] nodes.setdefault(source, edge.start_node()) target = edge.end_node()['name'] nodes.setdefault(target, edge.end_node()) denied = [] for x in self.__denied_ace: try: if x['dnMaster:START_ID'] == source and x[ 'dnSlave:END_ID'] == target and x[ 'keyword:TYPE'] == edge.type(): denied.append(x) except: if x[':START_ID'] == source and x[ ':END_ID'] == target and x[':TYPE'] == edge.type(): denied.append(x) if len(denied) > 0: self.logger.debug('DENY edge (%s) --[%s]--> (%s)', source, edge.type(), target) edge['DENY'] = '1' # Step 2 : build relation map for edge in graph.relationships(): if edge['denied']: continue source = edge.start_node()['name'] target = edge.end_node()['name'] rels.setdefault(source, dict()) rels[source].setdefault(target, []) rels[source][target].append(edge.type()) # Step 3 : map denied to relationships nolink_nodes = [] for source in rels: path_count = 0 denies = 0 for rel in self.__get_rels(rels, source): if rel['target'] == graph_target: path_count += 1 denied = [] for x in self.__denied_ace: try: if x['dnMaster:START_ID'] == source and x[ 'dnSlave:END_ID'] == target and x[ 'keyword:TYPE'] == edge.type(): denied.append(x) except: if x[':START_ID'] == source and x[ ':END_ID'] == target and x[ ':TYPE'] == edge.type(): denied.append(x) if len(denied) > 0: path_count -= 1 denies += 1 deny_edge = Relationship(nodes[rel['source']], 'DENY_{}'.format(rel['type']), nodes[rel['target']], DENY=1) graph |= deny_edge if path_count == 0 and denies > 0: nolink_nodes.append(source) # Step 4 : tag unlinked nodes for node in graph.nodes(): if node['name'] in nolink_nodes: node['NO_LINKS'] = True return graph