Conditions | 26 |
Total Lines | 146 |
Code Lines | 101 |
Lines | 0 |
Ratio | 0 % |
Changes | 0 |
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
Complex classes like transform_benchmark_to_pcidss.main() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
1 | #!/usr/bin/env python2 |
||
80 | def main(): |
||
81 | logging.basicConfig(format='%(levelname)s:%(message)s', |
||
82 | level=logging.DEBUG) |
||
83 | |||
84 | if len(sys.argv) < 4: |
||
85 | sys.stderr.write("transform_benchmark_to_pcidss.py PCI_DSS.json " |
||
86 | "SOURCE_XCCDF DESTINATION_XCCDF\n") |
||
87 | sys.exit(1) |
||
88 | |||
89 | id_tree = None |
||
90 | with open(sys.argv[1], "r") as f: |
||
91 | id_tree = json.load(f) |
||
92 | |||
93 | benchmark = ElementTree.parse(sys.argv[2]) |
||
94 | |||
95 | rules = [] |
||
96 | for rule in \ |
||
97 | benchmark.findall(".//{%s}Rule" % (XCCDF_NAMESPACE)): |
||
98 | rules.append(rule) |
||
99 | rule_usage_map = {} |
||
100 | |||
101 | # only PCI-DSS related rules in that list, to speed-up processing |
||
102 | filtered_rules = [] |
||
103 | for rule in rules: |
||
104 | for ref in rule.findall("./{%s}reference" % (XCCDF_NAMESPACE)): |
||
105 | if ref.get("href") == REMOTE_URL: |
||
106 | filtered_rules.append(rule) |
||
107 | break |
||
108 | |||
109 | values = [] |
||
110 | for value in \ |
||
111 | benchmark.findall(".//{%s}Value" % (XCCDF_NAMESPACE)): |
||
112 | values.append(value) |
||
113 | |||
114 | # decide on usage of .iter or .getiterator method of elementtree class. |
||
115 | # getiterator is deprecated in Python 3.9, but iter is not available in |
||
116 | # older versions |
||
117 | if getattr(benchmark, "iter", None) == None: |
||
118 | parent_map = dict((c, p) for p in benchmark.getiterator() for c in p) |
||
119 | else: |
||
120 | parent_map = dict((c, p) for p in benchmark.iter() for c in p) |
||
121 | for rule in \ |
||
122 | benchmark.findall(".//{%s}Rule" % (XCCDF_NAMESPACE)): |
||
123 | parent_map[rule].remove(rule) |
||
124 | for value in \ |
||
125 | benchmark.findall(".//{%s}Value" % (XCCDF_NAMESPACE)): |
||
126 | parent_map[value].remove(value) |
||
127 | for group in \ |
||
128 | benchmark.findall(".//{%s}Group" % (XCCDF_NAMESPACE)): |
||
129 | parent_map[group].remove(group) |
||
130 | |||
131 | root_element = benchmark.getroot() |
||
132 | for id_, desc, children in id_tree: |
||
133 | element = \ |
||
134 | construct_xccdf_group(id_, desc, children, |
||
135 | filtered_rules, rule_usage_map) |
||
136 | root_element.append(element) |
||
137 | |||
138 | if len(values) > 0: |
||
139 | group = ElementTree.Element("{%s}Group" % (XCCDF_NAMESPACE)) |
||
140 | group.set("id", ssg.constants.OSCAP_GROUP_VAL) |
||
141 | group.set("selected", "true") |
||
142 | title = ElementTree.Element("{%s}title" % (XCCDF_NAMESPACE)) |
||
143 | title.text = "Values" |
||
144 | group.append(title) |
||
145 | description = ElementTree.Element("{%s}description" % (XCCDF_NAMESPACE)) |
||
146 | description.text = "Group of values used in PCI-DSS profile" |
||
147 | group.append(description) |
||
148 | |||
149 | for value in values: |
||
150 | copied_value = copy.deepcopy(value) |
||
151 | group.append(copied_value) |
||
152 | |||
153 | root_element.append(group) |
||
154 | |||
155 | unused_rules = [] |
||
156 | for rule in rules: |
||
157 | if rule.get("id") not in rule_usage_map: |
||
158 | # this rule wasn't added yet, it would be lost unless we added it |
||
159 | # to a special non-PCI-DSS group |
||
160 | unused_rules.append(rule) |
||
161 | |||
162 | for ref in rule.findall("./{%s}reference" % (XCCDF_NAMESPACE)): |
||
163 | if ref.get("href") == REMOTE_URL: |
||
164 | logging.error( |
||
165 | "Rule '%s' references PCI-DSS '%s' but doesn't match " |
||
166 | "any Group ID in our requirement tree. Perhaps it's " |
||
167 | "referencing something we don't consider applicable on " |
||
168 | "the Operating System level?", |
||
169 | rule.get("id"), ref.text |
||
170 | ) |
||
171 | sys.exit(1) |
||
172 | |||
173 | if len(unused_rules) > 0: |
||
174 | logging.warning( |
||
175 | "%i rules don't reference PCI-DSS!" % (len(unused_rules)) |
||
176 | ) |
||
177 | |||
178 | group = ElementTree.Element("{%s}Group" % (XCCDF_NAMESPACE)) |
||
179 | group.set("id", ssg.constants.OSCAP_GROUP_NON_PCI) |
||
180 | group.set("selected", "true") |
||
181 | title = ElementTree.Element("{%s}title" % (XCCDF_NAMESPACE)) |
||
182 | title.text = "Non PCI-DSS" |
||
183 | group.append(title) |
||
184 | description = ElementTree.Element("{%s}description" % (XCCDF_NAMESPACE)) |
||
185 | description.text = "Rules that are not part of PCI-DSS" |
||
186 | group.append(description) |
||
187 | |||
188 | for rule in unused_rules: |
||
189 | copied_rule = copy.deepcopy(rule) |
||
190 | group.append(copied_rule) |
||
191 | |||
192 | root_element.append(group) |
||
193 | |||
194 | # change the Benchmark ID to avoid validation issues |
||
195 | root_element.set( |
||
196 | "id", |
||
197 | root_element.get("id").replace("_benchmark_", "_benchmark_PCIDSS-") |
||
198 | ) |
||
199 | |||
200 | for title_element in \ |
||
201 | root_element.findall("./{%s}title" % (XCCDF_NAMESPACE)): |
||
202 | title_element.text += " (PCI-DSS centric)" |
||
203 | |||
204 | # filter out all profiles except PCI-DSS |
||
205 | for profile in \ |
||
206 | benchmark.findall("./{%s}Profile" % (XCCDF_NAMESPACE)): |
||
207 | if profile.get("id").endswith("pci-dss"): |
||
208 | # change the profile ID to avoid validation issues |
||
209 | profile.set( |
||
210 | "id", |
||
211 | profile.get("id").replace("pci-dss", "pci-dss_centric") |
||
212 | ) |
||
213 | else: |
||
214 | root_element.remove(profile) |
||
215 | continue |
||
216 | |||
217 | # filter out old group selectors from the PCI-DSS profile |
||
218 | for select in profile.findall("./{%s}select" % (XCCDF_NAMESPACE)): |
||
219 | if select.get("idref").startswith(ssg.constants.OSCAP_GROUP): |
||
220 | # we will remove all group selectors, all PCI-DSS groups are |
||
221 | # selected by default so we don't need any in the final |
||
222 | # PCI-DSS Benchmark |
||
223 | profile.remove(select) |
||
224 | |||
225 | benchmark.write(sys.argv[3]) |
||
226 | |||
229 |