-
Notifications
You must be signed in to change notification settings - Fork 56
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
First iteration on a new filter system to allow more granular configu…
…ration (#110) * new_filter_system: add filter class and builder + tests * new_filter_system: add pydash lobrary * new_filter_system: Add disabled in RuleMode * new_filter_system: remove test code * new_filter_system: add whitelisted to model * new_filter_system: add support to base model * new_filter_system: add support for rule config * new_filter_system: update docs config * new_filter_system: add rule_config * new_filter_system: add docs * new_filter_system: remove default conf * new_filter_system: update changelog and docs * new_filter_system: upgrade version * new_filter_system: update changelog * new_filter_system: update docs * new_filter_system: apply comments from PR
- Loading branch information
Showing
13 changed files
with
385 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
VERSION = (0, 15, 1) | ||
VERSION = (0, 16, 0) | ||
|
||
__version__ = ".".join(map(str, VERSION)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import operator | ||
import re | ||
from typing import Any, Callable, Dict, List, Optional, Union | ||
|
||
from pydantic import BaseModel, validator | ||
from pydash.objects import get | ||
|
||
from cfripper.model.enums import RuleMode, RuleRisk | ||
|
||
IMPLEMENTED_FILTER_FUNCTIONS = { | ||
"eq": lambda *args, **kwargs: operator.eq(*args), | ||
"ne": lambda *args, **kwargs: operator.ne(*args), | ||
"lt": lambda *args, **kwargs: operator.lt(*args), | ||
"gt": lambda *args, **kwargs: operator.gt(*args), | ||
"le": lambda *args, **kwargs: operator.le(*args), | ||
"ge": lambda *args, **kwargs: operator.ge(*args), | ||
"not": lambda *args, **kwargs: operator.not_(*args), | ||
"or": lambda *args, **kwargs: any(args), | ||
"and": lambda *args, **kwargs: all(args), | ||
"in": lambda a, b, *args, **kwargs: operator.contains(b, a), | ||
"regex": lambda *args, **kwargs: bool(re.match(*args)), | ||
"ref": lambda param_name, *args, **kwargs: get(kwargs, param_name), | ||
} | ||
|
||
|
||
def is_resolvable_dict(value: Any) -> bool: | ||
return isinstance(value, dict) and len(value) == 1 and next(iter(value)) in IMPLEMENTED_FILTER_FUNCTIONS | ||
|
||
|
||
def build_evaluator(tree: Union[str, int, float, bool, List, Dict]) -> Callable: | ||
if is_resolvable_dict(tree): | ||
function_name, nodes = list(tree.items())[0] | ||
if not isinstance(nodes, list): | ||
nodes = [nodes] | ||
nodes = [build_evaluator(node) for node in nodes] | ||
function_resolver = IMPLEMENTED_FILTER_FUNCTIONS[function_name] | ||
return lambda kwargs: function_resolver(*[node(kwargs) for node in nodes], **kwargs) | ||
|
||
return lambda kwargs: tree | ||
|
||
|
||
class Filter(BaseModel): | ||
reason: str = "" | ||
eval: Union[Dict, Callable] | ||
rule_mode: Optional[RuleMode] = None | ||
risk_value: Optional[RuleRisk] = None | ||
|
||
@validator("eval", pre=True) | ||
def set_eval(cls, eval): | ||
return build_evaluator(eval) | ||
|
||
def __call__(self, **kwargs): | ||
return self.eval(kwargs) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
from typing import List, Optional | ||
|
||
from pydantic import BaseModel | ||
|
||
from cfripper.config.filter import Filter | ||
from cfripper.model.enums import RuleMode, RuleRisk | ||
|
||
|
||
class RuleConfig(BaseModel): | ||
rule_mode: Optional[RuleMode] = None | ||
risk_value: Optional[RuleRisk] = None | ||
filters: List[Filter] = [] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
Allows to overwrite the default behaviour of the rule, such as changing the rule mode and risk value. It accepts a more | ||
granular configuration using the filter. | ||
|
||
{{ inline_source('cfripper.config.rule_config.RuleConfig') }} | ||
|
||
## Filters | ||
|
||
When adding a failure or warning it will check if there is a filter that matches the current context and set the new | ||
risk or mode. Context depends on each rule and is available inside each rule's documentation. | ||
The object accepts a reason parameter to say why that filter exists. | ||
|
||
{{ inline_source('cfripper.config.filter.Filter') }} | ||
|
||
!!! warning | ||
Only available for the following rules: | ||
|
||
- Not supported yet | ||
|
||
### Filter preference | ||
|
||
Following the cascade style, takes preference always the last value set following this structure: | ||
|
||
``` | ||
Rule Standard -> Rule Config -> Filter #1 -> ... -> Filter #N | ||
``` | ||
|
||
|
||
### Implemented filter functions | ||
| Function | Description | Example | | ||
|:----------:|:---------------------------------------------------------------------------:|:---------------------------------------:| | ||
| `eq` | Same as a == b | `{"eq": ["string", "string"]}` | | ||
| `ne` | Same as a != b | `{"ne": ["string", "not_that_string"]}` | | ||
| `lt` | Same as a < b | `{"lt": [0, 1]}` | | ||
| `gt` | Same as a > b | `{"gt": [1, 0]}` | | ||
| `le` | Same as a <= b | `{"le": [1, 1]}` | | ||
| `ge` | Same as a >= b | `{"ge": [1, 1]}` | | ||
| `not` | Same as not a | `{"not": True}` | | ||
| `or` | True if any arg is True | `{"or": [False, True]}` | | ||
| `and` | True if all args are True | `{"and": [True, True]}` | | ||
| `in` | Same as a in b | `{"in": ["b", ["a", "b"]]}` | | ||
| `regex` | True if b match pattern a | `{"regex": [r"^\d+$", "5"]}` | | ||
| `ref` | Get the value at any depth of the context based on the path described by a. | `{"ref": "param_a.param_b"}` | | ||
|
||
### Examples | ||
|
||
Disable the rule if the role name is prefixed with `sandbox-` and the principal equals `arn:aws:iam::123456789012:role/test-role`. | ||
```python3 | ||
Filter( | ||
reason="", | ||
rule_mode=RuleMode.DISABLED, | ||
eval={ | ||
"and": [ | ||
{"regex": ["^sandbox-.*$", {"ref": "resource.Properties.RoleName"}]}, | ||
{"eq": [{"ref": "principal"}, "arn:aws:iam::123456789012:role/test-role"]}, | ||
] | ||
}, | ||
) | ||
``` | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.