-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathbrain.py
86 lines (68 loc) · 2.8 KB
/
brain.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# import Node classes
from attacktree.models import Action, Block, Goal, Node
# import some useful dicts
from attacktree.models import rules
import logging
class Brain(object):
def __init__(self):
self.exploitChain = []
# Walk the tree, adding to the chain (DFS)
# If we hit the goal, add that chain to our paths
def pathsToVictory(
self, node: Node, paths: list = None, chain: list = None, walked: dict = None
):
if walked is None:
walked = {}
if paths is None:
paths = []
if chain is None:
chain = []
chain.append(node)
# If this node is a Goal then YAY! We have a goal
if isinstance(node, Goal):
paths.append(chain.copy())
return paths
edges = node.getEdges()
for edge in edges:
if edge not in walked:
self.pathsToVictory(
edge.childNode, paths, chain=chain.copy(), walked=walked
)
walked[edge] = True # Stops walking a cycle more than once
return paths
# Walk the given path, add up stats and annotate edges
def evaluatePath(self, path):
# It's not the nodes we need to evaluate, it's the edges. As those are what get changed adding a block
results = {}
for key in rules: # Pre-load data from rules
results[key] = rules[key]["startWith"]
prevNode = None
for node in path:
# TODO: Introduce pDiscovery value (or pSuccess on Discovery() )
if isinstance(node, (Action)):
results["attackCost"] += node.cost
results["time"] += node.time
results["pSuccess"] = int((results["pSuccess"] * node.pSuccess) / 100)
if isinstance(node, (Block)):
results["defenceCost"] += node.cost
results["pSuccess"] -= node.pDefend
# TODO block time
if prevNode is not None:
edgeToThisNode = None
for edge in prevNode.edges:
if edge.childNode == node:
edgeToThisNode = edge
# This shouldn't happen and we should try to get rid of this check.
if edgeToThisNode is None:
logging.error(
f"""
Could not find an edge to {node.label}
PrevNode: {prevNode.label}
Path: {path}"""
)
else:
edgeToThisNode.pSuccess = results["pSuccess"]
prevNode = node
# Can't just throw in a backfref because a node can have multiple parents
# End outer for by setting current node as the next (prevNode )
return results