Coverage for turvallisuusneuvonta/csaf/core/rules/mandatory/mandatory.py: 94.77%
96 statements
« prev ^ index » next coverage.py v7.4.1, created at 2024-02-05 19:27:17 +00:00
« prev ^ index » next coverage.py v7.4.1, created at 2024-02-05 19:27:17 +00:00
1from typing import Dict, List, Tuple, no_type_check
3import jmespath
5# import turvallisuusneuvonta.csaf.core.rules.mandatory.acyclic_product_ids as acy_product_ids
6# import turvallisuusneuvonta.csaf.core.rules.mandatory.consistent_product_status as con_pro_sta
7import turvallisuusneuvonta.csaf.core.rules.mandatory.defined_group_ids as def_gro_ids
8import turvallisuusneuvonta.csaf.core.rules.mandatory.defined_product_ids as def_pro_ids
9import turvallisuusneuvonta.csaf.core.rules.mandatory.translator_and_source_lang as tra_and_sou_lan
10import turvallisuusneuvonta.csaf.core.rules.mandatory.unique_group_ids as uni_gro_ids
11import turvallisuusneuvonta.csaf.core.rules.mandatory.unique_product_ids as uni_pro_ids
12import turvallisuusneuvonta.csaf.core.rules.mandatory.valid_category_name as val_cat_nam
15@no_type_check
16def guess_max_depth(map_or_seq):
17 """HACK A DID ACK - please delete me when cleaning up."""
18 if isinstance(map_or_seq, dict): 18 ↛ 19line 18 didn't jump to line 19, because the condition on line 18 was never true
19 return 1 + max(map(guess_max_depth, map_or_seq.values()), default=0)
20 elif isinstance(map_or_seq, list): 20 ↛ 21line 20 didn't jump to line 21, because the condition on line 20 was never true
21 return 1 + max(map(guess_max_depth, map_or_seq[0].values()), default=0)
22 return 0
25@no_type_check
26def is_valid(document: dict) -> bool:
27 """Complete validation of all mandatory rules.
29 This is a spike - we throw it away when all rules are in and back comes something maintainable.
30 """
31 if not is_valid_category(document):
32 return False
34 if jmespath.search(tra_and_sou_lan.TRIGGER_JMES_PATH, document) == tra_and_sou_lan.TRIGGER_VALUE:
35 if not is_valid_translator(document):
36 return False
38 if not is_valid_unique_product_ids(document):
39 return False
41 if not is_valid_unique_group_ids(document):
42 return False
44 if not is_valid_defined_product_ids(document):
45 return False
47 if not is_valid_defined_group_ids(document):
48 return False
50 return NotImplemented
53@no_type_check
54def is_valid_unique_product_ids(document: dict) -> bool:
55 """Temporary implementation of rule for unique product ids."""
56 prod_ids = []
57 for path in uni_pro_ids.CONDITION_JMES_PATHS:
58 pids = jmespath.search(path, document)
59 if pids is not None:
60 prod_ids.extend(pids)
61 probe = jmespath.search('product_tree.branches[]', document)
62 trials = guess_max_depth(probe) + 1
63 ipath = 'product_tree.branches[].product.product_id'
64 inject = 'branches[].product.'
65 for trial in range(trials):
66 harvest = jmespath.search(ipath, document)
67 if harvest: 67 ↛ 68line 67 didn't jump to line 68, because the condition on line 67 was never true
68 prod_ids.extend(harvest)
69 ipath = ipath.replace('product.', inject)
70 if len(prod_ids) > len(set(prod_ids)):
71 return False
73 return True
76@no_type_check
77def is_valid_unique_group_ids(document: dict) -> bool:
78 """Temporary implementation of rule for unique group ids."""
79 group_ids = jmespath.search(uni_gro_ids.CONDITION_JMES_PATH, document)
80 if group_ids is not None:
81 if len(group_ids) > len(set(group_ids)):
82 return False
84 return True
87@no_type_check
88def is_valid_defined_product_ids(document: dict) -> bool:
89 """Temporary implementation of rule for defined product ids."""
90 defined_prod_ids = jmespath.search(def_pro_ids.TRIGGER_JMES_PATH, document)
91 if defined_prod_ids is None:
92 defined_prod_ids = []
93 known_prod_ids = set(defined_prod_ids)
94 for path in def_pro_ids.CONDITION_JMES_PATHS:
95 claim_prod_ids = jmespath.search(path, document)
96 if claim_prod_ids is not None:
97 if any(claim_prod_id not in known_prod_ids for claim_prod_id in claim_prod_ids):
98 return False
100 return True
103@no_type_check
104def is_valid_defined_group_ids(document: dict) -> bool:
105 """Temporary implementation of rule for defined group ids."""
106 defined_group_ids = jmespath.search(def_gro_ids.TRIGGER_JMES_PATH, document)
107 if defined_group_ids is None: 107 ↛ 109line 107 didn't jump to line 109, because the condition on line 107 was never false
108 defined_group_ids = []
109 known_group_ids = set(defined_group_ids)
110 for path in def_gro_ids.CONDITION_JMES_PATHS:
111 claim_group_ids = jmespath.search(path, document)
112 if claim_group_ids is not None:
113 if any(claim_group_id not in known_group_ids for cl_seq in claim_group_ids for claim_group_id in cl_seq):
114 return False
116 return True
119@no_type_check
120def exists(document: dict, claims: Dict[str, List[str]]) -> Tuple[Tuple[str, str, bool]]:
121 """Verify the existence and return tuple of triplets with claim, path and result."""
122 return tuple(
123 (claim, path, bool(jmespath.search(path, document))) for claim, paths in claims.items() for path in paths
124 )
127@no_type_check
128def must_skip(document: dict, path: str, skip_these: Tuple[str, ...]) -> Tuple[str, str, bool]:
129 """Verify any skips and return tuple of triplets with claim, path and result."""
130 value = jmespath.search(path, document)
131 return value, path, any(value == skip for skip in skip_these)
134@no_type_check
135def is_valid_category(document: dict) -> bool:
136 """Verify category value."""
137 return val_cat_nam.is_valid(jmespath.search(val_cat_nam.CONDITION_JMES_PATH, document))
140@no_type_check
141def is_valid_translator(document: dict) -> bool:
142 """Verify source_lang value is present for translator."""
143 if jmespath.search(tra_and_sou_lan.TRIGGER_JMES_PATH, document) != tra_and_sou_lan.TRIGGER_VALUE: 143 ↛ 144line 143 didn't jump to line 144, because the condition on line 143 was never true
144 return False
145 return bool(jmespath.search(tra_and_sou_lan.CONDITION_JMES_PATH, document))