Package: adtree-viz
adtree-vizIntroAn Attack-Defense Tree modelling lib that allows user to model attack-defense scenarios using an internal DSL.Project inspired byhttps://github.com/hyakuhei/attackTreesandhttps://github.com/tahti/ADTool2.The main goals are:add support for AND nodesbe able to break down a large tree into multiple subtrees.keep it simple, only Attack and Defense nodesUsageRequirements:GraphvizPython 3.9Install the librarypipinstalladtree-vizQuick startfromadtree.modelsimportAttack,Defence,AndGate,ADTreefromadtree.rendererimportRendererfromadtree.themesimportRedBlueFillThemetree=ADTree("REFS.01",Attack("the goal",[Attack("path1",[Defence("defend path1",[Attack("path1 defence defeated")])]),Attack("path2",[Attack("path2.1"),AndGate([Attack("path3.1"),Attack("path3.2"),]),]),]))theme=RedBlueFillTheme()renderer=Renderer(theme=theme,output_format="png",view=True)renderer.render(tree=tree,filename="my-adtree")The above should produce an attack-defence tree like this:Composing treesTrees can be composed of multiple subtrees.
Which of the subtrees get expanded is decided at render time based on thesubtrees_to_expandvariable.fromadtree.modelsimportAttack,ADTree,ExternalADTreefromadtree.rendererimportRendererfromadtree.themesimportNoFormatThemesome_external_ref=ExternalADTree("EXT.01","External resource covered by other docs")some_internal_ref1=ADTree("INT.01",root_node=Attack("internal path1",[Attack("path 1.1",[ADTree("INT.01.A",Attack("nested path 1.1A"))])]))some_internal_ref2=ADTree("INT.02",root_node=Attack("internal path2",[Attack("path 2.1")]))tree=ADTree("REFS.01",Attack("node1",[some_external_ref,some_internal_ref1,some_internal_ref2]))theme=NoFormatTheme()renderer=Renderer(theme=theme,output_format="png",view=False)# Default is to not expandrenderer.render(tree=tree,filename="default")# Optionally expand some nodesrenderer.render(tree=tree,subtrees_to_expand=[some_internal_ref1],filename="partially_expanded")The above will render two files.One with all the subtrees collapsed (the default):And another file with one subtree expanded:Analysing treesCurrently, there is only one analyser available, the IsDefendedAnalyser.
Traverse the tree and mark each nodes as either defended or undefended
A node is considered defended if:is a Defence node and has no childrenis an Attack node and has a direct defended Defence node as childis an Attack or Defence node and all child nodes are defended nodesis an AndGate and at least one child node is defendedExample with custom rendering of the defended nodesfromadtree.modelsimportNodeType,Node,Attack,ADTree,Defence,AndGatefromadtree.analysersimportIsDefendedAnalyserfromadtree.rendererimportRendererfromadtree.themesimportNoFormatThemeclassCustomIsDefendedTheme(NoFormatTheme):defget_node_attrs_for(self,node:Node):metadata_attrs={"style":"filled"}ifnode.get_node_type()==NodeType.DEFENCE:metadata_attrs|={"shape":"box",}ifnode.get_node_type()==NodeType.AND_GATE:metadata_attrs|={"shape":"triangle",}ifnode.has_metadata(IsDefendedAnalyser.METADATA_KEY):fillcolor="#C8FFCB"ifnode.get_metadata(IsDefendedAnalyser.METADATA_KEY)else"#FFD3D6"metadata_attrs|={"fillcolor":fillcolor,}returnmetadata_attrstree=ADTree("REFS.01",Attack("the goal",[Attack("path1",[Defence("defend path1",[Attack("path1 defence defeated")])]),Attack("path2",[Attack("path2.1",[Defence("def2.1"),Attack("path2.1.1")]),AndGate([Attack("path3.1"),Attack("path3.2",[Defence("defended")]),]),]),]))analyser=IsDefendedAnalyser()analyser.analyse_tree(tree)theme=CustomIsDefendedTheme()renderer=Renderer(theme=theme,output_format="png",view=False)# Default is to not expandrenderer.render(tree=tree,filename="default")The above should produce an attack-defence tree like this:DevelopmentCreate a venvpython3.9-mvenvvenvActivate.venv/bin/activateInstall depspipinstall-rrequirements.txtRun testsPYTHONPATH=srcpython-mpytestRun individual test filePYTHONPATH=srcpython-mpytest./test/adtree/test_theme.pyRun individual test methodsPYTHONPATH=srcpython-mpytest--capture=no./test/adtree/test_theme.py-k"metadata"Release to Github and PyPiCreate tag and push./release.shManually build and releaseRun the below to generate a distributable archive:python3-mbuildTheadtree-viz-x.xx.x.tar.gzarchive can be found in thedistfolder.Deploy to PyPipython3-mtwineupload-rpypidist/*# Use __token__ as username# Use PyPi API TOKEN as password