Skip to content
Snippets Groups Projects
Commit 92bdca3e authored by martiivGylden's avatar martiivGylden
Browse files

Finished parsing dynamics components

parent eb2ac131
No related branches found
No related tags found
No related merge requests found
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
#Generic fields for all rows in the CSV file #Generic fields for all rows in the CSV file
Id = "Id" # The id of the entity Id = "Id" # The id of the entity
Name = "Name" # ! Identifier, can be used to distinguish diagram components
textArea1 = "Text Area 1" textArea1 = "Text Area 1"
textArea2 = "Text Area 2" textArea2 = "Text Area 2"
...@@ -76,3 +77,12 @@ ConsequenceDynamic = "Consequence" # The consequence dynamics ...@@ -76,3 +77,12 @@ ConsequenceDynamic = "Consequence" # The consequence dynamics
AttackDynamic = "Attack" # The attack dynamics AttackDynamic = "Attack" # The attack dynamics
ERDynamic = "ER" # The ER dynamics ERDynamic = "ER" # The ER dynamics
BowtieDynamicType = textArea3 # The bowtie dynamics BowtieDynamicType = textArea3 # The bowtie dynamics
# ! Note all metric fields use ID and name as the fields for the metric
# ! The ID will be used to link them in the dynamic matrix
# Lines
From = "Line Source"
To = "Line Destination"
...@@ -17,12 +17,15 @@ def parseDiagramFile(csvFile): ...@@ -17,12 +17,15 @@ def parseDiagramFile(csvFile):
consequences = {} consequences = {}
#consequences = parseConsequences(df, consequences) #consequences = parseConsequences(df, consequences)
# ER components
erComponents = {}
#List containing all metrics #List containing all metrics
metrics = [] metrics = []
#List containing all attacks #List containing all attacks
attacks = [] attacks = []
parseDynamic(df, metrics) parseDynamic(df, metrics)
...@@ -67,7 +70,7 @@ def parseAttacks(df, attackDict): ...@@ -67,7 +70,7 @@ def parseAttacks(df, attackDict):
) )
attackDict[df.Id[i]] = attack attackDict[df.Id[i]] = attack
return attackDict return attackDict
#Parses metrics components and adds it to list #Parses metrics components and adds it to list
def parseDynamic(df, metricList): def parseDynamic(df, metricList):
...@@ -81,8 +84,8 @@ def parseDynamic(df, metricList): ...@@ -81,8 +84,8 @@ def parseDynamic(df, metricList):
) )
threatDynamic.metrics = extractMetrics(df, i, 4) # Extracts metrics from the dynamic component threatDynamic.metrics = extractMetrics(df, i, 4) # Extracts metrics from the dynamic component
joinMetrcs(threatDynamic.metrics, metricList) # Adds the metrics to the global metric list joinMetrcs(threatDynamic.metrics, metricList) # Adds the metrics to the global metric list
threatDynamic.associateBowtie(df, threatDynamic.type) # Associate the dynamic with the correct components
elif df[const.textArea3][i] == const.ConsequenceDynamic: elif df[const.textArea3][i] == const.ConsequenceDynamic:
consequenceDynamic = dynamic.BowtieDynamic( consequenceDynamic = dynamic.BowtieDynamic(
...@@ -91,6 +94,7 @@ def parseDynamic(df, metricList): ...@@ -91,6 +94,7 @@ def parseDynamic(df, metricList):
) )
consequenceDynamic.metrics = extractMetrics(df, i, 4) # Extracts metrics from the dynamic component consequenceDynamic.metrics = extractMetrics(df, i, 4) # Extracts metrics from the dynamic component
joinMetrcs(threatDynamic.metrics, metricList) # Adds the metrics to the global metric list joinMetrcs(threatDynamic.metrics, metricList) # Adds the metrics to the global metric list
consequenceDynamic.associateBowtie(df, consequenceDynamic.type) # Associate the dynamic with the correct components
elif df[const.textArea3][i] == const.AttackDynamic: elif df[const.textArea3][i] == const.AttackDynamic:
...@@ -100,15 +104,18 @@ def parseDynamic(df, metricList): ...@@ -100,15 +104,18 @@ def parseDynamic(df, metricList):
) )
attackDynamic.metrics = extractMetrics(df, i, 4) attackDynamic.metrics = extractMetrics(df, i, 4)
joinMetrcs(threatDynamic.metrics, metricList) # Adds the metrics to the global metric list joinMetrcs(threatDynamic.metrics, metricList) # Adds the metrics to the global metric list
attackDynamic.associateBowtie(df,attackDynamic.type) # Associate the dynamic with the correct components
elif df[const.textArea3][i] == const.ERDynamic: elif df[const.textArea3][i] == const.ERDynamic:
erDynamic = dynamic.ERDynamic( erDynamic = dynamic.ERDynamic(
df[const.id][i], # Component ID LucidChart df[const.Id][i], # Component ID LucidChart
df.textArea3[i], # Name of dynamic df[const.textArea3][i], # Component type
df[const.textArea5][i] # Description
) )
erDynamic.metrics = extractMetrics(df, i, 8) erDynamic.metrics = extractMetrics(df, i, 8)
joinMetrcs(threatDynamic.metrics, metricList) # Adds the metrics to the global metric list joinMetrcs(threatDynamic.metrics, metricList) # Adds the metrics to the global metric list
#erDynamic.associatedERComponents(df)
def extractMetrics(df, index, startRange): def extractMetrics(df, index, startRange):
...@@ -117,8 +124,8 @@ def extractMetrics(df, index, startRange): ...@@ -117,8 +124,8 @@ def extractMetrics(df, index, startRange):
metricID = "Text Area "+str(j) metricID = "Text Area "+str(j)
metricName = "Text Area "+str(j+1) metricName = "Text Area "+str(j+1)
if pd.isnull(df[metric][index]) == False: # If the text area is not empty if pd.isnull(df[metricID][index]) == False: # If the text area is not empty
print("Metric: ID", df[metricID][index], "Name: ", df[metricName][index]) log.info("Metric: ID", df[metricID][index], "Name: ", df[metricName][index])
metric = dynamic.Metric(df[metricID][index], df[metricName][index]) metric = dynamic.Metric(df[metricID][index], df[metricName][index])
listOfMetrics.append(metric) listOfMetrics.append(metric)
else: else:
...@@ -133,8 +140,8 @@ def extractMetrics(df, index, startRange): ...@@ -133,8 +140,8 @@ def extractMetrics(df, index, startRange):
""" """
def joinMetrcs(localMetrics, globalMetrics): def joinMetrcs(localMetrics, globalMetrics):
duplicateMetrics = 0 # Counter for duplicate metrics per function run duplicateMetrics = 0 # Counter for duplicate metrics per function run
for i in range(globalMetrics): for i in range(len(globalMetrics)):
for j in range(localMetrics): for j in range(len(localMetrics)):
if globalMetrics[i].name == localMetrics[j].name: # Local metric already exists in the global metric list if globalMetrics[i].name == localMetrics[j].name: # Local metric already exists in the global metric list
duplicateMetrics += 1 duplicateMetrics += 1
break # Check next entry break # Check next entry
......
Har komponenter Har komponenter
Lagt til lokale metrics i hver komponent Lagt til lokale metrics i hver komponent
1. Må nå lage en global metric liste 1. Må nå lage en global metric liste FERDIG
2. Må lage ER dynamikk liste 2. Må lage ER dynamikk liste
3. Må koble dynamic komponenter til trusselkomponent 3. Må koble dynamic komponenter til trusselkomponent
......
import ERFormatConstants as const
import logging as log import logging as log
# Dynamics class parent class for both the bowtie dynamics and the architecture dynamics # Dynamics class parent class for both the bowtie dynamics and the architecture dynamics
...@@ -13,30 +14,6 @@ class DynamicComponent: ...@@ -13,30 +14,6 @@ class DynamicComponent:
def __str__(self) -> str: def __str__(self) -> str:
return f"Dynamic Component: {self.componentID}, {len(self.metrics)}" return f"Dynamic Component: {self.componentID}, {len(self.metrics)}"
#Simple contains function to check if metric already exists
def containsMetric(metricList, metric):
if len(metricList)==0:
return False
for i in metricList:
if i.name == metric:
return True
return False
# Function used to add a metric to the dynamics list
# The function will check if the metric already exists in the global list, if it does it will not be added to the global list
def addMetrics(self, globalMetricList , newMetric, description, metricType ):
metric = Metric(newMetric, description, metricType)
#Check if metric is already in the global metrics list if it is the metric will not be added to the global list
if DynamicComponent.containsMetric(globalMetricList, newMetric) == False:
globalMetricList = globalMetricList.append(metric)
log.info(f"Added metric {newMetric} to GLOBAL dynamics list with ID: {self.id}")
else:
log.info(f"Metric {newMetric} already exists in GLOBAL dynamics list with ID: {self.id}")
self.metrics.append(metric)
log.info(f"Added metric {newMetric} to LOCAL dynamics list with ID: {self.id}")
#Metric class, will be used for all dynamics #Metric class, will be used for all dynamics
class Metric: class Metric:
def __init__(self, ID, name) -> None: def __init__(self, ID, name) -> None:
...@@ -45,7 +22,7 @@ class Metric: ...@@ -45,7 +22,7 @@ class Metric:
self.ID = ID # ID of the metric used to locate in dynamics matrics self.ID = ID # ID of the metric used to locate in dynamics matrics
self.name = name # Name of the metric self.name = name # Name of the metric
# Metrics found in the metric table # Metrics found in the metric table
...@@ -57,17 +34,112 @@ class BowtieDynamic(DynamicComponent): ...@@ -57,17 +34,112 @@ class BowtieDynamic(DynamicComponent):
def __init__(self, componentID, type) -> None: def __init__(self, componentID, type) -> None:
super().__init__(componentID) super().__init__(componentID)
self.type = type # Type of dynamicM self.type = type # Type of dynamicM
self.associatedThreat = None # List of threats associated with the dynamic self.associatedThreat = None # Threat associated with the dynamic
self.associatedAttack = None # List of attacks associated with the dynamic self.associatedAttack = None # Attack associated with the dynamic
self.associatedConsequence = None # Consequence associated with the dynamic
"""_summary_
Handles the associated dynamics for the bowtie model as they are different from the ER model
ER model has one type of dynamic component with metrics however, the bowtie model has three dynamic types and needs more parsing
than the ER model du to the modeling annotation.
Abstracting this saves time
"""
def associateBowtie(self, df, componentType ):
componentId = self.componentID # Define the ID of the component
#Find the lines associated with the component
lines = df.loc[df['Name']=='Line'] # Find all lines in the diagram
lineSource = lines.loc[lines[const.From] == componentId] # Find the line where the component is the source
lineDestination = lines.loc[lines[const.To] == componentId] # ! The component SHOULD be source however, to error handle we need to check for destination as well
if lineSource.isnull().values.any() == True:
lineOne = lineSource
else:
lineOne = lineDestination
if lineOne[const.From].item() == componentId: # If the component is the source
lineTwo = df.loc[df[const.Id] == lineOne[const.To].item()] # Find the component associated with the line
else:
lineTwo = df.loc[df[const.Id] == lineOne[const.From].item()] # Find the component associated with the line
# ! Edge case, if the second line is in fact not a second line it is an attack meaning that the dynamic component is an attack
if componentType == const.Attack: # If the associated component is an attack
self.associatedAttack = lineTwo # ! The "line" is an attack, not a line, we add it to the associated attack field and move on
return # The attack is the only component associated with the dynamic
sourceComponent = df.loc[df[const.Id]==lineTwo[const.From].item()]
destinationComponent = df.loc[df[const.Id]==lineTwo[const.To].item()]
if componentType == const.ThreatDynamic: # If the component is a threat
if sourceComponent[const.textArea1].item() == const.Threat: # Checks if source or destination is the threat
self.associatedThreat = sourceComponent
self.associatedAttack = destinationComponent
else:
self.associatedThreat = destinationComponent
self.associatedAttack = sourceComponent
elif componentType == const.ConsequenceDynamic: # If the component is a consequence
if sourceComponent[const.textArea1].item() == const.Consequence:
self.associatedConsequence = sourceComponent
self.associatedAttack = destinationComponent
else:
self.associatedConsequence = destinationComponent
self.associatedAttack = sourceComponent
class ERDynamic(DynamicComponent): class ERDynamic(DynamicComponent):
def __init__(self, componentID, type, description) -> None: def __init__(self, componentID, type, description) -> None:
super().__init__(componentID, type) super().__init__(componentID)
self.description = description # Description of the dynamic self.description = description # Description of the dynamic
self.associatedComponent = None # Associated ER component self.associatedERComponents = [] # Associated ER component
self.type = type
"""_summary_
\ No newline at end of file Function will use the dynamic component ID to find linked threats, ER components, attacks and consequences
This will be needed to associate the dynamics with the correct components and analyze relationships
"""
def associatER(self, df):
componentId = self.componentID # Define the ID of the component
#Find the lines associated with the component
lines = df.loc[df['Name']=='Line'] # Find all lines in the diagram
relevantLines = [] # List of lines relevant to the component
for i in range(len(lines)):
line = lines.iloc[i]
if line[const.From] == componentId or line[const.To] == componentId: # If the line is associated with the component
relevantLines.append(lines.iloc[i]) # Add the line to the relevant lines list
log.info("Amount of relevant lines found:", len(relevantLines))
for i in range(len(relevantLines)):
line = relevantLines[i]
lineSource = line[const.From] # The source of the line
lineDestination = line[const.To]
if lineSource == componentId: # If the line is associated with the component
associatedComponentID = lineDestination
else:
associatedComponentID = lineSource
associatedComponent = df.iloc[df.index[df[const.Id] == associatedComponentID]] # Find the component associated with the line
self.associatedERComponents.append(associatedComponent) # Add the associated component to the list of associated components
log.info("Associated components found: ", self.associatedERComponents)
return
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment