forked from RedHatProductSecurity/osidb
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathchecks.py
116 lines (92 loc) · 3.37 KB
/
checks.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
"""
OSIM entity requirement check definition
"""
import inspect
from .exceptions import WorkflowDefinitionError
class MetaCheckParser(type):
"""
meta-class to define class property to emultate class constant
this dance happens because of the hard-to-prevent cycle we have in the dependencies
Flaw is based on WorkflowModel which uses WorkflowFramework which contains
Workflow model which contains Check which calls CheckParser which would like to have
model class constant - at least for now - containing Flaw class
"""
@property
def model(cls):
"""model class property"""
# import here to prevent cycle
from osidb.models import Flaw
# constant model for now
# generalize when needed
return Flaw
class CheckParser(metaclass=MetaCheckParser):
"""check description parser"""
ATTRIBUTE_MAP = {
"major_incident": "is_major_incident",
"cve": "cve_id",
"cwe": "cwe_id",
}
@classmethod
def map_attribute(cls, attr):
"""maps from external to internal attribute names"""
if attr in cls.ATTRIBUTE_MAP:
return cls.ATTRIBUTE_MAP[attr]
return attr
@classmethod
def parse(cls, check_desc):
"""
based on the textual check description tries to find a corresponding implementation
returns:
(check implementation doc text, check implementation)
or None if no corresponding implementation
"""
check_desc = check_desc.lower().replace(" ", "_")
for func in [
cls.desc2property,
cls.desc2not_property,
cls.decs2non_empty,
]:
result = func(check_desc)
if result is not None:
return result
raise WorkflowDefinitionError(
f"Unknown or incorrect check definition: {check_desc}"
)
@classmethod
def desc2property(cls, check_desc):
"""native property check"""
check_desc = cls.map_attribute(check_desc)
if hasattr(cls.model, check_desc):
func = getattr(cls.model, check_desc)
return (
inspect.getdoc(func),
lambda instance: getattr(instance, check_desc),
)
@classmethod
def desc2not_property(cls, check_desc):
"""negative native property check"""
if check_desc.startswith("not_"):
attr = cls.map_attribute(check_desc[4:])
result = cls.desc2property(attr)
if result is not None:
doc, func = result
return (
f"negative of: {doc}",
lambda instance: not func(instance),
)
@classmethod
def decs2non_empty(cls, check_desc):
"""attribute non-emptiness check"""
if check_desc.startswith("has_"):
attr = cls.map_attribute(check_desc[4:])
if hasattr(cls.model, attr):
message = (
f"check that {cls.model.__name__} attribute {attr} has a value set"
)
# TODO: Create "empty" check helper which would check emptiness based
# on a field type
EMPTY_VALUES = [None, ""]
return (
message,
lambda instance: getattr(instance, attr) not in EMPTY_VALUES,
)