-
Notifications
You must be signed in to change notification settings - Fork 9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve OVAL test info #126
Conversation
ab3abc8
to
9d8aa34
Compare
9d8aa34
to
65c32ec
Compare
65c32ec
to
fcf41f2
Compare
There is a conflict. Can you please rebase the PR? |
da9abf6
to
f918805
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
General feedback: it would be better to put some hints to the PR description for the reviewer regarding what the reviewer should focus on.
def _collected_object_is_not_none_and_contain_var_ref(element, collected_object): | ||
return collected_object is not None and 'var_ref' in element.attrib | ||
|
||
def _get_ref_var(self, element, xml_collected_object): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can make the code in this method nicer by reversing the condition and returning 'no_value' right after the "if" statement.
import uuid | ||
|
||
|
||
class SharedStaticMethodsOfParser: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we strongly need unit tests, and these methos would be a nice start with unit testing
operation = element.get("operation") | ||
if operation is not None: | ||
out.append(("operation", operation)) | ||
return [SharedStaticMethodsOfParser.transform_tuples_to_dict(out)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the benefit of creating a list of tuples and then converting it to a dict instead of creating a dictionary from the beginning? It isn't obvious. It would be great to have a better naming or a comment so that the things would become more clear.
div.appendChild(get_label("", test_info.test_id)); | ||
div.appendChild(get_label("pf-m-blue", test_info.comment)); | ||
if (test_info.check) { | ||
div.appendChild(get_label("pf-m-cyan", `Check atribute: ${test_info.check}`)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's nice that it shows now the value of the check
and check_existence
attributes. But I'm afraid that no user except from the content authors know what this means. It would be better to show also the meaning of that attribute.
It can, for example check_existence="none_exist"
, say: This check requires that no such object can exist on the system.
You can find the possible values and their meaning in the OVAL specification. The report generate could translat attributus values to some helpful text.
const div = DIV.cloneNode(); | ||
div.className = "pf-c-accordion__expanded-content-body"; | ||
div.appendChild(get_label("", test_info.test_id)); | ||
div.appendChild(get_label("pf-m-blue", test_info.comment)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment becames a tooltip also for the check and check_existence rectangles. I don't think that it's useful to repeat it over and over. I think they could have a different tool tip, maybe related to the maining of the elements (see also the comment below).
b8ff2aa
to
8738eea
Compare
@Honny1 If you do some changes you need to summarize them in a comment in the PR so that the visitors know what changed. |
8738eea
to
1a05a3d
Compare
@jan-cerny Okay. Changes:
|
"all": "collect all values", | ||
"at least one": "collect at least one value", | ||
"none exist": "not collect any of the values", | ||
"none satisfy": "not collect any of the values", | ||
"only one": "collect only one of the values" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find this very confusing. The point of the "check" attribute isn't the data collection process. It defines the relationship between objects and states. The value of the check attribute defines how many of the collected objects must satisfy the given state for the test to return true.
Please read the CheckEnumeration type definition in the OVAL common schema.
"only one": "collect only one of the values" | ||
}; | ||
const CHECK_EXISTENCE_ATTRIBUTE_TO_TEXT = { | ||
"all_exist": "The test requires that all distinct groups of information as defined by the OVAL object exist in the endpoint in order for the OVAL test to evaluate to \"true\".", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find this too complex and difficult to understand. I like the definition in the specification more than this. Try to make it more clear. For example "all distinct groups of information as defined by the OVAL object" can be simplified to "objects defined by the test".
oval_object = self.objects_parser.get_object(object_id) | ||
state_id = item.attrib.get("state_ref") | ||
if state_id is not None: | ||
oval_state = self.states_parser.get_state(state_id) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know the details but I'm curious: Why is this a loop? In each iteration it overwrites the oval_object and oval_state. Wouldn't it be better to just pick the last item? And why is the self.tests[test_id]
an iterable? Does that mean that there are more tests with the same ID?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, you are right. This for loop is useless. The value contained in self.tests
is a dictionary where the key is test_id and the value is an XML element. This loop is used to iterate through the children of the test XML element to get objects and states with a different namespaces. I will simplify this code to make it more readable and replace the unnecessary loop with xPath.
1a05a3d
to
a589abc
Compare
Changes:
|
out[id_in_dict] = self._get_ref_var(element, xml_collected_object) | ||
return [out] | ||
|
||
def _get_item(self, item_ref): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find the name confusing, instead of "item" it returns some dictionary
out
is almost never a good name for anything
out[id_in_dict] = element.text | ||
else: | ||
out[id_in_dict] = self._get_ref_var(element, xml_collected_object) | ||
return [out] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does this function return a list that contains a single item and that is a dictionary? That sounds suspicious and is a sign of a bad design. Please investigate this. If you really need this wrapping to a list it probably should be done one level of abstaraction above.
Also I suggest giving the variable a different name than out
. Think what it actually contains and give it a descriptive name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This wrapping is caused by extending the abstraction of the OVAL objects. The OVAL object class has an oval_data attribute that stores a list that contains dictionaries of attributes and values. These dictionaries are stored in a list because they are used to populate more instances of objects that have been collected. In this case, the usual object approach has been changed to be more capable of using different types of OVAL objects and storing multiple instances of OVAL objects.
var_id = element.get('var_ref') | ||
for item in xml_collected_object: | ||
if var_id == item.get('variable_id'): | ||
variable_value += item.text |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
More pythonic way of doing this would be to collect these in a list and after that merge the items in the list using .join()
method.
operation = element.get("operation") | ||
if operation is not None: | ||
out["operation"] = operation | ||
return [out] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this method has also similar understandability problems as the other similar methods - return value is a list that contains a single item which is a dict that has a generic name
a589abc
to
dc069a1
Compare
dc069a1
to
3867e0f
Compare
Changes:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have generated a report for a fedora scan and I have checked the chekd and check_existence boxes in multiple rules and triggered their tooltips.
Great job!
This PR adds: