From 35fa765423c25c1733e682617ebe1b965297baf4 Mon Sep 17 00:00:00 2001 From: martiivGylden <martin.iversen@gyldendal.no> Date: Wed, 20 Mar 2024 14:17:50 +0100 Subject: [PATCH] Working on metrics, slow progress --- dashBoard.py | 26 +++++++++++---------- diagramParser.py | 8 +++---- dynamics.py | 12 ++++++---- matrices.py | 60 +++++++++++++++++++++++++++++++++++++++--------- requirements.txt | 21 +++++++++++++++++ 5 files changed, 95 insertions(+), 32 deletions(-) diff --git a/dashBoard.py b/dashBoard.py index 7f267dd..91e47c2 100644 --- a/dashBoard.py +++ b/dashBoard.py @@ -40,7 +40,7 @@ def openFile(): def createThreats(diagram: Diagram, top): for threat in diagram.threats.values(): - metrics, components = findMetrics(diagram, threat.id) + metrics, components = findMetrics(diagram, threat.componentID, "bowtie") threatFrame = Frame(top) threatFrame.pack() @@ -64,21 +64,23 @@ def createThreats(diagram: Diagram, top): -def findMetrics(diagram, id): - relevantDynamic = [] +def findMetrics(diagram, id:int, typeOfObject:str): + relevantMetrics = [] relatedComponents = [] - for metric in diagram.metrics.values(): - if id in metric.erID: - relevantDynamic.append(metric.ID) - relatedComponents.append(metric.erID) - - elif id in metric.bowtieID: - relevantDynamic.append(metric.ID) - relatedComponents.append(metric.bowtieID) + for metric in diagram.metrics.values(): + if typeOfObject == "bowtie": + if id in metric.bowtieID: + relevantMetrics.append(metric.ID) + relatedComponents.append(metric.erID) + + elif typeOfObject == "er": + if id in metric.erID: + relevantMetrics.append(metric.ID) + relatedComponents.append(metric.bowtieID) - return relevantDynamic, relatedComponents + return relevantMetrics, relatedComponents def createDynamic(diagram: Diagram, top): diff --git a/diagramParser.py b/diagramParser.py index b8241ea..18d4bf4 100644 --- a/diagramParser.py +++ b/diagramParser.py @@ -23,9 +23,9 @@ def parseDiagramFile(csvFile) -> component.Diagram: consequences = parseConsequences(df, consequences) metrics, dynamics = parseDynamic(df, metrics, dynamics) - metricsMatrix, metrics = matrix.parseTable(df, metrics) #Parse the table - - print(metricsMatrix) + + + metricsMatrix, metrics = matrix.parseTable(df, metrics, diagram) #Parse the table return diagram @@ -100,8 +100,6 @@ def parseDynamic(df, metricDict, dynamicsDict): df[const.Id][i], # Component ID LucidChart df[const.textArea3][i] # Name of dynamic ) - #attackDynamic.metrics = extractMetrics(df, i, 4) - #metricList = joinMetrcs(attackDynamic.metrics, metricList) # Adds the metrics to the global metric list attackDynamic.associateBowtie(df,attackDynamic.type, metricDict) # Associate the dynamic with the correct components dynamicsDict[df.Id[i]] = attackDynamic diff --git a/dynamics.py b/dynamics.py index 5f0d4ea..4c55a4e 100644 --- a/dynamics.py +++ b/dynamics.py @@ -104,6 +104,7 @@ class BowtieDynamic(DynamicComponent): # ! 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 + self.linkMetric(df, metricsDict) return # The attack is the only component associated with the dynamic sourceComponent = df.loc[df[const.Id]==lineTwo[const.From].item()] # Defines the source of the line connecting threats/consequences and attacks @@ -145,10 +146,11 @@ class BowtieDynamic(DynamicComponent): if(dynamicComponent["Text Area "+str(i)].isnull().values.any() == True): # If there are no metrics left break # Break the loop - - + metricID = dynamicComponent["Text Area "+str(i)].item() # Find the metric ID in the component - metricName = dynamicComponent["Text Area "+str(i+1)].item() # Find the metric Name + metricID = int(metricID) + + metricName = dynamicComponent["Text Area "+str(i+1)].item() # Find the metric Name self.metrics.append(metricID) # ? Adds the metric to the metric list associated with the dynamic component specifically @@ -246,7 +248,9 @@ class ERDynamic(DynamicComponent): if(dynamicComponent["Text Area "+str(i)].isnull().values.any() == True): # No more metrics break - metricID = dynamicComponent["Text Area "+str(i)].item() # Find the metric ID + metricID = dynamicComponent["Text Area "+str(i)].item() # Find the metric ID + metricID = int(metricID) + metricName = dynamicComponent["Text Area "+str(i+1)].item() # Find the metric ID self.metrics.append(metricID) # ? Adds the metric to the metric list associated with the dynamic component specifically diff --git a/matrices.py b/matrices.py index 44d76aa..6a96260 100644 --- a/matrices.py +++ b/matrices.py @@ -7,7 +7,7 @@ Parses csv table and returns a dataframe This is quite finicky as lucidchart has a very weird way of structuring tables as it is based on when different cells were created This is quite a big EDGE case and will only work for the specific table shape that I have created """ -def parseTable(df, metricsDict): +def parseTable(df, metricsDict, diagram): cols = [const.Er_ID, const.Bowtie_ID, const.Metric_ID, const.Metric_Name, const.Value, const.Measure_date, const.Frequency ,const.Measurement_guide] @@ -16,10 +16,11 @@ def parseTable(df, metricsDict): matrics = pd.DataFrame(columns=cols) length = len(table.columns) + length = length-7 # Setting the length equal to the amount of text fields + stopLength = length-15 - print(stopLength) - + # ! Parsing the first row of the table which has a fucked structure because lucidchart is garbage : ) erID1 = table[const.textArea4].item() # Define the ER ID BowTieID1 = table[const.textArea5].item() # Define the Bowtie ID @@ -30,11 +31,11 @@ def parseTable(df, metricsDict): Frequency1 = table[f"Text Area {length-6}"].item() # Define the Frequency Guide1 = table[f"Text Area {length-5}"].item() # Define the Measurement guide - + MetricID1 = int(MetricID1) matrics.loc[0] = erID1, BowTieID1, MetricID1, MetricName1, Value1, MeasureDate1, Frequency1, Guide1 # Fill inn dataframe # TODO Error handle/Communicate to end user here, "You seem to have a metric in your table which is not used etc" - metricsdict = fillMetricinfo(erID1, BowTieID1, MetricID1, MetricName1, Value1, MeasureDate1, Frequency1, Guide1, metricsDict) + fillMetricinfo(erID1, BowTieID1, MetricID1, MetricName1, Value1, MeasureDate1, Frequency1, Guide1, metricsDict, diagram) # Parsing the second row, this row is also specialized @@ -47,9 +48,11 @@ def parseTable(df, metricsDict): Frequency2 = table[f"Text Area {length-1}"].item() # Define the Frequency Guide2 = table[f"Text Area {length}"].item() # Define the Measurement guide + MetricID2 = int(MetricID2) matrics.loc[1] = erID2, BowTieID2, MetricID2, MetricName2, Value2, MeasureDate2, Frequency2, Guide2 metric = metricsDict[MetricID2] # Access the appropriate metric in the dictionary + fillMetricinfo(erID2, BowTieID2, MetricID2, MetricName2, Value2, MeasureDate2, Frequency2, Guide2, metricsDict, diagram) # TODO Error handle/Communicate to end user here, "You seem to have a metric in your table which is not used etc" if metric == None: @@ -74,10 +77,9 @@ def parseTable(df, metricsDict): series = pd.Series([erID, BowTieID, MetricID, MetricName, Value, MeasureDate, Frequency, Guide]) matrics.loc[matricsIndex] = erID, BowTieID, MetricID, MetricName, Value, MeasureDate, Frequency, Guide + fillMetricinfo(erID, BowTieID, MetricID, MetricName, Value, MeasureDate, Frequency, Guide,metricsDict, diagram) matricsIndex += 1 - - print(matrics) - + return matrics, metricsDict def handleMissingMetric(): @@ -93,15 +95,43 @@ def fillMetricinfo(erID1: str, Value1: str, MeasureDate1: str, Frequency1: str, - Guide1: str, metricsDict: dict)-> dict: + Guide1: str, metricsDict: dict, diagram)-> dict: """Function will fill in the metric information in the dataframe into the metric object and return the updated dictionary """ + MetricID1 = int(MetricID1) + metric = metricsDict[MetricID1] # Access the appropriate metric in the dictionary if metric == None: print("Metric is not used in the diagram!!!") return + if erID1 == "ID" or erID1 != None: + #TODO FML + pass + else: + erID1 = erID1.split(",") + erID1 = [eval(i) for i in erID1] # Parse ERID list to int + + for i in erID1: + print("TODO") + + if type(BowTieID1) == str: + if "," in BowTieID1: # If the amount of associated bowtie IDs is only one or none + BowTieID1 = BowTieID1.split(",") + BowTieID1 = [eval(i) for i in BowTieID1] # Parse BowtieID to int + + for i in range(len(BowTieID1)): + BowTieID1[i] = findComponentIDBowtie(BowTieID1[i], diagram) + else: + BowTieID1 = findComponentIDBowtie(BowTieID1, diagram) + BowTieID1 = [BowTieID1] + else: + BowTieID1 = int(BowTieID1) + + BowTieID1 = findComponentIDBowtie(BowTieID1, diagram) + BowTieID1 = [BowTieID1] + # Updates the metric with the information found in the dynamics matrix metric.erID = erID1 # Should be string metric.bowtieID = BowTieID1 # is list and should be i guess @@ -112,7 +142,15 @@ def fillMetricinfo(erID1: str, metric.guide = Guide1 # Should be string metricsDict[MetricID1] = metric - + return metricsDict - \ No newline at end of file +def findComponentIDBowtie(id, diagram): + + for threat in diagram.threats.values(): + if threat.id == str(id): + return threat.componentID + + for consequence in diagram.consequences.values(): + if consequence.id == str(id): + return consequence.componentID \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index fae9383..dd57884 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,23 @@ pandas==2.2.1 numpy==1.26.4 + + +15: <dynamics.Metric object at 0x11ef92c00>, +1: <dynamics.Metric object at 0x11ef93e60>, +2: <dynamics.Metric object at 0x11efc0650>, +3: <dynamics.Metric object at 0x11efc0860>, +10: <dynamics.Metric object at 0x11efc0a70>, + 11: <dynamics.Metric object at 0x11efc0c80>, + 12: <dynamics.Metric object at 0x11efc0e90>, + 13: <dynamics.Metric object at 0x11efc10d0>, + 4: <dynamics.Metric object at 0x11ef93b90>, + 5: <dynamics.Metric object at 0x11efc0e00>, + 6: <dynamics.Metric object at 0x11efc0bc0>, + 7: <dynamics.Metric object at 0x11efc0a10>, + 9: <dynamics.Metric object at 0x11efc0dd0>, + 16: <dynamics.Metric object at 0x11efc0440>, + 19: <dynamics.Metric object at 0x11efc12e0>, + 20: <dynamics.Metric object at 0x11efc1e50>, + 8: <dynamics.Metric object at 0x11efecf80>, + 17: <dynamics.Metric object at 0x11efed760>, + 18: <dynamics.Metric object at 0x11efeda90> \ No newline at end of file -- GitLab