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

1from typing import Dict, List, Tuple, no_type_check 

2 

3import jmespath 

4 

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 

13 

14 

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 

23 

24 

25@no_type_check 

26def is_valid(document: dict) -> bool: 

27 """Complete validation of all mandatory rules. 

28 

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 

33 

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 

37 

38 if not is_valid_unique_product_ids(document): 

39 return False 

40 

41 if not is_valid_unique_group_ids(document): 

42 return False 

43 

44 if not is_valid_defined_product_ids(document): 

45 return False 

46 

47 if not is_valid_defined_group_ids(document): 

48 return False 

49 

50 return NotImplemented 

51 

52 

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 

72 

73 return True 

74 

75 

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 

83 

84 return True 

85 

86 

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 

99 

100 return True 

101 

102 

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 

115 

116 return True 

117 

118 

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 ) 

125 

126 

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) 

132 

133 

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)) 

138 

139 

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))