diff --git a/docs/templates/template_reference.md b/docs/templates/template_reference.md index fabe08824252..66f1ba668b96 100644 --- a/docs/templates/template_reference.md +++ b/docs/templates/template_reference.md @@ -1118,6 +1118,9 @@ escape_yaml_key - Escape uppercase letters and `^` with additional `^` and convert letters to lovercase. This is because of OVAL's name argument limitations. +join_comma_and +- Join list using comma and "and". Example ["a", "b", "c"] -> "a, b and c". + quote - Escape string to be used as POSIX shell value. Like Ansible `quote`. diff --git a/linux_os/guide/services/ssh/ssh_server/firewalld_sshd_port_enabled/ansible/shared.yml b/linux_os/guide/services/ssh/ssh_server/firewalld_sshd_port_enabled/ansible/shared.yml index 7b0bda3f10c4..8167cf7b34aa 100644 --- a/linux_os/guide/services/ssh/ssh_server/firewalld_sshd_port_enabled/ansible/shared.yml +++ b/linux_os/guide/services/ssh/ssh_server/firewalld_sshd_port_enabled/ansible/shared.yml @@ -6,13 +6,7 @@ {{{ ansible_instantiate_variables("firewalld_sshd_zone") }}} -- name: '{{{ rule_title }}} - Ensure firewalld and NetworkManager packages are installed' - ansible.builtin.package: - name: "{{ item }}" - state: present - with_items: - - firewalld - - NetworkManager +{{{ ansible_package_install(["firewalld", "NetworkManager"]) }}} - name: '{{{ rule_title }}} - Collect facts about system services' ansible.builtin.service_facts: diff --git a/linux_os/guide/system/accounts/accounts-pam/locking_out_password_attempts/accounts_passwords_pam_faillock_dir/ansible/shared.yml b/linux_os/guide/system/accounts/accounts-pam/locking_out_password_attempts/accounts_passwords_pam_faillock_dir/ansible/shared.yml index e199dc3dca83..f03e107fa1b0 100644 --- a/linux_os/guide/system/accounts/accounts-pam/locking_out_password_attempts/accounts_passwords_pam_faillock_dir/ansible/shared.yml +++ b/linux_os/guide/system/accounts/accounts-pam/locking_out_password_attempts/accounts_passwords_pam_faillock_dir/ansible/shared.yml @@ -7,14 +7,7 @@ {{{ ansible_pam_faillock_enable() }}} {{{ ansible_pam_faillock_parameter_value("dir", "var_accounts_passwords_pam_faillock_dir") }}} -- name: '{{{ rule_title }}} - Ensure necessary SELinux packages are installed' - ansible.builtin.package: - name: "{{ item }}" - state: present - with_items: - - python3-libselinux - - python3-policycoreutils - - policycoreutils-python-utils +{{{ ansible_package_install(["python3-libselinux", "python3-policycoreutils", "policycoreutils-python-utils"], "necessary SELinux") }}} - name: '{{{ rule_title }}} - Create the tally directory if it does not exist' ansible.builtin.file: diff --git a/linux_os/guide/system/network/network-firewalld/ruleset_modifications/firewalld_loopback_traffic_restricted/ansible/shared.yml b/linux_os/guide/system/network/network-firewalld/ruleset_modifications/firewalld_loopback_traffic_restricted/ansible/shared.yml index 475705446586..1cc3861b26a2 100644 --- a/linux_os/guide/system/network/network-firewalld/ruleset_modifications/firewalld_loopback_traffic_restricted/ansible/shared.yml +++ b/linux_os/guide/system/network/network-firewalld/ruleset_modifications/firewalld_loopback_traffic_restricted/ansible/shared.yml @@ -4,12 +4,7 @@ # strategy = configure # disruption = low -- name: '{{{ rule_title }}} - Ensure firewalld Package is Installed' - ansible.builtin.package: - name: "{{ item }}" - state: present - with_items: - - firewalld +{{{ ansible_package_install(["firewalld"]) }}} - name: '{{{ rule_title }}} - Collect Facts About System Services' ansible.builtin.service_facts: diff --git a/linux_os/guide/system/network/network-firewalld/ruleset_modifications/firewalld_loopback_traffic_trusted/ansible/shared.yml b/linux_os/guide/system/network/network-firewalld/ruleset_modifications/firewalld_loopback_traffic_trusted/ansible/shared.yml index 311650f72ee8..1d14fd889d08 100644 --- a/linux_os/guide/system/network/network-firewalld/ruleset_modifications/firewalld_loopback_traffic_trusted/ansible/shared.yml +++ b/linux_os/guide/system/network/network-firewalld/ruleset_modifications/firewalld_loopback_traffic_trusted/ansible/shared.yml @@ -4,12 +4,7 @@ # strategy = configure # disruption = low -- name: '{{{ rule_title }}} - Ensure firewalld Package is Installed' - ansible.builtin.package: - name: "{{ item }}" - state: present - with_items: - - firewalld +{{{ ansible_package_install(["firewalld"]) }}} - name: '{{{ rule_title }}} - Collect Facts About System Services' ansible.builtin.service_facts: diff --git a/linux_os/guide/system/network/network-wireless/wireless_software/wireless_disable_interfaces/ansible/shared.yml b/linux_os/guide/system/network/network-wireless/wireless_software/wireless_disable_interfaces/ansible/shared.yml index be7a30c34a31..d7b9f542435e 100644 --- a/linux_os/guide/system/network/network-wireless/wireless_software/wireless_disable_interfaces/ansible/shared.yml +++ b/linux_os/guide/system/network/network-wireless/wireless_software/wireless_disable_interfaces/ansible/shared.yml @@ -4,12 +4,7 @@ # complexity = low # disruption = medium -- name: Ensure NetworkManager is installed - ansible.builtin.package: - name: "{{ item }}" - state: present - with_items: - - NetworkManager +{{{ ansible_package_install(["NetworkManager"]) }}} - name: Deactivate Wireless Network Interfaces command: nmcli radio wifi off diff --git a/linux_os/guide/system/software/integrity/fips/grub2_enable_fips_mode/ansible/shared.yml b/linux_os/guide/system/software/integrity/fips/grub2_enable_fips_mode/ansible/shared.yml index 3af960a36984..82ee56ec83f7 100644 --- a/linux_os/guide/system/software/integrity/fips/grub2_enable_fips_mode/ansible/shared.yml +++ b/linux_os/guide/system/software/integrity/fips/grub2_enable_fips_mode/ansible/shared.yml @@ -26,17 +26,11 @@ register: aesni_supported check_mode: no -- name: Ensure dracut-fips-aesni is installed - package: - name: dracut-fips-aesni - state: present +{{{ ansible_package_install(["dracut-fips-aesni"]) }}} when: - aesni_supported.rc == 0 -- name: Install dracut-fips - package: - name: dracut-fips - state: present +{{{ ansible_package_install(["dracut-fips"]) }}} - name: Rebuild initramfs command: dracut -f diff --git a/linux_os/guide/system/software/integrity/fips/package_dracut-fips-aesni_installed/ansible/shared.yml b/linux_os/guide/system/software/integrity/fips/package_dracut-fips-aesni_installed/ansible/shared.yml index 7c3e3c4f4160..618d95efcb62 100644 --- a/linux_os/guide/system/software/integrity/fips/package_dracut-fips-aesni_installed/ansible/shared.yml +++ b/linux_os/guide/system/software/integrity/fips/package_dracut-fips-aesni_installed/ansible/shared.yml @@ -9,9 +9,6 @@ register: aesni_supported check_mode: no -- name: Ensure dracut-fips-aesni is installed - package: - name: dracut-fips-aesni - state: present +{{{ ansible_package_install(["dracut-fips-aesni"]) }}} when: - aesni_supported.rc == 0 diff --git a/linux_os/guide/system/software/integrity/software-integrity/aide/aide_build_database/ansible/shared.yml b/linux_os/guide/system/software/integrity/software-integrity/aide/aide_build_database/ansible/shared.yml index d9b022f0d54a..c0ca52e48f76 100644 --- a/linux_os/guide/system/software/integrity/software-integrity/aide/aide_build_database/ansible/shared.yml +++ b/linux_os/guide/system/software/integrity/software-integrity/aide/aide_build_database/ansible/shared.yml @@ -3,12 +3,8 @@ # strategy = restrict # complexity = low # disruption = low -- name: "Ensure AIDE is installed" - package: - name: "{{ item }}" - state: present - with_items: - - aide + +{{{ ansible_package_install(['aide'], name="AIDE") }}} - name: "Build and Test AIDE Database" {{% if 'sle' in product %}} diff --git a/linux_os/guide/system/software/integrity/software-integrity/aide/aide_check_audit_tools/ansible/shared.yml b/linux_os/guide/system/software/integrity/software-integrity/aide/aide_check_audit_tools/ansible/shared.yml index b40cc174d0eb..7c8a5bf961b0 100644 --- a/linux_os/guide/system/software/integrity/software-integrity/aide/aide_check_audit_tools/ansible/shared.yml +++ b/linux_os/guide/system/software/integrity/software-integrity/aide/aide_check_audit_tools/ansible/shared.yml @@ -4,13 +4,7 @@ # complexity = low # disruption = low -- name: Ensure aide is installed - package: - name: "{{ item }}" - state: present - with_items: - - aide - +{{{ ansible_package_install(['aide'], name="AIDE") }}} - name: Set audit_tools fact set_fact: diff --git a/linux_os/guide/system/software/integrity/software-integrity/aide/aide_periodic_cron_checking/ansible/shared.yml b/linux_os/guide/system/software/integrity/software-integrity/aide/aide_periodic_cron_checking/ansible/shared.yml index 7d4063bda297..be6c8d1d533c 100644 --- a/linux_os/guide/system/software/integrity/software-integrity/aide/aide_periodic_cron_checking/ansible/shared.yml +++ b/linux_os/guide/system/software/integrity/software-integrity/aide/aide_periodic_cron_checking/ansible/shared.yml @@ -3,12 +3,8 @@ # strategy = restrict # complexity = low # disruption = low -- name: "Ensure AIDE is installed" - package: - name: - - aide - - crontabs - state: present + +{{{ ansible_package_install(['aide', 'crontabs'], name="AIDE") }}} - name: Set cron package name - RedHat set_fact: diff --git a/linux_os/guide/system/software/integrity/software-integrity/aide/aide_scan_notification/ansible/shared.yml b/linux_os/guide/system/software/integrity/software-integrity/aide/aide_scan_notification/ansible/shared.yml index 45db52bf238c..58289b10eb28 100644 --- a/linux_os/guide/system/software/integrity/software-integrity/aide/aide_scan_notification/ansible/shared.yml +++ b/linux_os/guide/system/software/integrity/software-integrity/aide/aide_scan_notification/ansible/shared.yml @@ -5,12 +5,7 @@ # disruption = low - (xccdf-var var_aide_scan_notification_email) -- name: "Ensure AIDE is installed" - package: - name: - - aide - - crontabs - state: present +{{{ ansible_package_install(['aide', 'crontabs'], name="AIDE") }}} - name: "{{{ rule_title }}}" cron: diff --git a/shared/macros/10-ansible.jinja b/shared/macros/10-ansible.jinja index 47103022b21c..4ad993b7aa6f 100644 --- a/shared/macros/10-ansible.jinja +++ b/shared/macros/10-ansible.jinja @@ -771,6 +771,37 @@ The following macro remediates Audit syscall rule in :code:`/etc/audit/audit.rul {{%- endmacro -%}} +{{# +Ansible ansible.builtin.package wrapping macro, ensure package(s) are installed + +:param package: Package(s) to ensure are installed +:type package: str | list[str] +:param name: Name used in task name. If not set, package names joined with comma and "and". +:type name: None | str + +#}} +{{%- macro ansible_package_install(package, name=none) -%}} +{{%- if (package is sequence) and (package is not mapping) and (package is not string) -%}} +{{%- set packages = package -%}} +{{%- else %}} +{{%- set packages = [package] -%}} +{{%- endif %}} +{{%- if name is none %}} +{{%- set name = "the " ~ (packages | join_comma_and) -%}} +{{%- endif %}} +- name: "{{{ rule_title }}} - Ensure {{{ name }}} {{% if packages | length > 1 %}}Packages Are{{% else %}}Package Is{{% endif %}} Installed" + ansible.builtin.package: + name: +{{%- for p in packages %}} +{{%- if p in platform_package_overrides %}} + {{%- set p = platform_package_overrides[p] %}} +{{%- endif %}} + - "{{{ p }}}" +{{%- endfor %}} + state: present +{{%- endmacro -%}} + + {{# Macro used to check if authselect files are intact. When used, it will exit the respective script if any authselect file was modified without proper use of authselect tool and diff --git a/shared/macros/10-bash.jinja b/shared/macros/10-bash.jinja index 3316c4875614..020393b5c97e 100644 --- a/shared/macros/10-bash.jinja +++ b/shared/macros/10-bash.jinja @@ -603,6 +603,9 @@ done #}} {{%- macro bash_package_install(package) -%}} +{{%- if package in platform_package_overrides -%}} + {{%- set package = platform_package_overrides[package] -%}} +{{%- endif -%}} {{%- if pkg_manager is defined -%}} {{%- if pkg_manager == "yum" or pkg_manager == "dnf" -%}} if ! rpm -q --quiet "{{{ package }}}" ; then @@ -632,6 +635,9 @@ zypper install -y "{{{ package }}}" #}} {{%- macro bash_package_remove(package) -%}} +{{%- if package in platform_package_overrides -%}} + {{%- set package = platform_package_overrides[package] -%}} +{{%- endif -%}} {{%- if pkg_manager is defined -%}} {{%- if pkg_manager == "yum" or pkg_manager == "dnf" -%}} if rpm -q --quiet "{{{ package }}}" ; then diff --git a/ssg/jinja.py b/ssg/jinja.py index 7aee25b5ecc3..127d93d7d114 100644 --- a/ssg/jinja.py +++ b/ssg/jinja.py @@ -24,6 +24,7 @@ escape_id, escape_regex, escape_yaml_key, + join_comma_and, sha256 ) @@ -95,6 +96,7 @@ def _get_jinja_environment(substitutions_dict): _get_jinja_environment.env.filters['escape_id'] = escape_id _get_jinja_environment.env.filters['escape_regex'] = escape_regex _get_jinja_environment.env.filters['escape_yaml_key'] = escape_yaml_key + _get_jinja_environment.env.filters['join_comma_and'] = join_comma_and _get_jinja_environment.env.filters['quote'] = shell_quote _get_jinja_environment.env.filters['sha256'] = sha256 diff --git a/ssg/utils.py b/ssg/utils.py index 1c2ac1d42511..789ce938665d 100644 --- a/ssg/utils.py +++ b/ssg/utils.py @@ -470,3 +470,7 @@ def apply_formatting_on_dict_values(source_dict, string_dict, ignored_keys=froze else: new_dict[k] = v return new_dict + + +def join_comma_and(lst): + return ", ".join(lst[:-2] + [" and ".join(lst[-2:])]) diff --git a/tests/unit/ssg-module/test_jinja.py b/tests/unit/ssg-module/test_jinja.py index 7545515a4879..20909fcf41db 100644 --- a/tests/unit/ssg-module/test_jinja.py +++ b/tests/unit/ssg-module/test_jinja.py @@ -26,3 +26,11 @@ def test_macro_expansion(): complete_defs = get_definitions_with_substitution(dict(global_var="value")) assert complete_defs["expand_to_global_var"]() == "value" + + +def test_join_comma_and(): + assert ssg.jinja.join_comma_and([]) == "" + assert ssg.jinja.join_comma_and(["first"]) == "first" + assert ssg.jinja.join_comma_and(["first", "last"]) == "first and last" + assert ssg.jinja.join_comma_and(["first", "b", "last"]) == "first, b and last" + assert ssg.jinja.join_comma_and(["first", "b", "c", "last"]) == "first, b, c and last"