From 6d2b34c15e8259cc1c3a4e9639b83bacca37ee08 Mon Sep 17 00:00:00 2001 From: Evgeny Kolesnikov Date: Tue, 30 Jan 2024 13:06:41 +0100 Subject: [PATCH 1/4] Remove all references to prodtype (Code and Tests) --- controls/pcidss_4.yml | 8 +- shared/macros/10-oval.jinja | 8 +- shared/schemas/rule.json | 1 - ssg/build_ovals.py | 4 +- ssg/build_sce.py | 9 +- ssg/build_yaml.py | 42 +--- ssg/entities/profile.py | 1 - ssg/fixes.py | 9 +- ssg/jinja.py | 8 +- ssg/rule_dir_stats.py | 50 ----- ssg/rule_yaml.py | 8 - ssg/utils.py | 25 ++- tests/ssg_test_suite/common.py | 9 +- tests/ssg_test_suite/rule.py | 11 - tests/unit/ssg-module/data/accounts_tmout.yml | 1 - .../data/accounts_tmout_without_ocil.yml | 1 - .../ssg-module/data/file_owner_grub2_cfg.yml | 1 - tests/unit/ssg-module/data/selinux.yml | 1 - .../data/sshd_disable_root_login.yml | 1 - .../guide/configure_crypto_policy/rule.yml | 2 - .../guide/package_abrt_removed/rule.yml | 2 - .../rules/selinux_state.yml | 1 - tests/unit/ssg-module/test_rule_dir_stats.py | 71 ------- .../data/rule_reference_fail/rule_1/rule.yml | 2 - .../data/rule_reference_fail/rule_2/rule.yml | 2 - .../data/rule_reference_pass/rule_1/rule.yml | 2 - .../data/rule_reference_pass/rule_2/rule.yml | 2 - .../test_application/rule_1/rule.yml | 2 - .../test_application/rule_2/rule.yml | 2 - utils/autoprodtyper.py | 85 -------- utils/convert_prodtype_ds_check.py | 72 ------- ...ert_prodtype_into_default_profile_entry.py | 195 ------------------ utils/convert_prodtype_remove_prodtype.sh | 14 -- utils/fix_rules.py | 37 +--- utils/gen_srg_table.py | 2 +- utils/generate_profile.py | 8 +- utils/mod_checks.py | 4 +- utils/mod_fixes.py | 4 +- utils/mod_prodtype.py | 195 ------------------ utils/rule_dir_json.py | 3 +- 40 files changed, 52 insertions(+), 853 deletions(-) delete mode 100755 utils/autoprodtyper.py delete mode 100755 utils/convert_prodtype_ds_check.py delete mode 100755 utils/convert_prodtype_into_default_profile_entry.py delete mode 100755 utils/convert_prodtype_remove_prodtype.sh delete mode 100755 utils/mod_prodtype.py diff --git a/controls/pcidss_4.yml b/controls/pcidss_4.yml index 0936fe93453..eb942fe1100 100644 --- a/controls/pcidss_4.yml +++ b/controls/pcidss_4.yml @@ -845,7 +845,7 @@ controls: title: When using remote-access technologies, technical controls prevent copy and/or relocation of PAN for all personnel, except for those with documented, explicit authorization and a legitimate, defined business need. - description: |- + description: |- PAN cannot be copied or relocated by unauthorized personnel using remote-access technologies. Storing or relocating PAN onto local hard drives, removable electronic media, and other storage devices brings these devices into scope for PCI DSS. @@ -2053,7 +2053,7 @@ controls: - accounts_passwords_pam_tally2_unlock_time - var_accounts_passwords_pam_tally2_unlock_time=1800 - cracklib_accounts_password_pam_retry - + - id: 8.3.5 title: If passwords/passphrases are used as authentication factors to meet Requirement 8.3.1, they are set and reset for each user. @@ -3004,8 +3004,8 @@ controls: - base status: automated notes: |- - The selected rules might need updates in order to restrict their applicabilities or their - prodtypes to avoid conflicts. + The selected rules might need updates in order to restrict their platform applicability + to avoid conflicts. rules: # specific products should update the variable value when defining the profile based on # this control file. diff --git a/shared/macros/10-oval.jinja b/shared/macros/10-oval.jinja index a3ef9910a09..63eb602caa5 100644 --- a/shared/macros/10-oval.jinja +++ b/shared/macros/10-oval.jinja @@ -7,7 +7,7 @@ Generates the :code:`` tag for OVAL check using correct product platfo #}} {{%- macro oval_affected(products) %}} -{{{ prodtype_to_platform(products)|indent(2) }}} +{{{ product_to_platform(products)|indent(2) }}} {{%- endmacro %}} @@ -132,7 +132,7 @@ Generates the :code:`` tag for OVAL check using correct product platfo {{{ oval_metadata("Ensure '" + parameter + "' is configured with value '" + value | replace("(?i)", "") | replace("(?-i)", "") + (" in section '" + section if section else "") + "' in " + path) }}} - {{% set dir_path = path + ".d" %}} + {{% set dir_path = path + ".d" %}} {{{- oval_line_in_file_criterion(path, parameter) }}} @@ -1057,9 +1057,9 @@ Generates the :code:`` tag for OVAL check using correct product platfo {{% if product in ['opensuse', 'sle12','sle15'] %}} - - {{% else %}} + {{% else %}} {{% endif %}} diff --git a/shared/schemas/rule.json b/shared/schemas/rule.json index 7214e728a6d..e5b1a930532 100644 --- a/shared/schemas/rule.json +++ b/shared/schemas/rule.json @@ -84,7 +84,6 @@ "required": [ "documentation_complete", "title", - "prodtype", "description", "rationale", "severity" diff --git a/ssg/build_ovals.py b/ssg/build_ovals.py index ba556bbd4b0..3853ac580c2 100644 --- a/ssg/build_ovals.py +++ b/ssg/build_ovals.py @@ -6,7 +6,6 @@ from .oval_object_model import OVALDocument from .build_yaml import Rule, DocumentationNotComplete from .jinja import process_file_with_macros -from .rule_yaml import parse_prodtype from .id_translate import IDTranslator from .xml import ElementTree @@ -117,8 +116,7 @@ def _get_context(self, directory, from_benchmark): local_env_yaml = dict(**self.env_yaml) local_env_yaml["rule_id"] = rule.id_ local_env_yaml["rule_title"] = rule.title - prodtypes = parse_prodtype(rule.prodtype) - local_env_yaml["products"] = prodtypes # default is all + local_env_yaml["products"] = {self.product} return local_env_yaml return self.env_yaml diff --git a/ssg/build_sce.py b/ssg/build_sce.py index 80f3c7ed096..d4cbdb4a509 100644 --- a/ssg/build_sce.py +++ b/ssg/build_sce.py @@ -11,7 +11,6 @@ xlink_namespace, XCCDF12_NS, SCE_SYSTEM ) from .jinja import process_file_with_macros -from .rule_yaml import parse_prodtype from .rules import get_rule_dir_id, get_rule_dir_sces, find_rule_dirs_in_paths from . import utils, products @@ -134,15 +133,9 @@ def checks(env_yaml, yaml_path, sce_dirs, template_builder, output): # and move on. continue - prodtypes = parse_prodtype(rule.prodtype) - if prodtypes and 'all' not in prodtypes and product not in prodtypes: - # The prodtype exists, isn't all and doesn't contain this current - # product, so we're best to skip this rule altogether. - continue - local_env_yaml['rule_id'] = rule.id_ local_env_yaml['rule_title'] = rule.title - local_env_yaml['products'] = prodtypes # default is all + local_env_yaml["products"] = {product} for _path in get_rule_dir_sces(_dir_path, product): # To be compatible with later checks, use the rule_id (i.e., the diff --git a/ssg/build_yaml.py b/ssg/build_yaml.py index c9f040d3b50..2eee61b6959 100644 --- a/ssg/build_yaml.py +++ b/ssg/build_yaml.py @@ -36,7 +36,6 @@ FIX_TYPE_TO_SYSTEM ) from .rules import get_rule_dir_yaml, is_rule_dir -from .rule_yaml import parse_prodtype from .cce import is_cce_format_valid, is_cce_value_valid from .yaml import DocumentationNotComplete, open_and_macro_expand @@ -461,7 +460,6 @@ class Group(XCCDFEntity): GENERIC_FILENAME = "group.yml" KEYS = dict( - prodtype=lambda: "all", description=lambda: "", warnings=lambda: list(), requires=lambda: list(), @@ -682,7 +680,6 @@ class Rule(XCCDFEntity, Templatable): """Represents XCCDF Rule """ KEYS = dict( - prodtype=lambda: "all", description=lambda: "", rationale=lambda: "", severity=lambda: "", @@ -741,22 +738,16 @@ def __deepcopy__(self, memo): return result @staticmethod - def _has_platforms_to_convert(env_yaml, rule, product_cpes): + def _has_platforms_to_convert(rule, product_cpes): # Convert the platform names to CPE names # But only do it if an env_yaml was specified (otherwise there would - # be no product CPEs to lookup), and the rule's prodtype matches the - # product being built also if the rule already has cpe_platform_names + # be no product CPEs to lookup) and if the rule already has cpe_platform_names # specified (compiled rule) do not evaluate platforms again - return ( - env_yaml and - (env_yaml["product"] in parse_prodtype(rule.prodtype) or - rule.prodtype == "all") and - (product_cpes and not rule.cpe_platform_names) - ) + return product_cpes and not rule.cpe_platform_names @staticmethod - def _convert_platform_names(env_yaml, rule, product_cpes): - if not Rule._has_platforms_to_convert(env_yaml, rule, product_cpes): + def _convert_platform_names(rule, product_cpes): + if not Rule._has_platforms_to_convert(rule, product_cpes): return # parse platform definition and get CPEAL platform for platform in rule.platforms: @@ -793,7 +784,8 @@ def from_yaml(cls, yaml_file, env_yaml=None, product_cpes=None, sce_metadata=Non if rule.platform is not None: rule.platforms.add(rule.platform) - cls._convert_platform_names(env_yaml, rule, product_cpes) + cls._convert_platform_names(rule, product_cpes) + # Only load policy specific content if rule doesn't have it defined yet if not rule.policy_specific_content: rule.load_policy_specific_content(yaml_file, env_yaml) @@ -803,7 +795,6 @@ def from_yaml(cls, yaml_file, env_yaml=None, product_cpes=None, sce_metadata=Non rule.sce_metadata["relative_path"] = os.path.join( env_yaml["product"], "checks/sce", rule.sce_metadata['filename']) - rule.validate_prodtype(yaml_file) rule.validate_identifiers(yaml_file) rule.validate_references(yaml_file) return rule @@ -986,15 +977,6 @@ def validate_references(self, yaml_file): .format(ref_type=ref_type, yaml_file=yaml_file)) raise ValueError(msg) - def validate_prodtype(self, yaml_file): - for ptype in self.prodtype.split(","): - if ptype.strip() != ptype: - msg = ( - "Comma-separated '{prodtype}' prodtype " - "in {yaml_file} contains whitespace." - .format(prodtype=self.prodtype, yaml_file=yaml_file)) - raise ValueError(msg) - def add_fixes(self, fixes): self.fixes = fixes @@ -1298,11 +1280,7 @@ def load_benchmark_or_group(self, guide_directory): if self.group_file: group = Group.from_yaml(self.group_file, self.env_yaml, self.product_cpes) - prodtypes = parse_prodtype(group.prodtype) - if "all" in prodtypes or self.product in prodtypes: - self.all_groups[group.id_] = group - else: - return None + self.all_groups[group.id_] = group return group @@ -1421,10 +1399,6 @@ def _process_rule(self, rule): "The rule '%s' isn't mapped to any component! Insert the " "rule ID to at least one file in '%s'." % (rule.id_, self.components_dir)) - prodtypes = parse_prodtype(rule.prodtype) - if "all" not in prodtypes and self.product not in prodtypes: - # TODO: remove prodtype - pass self.all_rules[rule.id_] = rule self.loaded_group.add_rule( rule, env_yaml=self.env_yaml, product_cpes=self.product_cpes) diff --git a/ssg/entities/profile.py b/ssg/entities/profile.py index 852d8bdaa66..38ea4cdbf10 100644 --- a/ssg/entities/profile.py +++ b/ssg/entities/profile.py @@ -58,7 +58,6 @@ def resolve(self, all_profiles, rules_by_id, controls_manager=None): if rid not in rules_by_id: msg = ( "Rule {rid} is selected by {profile}, but the rule is not available. " - "This may be caused by a discrepancy of prodtypes." .format(rid=rid, profile=self.id_)) raise ValueError(msg) diff --git a/ssg/fixes.py b/ssg/fixes.py index d8834f979a8..a6c56348b0c 100644 --- a/ssg/fixes.py +++ b/ssg/fixes.py @@ -4,8 +4,7 @@ import os from .build_remediations import parse_from_file_without_jinja -from .rule_yaml import parse_prodtype -from .utils import read_file_list +from .utils import read_file_list, parse_platform from .build_remediations import REMEDIATION_TO_EXT_MAP as REMEDIATION_MAP @@ -48,10 +47,10 @@ def applicable_platforms(fix_path): if 'platform' not in config: raise ValueError("Malformed fix: missing platform" % fix_path) - return parse_prodtype(config['platform']) + return parse_platform(config['platform']) -def parse_platform(fix_contents): +def find_platform_line(fix_contents): """ Parses the platform configuration item to determine the line number that the platforms configuration option is on. If this key is not found, None @@ -81,7 +80,7 @@ def set_applicable_platforms(fix_contents, new_platforms): platforms. """ - platform_line = parse_platform(fix_contents) + platform_line = find_platform_line(fix_contents) if platform_line is None: raise ValueError("When parsing config file, unable to find platform " "line!\n\n%s" % "\n".join(fix_contents)) diff --git a/ssg/jinja.py b/ssg/jinja.py index b4641f87bef..e8446b47796 100644 --- a/ssg/jinja.py +++ b/ssg/jinja.py @@ -16,9 +16,9 @@ from .constants import JINJA_MACROS_DIRECTORY from .utils import (required_key, - prodtype_to_name, + product_to_name, name_to_platform, - prodtype_to_platform, + product_to_platform, banner_regexify, banner_anchor_wrap, escape_id, @@ -135,9 +135,9 @@ def process_file(filepath, substitutions_dict): def add_python_functions(substitutions_dict): - substitutions_dict['prodtype_to_name'] = prodtype_to_name + substitutions_dict['product_to_name'] = product_to_name substitutions_dict['name_to_platform'] = name_to_platform - substitutions_dict['prodtype_to_platform'] = prodtype_to_platform + substitutions_dict['product_to_platform'] = product_to_platform substitutions_dict['url_encode'] = url_encode substitutions_dict['raise'] = raise_exception substitutions_dict['expand_yaml_path'] = expand_yaml_path diff --git a/ssg/rule_dir_stats.py b/ssg/rule_dir_stats.py index 80f642c738c..5fc06e188e6 100644 --- a/ssg/rule_dir_stats.py +++ b/ssg/rule_dir_stats.py @@ -414,56 +414,6 @@ def two_plus_remediation(rule_obj, r_type): (rule_id, r_type, ','.join(rule_obj['remediations'][r_type])) -def prodtypes_oval(rule_obj): - """ - For a rule object, check if the prodtypes match between the YAML and the - OVALs. - """ - - rule_id = rule_obj['id'] - - rule_products = set(rule_obj.get('products', [])) - if not rule_products: - return - - oval_products = set() - for oval in rule_obj.get('ovals', []): - oval_products.update(rule_obj['ovals'][oval].get('products', [])) - if not oval_products: - return - - sym_diff = sorted(rule_products.symmetric_difference(oval_products)) - check = len(sym_diff) > 0 - if check: - return "\trule_id:%s has a different prodtypes between YAML and OVALs: %s" % \ - (rule_id, ','.join(sym_diff)) - - -def prodtypes_remediation(rule_obj, r_type): - """ - For a rule object, check if the prodtypes match between the YAML and the - remediations of type r_type. - """ - - rule_id = rule_obj['id'] - - rule_products = set(rule_obj.get('products', [])) - if not rule_products: - return - - remediation_products = set() - for remediation in rule_obj.get('remediations', dict()).get(r_type, dict()): - remediation_products.update(rule_obj['remediations'][r_type][remediation]['products']) - if not remediation_products: - return - - sym_diff = sorted(rule_products.symmetric_difference(remediation_products)) - check = len(sym_diff) > 0 and rule_products and remediation_products - if check: - return "\trule_id:%s has a different prodtypes between YAML and %s remediations: %s" % \ - (rule_id, r_type, ','.join(sym_diff)) - - def product_names_oval(rule_obj): """ For a rule_obj, check the scope of the platforms versus the product name diff --git a/ssg/rule_yaml.py b/ssg/rule_yaml.py index 13ffdcffdac..5cc759ace49 100644 --- a/ssg/rule_yaml.py +++ b/ssg/rule_yaml.py @@ -151,14 +151,6 @@ def get_yaml_contents(rule_obj): return file_description(yaml_file, yaml_contents) -def parse_prodtype(prodtype): - """ - From a prodtype line, returns the set of products listed. - """ - - return set(map(lambda x: x.strip(), prodtype.split(','))) - - def get_section_lines(file_path, file_contents, key_name): """ From the given file_path and file_contents, find the lines describing the section diff --git a/ssg/utils.py b/ssg/utils.py index 010b0b39e3d..a1da491a543 100644 --- a/ssg/utils.py +++ b/ssg/utils.py @@ -128,9 +128,9 @@ def map_name(version): % (version)) -def prodtype_to_name(prod): +def product_to_name(prod): """ - Converts a vaguely-prodtype-like thing into one or more full product names. + Converts a vaguely-product-id-like thing into one or more full product names. """ for name, prod_type in FULL_NAME_TO_PRODUCT_MAPPING.items(): if prod == prod_type: @@ -150,14 +150,14 @@ def name_to_platform(names): return "\n".join(map(name_to_platform, names)) -def prodtype_to_platform(prods): +def product_to_platform(prods): """ - Converts one or more prodtypes into a string with one or more + Converts one or more product ids into a string with one or more elements. """ if isinstance(prods, str): - return name_to_platform(prodtype_to_name(prods)) - return "\n".join(map(prodtype_to_platform, prods)) + return name_to_platform(product_to_name(prods)) + return "\n".join(map(product_to_platform, prods)) def parse_name(product): @@ -179,9 +179,17 @@ def parse_name(product): return prod_tuple(_product, _product_version) +def parse_platform(platform): + """ + From a platform line, returns the set of platforms listed. + """ + + return set(map(lambda x: x.strip(), platform.split(','))) + + def get_fixed_product_version(product, product_version): # Some product versions have a dot in between the numbers - # While the prodtype doesn't have the dot, the full product name does + # While the product id doesn't have the dot, the full product name does if product == "ubuntu" or product == "macos": product_version = product_version[:2] + "." + product_version[2:] return product_version @@ -230,8 +238,7 @@ def is_applicable_for_product(platform, product): def is_applicable(platform, product): """ Function to check if a platform is applicable for the product. - Handles when a platform is really a list of products, i.e., a - prodtype field from a rule.yml. + Handles when a platform is really a list of products. Returns true iff product is applicable for the platform or list of products diff --git a/tests/ssg_test_suite/common.py b/tests/ssg_test_suite/common.py index 99af208f68c..9678fb834b9 100644 --- a/tests/ssg_test_suite/common.py +++ b/tests/ssg_test_suite/common.py @@ -20,7 +20,6 @@ from ssg.jinja import process_file_with_macros from ssg.products import product_yaml_path, load_product_yaml from ssg.rules import get_rule_dir_yaml, is_rule_dir -from ssg.rule_yaml import parse_prodtype from ssg.utils import mkdir_p from ssg_test_suite.log import LogHelper @@ -309,19 +308,13 @@ def load_rule_and_env(rule_dir_path, env_yaml, product=None): rule = RuleYAML.from_yaml(rule_path, env_yaml) rule.normalize(product) - # Note that most places would check prodtype, but we don't care - # about that here: if the rule is available to the product, we - # load and parse it anyways as we have no knowledge of the - # top-level profile or rule passed into the test suite. - prodtypes = parse_prodtype(rule.prodtype) - # Our local copy of env_yaml needs some properties from rule.yml # for completeness. local_env_yaml = dict() local_env_yaml.update(env_yaml) local_env_yaml['rule_id'] = rule.id_ local_env_yaml['rule_title'] = rule.title - local_env_yaml['products'] = prodtypes + local_env_yaml["products"] = {product} return rule, local_env_yaml diff --git a/tests/ssg_test_suite/rule.py b/tests/ssg_test_suite/rule.py index 4650e6bfdd0..583e7ae2045 100644 --- a/tests/ssg_test_suite/rule.py +++ b/tests/ssg_test_suite/rule.py @@ -322,17 +322,6 @@ def _get_rules_to_test(self): rule, local_env_yaml = common.load_rule_and_env( dirpath, product_yaml, product) - # Before we get too far, we wish to search the rule YAML to see if - # it is applicable to the current product. If we have a product - # and the rule isn't applicable for the product, there's no point - # in continuing with the rest of the loading. This should speed up - # the loading of the templated tests. Note that we've already - # parsed the prodtype into local_env_yaml - if product and local_env_yaml['products']: - prodtypes = local_env_yaml['products'] - if "all" not in prodtypes and product not in prodtypes: - continue - tests_dir = os.path.join(dirpath, "tests") template_name = None if rule.template and rule.template['vars']: diff --git a/tests/unit/ssg-module/data/accounts_tmout.yml b/tests/unit/ssg-module/data/accounts_tmout.yml index e8400ed73fa..9976ed64f00 100644 --- a/tests/unit/ssg-module/data/accounts_tmout.yml +++ b/tests/unit/ssg-module/data/accounts_tmout.yml @@ -1,4 +1,3 @@ -prodtype: alinux2,alinux3,fedora,ol7,ol8,ol9,rhcos4,rhel7,rhel8,rhel9,rhv4,sle12,sle15,ubuntu2004,ubuntu2204 title: Set Interactive Session Timeout description: 'Setting the TMOUT option in /etc/profile ensures that diff --git a/tests/unit/ssg-module/data/accounts_tmout_without_ocil.yml b/tests/unit/ssg-module/data/accounts_tmout_without_ocil.yml index 1feaeb55ceb..275be8dcaf7 100644 --- a/tests/unit/ssg-module/data/accounts_tmout_without_ocil.yml +++ b/tests/unit/ssg-module/data/accounts_tmout_without_ocil.yml @@ -1,4 +1,3 @@ -prodtype: alinux2,alinux3,fedora,ol7,ol8,ol9,rhcos4,rhel7,rhel8,rhel9,rhv4,sle12,sle15,ubuntu2004,ubuntu2204 title: Set Interactive Session Timeout description: 'Setting the TMOUT option in /etc/profile ensures that diff --git a/tests/unit/ssg-module/data/file_owner_grub2_cfg.yml b/tests/unit/ssg-module/data/file_owner_grub2_cfg.yml index 83d5532f557..e086b375c28 100644 --- a/tests/unit/ssg-module/data/file_owner_grub2_cfg.yml +++ b/tests/unit/ssg-module/data/file_owner_grub2_cfg.yml @@ -22,7 +22,6 @@ platforms: !!set cpe_platform_names: !!set machine: null inherited_platforms: [] -prodtype: rhel7,rhel8,fedora,ol7,ol8 rationale: Only root should be able to modify important boot parameters. references: {cis: 1.4.1, cis-csc: '12,13,14,15,16,18,3,5', cjis: 5.5.2.2, cobit5: 'APO01.06,DSS05.04,DSS05.07,DSS06.02', cui: 3.4.5, disa: 'CCI-000225', hipaa: '164.308(a)(1)(ii)(B),164.308(a)(7)(i),164.308(a)(7)(ii)(A),164.310(a)(1),164.310(a)(2)(i),164.310(a)(2)(ii),164.310(a)(2)(iii),164.310(b),164.310(c),164.310(d)(1),164.310(d)(2)(iii)', diff --git a/tests/unit/ssg-module/data/selinux.yml b/tests/unit/ssg-module/data/selinux.yml index 59839e8750e..90c5807d54f 100644 --- a/tests/unit/ssg-module/data/selinux.yml +++ b/tests/unit/ssg-module/data/selinux.yml @@ -1,4 +1,3 @@ -prodtype: all title: SELinux description: 'SELinux is a feature of the Linux kernel which can be diff --git a/tests/unit/ssg-module/data/sshd_disable_root_login.yml b/tests/unit/ssg-module/data/sshd_disable_root_login.yml index 16e0cfb3dd3..5836c8cf929 100644 --- a/tests/unit/ssg-module/data/sshd_disable_root_login.yml +++ b/tests/unit/ssg-module/data/sshd_disable_root_login.yml @@ -21,7 +21,6 @@ ocil: 'To determine how the SSH daemon''s PermitRootLogin option is set ocil_clause: the required value is not set oval_external_content: null platforms: null -prodtype: all rationale: 'Even though the communications channel may be encrypted, an additional layer of diff --git a/tests/unit/ssg-module/test_playbook_builder_data/guide/configure_crypto_policy/rule.yml b/tests/unit/ssg-module/test_playbook_builder_data/guide/configure_crypto_policy/rule.yml index 9d0a0d08789..25295059be3 100644 --- a/tests/unit/ssg-module/test_playbook_builder_data/guide/configure_crypto_policy/rule.yml +++ b/tests/unit/ssg-module/test_playbook_builder_data/guide/configure_crypto_policy/rule.yml @@ -1,7 +1,5 @@ documentation_complete: true -prodtype: fedora,ol8,rhcos4,rhel8,rhel9,rhv4 - title: 'Configure System Cryptography Policy' description: |- diff --git a/tests/unit/ssg-module/test_playbook_builder_data/guide/package_abrt_removed/rule.yml b/tests/unit/ssg-module/test_playbook_builder_data/guide/package_abrt_removed/rule.yml index 5becd90b76b..4cd1683030f 100644 --- a/tests/unit/ssg-module/test_playbook_builder_data/guide/package_abrt_removed/rule.yml +++ b/tests/unit/ssg-module/test_playbook_builder_data/guide/package_abrt_removed/rule.yml @@ -1,7 +1,5 @@ documentation_complete: true -prodtype: fedora,ol7,ol8,rhel7,rhel8,rhel9 - title: 'Uninstall Automatic Bug Reporting Tool (abrt)' description: |- diff --git a/tests/unit/ssg-module/test_playbook_builder_data/rules/selinux_state.yml b/tests/unit/ssg-module/test_playbook_builder_data/rules/selinux_state.yml index 64e6cee7fcf..ec3b0d2024a 100644 --- a/tests/unit/ssg-module/test_playbook_builder_data/rules/selinux_state.yml +++ b/tests/unit/ssg-module/test_playbook_builder_data/rules/selinux_state.yml @@ -14,7 +14,6 @@ ocil_clause: SELINUX is not set to enforcing oval_external_content: null platforms: - machine -prodtype: rhel7,rhel8,fedora,ol7,ol8,rhv4 rationale: 'Setting the SELinux state to enforcing ensures SELinux is able to confine potentially compromised processes to the security policy, which is designed to diff --git a/tests/unit/ssg-module/test_rule_dir_stats.py b/tests/unit/ssg-module/test_rule_dir_stats.py index 25235af8e31..7b937d81d09 100644 --- a/tests/unit/ssg-module/test_rule_dir_stats.py +++ b/tests/unit/ssg-module/test_rule_dir_stats.py @@ -115,74 +115,3 @@ def test_two_plus_remediation(): assert not rds.two_plus_remediation(one_rule, 'bash') assert not rds.two_plus_remediation(empty_rule, 'bash') assert not rds.two_plus_remediation(empty_rule, 'anaconda') - - -def test_prodtypes_oval(): - bad_rule = { - "id": "bad_rule", - "products": ["rhel8"], - "ovals": { - "rhel7.xml": { - "products": ["rhel7"] - } - } - } - good_rule = { - "id": "good_rule", - "products": ["rhel7"], - "ovals": { - "rhel7.xml": { - "products": ["rhel7"] - } - } - } - empty_rule = { - "id": "empty_rule" - } - no_oval_rule = { - "id": "empty_rule", - "products": ["rhel7"] - } - - assert rds.prodtypes_oval(bad_rule) - assert not rds.prodtypes_oval(good_rule) - assert not rds.prodtypes_oval(empty_rule) - assert not rds.prodtypes_oval(no_oval_rule) - - -def test_prodtypes_remediation(): - bad_rule = { - "id": "bad_rule", - "products": ["rhel8"], - "remediations": { - "bash": { - "rhel7.sh": { - "products": ["rhel7"] - } - } - } - } - good_rule = { - "id": "good_rule", - "products": ["rhel7"], - "remediations": { - "bash": { - "rhel7.sh": { - "products": ["rhel7"] - } - } - } - } - empty_rule = { - "id": "empty_rule" - } - no_remediation_rule = { - "id": "empty_rule", - "products": ["rhel7"] - } - - assert rds.prodtypes_remediation(bad_rule, 'bash') - assert not rds.prodtypes_remediation(good_rule, 'bash') - assert not rds.prodtypes_remediation(empty_rule, 'bash') - assert not rds.prodtypes_remediation(no_remediation_rule, 'bash') - assert not rds.prodtypes_remediation(no_remediation_rule, 'ansible') diff --git a/tests/unit/ssg_test_suite/data/rule_reference_fail/rule_1/rule.yml b/tests/unit/ssg_test_suite/data/rule_reference_fail/rule_1/rule.yml index c510315885f..af5028634b9 100644 --- a/tests/unit/ssg_test_suite/data/rule_reference_fail/rule_1/rule.yml +++ b/tests/unit/ssg_test_suite/data/rule_reference_fail/rule_1/rule.yml @@ -1,7 +1,5 @@ documentation_complete: true -prodtype: fedora - title: Rule 1 identifiers: diff --git a/tests/unit/ssg_test_suite/data/rule_reference_fail/rule_2/rule.yml b/tests/unit/ssg_test_suite/data/rule_reference_fail/rule_2/rule.yml index 00bc70ffe53..799abc11a07 100644 --- a/tests/unit/ssg_test_suite/data/rule_reference_fail/rule_2/rule.yml +++ b/tests/unit/ssg_test_suite/data/rule_reference_fail/rule_2/rule.yml @@ -1,7 +1,5 @@ documentation_complete: true -prodtype: fedora - title: Rule 2 identifiers: diff --git a/tests/unit/ssg_test_suite/data/rule_reference_pass/rule_1/rule.yml b/tests/unit/ssg_test_suite/data/rule_reference_pass/rule_1/rule.yml index d3b4d3d394a..966a7b3f6d2 100644 --- a/tests/unit/ssg_test_suite/data/rule_reference_pass/rule_1/rule.yml +++ b/tests/unit/ssg_test_suite/data/rule_reference_pass/rule_1/rule.yml @@ -1,7 +1,5 @@ documentation_complete: true -prodtype: fedora - title: Rule 2 identifiers: diff --git a/tests/unit/ssg_test_suite/data/rule_reference_pass/rule_2/rule.yml b/tests/unit/ssg_test_suite/data/rule_reference_pass/rule_2/rule.yml index c510315885f..af5028634b9 100644 --- a/tests/unit/ssg_test_suite/data/rule_reference_pass/rule_2/rule.yml +++ b/tests/unit/ssg_test_suite/data/rule_reference_pass/rule_2/rule.yml @@ -1,7 +1,5 @@ documentation_complete: true -prodtype: fedora - title: Rule 1 identifiers: diff --git a/tests/unit/utils/oscal/data/test_root/applications/test_application/rule_1/rule.yml b/tests/unit/utils/oscal/data/test_root/applications/test_application/rule_1/rule.yml index 55ef04b60a4..274f2c4c1a4 100644 --- a/tests/unit/utils/oscal/data/test_root/applications/test_application/rule_1/rule.yml +++ b/tests/unit/utils/oscal/data/test_root/applications/test_application/rule_1/rule.yml @@ -1,5 +1,3 @@ -prodtype: ocp4 - title: 'rule_1' description: |- diff --git a/tests/unit/utils/oscal/data/test_root/applications/test_application/rule_2/rule.yml b/tests/unit/utils/oscal/data/test_root/applications/test_application/rule_2/rule.yml index 97c7fbde30e..2e4bc25ac0a 100644 --- a/tests/unit/utils/oscal/data/test_root/applications/test_application/rule_2/rule.yml +++ b/tests/unit/utils/oscal/data/test_root/applications/test_application/rule_2/rule.yml @@ -1,5 +1,3 @@ -prodtype: ocp4 - title: 'rule_2' description: |- diff --git a/utils/autoprodtyper.py b/utils/autoprodtyper.py deleted file mode 100755 index 198a550b96b..00000000000 --- a/utils/autoprodtyper.py +++ /dev/null @@ -1,85 +0,0 @@ -#!/usr/bin/python3 - -import os -import argparse -import json - -import ssg.build_yaml -import ssg.environment -import ssg.products -import ssg.rules -import ssg.yaml -import ssg.utils -import ssg.rule_yaml - -from mod_prodtype import add_products - -SSG_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) - - -def parse_args(): - parser = argparse.ArgumentParser(description="Automatically add a missing product " - "reference to the prodtype key of a rule.yml based " - "on inclusion in a specified profile") - parser.add_argument("-j", "--json", type=str, action="store", - default="build/rule_dirs.json", help="File to read " - "json output of rule_dir_json from (defaults to " - "build/rule_dirs.json") - parser.add_argument("-c", "--build-config-yaml", default="build/build_config.yml", - help="YAML file with information about the build configuration. " - "Defaults to build/build_config.yml") - parser.add_argument("-p", "--profiles-root", - help="Override where to look for profile files.") - parser.add_argument("product", type=str, help="Product to add prod types for") - parser.add_argument("profile", type=str, help="Profile to iterate over") - - return parser.parse_args() - - -def autoprodtype(env_yaml, rule_dirs, profile_path, product): - profile = ssg.build_yaml.ProfileWithInlinePolicies.from_yaml(profile_path, env_yaml) - - for rule_id in profile.selected + profile.unselected: - if rule_id not in rule_dirs: - msg = "Unable to find rule in rule_dirs.json: {0}" - msg = msg.format(rule_id) - raise ValueError(msg) - - add_products(rule_dirs[rule_id], [product], silent=True) - - -def main(): - args = parse_args() - - json_file = open(args.json, 'r') - all_rules = json.load(json_file) - - linux_products, other_products = ssg.products.get_all(SSG_ROOT) - all_products = linux_products.union(other_products) - if args.product not in all_products: - msg = "Unknown product {0}: check SSG_ROOT and try again" - msg = msg.format(args.product) - raise ValueError(msg) - - product_base = os.path.join(SSG_ROOT, "products", args.product) - product_yaml = os.path.join(product_base, "product.yml") - env_yaml = ssg.environment.open_environment( - args.build_config_yaml, product_yaml, os.path.join(SSG_ROOT, "product_properties")) - - profiles_root = os.path.join(product_base, "profiles") - if args.profiles_root: - profiles_root = args.profiles_root - - profile_filename = args.profile + ".profile" - profile_path = os.path.join(profiles_root, profile_filename) - if not os.path.exists(profile_path): - msg = "Unknown profile {0}: check profile, --profiles-root, and try again. " - msg += "Note that profiles should not include '.profile' suffix." - msg = msg.format(args.profile) - raise ValueError(msg) - - autoprodtype(env_yaml, all_rules, profile_path, args.product) - - -if __name__ == "__main__": - main() diff --git a/utils/convert_prodtype_ds_check.py b/utils/convert_prodtype_ds_check.py deleted file mode 100755 index 7e31d212111..00000000000 --- a/utils/convert_prodtype_ds_check.py +++ /dev/null @@ -1,72 +0,0 @@ -#!/usr/bin/env python - -import os -from xml.etree import ElementTree - -NAMESPACES = dict( - xccdf_ns="http://scap.nist.gov/schema/scap/source/1.2", - profile_ns="http://checklists.nist.gov/xccdf/1.2", -) - -SSG_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) - - -def fname_to_etree(fname): - input_tree = ElementTree.parse(fname) - return input_tree - - -def get_profiles_from_etree(tree): - xpath_expr = ".//{%s}Profile" % NAMESPACES["profile_ns"] - xccdfs = tree.findall(xpath_expr) - return xccdfs - - -def get_selections_from_etree(tree): - xpath_expr = ".//{%s}select" % NAMESPACES["profile_ns"] - xccdfs = tree.findall(xpath_expr) - return xccdfs - - -def get_rules_from_etree(tree): - xpath_expr = ".//{%s}Rule" % NAMESPACES["profile_ns"] - xccdfs = tree.findall(xpath_expr) - return xccdfs - - -def extract_tree_from_file(fname): - return fname_to_etree(fname) - - -def get_ds_stats(filename): - tree = extract_tree_from_file(filename) - profiles = sorted(get_profiles_from_etree(tree), key=lambda x: x.attrib["id"]) - rules = sorted(get_rules_from_etree(tree), key=lambda x: x.attrib["id"]) - yield f"Found {len(profiles)} profiles, {len(rules)} rules\n" - rules_selections = {} - for p in profiles: - p_id = p.attrib["id"].removeprefix("xccdf_org.ssgproject.content_") - selections = sorted(get_selections_from_etree(p), key=lambda x: x.attrib["idref"]) - yield f"{p_id} (selections: {len(selections)})\n" - for sel in selections: - r_id = sel.attrib["idref"].removeprefix("xccdf_org.ssgproject.content_") - r_selected = sel.attrib["selected"].lower() == "true" - yield f" {'+' if r_selected else '-'}{r_id}\n" - r_stats = rules_selections.get(r_id, {"selected": 0, "unselected": 0}) - r_stats["selected" if r_selected else "unselected"] += 1 - rules_selections[r_id] = r_stats - for r in rules: - r_id = r.attrib["id"].removeprefix("xccdf_org.ssgproject.content_") - r_selected = r.attrib["selected"].lower() == "true" - in_profiles = f"selected: {rules_selections[r_id]['selected']}, unselected: {rules_selections[r_id]['unselected']}" if r_id in rules_selections else "absent" - yield f"{'+' if r_selected else '-'}{r_id} (profiles: {in_profiles})\n" - - -if __name__ == "__main__": - for d in os.listdir(f"{SSG_ROOT}/products"): - fn = f"{SSG_ROOT}/build/ssg-{d}-ds.xml" - if os.path.isfile(fn): - stats = get_ds_stats(fn) - with open(f"{SSG_ROOT}/build/ssg-{d}-ds.prof-stats", "w") as f: - print(f"Writing stats for {d}") - f.writelines(stats) diff --git a/utils/convert_prodtype_into_default_profile_entry.py b/utils/convert_prodtype_into_default_profile_entry.py deleted file mode 100755 index 85c39d21135..00000000000 --- a/utils/convert_prodtype_into_default_profile_entry.py +++ /dev/null @@ -1,195 +0,0 @@ -#!/usr/bin/python3 - -import os -import argparse - -import ssg.rules -import ssg.utils -import ssg.products -import ssg.rule_yaml -import ssg.build_yaml -import ssg.build_profile -import ssg.entities.profile_base -import ssg.controls -import ssg.build_cpe -import ssg.yaml - -SSG_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) -GUIDE_RULES = {} - - -def parse_args(): - parser = argparse.ArgumentParser() - parser.add_argument("-p", "--product", type=str, action="store", - help="Product (defaults to all if not set)") - return parser.parse_args() - - -def collect_rule_ids_and_dirs(rules_dir): - for rule_dir in sorted(ssg.rules.find_rule_dirs(rules_dir)): - yield ssg.rules.get_rule_dir_id(rule_dir), rule_dir - - -def handle_rule_yaml(env, rule_dir): - rule_file = ssg.rules.get_rule_dir_yaml(rule_dir) - rule_yaml = ssg.build_yaml.Rule.from_yaml(rule_file, env) - return rule_file, rule_yaml - - -def get_rules(product, product_path, env): - guide_path = os.path.abspath(os.path.join(product_path, product['benchmark_root'])) - if guide_path not in GUIDE_RULES: - print(f"Loading rules from '{guide_path}'...", end=""), - GUIDE_RULES[guide_path] = {} - for rule_id, rule_dir in collect_rule_ids_and_dirs(guide_path): - try: - rule_file, rule_yaml = handle_rule_yaml(env, rule_dir) - GUIDE_RULES[guide_path][rule_yaml.id_] = rule_yaml - except ssg.yaml.DocumentationNotComplete: - # Happens on non-debug build when a rule is "documentation-incomplete" - continue - print(len(GUIDE_RULES[guide_path])) - return GUIDE_RULES[guide_path] - - -def get_products_and_rules(root_path): - linux_products, other_products = ssg.products.get_all(root_path) - all_products = linux_products.union(other_products) - for product_id in all_products: - product_path = ssg.products.product_yaml_path(root_path, product_id) - product_props_path = os.path.join(root_path, "product_properties") - product = ssg.products.load_product_yaml(product_path) - product.read_properties_from_directory(product_props_path) - env = dict(product) - rules = get_rules(product, os.path.join(root_path, "products", product_id), env) - yield product_id, product, env, rules - - -def unselect_rules_in_profile(product, profile, profile_path, prof_unsel): - if len(prof_unsel) == 0: - return - - comment = f"# Following rules once had a prodtype incompatible with the {product['product']} product" - with open(profile_path, 'r') as f: - lines = f.readlines() - comment_line = 0 - indent = 0 - sel_start = 0 - sel_end = 0 - already_unselected = [] - for i, line in enumerate(lines): - strip_line = line.strip() - if strip_line.startswith("- '!") or strip_line.startswith('- "!'): - already_unselected.append(strip_line[4:-1]) - continue - if comment in line: - comment_line = i - continue - if strip_line.startswith("#") or not strip_line.strip(): - continue - if line.startswith("selections:"): - sel_start = i - sel_end = len(lines) - 1 - continue - if sel_start != 0: - if not strip_line.startswith("-"): - sel_end = i - 1 - elif indent == 0: - indent = line.find("-") - - for unsel in prof_unsel: - if unsel in already_unselected: - continue - lines.insert(sel_end+1, f"{indent * ' '}- '!{unsel}'\n") - if comment_line == 0: - lines.insert(sel_end+1, f"{indent * ' '}{comment}\n") - - with open(profile_path, 'w') as f: - f.writelines(lines) - - -def select_rules_in_default_profile(product, profiles_root, prof_def_sel): - if len(prof_def_sel) == 0: - return - - prefix = (f"documentation_complete: true\n" - f"\n" - f"hidden: true\n" - f"\n" - f"title: Default Profile for {product['full_name']}\n" - f"\n" - f"description: |-\n" - f" This profile contains all the rules that once belonged to the\n" - f" {product['product']} product via 'prodtype'. This profile won't\n" - f" be rendered into an XCCDF Profile entity, nor it will select any\n" - f" of these rules by default. The only purpose of this profile\n" - f" is to keep a rule in the product's XCCDF Benchmark.\n" - f"\n" - f"selections:\n") - - path = os.path.join(SSG_ROOT, "products", product['product'], profiles_root) - with open(f"{path}/default.profile", "w") as f: - f.write(prefix) - for sel in prof_def_sel: - f.write(f" - {sel}\n") - - -def main(): - args = parse_args() - for product_id, product, env, all_rules in get_products_and_rules(SSG_ROOT): - if args.product: - if product_id != args.product: - continue - print(f"Product '{product_id}', profiles:") - - product_cpes = ssg.build_cpe.ProductCPEs() - product_cpes.load_product_cpes(env) - - controls_path = os.path.join(SSG_ROOT, "controls") - controls_manager = ssg.controls.ControlsManager(controls_path, env) - controls_manager.load() - - profile_paths = ssg.products.get_profile_files_from_root(env, product) - all_sels = set() - for profile_path in profile_paths: - try: - profile = ssg.build_yaml.ProfileWithInlinePolicies.from_yaml(profile_path, env, product_cpes) - except ssg.yaml.DocumentationNotComplete: - continue - if profile.id_ == 'default': - # Whatever is there — we are going to overwrite it - continue - profile.resolve_controls(controls_manager) - sels = sorted(profile.selected) - unsels = sorted(profile.unselected) - extends = profile.extends if profile.extends else "no" - print(f" {profile.id_} (extends: {extends}, selections: {len(sels)}/{len(unsels)})", end="") - prof_unsel = set() - for sel in sels: - if sel in all_rules: - if all_rules[sel].prodtype == '' or all_rules[sel].prodtype is None: - raise Exception("Should not happen!") - if product_id not in all_rules[sel].prodtype and all_rules[sel].prodtype != 'all': - if sel not in unsels: - #print(f' - {sel}') - prof_unsel.add(sel) - print(f' -{len(prof_unsel)}') - all_sels.update(sels) - all_sels.difference_update(unsels) - - unselect_rules_in_profile(product, profile, profile_path, prof_unsel) - - prof_def_sel = set() - print(' default (hidden)', end="") - for rul_id, rul in all_rules.items(): - if product_id in rul.prodtype or rul.prodtype == 'all': - if rul_id not in all_sels: - #print(f' + {rul_id}') - prof_def_sel.add(rul_id) - print(f' +{len(prof_def_sel)}') - - select_rules_in_default_profile(product, env['profiles_root'], prof_def_sel) - - -if __name__ == "__main__": - main() diff --git a/utils/convert_prodtype_remove_prodtype.sh b/utils/convert_prodtype_remove_prodtype.sh deleted file mode 100755 index c3ec87e5815..00000000000 --- a/utils/convert_prodtype_remove_prodtype.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh - -guides="linux_os/guide \ -products/chromium/guide \ -applications \ -products/firefox/guide \ -apple_os" - -script=$(realpath "$0") -root=$(dirname "$script") - -for path in $guides; do - find "$root/../$path" -type f -print0 | xargs -0 sed -i "/prodtype:/d" -done diff --git a/utils/fix_rules.py b/utils/fix_rules.py index f6cf095c3d8..3c43b49357a 100755 --- a/utils/fix_rules.py +++ b/utils/fix_rules.py @@ -47,8 +47,6 @@ def has_empty_identifier(rule_path, rule, rule_lines): def has_no_cce(yaml_file, product_yaml=None): rule = yaml.open_and_macro_expand(yaml_file, product_yaml) product = product_yaml["product"] - if "prodtype" in rule and product not in rule["prodtype"]: - return False if 'identifiers' in rule and rule['identifiers'] is None: return True @@ -417,15 +415,6 @@ def fix_invalid_cce(file_contents, yaml_contents): return remove_section_keys(file_contents, yaml_contents, section, invalid_identifiers) -def fix_prodtypes(file_contents, yaml_contents): - section = 'prodtype' - sorted_prodtypes = yaml_contents[section].split(",") - sorted_prodtypes.sort() - out = ",".join(sorted_prodtypes) - - return rewrite_keyless_section(file_contents, yaml_contents, section, out) - - def has_product_cce(yaml_contents, product): section = 'identifiers' @@ -586,13 +575,6 @@ def fix_callback(file_contents, yaml_contents): cce_pool.remove_cce_from_file(cce) -def has_unsorted_prodtype(rule_path, rule, rule_lines): - if 'prodtype' in rule: - prodtypes = rule['prodtype'].split(',') - return prodtypes != sorted(prodtypes) - return False - - @command("empty_identifiers", "check and fix rules with empty identifiers") def fix_empty_identifiers(args, product_yaml): results = find_rules(args, has_empty_identifier) @@ -733,22 +715,6 @@ def sort_subkeys(args, product_yaml): exit(int(len(results) > 0)) -@command("sort_prodtypes", "sorts the products in the prodtype") -def sort_prodtypes(args, product_yaml): - results = find_rules(args, has_unsorted_prodtype) - for result in results: - rule_path = result[0] - product_yaml = result[2] - - if args.dry_run: - print(rule_path + " prodtype is unsorted") - continue - - fix_file(rule_path, product_yaml, fix_prodtypes) - - exit(int(len(results) > 0)) - - @command("test_all", "Perform all checks on all rules") def test_all(args, product_yaml): result = 0 @@ -759,8 +725,7 @@ def test_all(args, product_yaml): (has_empty_references, "empty references"), (has_int_reference, "unsorted references"), (has_duplicated_subkeys, "duplicated subkeys"), - (has_unordered_sections, "unsorted references"), - (has_unsorted_prodtype, "unsorted prodtype") + (has_unordered_sections, "unsorted references") ] for item in rule_data_generator(args): rule_path, rule, rule_lines, _, _ = item diff --git a/utils/gen_srg_table.py b/utils/gen_srg_table.py index ff5b7ed0261..1496ed45d0f 100644 --- a/utils/gen_srg_table.py +++ b/utils/gen_srg_table.py @@ -50,6 +50,6 @@ def get_rules_by_srgid(build_dir, product): data = dict() data["srgs"] = ssg.build_stig.parse_srgs(args.srgs) data["rules_by_srgid"] = get_rules_by_srgid(args.build_dir, args.product) - data["full_name"] = ssg.utils.prodtype_to_name(args.product) + data["full_name"] = ssg.utils.product_to_name(args.product) render_template(data, SRGMAP_TEMPLATE, args.srgmap) render_template(data, SRGMAP_FLAT_TEMPLATE, args.srgmap_flat) diff --git a/utils/generate_profile.py b/utils/generate_profile.py index 4fd3f93e254..b02b12b839e 100755 --- a/utils/generate_profile.py +++ b/utils/generate_profile.py @@ -48,8 +48,6 @@ def setup_argument_parser() -> argparse.ArgumentParser: list_parser = subparsers.add_parser('list', help='List controls within a benchmark') list_parser.set_defaults(func=list_controls) generate_parser = subparsers.add_parser('generate', help='Generate a control from benchmark') - generate_parser.add_argument('-p', '--product-type', required=True, - help='Product name to generate in output') generate_parser.add_argument('-c', '--control', help='Control ID to generate') generate_parser.add_argument('-s', '--section', help='Section ID to generate, including containing controls') @@ -203,9 +201,8 @@ def _generate(self, node: pycompliance.Node) -> dict: class RuleGenerator(Generator): - def __init__(self, benchmark: pycompliance.Benchmark, product_type: str): + def __init__(self, benchmark: pycompliance.Benchmark): super().__init__(benchmark) - self.product_type = product_type def generate(self, control: pycompliance.Control): if not isinstance(control, pycompliance.Control): @@ -216,7 +213,6 @@ def generate(self, control: pycompliance.Control): ) output = { 'documentation_complete': False, - 'prodtype': self.product_type, 'title': LiteralUnicode(control.title), 'description': description, 'rationale': LiteralUnicode(control.rationale), @@ -275,7 +271,7 @@ def generate_control(args): control = b.find(args.control) section = b.find(args.section) if control: - r = RuleGenerator(b, args.product_type) + r = RuleGenerator(b) r.generate(control) elif section: r = SectionGenerator(b) diff --git a/utils/mod_checks.py b/utils/mod_checks.py index 3d237d23fce..19ecb5cca63 100755 --- a/utils/mod_checks.py +++ b/utils/mod_checks.py @@ -100,8 +100,8 @@ def replace_platforms(rule_obj, platforms): file=sys.stderr) sys.exit(1) - match = ssg.rule_yaml.parse_prodtype(parsed_platform[0]) - replacement = ssg.rule_yaml.parse_prodtype(parsed_platform[1]) + match = ssg.utils.parse_platform(parsed_platform[0]) + replacement = ssg.utils.parse_platform(parsed_platform[1]) if match.issubset(current_platforms): new_platforms.difference_update(match) diff --git a/utils/mod_fixes.py b/utils/mod_fixes.py index ae612403c13..3dc665ee583 100755 --- a/utils/mod_fixes.py +++ b/utils/mod_fixes.py @@ -102,8 +102,8 @@ def replace_platforms(rule_obj, lang, platforms): file=sys.stderr) sys.exit(1) - match = ssg.rule_yaml.parse_prodtype(parsed_platform[0]) - replacement = ssg.rule_yaml.parse_prodtype(parsed_platform[1]) + match = ssg.utils.parse_platform(parsed_platform[0]) + replacement = ssg.utils.parse_platform(parsed_platform[1]) if match.issubset(current_platforms): new_platforms.difference_update(match) diff --git a/utils/mod_prodtype.py b/utils/mod_prodtype.py deleted file mode 100755 index 26d41f64e15..00000000000 --- a/utils/mod_prodtype.py +++ /dev/null @@ -1,195 +0,0 @@ -#!/usr/bin/python3 - -import sys -import os -import argparse -import json - -import ssg.rules -import ssg.utils -import ssg.rule_yaml - -SSG_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) - - -def parse_args(): - parser = argparse.ArgumentParser() - parser.add_argument("-j", "--json", type=str, action="store", default="build/rule_dirs.json", - help="File to read json output of rule_dir_json from (defaults " - "to build/rule_dirs.json)") - parser.add_argument("rule_id", type=str, help="Rule to change, by id") - parser.add_argument("action", choices=['add', 'remove', 'list', 'replace'], - help="Rule to change, by id") - parser.add_argument("products", type=str, nargs='*', - help="Products to perform action with on rule_id. For replace, " - "the expected format is " - "product[,other_product]~product[,other_product] " - "where the first half is the products that are required to " - "match, and are replaced by the products in the second half " - "if all match.") - return parser.parse_args() - - -def list_products(rule_obj): - yaml_file, yaml_contents = ssg.rule_yaml.get_yaml_contents(rule_obj) - prodtype_section = ssg.rule_yaml.get_section_lines(yaml_file, yaml_contents, 'prodtype') - - print("Computed products:") - for product in sorted(rule_obj.get('products', [])): - print(" - %s" % product) - print("") - - if prodtype_section: - prodtype_contents = ssg.rule_yaml.parse_from_yaml(yaml_contents, prodtype_section) - prodtype = ssg.rule_yaml.parse_prodtype(prodtype_contents['prodtype']) - print("Listed products:") - for product in prodtype: - print(" - %s" % product) - else: - print("Empty listed prodtype in the file") - - -def add_products(rule_obj, products, silent=False): - yaml_file, yaml_contents = ssg.rule_yaml.get_yaml_contents(rule_obj) - prodtype_section = ssg.rule_yaml.get_section_lines(yaml_file, yaml_contents, 'prodtype') - - if not prodtype_section: - new_prodtype = sorted(set(products)) - new_prodtype_str = ','.join(new_prodtype) - - doc_complete_section = ssg.rule_yaml.get_section_lines(yaml_file, yaml_contents, - 'documentation_complete') - if not doc_complete_section: - print("Cannot modify empty prodtype with missing documentation_complete... " - "Are you sure this is a rule file? %s" % yaml_file, file=sys.stderr) - sys.exit(1) - - start_line = doc_complete_section[1]+1 - - if not silent: - print("Current prodtype is empty, not adding the new prodtype.") - else: - prodtype_contents = ssg.rule_yaml.parse_from_yaml(yaml_contents, prodtype_section) - prodtype = prodtype_contents['prodtype'] - - new_prodtype = ssg.rule_yaml.parse_prodtype(prodtype) - new_prodtype.update(products) - new_prodtype_str = ','.join(sorted(new_prodtype)) - - print("Modifying %s:" % yaml_file) - print(" Current prodtype: %s" % prodtype) - print(" New prodtype: %s" % new_prodtype_str) - - yaml_contents = ssg.rule_yaml.update_key_value(yaml_contents, 'prodtype', - prodtype, new_prodtype_str) - - ssg.utils.write_list_file(yaml_file, yaml_contents) - - -def remove_products(rule_obj, products): - yaml_file, yaml_contents = ssg.rule_yaml.get_yaml_contents(rule_obj) - prodtype_section = ssg.rule_yaml.get_section_lines(yaml_file, yaml_contents, 'prodtype') - - if not prodtype_section: - print("Cannot modify empty prodtype to remove products from %s" % - yaml_file, file=sys.stderr) - sys.exit(1) - - prodtype_contents = ssg.rule_yaml.parse_from_yaml(yaml_contents, prodtype_section) - prodtype = prodtype_contents['prodtype'] - - new_prodtype = ssg.rule_yaml.parse_prodtype(prodtype) - new_prodtype = new_prodtype.difference(products) - new_prodtype_str = ','.join(sorted(new_prodtype)) - - print("Current prodtype: %s" % prodtype) - - if new_prodtype: - print("New prodtype: %s" % new_prodtype_str) - yaml_contents = ssg.rule_yaml.update_key_value(yaml_contents, 'prodtype', - prodtype, new_prodtype_str) - else: - print("New prodtype is empty") - yaml_contents = ssg.rule_yaml.remove_lines(yaml_contents, prodtype_section) - - ssg.utils.write_list_file(yaml_file, yaml_contents) - - -def replace_products(rule_obj, products): - yaml_file, yaml_contents = ssg.rule_yaml.get_yaml_contents(rule_obj) - prodtype_section = ssg.rule_yaml.get_section_lines(yaml_file, yaml_contents, 'prodtype') - - if not prodtype_section: - print("Cannot modify empty prodtype to replace products from %s" % yaml_file, - file=sys.stderr) - sys.exit(1) - - parsed_changes = [] - for product in products: - parsed_product = product.split('~') - if not len(parsed_product) == 2: - print("Invalid product replacement description: %s" % product, - file=sys.stderr) - sys.exit(1) - - change = { - 'match': ssg.rule_yaml.parse_prodtype(parsed_product[0]), - 'replacement': ssg.rule_yaml.parse_prodtype(parsed_product[1]), - } - parsed_changes.append(change) - - prodtype_contents = ssg.rule_yaml.parse_from_yaml(yaml_contents, prodtype_section) - prodtype = prodtype_contents['prodtype'] - - current_prodtypes = ssg.rule_yaml.parse_prodtype(prodtype) - new_prodtypes = set(current_prodtypes) - - for change in parsed_changes: - if change['match'].issubset(current_prodtypes): - new_prodtypes.difference_update(change['match']) - new_prodtypes.update(change['replacement']) - - new_prodtype_str = ','.join(sorted(new_prodtypes)) - - print("Current prodtype: %s" % prodtype) - print("New prodtype: %s" % new_prodtype_str) - - yaml_contents = ssg.rule_yaml.update_key_value(yaml_contents, 'prodtype', - prodtype, new_prodtype_str) - - ssg.utils.write_list_file(yaml_file, yaml_contents) - - -def main(): - args = parse_args() - - json_file = open(args.json, 'r') - known_rules = json.load(json_file) - - if args.rule_id not in known_rules: - print("Error: rule_id:%s is not known!" % args.rule_id, file=sys.stderr) - print("If you think this is an error, try regenerating the JSON.", file=sys.stderr) - sys.exit(1) - - if args.action != "list" and not args.products: - print("Error: expected a list of products or replace transformations but " - "none given.", file=sys.stderr) - sys.exit(1) - - rule_obj = known_rules[args.rule_id] - print("rule_id:%s\n" % args.rule_id) - - if args.action == "list": - list_products(rule_obj) - elif args.action == "add": - add_products(rule_obj, args.products) - elif args.action == "remove": - remove_products(rule_obj, args.products) - elif args.action == "replace": - replace_products(rule_obj, args.products) - else: - print("Unknown option: %s" % args.action) - - -if __name__ == "__main__": - main() diff --git a/utils/rule_dir_json.py b/utils/rule_dir_json.py index 749bb9c2998..ee7b3196f93 100755 --- a/utils/rule_dir_json.py +++ b/utils/rule_dir_json.py @@ -100,8 +100,7 @@ def handle_rule_yaml(product_list, product_yamls, rule_id, rule_dir, guide_dir): rule_yaml = ssg.build_yaml.Rule.from_yaml(rule_file, env_yaml) rule_products = set() for product in product_list: - if ssg.utils.is_applicable(rule_yaml.prodtype, product): - rule_products.add(product) + rule_products.add(product) rule_products = sorted(rule_products) rule_obj['products'] = rule_products From eb3a99eba4678390094e3a4d3ba50753af517ea9 Mon Sep 17 00:00:00 2001 From: Evgeny Kolesnikov Date: Tue, 6 Feb 2024 22:46:46 +0100 Subject: [PATCH 2/4] Remove all references to prodtype (Docs) --- README.md | 2 - docs/manual/developer/01_introduction.md | 1 - docs/manual/developer/03_creating_content.md | 11 +-- docs/manual/developer/04_style_guide.md | 5 -- .../developer/05_tools_and_utilities.md | 79 +------------------ .../developer/06_contributing_with_content.md | 39 ++------- docs/modules/utils.rst | 8 -- docs/workshop/data/accounts_tmout/rule_yml | 2 - docs/workshop/lab3_profiles.adoc | 8 +- 9 files changed, 15 insertions(+), 140 deletions(-) diff --git a/README.md b/README.md index a79188f6dde..19f33470193 100644 --- a/README.md +++ b/README.md @@ -65,8 +65,6 @@ We use an OpenControl-inspired YAML rule format for input. Write once and generate security content in XCCDF, Ansible, and others. ```YAML -prodtype: rhel7 - title: 'Configure The Number of Allowed Simultaneous Requests' description: |- diff --git a/docs/manual/developer/01_introduction.md b/docs/manual/developer/01_introduction.md index 876abcd45b7..6d31016e883 100644 --- a/docs/manual/developer/01_introduction.md +++ b/docs/manual/developer/01_introduction.md @@ -98,7 +98,6 @@ The issue description must explicitly state the date and time (in UTC) when the The pull request removing the product should include the removal of 1. The product folder in `products/` 1. any Jinja templates that use the product - 1. the product from all `prodtype` 1. any product specific checks or remediations 1. any product specific templates 1. The removal must be documented in the [user guide](../user/30_content_notes.md#deprecated-content). diff --git a/docs/manual/developer/03_creating_content.md b/docs/manual/developer/03_creating_content.md index 07b0c1eb1f5..0fec8711a1c 100644 --- a/docs/manual/developer/03_creating_content.md +++ b/docs/manual/developer/03_creating_content.md @@ -180,13 +180,7 @@ Rules from multiple locations can be used for a single Benchmark. There is an optional key `additional_content_directories` for a list of paths to some arbitrary Groups of Rules to be included in the benchmark. Note that the additional directories cannot contain a benchmark file -(`benchmark.yml`), otherwise it fails to build the content. Of all the -rules collected only the following would become a part of the benchmark: - -- rules that have the `prodtype` specified in correspondence with the - benchmark; - -- rules that have no `prodtype` metadata. +(`benchmark.yml`), otherwise it fails to build the content. @@ -742,9 +736,6 @@ between XCCDF rules which directly implement the given controls (represented by The `rules` and `related_rules` keys consist of a list of rule IDs and variable selections. -If a rule needs to be chosen only in some of products despite its `prodtype` we -can use Jinja macros inside the controls file to choose products. - After we finish our analysis, we will insert our findings to the controls file, the file will look like this: diff --git a/docs/manual/developer/04_style_guide.md b/docs/manual/developer/04_style_guide.md index 5c0412851e2..262f817f6c7 100644 --- a/docs/manual/developer/04_style_guide.md +++ b/docs/manual/developer/04_style_guide.md @@ -226,11 +226,6 @@ This section describes the style guide around the `rule.yml` files. Rules sections must be in the following order, if they are present. * `documentation_complete` -* `prodtype` - * Comma separated list - * No spaces between items - * Items must be in alphabetical order - * Required on all new rules * `title` * Must be one line * Must be in [Title case](https://en.wikipedia.org/wiki/Title_case) diff --git a/docs/manual/developer/05_tools_and_utilities.md b/docs/manual/developer/05_tools_and_utilities.md index 86f8d5af927..e87e2ed5110 100644 --- a/docs/manual/developer/05_tools_and_utilities.md +++ b/docs/manual/developer/05_tools_and_utilities.md @@ -123,7 +123,6 @@ These sub-commands are: - `duplicate_subkeys`: finds (but doesn't fix!) any rules with duplicated `identifiers` or `references`. - `sort_subkeys`: sorts all subkeys under `identifiers` and `references`. -- `sort_prodtypes`: sorts the products in prodtype. - `add-cce`: automatically assign CCE identifiers to rules. To execute: @@ -156,7 +155,6 @@ Then based on the available pool you want to assign the CCEs, you can run someth ``` Note: Multiple rules can have the CCE at the same time by just adding space separated rule IDs. -Note: The rule should have the product assigned to the `prodtype` attribute or the `prodtype` should be empty. Example for `sle15` product: @@ -165,34 +163,6 @@ Example for `sle15` product: ``` -### `utils/autoprodtyper.py` – automatically add product to `prodtype` - -When building a profile for a new product version (such as forking -`ubuntu1804` into `ubuntu2004`), it is helpful to be able to build a -profile (adding in all rules that are necessary) and then attempt a -build. - -However, usually lots of rules will lack the new product in its `prodtype` -field. - -This is where `utils/autoprodtyper.py` comes in: point it at a product and -a profile and it will automatically modify the prodtype, adding this product. - -To execute: - -```bash - $ ./utils/autoprodtyper.py -``` - -For example: - -```bash - $ ./utils/autoprodtyper.py ubuntu2004 cis_level1_server -``` - -Note that it is generally good practice to commit all changes prior to running -one of these commands and then commit the results separately. - ### `utils/refchecker.py` – automatically check `rule.yml` for references This utility checks all `rule.yml` referenced from a given profile for the @@ -218,52 +188,12 @@ product-independent. Note that this utility does not modify the rule directories at all. -### `utils/mod_prodtype.py` – programmatically modify prodtype in `rule.yml` - -`utils/mod_prodtype.py` is a command-based utility for modifying `rule.yml` -files. It supports the following sub-commands: - -- `add`: add the given product(s) to the specified rule's prodtype. -- `list`: list computed and actual products in the specified rule's prodtype. -- `replace`: perform a pattern-match replacement on the specified rule's - prodtype. -- `remove`: remove the given product(s) from the specified rule's prodtype. - -To execute: - -```bash - $ ./utils/mod_prodtype.py [...other arguments...] -``` - -For an example of `add`: - -```bash - $ ./utils/mod_prodtype.py accounts_passwords_pam_tally2 add ubuntu2004 -``` - -For an example of `list`: - -```bash - $ ./utils/mod_prodtype.py accounts_passwords_pam_tally2 list -``` - -For an example of `replace`: - -```bash - $ ./utils/mod_prodtype.py accounts_passwords_pam_tally2 replace ubuntu2004~ubuntu1604,ubuntu1804,ubuntu2004 -``` - -For an example of `remove`: - -```bash - $ ./utils/mod_prodtype.py accounts_passwords_pam_tally2 remove ubuntu1604 ubuntu1804 ubuntu2004 -```` ### `utils/mod_checks.py` and `utils/mod_fixes.py` – programmatically modify check and fix applicability These two utilities have identical usage. Both modifies the platform/product -applicability of various files (either OVAL or hardening content), similar to -`utils/mod_prodtype.py` above. They supports the following sub-commands: +applicability of various files (either OVAL or hardening content). They support +the following sub-commands: - `add`: add the given platform(s) to the specified rule's OVAL check. **Note**: Only applies to shared content. @@ -613,9 +543,8 @@ $ python utils/generate_profile.py -i benchmark.xlsx list To generate a rule for a specific control: ``` -$ python utils/generate_profile.py -i benchmark.xlsx generate --product-type ocp -c 1.1.2 +$ python utils/generate_profile.py -i benchmark.xlsx generate -c 1.1.2 documentation_complete: false -prodtype: ocp title: |- Ensure that the API server pod specification file ownership is set to root:root description: 'Ensure that the API server pod specification file ownership is set to @@ -646,7 +575,7 @@ template: PLACEHOLDER To generate an entire section: ``` -$ python utils/generate_profile.py -i benchmark.xlsx generate --product-type ocp -s 1 +$ python utils/generate_profile.py -i benchmark.xlsx generate -s 1 ``` The `PLACEHOLDER` values must be filled in later, ideally when the rules are diff --git a/docs/manual/developer/06_contributing_with_content.md b/docs/manual/developer/06_contributing_with_content.md index ba3c4576b8a..13ee30506bb 100644 --- a/docs/manual/developer/06_contributing_with_content.md +++ b/docs/manual/developer/06_contributing_with_content.md @@ -518,9 +518,9 @@ the use of unversioned products here (e.g., `rhel` applies to `rhel7`, correct extension for content of that type (e.g., `.sh` for `bash` content). Further, all of these directories are optional and will only be searched for content if present. Lastly, the product naming of -content will not override the contents of `platform` or `prodtype` -fields in the content itself (e.g., if `rhel7` is not present in the -`rhel7.xml` OVAL check platform specifier, it will be included in the +content will not override the contents of `platform` field in +the content itself (e.g., if `rhel7` is not present in the `rhel7.xml` +OVAL check platform specifier, it will be included in the build artifacts but later removed because it doesn't match the platform). This means that any shared (or templated) checks won't be searched if a product-specific file is present but has the wrong applicability; @@ -542,31 +542,6 @@ For more information about these utilities, please see their help text. To interact with `rule.yml` files and the OVALs inside a rule directory, the following utilities are provided: -#### `utils/mod_prodtype.py` - -This utility modifies the prodtype field of rules. It supports several -commands: - -- `mod_prodtype.py list` - list the computed and actual - prodtype of the rule specified by `rule_id`. - -- `mod_prodtype.py add [ ...]` - add - additional products to the prodtype of the rule specified by - `rule_id`. - -- `mod_prodtype.py remove [ ...]` - - remove products to the prodtype of the rule specified by `rule_id`. - -- `mod_prodtype.py replace [ ...]` - - do the specified replacement transformations. A replacement - transformation is of the form `match~replace` where `match` and - `replace` are a comma separated list of products. If all of the - products in `match` exist in the original `prodtype` of the rule, - they are removed and the products in `replace` are added. - -This utility requires an up to date JSON tree created by -`rule_dir_json.py`. - #### `utils/mod_checks.py` This utility modifies the `` element of an OVAL check. It @@ -597,8 +572,10 @@ OVAL with the following commands: - `mod_checks.py replace [ replace [ Date: Fri, 9 Feb 2024 00:45:17 +0100 Subject: [PATCH 3/4] Replace bogus 'prodtype' with 'product' in Jinja expressions Some rules got it wrong. --- .../ftp_configure_vsftpd/ftp_configure_firewall/rule.yml | 2 +- linux_os/guide/services/ntp/service_ntp_enabled/rule.yml | 4 ++-- linux_os/guide/services/ntp/service_ntpd_enabled/rule.yml | 2 +- .../services/ssh/ssh_server/sshd_set_keepalive_0/rule.yml | 1 - .../package_audit-audispd-plugins_installed/rule.yml | 6 +++--- .../system/software/sudo/sudoers_no_root_target/rule.yml | 2 -- 6 files changed, 7 insertions(+), 10 deletions(-) diff --git a/linux_os/guide/services/ftp/ftp_configure_vsftpd/ftp_configure_firewall/rule.yml b/linux_os/guide/services/ftp/ftp_configure_vsftpd/ftp_configure_firewall/rule.yml index 24db0f19859..5bbba879d62 100644 --- a/linux_os/guide/services/ftp/ftp_configure_vsftpd/ftp_configure_firewall/rule.yml +++ b/linux_os/guide/services/ftp/ftp_configure_vsftpd/ftp_configure_firewall/rule.yml @@ -21,7 +21,7 @@ description: |- rationale: |- These settings configure the firewall to allow connections to an FTP server. - {{% if prodtype != "rhel7" %}} + {{% if product != "rhel7" %}} The first line allows initial connections to the FTP server port. FTP is an older protocol which is not very compatible with firewalls. During the initial FTP dialogue, the client and server negotiate an arbitrary port to be used for data transfer. The ip_conntrack_ftp module is used by diff --git a/linux_os/guide/services/ntp/service_ntp_enabled/rule.yml b/linux_os/guide/services/ntp/service_ntp_enabled/rule.yml index 50ea8f8563d..c375c0f2509 100644 --- a/linux_os/guide/services/ntp/service_ntp_enabled/rule.yml +++ b/linux_os/guide/services/ntp/service_ntp_enabled/rule.yml @@ -48,10 +48,10 @@ template: vars: servicename: ntp -{{% if prodtype in ["rhel7", "rhel8", "rhel9", "sle15"] %}} +{{% if product in ["rhel7", "rhel8", "rhel9", "sle15"] %}} warnings: - general: - {{% if prodtype == "rhel7" %}} + {{% if product == "rhel7" %}} The
ntp.service
Systemd unit is not available in {{{ full_name }}}.
ntpd.service
should be used instead together with the respective
service_ntpd_enabled
rule.. {{% else %}} diff --git a/linux_os/guide/services/ntp/service_ntpd_enabled/rule.yml b/linux_os/guide/services/ntp/service_ntpd_enabled/rule.yml index 0478d2e5a65..a54c9257bb6 100644 --- a/linux_os/guide/services/ntp/service_ntpd_enabled/rule.yml +++ b/linux_os/guide/services/ntp/service_ntpd_enabled/rule.yml @@ -50,7 +50,7 @@ template: platform: package[ntp] -{{% if prodtype in ["rhel8", "rhel9", "sle15"] %}} +{{% if product in ["rhel8", "rhel9", "sle15"] %}} warnings: - general: The
ntp
package is not available in {{{ full_name }}}. Please diff --git a/linux_os/guide/services/ssh/ssh_server/sshd_set_keepalive_0/rule.yml b/linux_os/guide/services/ssh/ssh_server/sshd_set_keepalive_0/rule.yml index a8ca3021253..40fde9becc2 100644 --- a/linux_os/guide/services/ssh/ssh_server/sshd_set_keepalive_0/rule.yml +++ b/linux_os/guide/services/ssh/ssh_server/sshd_set_keepalive_0/rule.yml @@ -1,7 +1,6 @@ documentation_complete: true # applicable only to products that ship OpenSSH<8.2 -# prodtypes: ??? title: 'Set SSH Client Alive Count Max to zero' diff --git a/linux_os/guide/system/auditing/package_audit-audispd-plugins_installed/rule.yml b/linux_os/guide/system/auditing/package_audit-audispd-plugins_installed/rule.yml index 800f854a540..052deab171c 100644 --- a/linux_os/guide/system/auditing/package_audit-audispd-plugins_installed/rule.yml +++ b/linux_os/guide/system/auditing/package_audit-audispd-plugins_installed/rule.yml @@ -34,9 +34,9 @@ template: pkgname@ubuntu1804: audispd-plugins pkgname@ubuntu2004: audispd-plugins -{{% if prodtype in ["rhel7", "rhel8", "rhel9"] %}} +{{% if product in ["rhel7", "rhel8", "rhel9"] %}} warnings: - general: - This package is not available in {{{ full_name }}}. The correct package - is called
audispd-plugins
. The rule
 is suggested as a replacement.
