Project: Checkov (Provisioning / Security & Compliance)
File: creating-a-solver.gm0ti.sw.md

id: gm0ti name: Creating a Solver file_version: 1.0.2 app_version: 0.9.4-0 file_blobs: checkov/common/checksinfra/solvers/complexsolvers/not_solver.py: 60e9301de2a35a51b0464babaf537104d82cf00a checkov/common/checksinfra/checksparser.py: 50130edc6639275b43dbd287572972b826eee687 checkov/common/checksinfra/solvers/complexsolvers/init.py: 2e25b8e1f51406fe5e2995019eb6046fdf3650f2 checkov/common/graph/checksinfra/solvers/basesolver.py: e84d471f6fc2e8ef12d82fa061784c57a7915d5c checkov/common/checksinfra/solvers/complexsolvers/basecomplexsolver.py: 186dd8805259132d32936fafc19c389d452869c4 checkov/common/checksinfra/solvers/connectionssolvers/orconnectionsolver.py: 38df2db8112768f7ee10facc3feac82b84affc32 checkov/common/checksinfra/solvers/attributesolvers/anyattributesolver.py: 5aa38478ce1174ea46d2cff94ec52358e8595369 checkov/common/checksinfra/solvers/attributesolvers/notcontainsattribute_solver.py: 0d44d643a7ba2f1fc78fa86ad53b46c47e546ee1 checkov/common/checksinfra/solvers/attributesolvers/notendingwithattributesolver.py: 334cc79488dc5f5f52e3d66ef9b24e3ad89f1e99 A Solver is a major component in our system. This document will describe what it is and how to add a new one. A Solver is a graph operator that impelements a certain piece of logic, such as AttributeEquals, GreaterThan, Exists and more. There are also more complext solvers such as the `And` solver which implement logic between two or more solvers When we add a new Solver, we create a class that inherits from `BaseSolver`. Some examples of `BaseSolver`s are `OrConnectionSolver`, `AnyResourceSolver`, `NotContainsAttributeSolver`, and `NotEndingWithAttributeSolver`. Note: some of these examples inherit indirectly from `BaseSolver`. NOTE: Inherit from `BaseComplexSolver` Most `BaseSolver`s inherit directly from `BaseComplexSolver` and almost none inherit directly from `BaseSolver`. In this document we demonstrate inheriting from `BaseComplexSolver`. Create a new class inheriting from `BaseComplexSolver` Place the file under ` checkov/common/checksinfra/solvers/complexsolvers`, e.g. `NotSolver` is defined in ` checkov/common/checksinfra/solvers/complexsolvers/not_solver.py`. Define `operator`. Implement `init`, `getoperation`, and `get_operation`. Update ` checkov/common/checksinfra/checksparser.py`. Update ` checkov/common/checksinfra/solvers/complexsolvers/init.py`. Profit We'll follow the implementation of `NotSolver` for this example. A `NotSolver` is a solver that inverts the logic of the solvers within it All `BaseComplexSolver`s are defined in files under ` checkov/common/checksinfra/solvers/complexsolvers`. <br/> We first need to define our class in the relevant file, and inherit from `BaseComplexSolver`: <!-- NOTE-swimm-snippet: the lines below link your snippet to Swimm --> ```python 5 from checkov.common.checksinfra.solvers.complexsolvers.basecomplexsolver import BaseComplexSolver 6 7 8 class NotSolver(BaseComplexSolver): 9 operator = Operators.NOT # noqa: CCE003 # a static attribute 10 11 def init(self, solvers: List[BaseSolver], resource_types: List[str]) -> None: ``` <br/> Note: the class name should end with "Solver". `BaseSolver`s should define this variable: `operator` <br/> <!-- NOTE-swimm-snippet: the lines below link your snippet to Swimm --> ```python 6 7 8 class NotSolver(BaseComplexSolver): 9 operator = Operators.NOT # noqa: CCE003 # a static attribute 10 11 def init(self, solvers: List[BaseSolver], resource_types: List[str]) -> None: 12 if len(solvers) != 1: ``` <br/> Here is how we do it for `NotSolver`: Implement `init`. <br/> <!-- NOTE-swimm-snippet: the lines below link your snippet to Swimm --> ```python 8 class NotSolver(BaseComplexSolver): 9 operator = Operators.NOT # noqa: CCE003 # a static attribute 10 11 def init(self, solvers: List[BaseSolver], resource_types: List[str]) -> None: 12 if len(solvers) != 1: 13 raise Exception('The "not" operator must have exactly one child') 14

