Skip to content

Commit

Permalink
Merge pull request #12 from hyakuhei/AggregatedModel
Browse files Browse the repository at this point in the history
Aggregated model
  • Loading branch information
hyakuhei authored Jul 19, 2021
2 parents aef1d31 + 6ebeed2 commit 66a3bf9
Show file tree
Hide file tree
Showing 10 changed files with 266 additions and 91 deletions.
25 changes: 25 additions & 0 deletions example_nest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from fluentm import Actor, Boundary, Process, Data, DataFlow, HTTP, TLS, SQL
from fluentm import report


scenes = {
# Example using variables, which is fine for small things but gets hard with longer flows
"Towers":[
DataFlow(
Process("Alice").inBoundary(Boundary("A Inner").inBoundary(Boundary("A Mid").inBoundary(Boundary("A Outer")))),
Process("Bob").inBoundary(Boundary("B Inner").inBoundary(Boundary("B Mid").inBoundary(Boundary("B Outer")))),
TLS("Helo"),
response=TLS("Hai")
)
],
"Enter Charlie":[
DataFlow(
Process("Charlie").inBoundary(Boundary("B Outer")),
Process("Alice"),
TLS("Yo")
)
]
}

if __name__ == "__main__":
report(scenes, outputDir="examples/nest")
30 changes: 30 additions & 0 deletions examples/nest/AggregatedDfd-dfd
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
digraph all {
color=blue rankdir=LR
node [fontname=Arial fontsize=14]
subgraph "cluster_A Outer" {
graph [color=red fontname=Arial fontsize=12 label="A Outer" line=dotted]
subgraph "cluster_A Mid" {
graph [color=red fontname=Arial fontsize=12 label="A Mid" line=dotted]
subgraph "cluster_A Inner" {
graph [color=red fontname=Arial fontsize=12 label="A Inner" line=dotted]
Alice
}
}
}
subgraph "cluster_B Outer" {
graph [color=red fontname=Arial fontsize=12 label="B Outer" line=dotted]
subgraph "cluster_B Mid" {
graph [color=red fontname=Arial fontsize=12 label="B Mid" line=dotted]
subgraph "cluster_B Inner" {
graph [color=red fontname=Arial fontsize=12 label="B Inner" line=dotted]
Bob
}
}
}
subgraph "cluster_B Outer" {
graph [color=red fontname=Arial fontsize=12 label="B Outer" line=dotted]
Charlie
}
Alice -> Bob [dir=both]
Charlie -> Alice [dir=forward]
}
Binary file added examples/nest/AggregatedDfd-dfd.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 19 additions & 0 deletions examples/nest/Enter Charlie-dfd
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
digraph "Enter Charlie" {
color=blue rankdir=LR
node [fontname=Arial fontsize=14]
subgraph "cluster_B Outer" {
graph [color=red fontname=Arial fontsize=12 label="B Outer" line=dotted]
Charlie
}
subgraph "cluster_A Outer" {
graph [color=red fontname=Arial fontsize=12 label="A Outer" line=dotted]
subgraph "cluster_A Mid" {
graph [color=red fontname=Arial fontsize=12 label="A Mid" line=dotted]
subgraph "cluster_A Inner" {
graph [color=red fontname=Arial fontsize=12 label="A Inner" line=dotted]
Alice
}
}
}
Charlie -> Alice [label="(1) Yo"]
}
Binary file added examples/nest/Enter Charlie-dfd.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
126 changes: 126 additions & 0 deletions examples/nest/ThreatModel.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
<html>
<head>
<title>
Threat Models
</title>
<style>
#dataFlowTable {
font-family: Arial, Helvetica, sans-serif;
border-collapse: collapse;
width: 100%;
}

#dataFlowTable td, #dataFlowTable th {
border: 1px solid #ddd;
padding: 8px;
}

#dataFlowTable tr:nth-child(even){background-color: #f2f2f2;}

#dataFlowTable tr:hover {background-color: #ddd;}