+        This package is not available in {{{ full_name }}} [{{{ product }}}]. The correct package
+        is called 
audispd-plugins
. {{% endif %}} diff --git a/linux_os/guide/system/software/sudo/sudoers_no_root_target/rule.yml b/linux_os/guide/system/software/sudo/sudoers_no_root_target/rule.yml index 2bb55b3cd8c..5e5a4320a76 100644 --- a/linux_os/guide/system/software/sudo/sudoers_no_root_target/rule.yml +++ b/linux_os/guide/system/software/sudo/sudoers_no_root_target/rule.yml @@ -1,7 +1,5 @@ documentation_complete: true -# Set prodtypes if needed, otherwise let the rule to be applicable for all products by omitting the prodtype declaration - title: "Don't target root user in the sudoers file" description: |- From 08d3fb743ecab85a195001738ef45ea20014ce23 Mon Sep 17 00:00:00 2001 From: Evgeny Kolesnikov Date: Mon, 12 Feb 2024 13:13:23 +0100 Subject: [PATCH 4/4] Minor fixes after removal of prodtype --- docs/manual/developer/03_creating_content.md | 3 +++ ssg/build_sce.py | 2 +- tests/ssg_test_suite/common.py | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/manual/developer/03_creating_content.md b/docs/manual/developer/03_creating_content.md index 0fec8711a1c..b24e6c82e72 100644 --- a/docs/manual/developer/03_creating_content.md +++ b/docs/manual/developer/03_creating_content.md @@ -736,6 +736,9 @@ between XCCDF rules which directly implement the given controls (represented by The `rules` and `related_rules` keys consist of a list of rule IDs and variable selections. +If a rule needs to be chosen only in some of the products we can use Jinja macros +inside the controls file to choose products. + After we finish our analysis, we will insert our findings to the controls file, the file will look like this: diff --git a/ssg/build_sce.py b/ssg/build_sce.py index d4cbdb4a509..cd740ae1364 100644 --- a/ssg/build_sce.py +++ b/ssg/build_sce.py @@ -135,7 +135,7 @@ def checks(env_yaml, yaml_path, sce_dirs, template_builder, output): local_env_yaml['rule_id'] = rule.id_ local_env_yaml['rule_title'] = rule.title - local_env_yaml["products"] = {product} + local_env_yaml['products'] = {product} for _path in get_rule_dir_sces(_dir_path, product): # To be compatible with later checks, use the rule_id (i.e., the diff --git a/tests/ssg_test_suite/common.py b/tests/ssg_test_suite/common.py index 9678fb834b9..ffa25548e18 100644 --- a/tests/ssg_test_suite/common.py +++ b/tests/ssg_test_suite/common.py @@ -314,7 +314,7 @@ def load_rule_and_env(rule_dir_path, env_yaml, product=None): local_env_yaml.update(env_yaml) local_env_yaml['rule_id'] = rule.id_ local_env_yaml['rule_title'] = rule.title - local_env_yaml["products"] = {product} + local_env_yaml['products'] = {product} return rule, local_env_yaml