Skip to content
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

Show most used rules of component #12001

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions build-scripts/profile_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,15 @@ def parse_most_used_components(subparsers):
choices=get_available_products_with_components_root(),
default=get_available_products_with_components_root(),
)
parser_most_used_components.add_argument(
"--used-rules",
default=False,
action="store_true",
help=(
"For every component, show the usage of each component's rule "
"in the profiles in given product."
),
)


def get_available_products_with_components_root():
Expand Down
7 changes: 7 additions & 0 deletions docs/manual/developer/05_tools_and_utilities.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,13 @@ Optionally, you can use this command to limit the statistics for a specific prod
$ ./build-scripts/profile_tool.py most-used-components --products rhel9
```

You can also get a list of the most used components with used rules for the RHEL9 product, you can use the `--used-rules` flag.
As shown in this command:

```bash
$ ./build-scripts/profile_tool.py most-used-components --products rhel9 --used-rules
```

The result will be a list of rules with the number of uses in the profiles.
The list can be generated as plain text, JSON or CVS.
Via the `--format FORMAT` parameter.
Expand Down
16 changes: 16 additions & 0 deletions utils/profile_tool/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,19 @@ def generate_output(dict_, format, csv_header):

for rule_id, rule_count in dict_.items():
print(f_string.format(rule_id, rule_count))


def _format_value_b(value_b, delim):
str_ = ""
if len(value_b) != 0:
values = ", ".join([f"{key}: {value}" for key, value in value_b.items()])
str_ = f"{delim}{values}"
return str_


def merge_dicts(dict_a, dict_b, delim):
out = {}
for key, value in dict_a.items():
value_b = dict_b.get(key, {})
out[key] = str(value) + _format_value_b(value_b, delim)
return out
41 changes: 35 additions & 6 deletions utils/profile_tool/most_used_components.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import ssg.components

from .most_used_rules import _sorted_dict_by_num_value
from .common import generate_output
from .common import generate_output, merge_dicts

PYTHON_2 = sys.version_info[0] < 3

Expand All @@ -17,10 +17,21 @@
)


def _count_components(components, rules_list, components_out):
def _count_rules_components(component_name, rules, used_rules_of_components_out):
used_rules = defaultdict(int)
if component_name in used_rules_of_components_out:
used_rules = used_rules_of_components_out[component_name]
for rule in rules:
used_rules[rule] += 1
used_rules_of_components_out[component_name] = used_rules


def _count_components(components, rules_list, components_out, used_rules_of_components_out):
for component_name, component in components.items():
if len(set(component.rules).intersection(set(rules_list))) > 0:
intersection = set(component.rules).intersection(set(rules_list))
if len(intersection) > 0:
components_out[component_name] += 1
_count_rules_components(component_name, intersection, used_rules_of_components_out)


def load_components(product):
Expand All @@ -33,7 +44,7 @@ def load_components(product):
return ssg.components.load(components_dir)


def _process_all_products_from_controls(components_out, products):
def _process_all_products_from_controls(components_out, used_rules_of_components_out, products):
if PYTHON_2:
raise Exception("This feature is not supported for python2.")

Expand All @@ -43,14 +54,32 @@ def _process_all_products_from_controls(components_out, products):
continue
controls_manager = load_controls_manager("./controls/", product)
for profile in _get_profiles_for_product(controls_manager, product):
_count_components(components, profile.rules, components_out)
_count_components(
components, profile.rules, components_out, used_rules_of_components_out
)


def _sort_rules_of_components(used_rules_of_components):
out = {}
for key, value in used_rules_of_components.items():
out[key] = _sorted_dict_by_num_value(value)
return out


def command_most_used_components(args):
components = defaultdict(int)
used_rules_of_components = {}

_process_all_products_from_controls(components, args.products)
_process_all_products_from_controls(components, used_rules_of_components, args.products)

sorted_components = _sorted_dict_by_num_value(components)
csv_header = "component_name,count_of_profiles"
if args.used_rules:
csv_header = "component_name,count_of_profiles,used_rules:count_of_profiles"
delim = " "
if args.format == "csv":
delim = ","
sorted_used_rules_of_components = _sort_rules_of_components(used_rules_of_components)
sorted_components = merge_dicts(sorted_components, sorted_used_rules_of_components, delim)

generate_output(sorted_components, args.format, csv_header)
3 changes: 2 additions & 1 deletion utils/profile_tool/most_used_rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ def _get_profiles_for_product(ctrls_mgr, product):

profiles = []
for file in profiles_files:
profiles.append(get_profile(profiles_files, file, ctrls_mgr.policies))
if "default.profile" not in file:
profiles.append(get_profile(profiles_files, file, ctrls_mgr.policies))
return profiles


Expand Down
10 changes: 7 additions & 3 deletions utils/profile_tool/profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,14 @@ def _get_sel(selected):
return policy, control, level

@staticmethod
def _get_levels(policy, level):
levels = [level]
def _get_levels(policy, level, levels=None):
if levels is None:
levels = set()
levels.add(level)

if policy.levels_by_id.get(level).inherits_from is not None:
levels.extend(policy.levels_by_id.get(level).inherits_from)
for parent_level in policy.levels_by_id.get(level).inherits_from:
levels.update(Profile._get_levels(policy, parent_level, levels))
return levels

def add_from_policy(self, policies, selected):
Expand Down
Loading