#dataFlowTable th {
padding-top: 12px;
padding-bottom: 12px;
text-align: left;
background-color: #a34a4a;
color: white;
}
h2 {
color: rgb(48, 27, 23);
font-family: verdana;
font-size: 25px;
}
p {
font-family: verdana;
font-size: 15px;
}
</style>
</head>
<body>
<h2> Aggregated Model</h2>
<p>This high level diagram gathers all flows in this model to show how components interact at a high level.</p>
<img src=AggregatedDfd-dfd.png >
<hr />

<h2> Towers </h2>
<img src="Towers-dfd.png">
<table id="dataFlowTable">
<tr>

<th>Flow ID</th>

<th>Pitcher</th>

<th>Catcher</th>

<th>Data Flow</th>

</tr>

<tr>

<td>1</td>

<td>Alice</td>

<td>Bob</td>

<td>TLS( Helo )</td>

</tr>


<tr>

<td>2</td>

<td>Bob</td>

<td>Alice</td>

<td>TLS( Hai )</td>

</tr>


</table>


<hr />

<h2> Enter Charlie </h2>
<img src="Enter Charlie-dfd.png">
<table id="dataFlowTable">
<tr>

<th>Flow ID</th>

<th>Pitcher</th>

<th>Catcher</th>

<th>Data Flow</th>

</tr>

<tr>

<td>1</td>

<td>Charlie</td>

<td>Alice</td>

<td>TLS( Yo )</td>

</tr>


</table>


<hr />

</body>
</html>
26 changes: 26 additions & 0 deletions examples/nest/Towers-dfd
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
digraph Towers {
color=blue rankdir=LR
node [fontname=Arial fontsize=14]
subgraph "cluster_A Outer" {
graph [color=red fontname=Arial fontsize=12 label="A Outer" line=dotted]
subgraph "cluster_A Mid" {
graph [color=red fontname=Arial fontsize=12 label="A Mid" line=dotted]
subgraph "cluster_A Inner" {
graph [color=red fontname=Arial fontsize=12 label="A Inner" line=dotted]
Alice
}
}
}
subgraph "cluster_B Outer" {
graph [color=red fontname=Arial fontsize=12 label="B Outer" line=dotted]
subgraph "cluster_B Mid" {
graph [color=red fontname=Arial fontsize=12 label="B Mid" line=dotted]
subgraph "cluster_B Inner" {
graph [color=red fontname=Arial fontsize=12 label="B Inner" line=dotted]
Bob
}
}
}
Alice -> Bob [label="(1) Helo"]
Bob -> Alice [label="(2) Hai"]
}
Binary file added examples/nest/Towers-dfd.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
130 changes: 39 additions & 91 deletions fluentm.py
Original file line number Diff line number Diff line change
Expand Up @@ -559,87 +559,7 @@ def renderDfd(graph: Digraph, title: str, outputDir: str):
return f"{title}-dfd.png"


def aggregatedDfd(scenes: dict):
print("### Starting Aggregated DFD ###")
graph = Digraph("Aggregated DFD")
graph.attr(rankdir="LR", color="blue")
graph.attr("node", fontname="Arial", fontsize="14")

clusterAttr = {
"fontname": "Arial",
"fontsize": "12",
"color": "red",
"line": "dotted",
}

boundaryClusters = {}

# Track which nodes should be placed in which clusters but place neither until we've built the subgraph structure.
placements = {}
edges = {}

# Gather the boundaries and understand how they're nested (but don't nest the graphviz objects ,yet)
# Graphviz subgraphs can't have nodes added, so you need to populate a graph with nodes first, then subgraph it under another graph
for scene in scenes:
# print(f"scene: {scene}")
for flow in scenes[scene]:
# print(flow)
for e in (flow.pitcher, flow.catcher):
if e.name in placements:
continue # skip to next loop

ptr = e
while hasattr(ptr, "boundary"):
if ptr.boundary not in boundaryClusters:
boundaryClusters[ptr.boundary] = Digraph(
name=f"cluster_{ptr.boundary.name}",
graph_attr=clusterAttr | {"label": ptr.boundary.name},
)
ptr = ptr.boundary

if hasattr(e, "boundary"):
placements[e.name] = boundaryClusters[e.boundary]
else:
placements[e.name] = graph

# Figure out which edges we need to draw (We want double ended lines)
for flow in scenes[scene]:
# Look to see if the reverse flow is already there in reverse
# If it is, update the line description to say it should go both ways
f = (flow.pitcher.name, flow.catcher.name) # Directional flow
revf = (f[1], f[0]) # Reverse that directional flow

# First, check if the flow is already in there but the other way around
if revf in edges:
edges[revf] = "BOTH"
elif f not in edges:
edges[f] = "LR"

# Place nodes in Graphs, ready for subgraphing
print(placements)
for n in placements:
placements[n].node(n)

# Subgraph the nodes
for c in boundaryClusters:
if hasattr(c, "boundary"):
boundaryClusters[c.boundary].subgraph(boundaryClusters[c])
else:
graph.subgraph(boundaryClusters[c])

for edge in edges:
print(edge)
if edges[edge] == "LR":
graph.edge_attr.update(dir="forward")
graph.edge(edge[0], edge[1])
elif edges[edge] == "BOTH":
graph.edge_attr.update(dir="both")
graph.edge(edge[0], edge[1])

return graph


def dfd(scenes: dict, title: str, dfdLabels=True, render=False):
def dfd(scenes: dict, title: str, dfdLabels=True, render=False, simplified=False):
graph = Digraph(title)
graph.attr(rankdir="LR", color="blue")
graph.attr("node", fontname="Arial", fontsize="14")
Expand Down Expand Up @@ -690,15 +610,39 @@ def dfd(scenes: dict, title: str, dfdLabels=True, render=False):
graph.subgraph(boundaryClusters[c])

# Add the edges
flowCounter = 1
for flow in scenes[title]:
if dfdLabels is True:
graph.edge(
flow.pitcher.name, flow.catcher.name, f"({flowCounter}) {flow.name}"
)
else:
graph.edge(flow.pitcher.name, flow.catcher.name, f"({flowCounter})")
flowCounter += 1

if simplified is True:
edges = (
{}
) # Map the edges and figure out if we need to be double or single ended
for flow in scenes[title]:
# This edge is flow.pitcher.name -> flow.catcher.name
# If we don't have this edge, first check to see if we have it the other way
if (flow.pitcher.name, flow.catcher.name) not in edges and (
flow.catcher.name,
flow.pitcher.name,
) not in edges:
edges[(flow.pitcher.name, flow.catcher.name)] = "forward"
elif (flow.pitcher.name, flow.catcher.name) not in edges and (
flow.catcher.name,
flow.pitcher.name,
) in edges:
edges[(flow.catcher.name, flow.pitcher.name)] = "both"

for edge in edges:
print(edge)
graph.edge(edge[0], edge[1], dir=edges[edge])

else: # simplified is False
flowCounter = 1
for flow in scenes[title]:
if dfdLabels is True:
graph.edge(
flow.pitcher.name, flow.catcher.name, f"({flowCounter}) {flow.name}"
)
else:
graph.edge(flow.pitcher.name, flow.catcher.name, f"({flowCounter})")
flowCounter += 1

return graph

Expand Down Expand Up @@ -747,7 +691,11 @@ def report(scenes: dict, outputDir: str, select=None, dfdLabels=True):
"dataFlowTable": dataFlowTable(scenes, key),
}

agg = aggregatedDfd(scenes)
compoundFlows = []
for flow in scenes.values():
compoundFlows = compoundFlows + flow

agg = dfd({"all": compoundFlows}, "all", simplified=True)
aggDfd = {
"graph": agg,
"dfdImage": renderDfd(agg, "AggregatedDfd", outputDir=outputDir),
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
graphviz==0.16
Jinja2==3.0.1
black==21.7b0

0 comments on commit 66a3bf9

Please sign in to comment.