diff --git a/dashBoard.py b/dashBoard.py index 4122119e9c8041a572110c4fd43e4cfd9a7070b4..c3e0337239bfb6c46e23f09c5ece25d5e6707198 100644 --- a/dashBoard.py +++ b/dashBoard.py @@ -59,8 +59,8 @@ def openFile(): description2Label = ttk.Label(mainFrame, text=descriptionString2, wraplength=0.3*windowWidth, style="ScorecardInfo.TLabel") description3Label = ttk.Label(mainFrame, text=descriptionString3, wraplength=0.9*windowWidth, style="ScorecardInfo.TLabel") - sortThreatButton = Button(mainFrame, text="Sort by threats", command=lambda: createThreatView(diagram, mainFrame), width=2, height=3) - sortIndicatorButton = Button(mainFrame, text="Sort by indicators", command=lambda: createIndicatorView(diagram, mainFrame), width=2, height=3) + sortThreatButton = Button(mainFrame, text="Sort by threats", command=lambda: createThreatView(diagram, listFrame, windowWidth), width=2, height=3) + sortIndicatorButton = Button(mainFrame, text="Sort by indicators", command=lambda: createIndicatorView(diagram, listFrame, windowWidth), width=2, height=3) analyticsLabel = ttk.Label(mainFrame, text="Features", style="ScorecardHeader.TLabel") analyticsRow3 = ttk.Label(mainFrame, text=f"Number of indicators: {len(diagram.indicators)}",style="ScorecardInfo.TLabel" ) @@ -98,7 +98,7 @@ def openFile(): # Create the list of threats createThreatView(diagram, listFrame, windowWidth) -def createThreatView(diagram: Diagram, frame, frameWidth): +def createThreatView(diagram: Diagram, frame: customtkinter.CTkScrollableFrame, frameWidth: int) -> None: """ Function will fetfch all threats, and create one frame for each, the frame will contain three more frames One for threat information, one for indicator information, and one for architecture information @@ -119,6 +119,11 @@ def createThreatView(diagram: Diagram, frame, frameWidth): s.configure('Indicator.TLabel', background='#C2F7C8', foreground="Black" ,font=('Helvetica', 15)) s.configure('IndicatorInfo.TLabel', background='#C2F7C8', foreground="Black" ,font=('Helvetica', 15, 'bold')) + # Clear the frame + if frame.children: + for widget in frame.winfo_children(): + widget.destroy() + rowIndex = 0 for key, value in diagram.threats.items(): #* Iterate through all threats @@ -207,104 +212,126 @@ def createThreatView(diagram: Diagram, frame, frameWidth): indicatorFrame.grid(row=rowIndex, column=1, sticky="nsew") rowIndex += 1 -def createIndicatorView(): - windowWidth = 1250 - windowHeight = 1200 - - diagram = parse.parseDiagramFile("diagrams/Case1.csv") - - top = Toplevel(guiRoot, bg="blue") - top.title("Result Window") - top.geometry("1250x1200") - top.minsize(windowWidth, windowHeight) +def createIndicatorView(diagram: Diagram, frame: customtkinter.CTkScrollableFrame, frameWidth: int) -> None: + """Function will fill a frame with all the used indicators in the diagrams, and show which components they are associated to + Moreover the list will be ranked based on usage, and the most used indicators will be shown first + + Args: + diagram (Diagram): The parsed diagram containing information about the threats, indicators and architecture components + frame (customtkinter.CTkScrollableFrame): The frame to fill with the indicators + frameWidth (int): width of the frame + """ - mainFrame = customtkinter.CTkScrollableFrame(top, width=windowWidth, height=windowHeight, bg_color="#155E53") - mainFrame.grid() - mainFrame.grid_rowconfigure(0, weight=1) + # Clear the frame + if frame.children: + for widget in frame.winfo_children(): + widget.destroy() - createMetrics(diagram, mainFrame, 1550) - -def createMetrics(diagram: Diagram, frame, canvasWidth): s = ttk.Style() s.theme_use('classic') - s.configure('Test.TFrame', background='#51D88F',foreground="#1A323B", relief='raised') - s.configure('Head.TLabel', background='#51D88F', foreground="#1A323B" ,font=('Helvetica', 20, 'bold')) - s.configure('Test.TLabel', background='#51D88F', foreground="#1A323B" ,font=('Helvetica', 20)) - s.configure('ListFrame.TFrame', background='white', foreground="#155E53") - s.configure('ListFrame.TLabel', background='white', foreground="#1A323B", font=('Helvetica', 20, 'bold')) - - metrics = diagram.metrics.values() - rowIndex = 0 - - scoreFrame = ttk.Frame(frame, height=100, width=canvasWidth, padding=10, style='Test.TFrame') - scoreFrame.grid(padx=10, pady=25, sticky="nsew") + s.configure('Indicator.TFrame', background='#C2F7C8',foreground="Black", relief='raised') + s.configure('IndicatorHeader.TLabel', background='#C2F7C8', foreground="Black" ,font=('Helvetica', 15, 'bold')) + s.configure('IndicatorInfo.TLabel', background='#C2F7C8', foreground="Black" ,font=('Helvetica', 15)) + - headerLabel = ttk.Label(scoreFrame, text="Diagram scorecard", font=("Helvetica", 25, "bold"), style="Head.TLabel") - label1 = ttk.Label(scoreFrame, text=f"Diagrams parsed! Below is the list of found metrics along with the amount of relationships. Further down you will find the list of metrics with usage and associated components", wraplength=0.5*canvasWidth ,font=("Helvetica", 20), style="Test.TLabel") - label2 = ttk.Label(scoreFrame, text=f"Number of metrics: {len(diagram.metrics)}", font=("Helvetica", 20), style="Test.TLabel") - label3 = ttk.Label(scoreFrame, text=f"Number of annotated relationships: {len(diagram.dynamics)}", font=("Helvetica", 20), style="Test.TLabel") + s.configure('Threat.TFrame', background='#6DB1FF',foreground="Black", relief='raised') + s.configure('Threat.TLabel', background='#6DB1FF', foreground="Black" ,font=('Helvetica', 15, 'bold')) + s.configure('ThreatInfo.TLabel', background='#6DB1FF', foreground="Black" ,font=('Helvetica', 15)) + + s.configure('Consequence.TFrame', background='#FE7070',foreground="Black", relief='raised') + s.configure('Consequence.TLabel', background='#FE7070', foreground="Black" ,font=('Helvetica', 15, 'bold')) + s.configure('ConsequenceInfo.TLabel', background='#FE7070', foreground="Black" ,font=('Helvetica', 15)) - headerLabel.grid(row=0, column=0, sticky="nw") - label1.grid(row=1, column=0, sticky="nw", pady=10) - label2.grid(row=2, column=0, sticky="nw") - label3.grid(row=3, column=0, sticky="nw") + s.configure('Architecture.TFrame', background='#CFE4FE',foreground="Black", relief='raised') + s.configure('Architecture.TLabel', background='#CFE4FE', foreground="Black" ,font=('Helvetica', 15, 'bold')) + s.configure('ArchitectureInfo.TLabel', background='#CFE4FE', foreground="Black" ,font=('Helvetica', 15)) - associatedList = {} # Needed to keep track of the number of associated components per metric - for metric in metrics: - numberOfAssociates = len(metric.bowtieID)+len(metric.erID) - associatedList[metric.ID] = numberOfAssociates - - rankedList = sorted(associatedList.items(), key=lambda x: x[1], reverse=True) - - for i in rankedList: - amountOFComponents = i[1] - metricID = i[0] - metricName = diagram.metrics[metricID].name - metricValue = diagram.metrics[metricID].value - metricDate = diagram.metrics[metricID].date - - metricFrame = ttk.Frame(frame ,style='Test.TFrame', height= 200, width=canvasWidth, padding=5) # Frame for each metric, should cover 80% of the window and stack vertically - metricFrame.grid(padx=10, pady=10, sticky="nsew") - metricFrame.grid_rowconfigure(0, weight=1) - metricFrame.grid_columnconfigure(0, weight=1) + + # * For each indicator, we need to find the threats and the architecture components that are associated with the indicator + listFrameIndex = 0 + for key, value in diagram.indicators.items(): + indicatorFrame = ttk.Frame(frame, style='Indicator.TFrame', width=0.8*frameWidth, padding=10) + # Define the indicator values + indicatorID = key + indicatorName = value.indicatorName + indicatorValue = value.value + date = value.date + frequency = value.frequency + interpretation = value.interpretation - rowIndex +=1 # Increment the row index for the next frame - ttk.Label(metricFrame, text= f"Metric number: {rowIndex}", style="Head.TLabel").grid(row=0, column=0, sticky="nw") + #* Defines relevant IDs for all entities + threatIDs = value.threatAssoicates.keys() # L + consequenceIDS = value.consequenceAssociates.keys() # List of consequences associated with the indicator + erIDs = value.erAssociates.keys() - ttk.Label(metricFrame, text= f"Metric Name: {metricName}", style="Test.TLabel").grid(row=1, column=0, sticky="nw") # First label = Metric id and description + amoubtOfAssociates = len(threatIDs) + len(consequenceIDS) + len(erIDs) - ttk.Label(metricFrame, text= f"Metric value: {metricValue}", style="Test.TLabel", wraplength=0.3*canvasWidth).grid(row=2, column=0, sticky="nw") # First label = Metric id and description - - ttk.Label(metricFrame, text = f"Number of associated components: {amountOFComponents}", style="Test.TLabel").grid(row=1, column=1, sticky="n") # Second label = Number of associated components in both diagrams + indicatorHead = ttk.Label(indicatorFrame, text=f"Indicator: {indicatorID} Name: {indicatorName}" , style="IndicatorHeader.TLabel") + indicatorDescription = ttk.Label(indicatorFrame, text=f"Indicator Value: {indicatorValue}", style="IndicatorInfo.TLabel") + indicatorDescription2 = ttk.Label(indicatorFrame, text=f"Indicator measurement date: {date} Proposed measurement frequency: {frequency}" , style="IndicatorInfo.TLabel") + indicatorDescription3 = ttk.Label(indicatorFrame, text=f"Indicator interpretation: {interpretation}", style="IndicatorInfo.TLabel", wraplength=0.4*frameWidth) + description4 = ttk.Label(indicatorFrame, text=f"Amount of associations: {amoubtOfAssociates}", style="IndicatorInfo.TLabel") + + indicatorHead.grid(row=0, column=0, sticky="nw", pady=15) + indicatorDescription.grid(row=1, column=0, sticky="nw", pady=5, columnspan=3) + indicatorDescription2.grid(row=2, column=0, sticky="nw", pady=5, columnspan=3) + indicatorDescription3.grid(row=3, column=0, sticky="nw", pady=5, columnspan=3) + description4.grid(row=4, column=0, sticky="nw", pady=5, columnspan=3) + + + threatFrame = ttk.Frame(indicatorFrame, style='Threat.TFrame', width=0.3*frameWidth, padding=10) + threatHeader = ttk.Label(threatFrame, text="Threats", style="Threat.TLabel") + threatHeader.grid(row=0, column=0, sticky="nw", pady=5) + + consequenceFrame = ttk.Frame(indicatorFrame, style='Consequence.TFrame', width=0.3*frameWidth, padding=10) + consequenceHeader = ttk.Label(consequenceFrame, text="Consequences", style="Consequence.TLabel") + consequenceHeader.grid(row=0, column=0, sticky="nw", pady=5) + + erIDFrame = ttk.Frame(indicatorFrame, style='Architecture.TFrame', width=0.3*frameWidth, padding=10) + architectureHeader = ttk.Label(erIDFrame, text="Architecture components", style="Architecture.TLabel") + architectureHeader.grid(row=0, column=0, sticky="nw", pady=5) + + #* Iterate over the various IDs and find the relevant information + rowIndex = 1 - ttk.Label (metricFrame, text = f"Last update: {metricDate}", style="Test.TLabel").grid(row=2, column=1, sticky="e") # Third label = Last update of the metric + for threatID in threatIDs: + threat = diagram.threats[threatID] + threatLabel = ttk.Label(threatFrame, text=f"Threat ID: {threatID} - Threat Name: {threat.name}", style="ThreatInfo.TLabel", wraplength=0.3*frameWidth) + threatLabel.grid(row=rowIndex, column=0, sticky="nw", pady=5) + rowIndex += 1 + rowIndex = 1 - for child in metricFrame.winfo_children(): - child.grid_configure(padx=3, pady=3) + for consequenceID in consequenceIDS: + consequence = diagram.consequences[consequenceID] + consequenceLabel = ttk.Label(consequenceFrame, text=f"Consequence ID: {consequenceID} - Consequence Name: {consequence.name}", style="ConsequenceInfo.TLabel", wraplength=0.3*frameWidth) + consequenceLabel.grid(row=rowIndex, column=0, sticky="nw", pady=5) + rowIndex += 1 - # Add 2 Frames, one withe Entity relationship components and one with bowtie components - erFrame = ttk.Frame(metricFrame, style='ListFrame.TFrame', height= 200, width=0.3*canvasWidth, padding=10) - erFrame.grid(row=3, column=0, sticky="nsew", rowspan=1, padx=10, pady=10) - ttk.Label(erFrame, text="Entity Relationship components", style="ListFrame.TLabel").grid(row=0, column=0, sticky="nw") + rowIndex = 1 - erList = utils.createERLabel(erFrame, diagram.metrics[metricID], diagram) - for i in range(len(erList)): - erList[i].grid(row=i+1, column=0, sticky="nw") + for erID in erIDs: + erComponent = diagram.erComponents[erID] + erLabel = ttk.Label(erIDFrame, text=f"ER ID: {erID} - ER Name: {erComponent.name}", style="ArchitectureInfo.TLabel", wraplength=0.3*frameWidth) + erLabel.grid(row=rowIndex, column=0, sticky="nw", pady=5) + rowIndex += 1 - bowTieFrame = ttk.Frame(metricFrame, style='ListFrame.TFrame', height= 200, width=0.3*canvasWidth, padding=10) - bowTieFrame.grid(row=3, column=1, sticky="nsew", rowspan=1, padx=10, pady=10) - ttk.Label(bowTieFrame, text="BowTie components", style="ListFrame.TLabel").grid(row=0, column=0, sticky="nw") + threatFrame.grid(row=5, column=0, sticky="nsew") + consequenceFrame.grid(row=5, column=1, sticky="nsew") + erIDFrame.grid(row=5, column=2, sticky="nsew") - bowTieList = utils.createBowtieLabel(bowTieFrame, diagram.metrics[metricID], diagram) + indicatorFrame.grid(row=listFrameIndex, column=0, sticky="nsew") + listFrameIndex += 1 + + + + - for i in range(len(bowTieList)): - bowTieList[i].grid(row=i+1, column=0, sticky="nw") - - return frame + + guiRoot = Tk() diff --git a/diagramParser.py b/diagramParser.py index 98fa73ecaf625dcce50e2b0ca1e6969ce78d1f1e..e7f5846bd40a4eca59b11af1f63bbddd0eadc80b 100644 --- a/diagramParser.py +++ b/diagramParser.py @@ -20,6 +20,8 @@ def parseDiagramFile(csvFile) -> component.Diagram: diagram = parseAttacks(df, diagram) return diagram + + # Function will parse the threats and add them to the dictionary def parseThreats(df,diagram: component.Diagram): @@ -137,5 +139,9 @@ def parseRelationshipComponentER(df: pd.DataFrame, diagram: component.Diagram, i entityToUpdate = diagram.erComponents[entityRelationshipId] entityToUpdate.linkedIndicators.update(indicatorList) - + + componentForUpdate = diagram.erComponents[entityRelationshipId] + for reason, key in specificIndicatorList.items(): + diagram.indicators[key].erAssociates[entityRelationshipId] = componentForUpdate + return diagram \ No newline at end of file