resource_types) 15 16 def getoperation(self, args: Any, *kwargs: Any) -> Any: 17 if len(args) != 1: ``` <br/> <!-- NOTE-swimm-snippet: the lines below link your snippet to Swimm --> ```python 13 raise Exception('The "not" operator must have exactly one child') 14 super().init(solvers, resource_types) 15 16 def getoperation(self, args: Any, *kwargs: Any) -> Any: 17 if len(args) != 1: 18 raise Exception('The "not" operator must have exactly one child') 19 return not args[0] 20 21 def get_operation(self, vertex: Dict[str, Any]) -> bool: # type:ignore[override] 22 return not self.solvers[0].get_operation(vertex) ``` <br/> <!-- NOTE-swimm-snippet: the lines below link your snippet to Swimm --> ```python 18 raise Exception('The "not" operator must have exactly one child') 19 return not args[0] 20 21 def get_operation(self, vertex: Dict[str, Any]) -> bool: # type:ignore[override] 22 return not self.solvers[0].get_operation(vertex) 23 ``` <br/> Every time we add new `BaseComplexSolver`s, we reference them in a few locations. We will still look at `NotSolver` as our example. <br/> 4\. Update ` checkov/common/checksinfra/checksparser.py`, as we do with `NotSolver` here: <!-- NOTE-swimm-snippet: the lines below link your snippet to Swimm --> ```python 19 NotEndingWithAttributeSolver, 20 AndSolver, 21 OrSolver, 22 NotSolver, 23 ConnectionExistsSolver, 24 ConnectionNotExistsSolver, 25 AndConnectionSolver, ``` <br/> In addition, in the same file: <!-- NOTE-swimm-snippet: the lines below link your snippet to Swimm --> ```python 93 operatorstocomplexsolverclasses: dict[str, Type[BaseComplexSolver]] = { 94 "and": AndSolver, 95 "or": OrSolver, 96 "not": NotSolver, 97 } 98 99 operatortoconnectionsolverclasses: dict[str, Type[BaseConnectionSolver]] = { ``` <br/> 4\. We modify ` checkov/common/checksinfra/solvers/complexsolvers/init.py`, for example: <!-- NOTE-swimm-snippet: the lines below link your snippet to Swimm --> ```python 1 from checkov.common.checksinfra.solvers.complexsolvers.or_solver import OrSolver # noqa 2 from checkov.common.checksinfra.solvers.complexsolvers.and_solver import AndSolver # noqa 3 from checkov.common.checksinfra.solvers.complexsolvers.not_solver import NotSolver # noqa 4 ``` <br/> <!-- THIS IS AN AUTOGENERATED SECTION. DO NOT EDIT THIS SECTION DIRECTLY --> <span id="f-ZDc3b7">init</span> - "checkov/common/checksinfra/solvers/complexsolvers/not_solver.py" L11 ```python def init(self, solvers: List[BaseSolver], resource_types: List[str]) -> None: ``` <span id="f-Z1IWbj3">getoperation</span> - "checkov/common/checksinfra/solvers/complexsolvers/not_solver.py" L16 ```python def getoperation(self, args: Any, *kwargs: Any) -> Any: ``` <span id="f-Z7ghIg">AnyResourceSolver</span> - "checkov/common/checksinfra/solvers/attributesolvers/anyattributesolver.py" L7 ```python class AnyResourceSolver(BaseAttributeSolver): ``` <span id="f-10523X">BaseComplexSolver</span> - "checkov/common/checksinfra/solvers/complexsolvers/basecomplexsolver.py" L9 ```python class BaseComplexSolver(BaseSolver): ``` <span id="f-2wxET6">BaseSolver</span> - "checkov/common/graph/checksinfra/solvers/basesolver.py" L9 ```python class BaseSolver: ``` <span id="f-I3t5K">getoperation</span> - "checkov/common/checksinfra/solvers/complexsolvers/notsolver.py" L21 ```python def get_operation(self, vertex: Dict[str, Any]) -> bool: # type:ignore[override] ``` <span id="f-Z136myH">NotContainsAttributeSolver</span> - "checkov/common/checksinfra/solvers/attributesolvers/notcontainsattribute_solver.py" L7 ```python class NotContainsAttributeSolver(ContainsAttributeSolver): ``` <span id="f-923Qq">NotEndingWithAttributeSolver</span> - "checkov/common/checksinfra/solvers/attributesolvers/notendingwithattributesolver.py" L7 ```python class NotEndingWithAttributeSolver(EndingWithAttributeSolver): ``` <span id="f-Z2wW09R">NotSolver</span> - "checkov/common/checksinfra/solvers/complexsolvers/not_solver.py" L8 ```python class NotSolver(BaseComplexSolver): ``` <span id="f-Z1HozjT">operator</span> - "checkov/common/checksinfra/solvers/complexsolvers/not_solver.py" L9 ```python operator = Operators.NOT # noqa: CCE003 # a static attribute ``` <span id="f-Z1oapTp">OrConnectionSolver</span> - "checkov/common/checksinfra/solvers/connectionssolvers/orconnectionsolver.py" L11 ```python class OrConnectionSolver(ComplexConnectionSolver): ``` <br/> This file was generated by Swimm. .