{{% for file in configuration_files %}}
-
{{% endfor %}}
diff --git a/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_retry/rule.yml b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_retry/rule.yml
index 6e25f29481a..1fe3c52f0a5 100644
--- a/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_retry/rule.yml
+++ b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_retry/rule.yml
@@ -5,7 +5,7 @@ title: 'Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
description: |-
To configure the number of retry prompts that are permitted per-session:
- {{% if product in ['ol8', 'ol9', 'rhel8', 'rhel9'] %}}
+ {{% if product in ['ol8', 'ol9'] or 'rhel' in product %}}
Edit the /etc/security/pwquality.conf to include
{{% else %}}
Edit the pam_pwquality.so statement in
@@ -56,7 +56,7 @@ ocil_clause: 'the value of "retry" is set to "0" or greater than "{{{ xccdf_valu
ocil: |-
Verify {{{ full_name }}} is configured to limit the "pwquality" retry option to {{{ xccdf_value("var_password_pam_retry") }}}.
- {{% if product in ['ol8', 'ol9', 'rhel8', 'rhel9'] %}}
+ {{% if product in ['ol8', 'ol9'] or 'rhel' in product %}}
Check for the use of the "pwquality" retry option in the pwquality.conf file with the following command:
$ grep retry /etc/security/pwquality.conf
{{% else %}}
@@ -75,7 +75,7 @@ platform: package[pam]
fixtext: |-
Configure {{{ full_name }}} to limit the "pwquality" retry option to {{{ xccdf_value("var_password_pam_retry") }}}.
- {{% if product in ['ol8', 'ol9', 'rhel8', 'rhel9'] %}}
+ {{% if product in ['ol8', 'ol9'] or 'rhel' in product %}}
Add the following line to the "/etc/security/pwquality.conf" file (or modify the line to have the required value):
retry={{{ xccdf_value("var_password_pam_retry") }}}
diff --git a/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_retry/tests/common.sh b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_retry/tests/common.sh
index 02bd487048c..0ab3da26636 100644
--- a/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_retry/tests/common.sh
+++ b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_retry/tests/common.sh
@@ -1,13 +1,13 @@
{{% if 'ubuntu' in product %}}
configuration_files=("common-password")
-{{% elif product in ['ol8', 'ol9', 'rhel8', 'rhel9'] %}}
+{{% elif product in ['ol8', 'ol9'] or 'rhel' in product %}}
configuration_files=("password-auth" "system-auth")
{{% else %}}
configuration_files=("system-auth")
{{% endif %}}
-{{% if product in ['ol8', 'ol9', 'rhel8', 'rhel9'] %}}
+{{% if product in ['ol8', 'ol9'] or 'rhel' in product %}}
authselect create-profile testingProfile --base-on sssd
for file in ${configuration_files[@]}; do
diff --git a/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_retry/tests/pwquality_conf_commented.fail.sh b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_retry/tests/pwquality_conf_commented.fail.sh
index 19cac93f41d..c61f9b6d5fa 100644
--- a/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_retry/tests/pwquality_conf_commented.fail.sh
+++ b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_retry/tests/pwquality_conf_commented.fail.sh
@@ -1,6 +1,6 @@
#!/bin/bash
# packages = authselect
-# platform = Oracle Linux 8,Oracle Linux 9,Red Hat Enterprise Linux 8,Red Hat Enterprise Linux 9
+# platform = Oracle Linux 8,Oracle Linux 9,multi_platform_rhel
# variables = var_password_pam_retry=3
source common.sh
diff --git a/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_retry/tests/pwquality_conf_correct.pass.sh b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_retry/tests/pwquality_conf_correct.pass.sh
index ae605f71726..601d3275906 100644
--- a/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_retry/tests/pwquality_conf_correct.pass.sh
+++ b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_retry/tests/pwquality_conf_correct.pass.sh
@@ -1,6 +1,6 @@
#!/bin/bash
# packages = authselect
-# platform = Oracle Linux 8,Oracle Linux 9,Red Hat Enterprise Linux 8,Red Hat Enterprise Linux 9
+# platform = Oracle Linux 8,Oracle Linux 9,multi_platform_rhel
# variables = var_password_pam_retry=3
source common.sh
diff --git a/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_retry/tests/pwquality_conf_correct_with_space.pass.sh b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_retry/tests/pwquality_conf_correct_with_space.pass.sh
index ce7f4b7a3cb..e4f1de0cc4a 100644
--- a/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_retry/tests/pwquality_conf_correct_with_space.pass.sh
+++ b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_retry/tests/pwquality_conf_correct_with_space.pass.sh
@@ -1,6 +1,6 @@
#!/bin/bash
# packages = authselect
-# platform = Oracle Linux 8,Oracle Linux 9,Red Hat Enterprise Linux 8,Red Hat Enterprise Linux 9
+# platform = Oracle Linux 8,Oracle Linux 9,multi_platform_rhel
# variables = var_password_pam_retry=3
source common.sh
diff --git a/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_retry/tests/pwquality_conf_overriden.fail.sh b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_retry/tests/pwquality_conf_overriden.fail.sh
index 962112d6a25..d70521e76fe 100644
--- a/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_retry/tests/pwquality_conf_overriden.fail.sh
+++ b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_retry/tests/pwquality_conf_overriden.fail.sh
@@ -1,6 +1,6 @@
#!/bin/bash
# packages = authselect
-# platform = Oracle Linux 8,Oracle Linux 9,Red Hat Enterprise Linux 8,Red Hat Enterprise Linux 9
+# platform = Oracle Linux 8,Oracle Linux 9,multi_platform_rhel
# variables = var_password_pam_retry=3
source common.sh
diff --git a/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_retry/tests/pwquality_conf_wrong.fail.sh b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_retry/tests/pwquality_conf_wrong.fail.sh
index ea2eb57fed5..dc7fe32d110 100644
--- a/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_retry/tests/pwquality_conf_wrong.fail.sh
+++ b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_retry/tests/pwquality_conf_wrong.fail.sh
@@ -1,6 +1,6 @@
#!/bin/bash
# packages = authselect
-# platform = Oracle Linux 8,Oracle Linux 9,Red Hat Enterprise Linux 8,Red Hat Enterprise Linux 9
+# platform = Oracle Linux 8,Oracle Linux 9,multi_platform_rhel
# variables = var_password_pam_retry=3
source common.sh
diff --git a/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_passwordauth/rule.yml b/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_passwordauth/rule.yml
index 13da3921ff6..d03a7af4415 100644
--- a/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_passwordauth/rule.yml
+++ b/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_passwordauth/rule.yml
@@ -63,7 +63,7 @@ ocil: |-
platform: package[pam]
-{{% if product in ['ol9', 'rhel9'] %}}
+{{% if product in ['ol9', 'rhel9', 'rhel10'] %}}
srg_requirement: 'The {{{ full_name }}} pam_unix.so module must be configured in the password-auth file to use a FIPS 140-3 approved cryptographic hashing algorithm for system authentication.'
fixtext: |-
diff --git a/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_passwordauth/tests/authselect_correct_value.pass.sh b/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_passwordauth/tests/authselect_correct_value.pass.sh
index abcdf02f5a2..ee1213c2df0 100644
--- a/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_passwordauth/tests/authselect_correct_value.pass.sh
+++ b/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_passwordauth/tests/authselect_correct_value.pass.sh
@@ -1,6 +1,6 @@
#!/bin/bash
# packages = authselect
-# platform = Oracle Linux 8,Oracle Linux 9,Red Hat Enterprise Linux 8,Red Hat Enterprise Linux 9,multi_platform_fedora
+# platform = Oracle Linux 8,Oracle Linux 9,multi_platform_rhel,multi_platform_fedora
# variables = var_password_hashing_algorithm_pam=sha512
authselect create-profile hardening -b sssd
diff --git a/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_passwordauth/tests/authselect_incorrect_option.fail.sh b/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_passwordauth/tests/authselect_incorrect_option.fail.sh
index 1572f0d9ba1..8d6be38f4d4 100644
--- a/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_passwordauth/tests/authselect_incorrect_option.fail.sh
+++ b/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_passwordauth/tests/authselect_incorrect_option.fail.sh
@@ -1,6 +1,6 @@
#!/bin/bash
# packages = authselect
-# platform = Oracle Linux 8,Oracle Linux 9,Red Hat Enterprise Linux 8,Red Hat Enterprise Linux 9,multi_platform_fedora
+# platform = Oracle Linux 8,Oracle Linux 9,multi_platform_rhel,multi_platform_fedora
# variables = var_password_hashing_algorithm_pam=sha512
authselect create-profile hardening -b sssd
diff --git a/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_passwordauth/tests/authselect_missing_option.fail.sh b/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_passwordauth/tests/authselect_missing_option.fail.sh
index 463b78e5527..13f217f0273 100644
--- a/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_passwordauth/tests/authselect_missing_option.fail.sh
+++ b/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_passwordauth/tests/authselect_missing_option.fail.sh
@@ -1,6 +1,6 @@
#!/bin/bash
# packages = authselect
-# platform = Oracle Linux 8,Oracle Linux 9,Red Hat Enterprise Linux 8,Red Hat Enterprise Linux 9,multi_platform_fedora
+# platform = Oracle Linux 8,Oracle Linux 9,multi_platform_rhel,multi_platform_fedora
# variables = var_password_hashing_algorithm_pam=sha512
authselect create-profile hardening -b sssd
diff --git a/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_passwordauth/tests/authselect_modified_pam.fail.sh b/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_passwordauth/tests/authselect_modified_pam.fail.sh
index a36ff143d44..5632949e220 100644
--- a/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_passwordauth/tests/authselect_modified_pam.fail.sh
+++ b/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_passwordauth/tests/authselect_modified_pam.fail.sh
@@ -1,6 +1,6 @@
#!/bin/bash
# packages = authselect
-# platform = Oracle Linux 8,Oracle Linux 9,Red Hat Enterprise Linux 8,Red Hat Enterprise Linux 9,multi_platform_fedora
+# platform = Oracle Linux 8,Oracle Linux 9,multi_platform_rhel,multi_platform_fedora
# variables = var_password_hashing_algorithm_pam=sha512
# remediation = none
diff --git a/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_passwordauth/tests/authselect_multiple_options.fail.sh b/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_passwordauth/tests/authselect_multiple_options.fail.sh
index b874f33d6da..7f6ff9a978f 100644
--- a/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_passwordauth/tests/authselect_multiple_options.fail.sh
+++ b/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_passwordauth/tests/authselect_multiple_options.fail.sh
@@ -1,6 +1,6 @@
#!/bin/bash
# packages = authselect
-# platform = Oracle Linux 8,Oracle Linux 9,Red Hat Enterprise Linux 8,Red Hat Enterprise Linux 9,multi_platform_fedora
+# platform = Oracle Linux 8,Oracle Linux 9,multi_platform_rhel,multi_platform_fedora
# variables = var_password_hashing_algorithm_pam=sha512
authselect create-profile hardening -b sssd
diff --git a/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_passwordauth/tests/authselect_wrong_control.fail.sh b/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_passwordauth/tests/authselect_wrong_control.fail.sh
index 98aff168eb6..10a02eb86d1 100644
--- a/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_passwordauth/tests/authselect_wrong_control.fail.sh
+++ b/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_passwordauth/tests/authselect_wrong_control.fail.sh
@@ -1,6 +1,6 @@
#!/bin/bash
# packages = authselect
-# platform = Oracle Linux 8,Oracle Linux 9,Red Hat Enterprise Linux 8,Red Hat Enterprise Linux 9,multi_platform_fedora
+# platform = Oracle Linux 8,Oracle Linux 9,multi_platform_rhel,multi_platform_fedora
# variables = var_password_hashing_algorithm_pam=sha512
authselect create-profile hardening -b sssd
diff --git a/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_systemauth/bash/shared.sh b/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_systemauth/bash/shared.sh
index 977e62cd3ea..77b57a39555 100644
--- a/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_systemauth/bash/shared.sh
+++ b/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_systemauth/bash/shared.sh
@@ -4,13 +4,13 @@
{{% if 'sle' in product or 'slmicro' in product -%}}
PAM_FILE_PATH="/etc/pam.d/common-password"
-CONTROL="required"
+{{% set control = "required" %}}
{{%- elif 'ubuntu' in product -%}}
{{{ bash_pam_unix_enable() }}}
PAM_FILE_PATH=/usr/share/pam-configs/cac_unix
{{%- else -%}}
PAM_FILE_PATH="/etc/pam.d/system-auth"
-CONTROL="sufficient"
+{{% set control = "sufficient" %}}
{{%- endif %}}
{{% if 'ubuntu' in product -%}}
@@ -31,7 +31,7 @@ if ! grep -qzP "Password-Initial:\s*\n\s+.*\s+pam_unix.so\s+.*\b$var_password_ha
fi
{{%- else -%}}
-{{{ bash_ensure_pam_module_configuration("$PAM_FILE_PATH", 'password', "$CONTROL", 'pam_unix.so', "$var_password_hashing_algorithm_pam", '', '') }}}
+{{{ bash_ensure_pam_module_configuration("$PAM_FILE_PATH", 'password', control, 'pam_unix.so', "$var_password_hashing_algorithm_pam", '', '') }}}
{{%- endif %}}
# Ensure only the correct hashing algorithm option is used.
diff --git a/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_systemauth/rule.yml b/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_systemauth/rule.yml
index aa69bb5dff8..dbc370188f3 100644
--- a/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_systemauth/rule.yml
+++ b/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_systemauth/rule.yml
@@ -90,7 +90,7 @@ ocil: |-
platform: package[pam]
fixtext: |-
- {{% if product in ['ol9', 'rhel9', 'ubuntu2204', 'ubuntu2404'] -%}}
+ {{% if product in ['ol9', 'rhel9', 'rhel10', 'ubuntu2204', 'ubuntu2404'] -%}}
Configure {{{ full_name }}} to use a FIPS 140-3 approved cryptographic hashing algorithm for system authentication.
{{% else %}}
Configure {{{ full_name }}} to use a FIPS 140-2 approved cryptographic hashing algorithm for system authentication.
@@ -106,7 +106,7 @@ fixtext: |-
password sufficient pam_unix.so {{{ xccdf_value("var_password_hashing_algorithm_pam") }}}
{{%- endif %}}
-{{% if product in ['ol9', 'rhel9'] -%}}
+{{% if product in ['ol9', 'rhel9', 'rhel10'] -%}}
srg_requirement: 'The {{{ full_name }}} pam_unix.so module must be configured in the system-auth file to use a FIPS 140-3 approved cryptographic hashing algorithm for system authentication.'
{{%- endif %}}
diff --git a/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_systemauth/tests/authselect_correct_value.pass.sh b/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_systemauth/tests/authselect_correct_value.pass.sh
index a665b3b10f9..264df72f1cf 100644
--- a/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_systemauth/tests/authselect_correct_value.pass.sh
+++ b/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_systemauth/tests/authselect_correct_value.pass.sh
@@ -1,6 +1,6 @@
#!/bin/bash
# packages = authselect
-# platform = Oracle Linux 8,Oracle Linux 9,Red Hat Enterprise Linux 8,Red Hat Enterprise Linux 9,multi_platform_fedora
+# platform = Oracle Linux 8,Oracle Linux 9,multi_platform_rhel,multi_platform_fedora
# variables = var_password_hashing_algorithm_pam=sha512
authselect create-profile hardening -b sssd
diff --git a/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_systemauth/tests/authselect_incorrect_option.fail.sh b/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_systemauth/tests/authselect_incorrect_option.fail.sh
index c498e86dd18..c5e65c44e0e 100644
--- a/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_systemauth/tests/authselect_incorrect_option.fail.sh
+++ b/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_systemauth/tests/authselect_incorrect_option.fail.sh
@@ -1,6 +1,6 @@
#!/bin/bash
# packages = authselect
-# platform = Oracle Linux 8,Oracle Linux 9,Red Hat Enterprise Linux 8,Red Hat Enterprise Linux 9,multi_platform_fedora
+# platform = Oracle Linux 8,Oracle Linux 9,multi_platform_rhel,multi_platform_fedora
# variables = var_password_hashing_algorithm_pam=sha512
authselect create-profile hardening -b sssd
diff --git a/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_systemauth/tests/authselect_missing_option.fail.sh b/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_systemauth/tests/authselect_missing_option.fail.sh
index 3653f7912d0..c61e9828d17 100644
--- a/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_systemauth/tests/authselect_missing_option.fail.sh
+++ b/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_systemauth/tests/authselect_missing_option.fail.sh
@@ -1,6 +1,6 @@
#!/bin/bash
# packages = authselect
-# platform = Oracle Linux 8,Oracle Linux 9,Red Hat Enterprise Linux 8,Red Hat Enterprise Linux 9,multi_platform_fedora
+# platform = Oracle Linux 8,Oracle Linux 9,multi_platform_rhel,multi_platform_fedora
# variables = var_password_hashing_algorithm_pam=sha512
authselect create-profile hardening -b sssd
diff --git a/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_systemauth/tests/authselect_modified_pam.fail.sh b/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_systemauth/tests/authselect_modified_pam.fail.sh
index 11ed319f10e..6499ed205a7 100644
--- a/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_systemauth/tests/authselect_modified_pam.fail.sh
+++ b/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_systemauth/tests/authselect_modified_pam.fail.sh
@@ -1,6 +1,6 @@
#!/bin/bash
# packages = authselect
-# platform = Oracle Linux 8,Oracle Linux 9,Red Hat Enterprise Linux 8,Red Hat Enterprise Linux 9,multi_platform_fedora
+# platform = Oracle Linux 8,Oracle Linux 9,multi_platform_rhel,multi_platform_fedora
# variables = var_password_hashing_algorithm_pam=sha512
# remediation = none
diff --git a/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_systemauth/tests/authselect_multiple_options.fail.sh b/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_systemauth/tests/authselect_multiple_options.fail.sh
index e4195021755..6b5b5767a1e 100644
--- a/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_systemauth/tests/authselect_multiple_options.fail.sh
+++ b/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_systemauth/tests/authselect_multiple_options.fail.sh
@@ -1,6 +1,6 @@
#!/bin/bash
# packages = authselect
-# platform = Oracle Linux 8,Oracle Linux 9,Red Hat Enterprise Linux 8,Red Hat Enterprise Linux 9,multi_platform_fedora
+# platform = Oracle Linux 8,Oracle Linux 9,multi_platform_rhel,multi_platform_fedora
# variables = var_password_hashing_algorithm_pam=sha512
authselect create-profile hardening -b sssd
diff --git a/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_systemauth/tests/authselect_wrong_control.fail.sh b/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_systemauth/tests/authselect_wrong_control.fail.sh
index d0413404b3a..a1a9ec1ec1b 100644
--- a/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_systemauth/tests/authselect_wrong_control.fail.sh
+++ b/linux_os/guide/system/accounts/accounts-pam/set_password_hashing_algorithm/set_password_hashing_algorithm_systemauth/tests/authselect_wrong_control.fail.sh
@@ -1,6 +1,6 @@
#!/bin/bash
# packages = authselect
-# platform = Oracle Linux 8,Oracle Linux 9,Red Hat Enterprise Linux 8,Red Hat Enterprise Linux 9,multi_platform_fedora
+# platform = Oracle Linux 8,Oracle Linux 9,multi_platform_rhel,multi_platform_fedora
# variables = var_password_hashing_algorithm_pam=sha512
authselect create-profile hardening -b sssd
diff --git a/linux_os/guide/system/permissions/files/file_permissions_ungroupowned/oval/shared.xml b/linux_os/guide/system/permissions/files/file_permissions_ungroupowned/oval/shared.xml
index 2abf8f046d9..9c7e307c69a 100644
--- a/linux_os/guide/system/permissions/files/file_permissions_ungroupowned/oval/shared.xml
+++ b/linux_os/guide/system/permissions/files/file_permissions_ungroupowned/oval/shared.xml
@@ -92,22 +92,7 @@
state_file_permissions_ungroupowned_sysroot
-
-
-
-
-
-
- /etc/nsswitch.conf
- ^\s*group:\s+(.*)$
- 1
-
-
-
- altfiles
-
+{{{ oval_test_nsswitch_uses_altfiles() }}}
=23.2.0
diff --git a/shared/macros/10-oval.jinja b/shared/macros/10-oval.jinja
index 53c187e404e..4570f252ec5 100644
--- a/shared/macros/10-oval.jinja
+++ b/shared/macros/10-oval.jinja
@@ -1702,3 +1702,25 @@ Generates an OVAL check that checks a particular field in the "/etc/shadow" file
{{%- endif %}}
{{%- endif %}}
{{%- endmacro -%}}
+
+{{#
+Generate OVAL test that tests if the system is configured to use nss-altfiles
+by checking if '/etc/nssswitch.conf' contains 'altfiles' in 'group' key.
+The macros generates the OVAL test including the dependent OVAL object and OVAL state.
+#}}
+{{%- macro oval_test_nsswitch_uses_altfiles() -%}}
+
+
+
+
+
+ /etc/nsswitch.conf
+ ^\s*group:\s+(.*)$
+ 1
+
+
+ altfiles
+
+{{%- endmacro -%}}
diff --git a/ssg/profiles.py b/ssg/profiles.py
new file mode 100644
index 00000000000..d2a1af208d7
--- /dev/null
+++ b/ssg/profiles.py
@@ -0,0 +1,349 @@
+from __future__ import absolute_import
+from __future__ import print_function
+
+import os
+import sys
+import yaml
+
+from .controls import ControlsManager, Policy
+from .products import (
+ get_profile_files_from_root,
+ load_product_yaml,
+ product_yaml_path,
+)
+
+
+if sys.version_info >= (3, 9):
+ dict_type = dict # Python 3.9+ supports built-in generics
+ list_type = list
+ tuple_type = tuple
+else:
+ from typing import Dict as dict_type # Fallback for older versions
+ from typing import List as list_type
+ from typing import Tuple as tuple_type
+
+
+class ProfileSelections:
+ """
+ A class to represent profile with sections of rules and variables.
+
+ Attributes:
+ -----------
+ profile_id : str
+ The unique identifier for the profile.
+ profile_title : str
+ The profile title associated with the profile id.
+ product_id : str
+ The product id associated with the profile.
+ product_title : str
+ The product title associated with the product id.
+ """
+ def __init__(self, profile_id, profile_title, product_id, product_title):
+ self.profile_id = profile_id
+ self.profile_title = profile_title
+ self.product_id = product_id
+ self.product_title = product_title
+ self.rules = []
+ self.unselected_rules = []
+ self.variables = {}
+
+
+def _load_product_yaml(content_dir: str, product: str) -> object:
+ """
+ Load the product YAML file and return its content as a Python object.
+
+ Args:
+ content_dir (str): The directory where the content is stored.
+ product (str): The name of the product.
+
+ Returns:
+ object: The loaded YAML content as a Python object.
+ """
+ file_yaml_path = product_yaml_path(content_dir, product)
+ return load_product_yaml(file_yaml_path)
+
+
+def _load_yaml_profile_file(file_path: str) -> dict_type:
+ """
+ Load the content of a YAML file intended to profiles definitions.
+
+ It is not necessary to process macros in this case.
+
+ Args:
+ file_path (str): The path to the YAML file.
+
+ Returns:
+ dict: The content of the YAML file as a dictionary.
+ """
+ with open(file_path, 'r') as file:
+ try:
+ return yaml.safe_load(file)
+ except yaml.YAMLError as e:
+ print(f"Error loading YAML profile file {file_path}: {e}")
+ return {}
+
+
+def _get_extended_profile_path(profiles_files: list, profile_name: str) -> str:
+ """
+ Retrieve the full path of a profile file from a list of profile file paths.
+
+ Args:
+ profiles_files (list of str): A list of file paths where profile files are located.
+ profile_name (str): The name of the profile to search for.
+
+ Returns:
+ str: The full path of the profile file if found, otherwise None.
+ """
+ profile_file = f"{profile_name}.profile"
+ profile_path = next((path for path in profiles_files if profile_file in path), None)
+ return profile_path
+
+
+def _process_profile_extension(profile: ProfileSelections, profile_yaml: dict,
+ profiles_files: list, policies: dict) -> ProfileSelections:
+ """
+ Processes the extension of a profile by recursively checking if the profile extends another
+ profile and updating the profile selections accordingly.
+
+ Args:
+ profile (ProfileSelections): The profile object to be processed.
+ profile_yaml (dict): The YAML content of the current profile.
+ profiles_files (list): List of profile file paths.
+ policies (dict): The policies defined in the current profile.
+
+ Returns:
+ ProfileSelections: The updated profile object.
+ """
+ extended_profile = profile_yaml.get("extends")
+ if isinstance(extended_profile, str):
+ extended_profile = _get_extended_profile_path(profiles_files, extended_profile)
+ if extended_profile is not None:
+ profile_yaml = _load_yaml_profile_file(extended_profile)
+ return _process_profile(profile, profile_yaml, profiles_files, policies)
+ return profile
+
+
+def _parse_control_line(control_line: str) -> tuple_type[str, str]:
+ """
+ Parses a control line string and returns a tuple containing the first and third parts of the
+ string, separated by a colon. If the string does not contain three parts, the second element
+ of the tuple defaults to 'all'.
+
+ Args:
+ control_line (str): The control line string to be parsed.
+
+ Returns:
+ tuple[str, str]: A tuple containing the first part of the control line and either the
+ third part or 'all' if the third part is not present.
+ """
+ parts = control_line.split(":")
+ if len(parts) == 3:
+ return parts[0], parts[2]
+ return parts[0], 'all'
+
+
+def _process_selected_variable(profile: ProfileSelections, variable: str) -> None:
+ """
+ Processes a selected variable and updates the profile's variables.
+
+ Args:
+ profile (ProfileSelections): The profile object containing variables.
+ variable (str): The variable in the format 'name=value'.
+
+ Raises:
+ ValueError: If the variable is not in the correct format.
+ """
+ variable_name, variable_value = variable.split('=', 1)
+ if variable_name not in profile.variables:
+ profile.variables[variable_name] = variable_value
+
+
+def _process_selected_rule(profile: ProfileSelections, rule: str) -> None:
+ """
+ Adds a rule to the profile's selected rules if it is not already selected or unselected.
+
+ Args:
+ profile (ProfileSelections): The profile containing selected and unselected rules.
+ rule (str): The rule to be added to the profile's selected rules.
+
+ Returns:
+ None
+ """
+ if rule not in profile.unselected_rules and rule not in profile.rules:
+ profile.rules.append(rule)
+
+
+def _process_control(profile: ProfileSelections, control: object) -> None:
+ """
+ Processes a control by iterating through its rules and applying the appropriate processing
+ function. Not that at this level rules list in control can include both variables and rules.
+ The function distinguishes between variable and rules based on the presence of an '='
+ character in the rule.
+
+ Args:
+ profile (ProfileSelections): The profile selections to be processed.
+ control: The control object containing rules to be processed.
+ """
+ for rule in control.rules:
+ if "=" in rule:
+ _process_selected_variable(profile, rule)
+ else:
+ _process_selected_rule(profile, rule)
+
+
+def _update_profile_with_policy(profile: ProfileSelections, policy: Policy, level: str) -> None:
+ """
+ Updates the given profile with controls from the specified policy based on the provided level.
+
+ Args:
+ profile (ProfileSelections): The profile to be updated.
+ policy (Policy): The policy containing controls to update the profile with.
+ level (str): The level of controls to be processed. If 'all', all controls are processed.
+ Otherwise, only controls matching the specified level are processed.
+
+ Returns:
+ None
+ """
+ for control in policy.controls:
+ if level == 'all' or level in control.levels:
+ _process_control(profile, control)
+
+
+def _process_controls(profile: ProfileSelections, control_line: str,
+ policies: dict) -> ProfileSelections:
+ """
+ Process a control file inheritance to update profile selections based on the given policies.
+
+ Args:
+ profile (ProfileSelections): The profile object to be processed.
+ control_line (str): A string representing the control line, which contains a policy ID and
+ optionally a level, separated by colons.
+ policies (dict): A dictionary of policies, where each key is a policy ID and each value is
+ a policy object containing the controls.
+
+ Returns:
+ ProfileSelections: The updated profile object.
+ """
+ policy_id, level = _parse_control_line(control_line)
+ policy = policies.get(policy_id)
+
+ if policy is None:
+ print(f"Policy {policy_id} not found")
+ return profile
+
+ _update_profile_with_policy(profile, policy, level)
+ return profile
+
+
+def _process_selections(profile: ProfileSelections, profile_yaml: dict,
+ policies: dict) -> ProfileSelections:
+ """
+ Processes the selections from the profile YAML and updates the profile accordingly.
+
+ Args:
+ profile (ProfileSelections): The profile object to be processed.
+ profile_yaml (dict): A dictionary containing the profile YAML data.
+ policies (dict): A dictionary containing policy information.
+
+ Returns:
+ profile: The updated profile object.
+ """
+ selections = profile_yaml.get("selections", [])
+ for selected in selections:
+ if selected.startswith("!"):
+ profile.unselected_rules.append(selected[1:])
+ elif "=" in selected:
+ variable_name, variable_value = selected.split('=', 1)
+ profile.variables[variable_name] = variable_value
+ elif ":" in selected:
+ profile = _process_controls(profile, selected, policies)
+ else:
+ profile.rules.append(selected)
+ return profile
+
+
+def _process_profile(profile: ProfileSelections, profile_yaml: dict, profiles_files: list,
+ policies: dict) -> ProfileSelections:
+ """
+ Processes a profile by handling profile extensions, and processing selections.
+
+ Args:
+ profile (ProfileSelections): The profile object to be processed.
+ profile_yaml (dict): The YAML content of the profile.
+ profiles_files (list): A list of profile file paths.
+ policies (dict): A dictionary of policies defined by control files.
+
+ Returns:
+ ProfileSelections: The processed profile object.
+ """
+ profile = _process_profile_extension(profile, profile_yaml, profiles_files, policies)
+ profile = _process_selections(profile, profile_yaml, policies)
+ return profile
+
+
+def _load_controls_manager(controls_dir: str, product_yaml: dict) -> object:
+ """
+ Loads and initializes a ControlsManager instance.
+
+ Args:
+ controls_dir (str): The directory containing control files.
+ product_yaml (dict): The product configuration in YAML format.
+
+ Returns:
+ object: An instance of ControlsManager with loaded controls.
+ """
+ control_mgr = ControlsManager(controls_dir, product_yaml)
+ control_mgr.load()
+ return control_mgr
+
+
+def _sort_profiles_selections(profiles: list) -> ProfileSelections:
+ """
+ Sorts profiles selections (rules and variables) by selections ids.
+
+ Args:
+ profiles (list): A list of ProfileSelections objects to be sorted.
+
+ Returns:
+ ProfileSelections: The sorted list of ProfileSelections objects.
+ """
+ for profile in profiles:
+ profile.rules = sorted(profile.rules)
+ profile.unselected_rules = sorted(profile.unselected_rules)
+ profile.variables = dict(sorted(profile.variables.items()))
+ return profiles
+
+
+def get_profiles_from_products(content_dir: str, products: list,
+ sorted: bool = False) -> list_type:
+ """
+ Retrieves profiles with respective variables from the given products.
+
+ Args:
+ content_dir (str): The directory containing the content.
+ products (list): A list of product names to retrieve profiles from.
+
+ Returns:
+ list: A list of ProfileVariables objects containing profile variables for each product.
+ """
+ profiles = []
+ controls_dir = os.path.join(content_dir, 'controls')
+
+ for product in products:
+ product_yaml = _load_product_yaml(content_dir, product)
+ product_title = product_yaml.get("full_name")
+ profiles_files = get_profile_files_from_root(product_yaml, product_yaml)
+ controls_manager = _load_controls_manager(controls_dir, product_yaml)
+ for file in profiles_files:
+ profile_id = os.path.basename(file).split('.profile')[0]
+ profile_yaml = _load_yaml_profile_file(file)
+ profile_title = profile_yaml.get("title")
+ profile = ProfileSelections(profile_id, profile_title, product, product_title)
+ profile = _process_profile(profile, profile_yaml, profiles_files,
+ controls_manager.policies)
+ profiles.append(profile)
+
+ if sorted:
+ profiles = _sort_profiles_selections(profiles)
+
+ return profiles
diff --git a/ssg/variables.py b/ssg/variables.py
index 66757e01df1..3196ad9acf5 100644
--- a/ssg/variables.py
+++ b/ssg/variables.py
@@ -4,16 +4,10 @@
import glob
import os
import sys
-import yaml
from collections import defaultdict
from .constants import BENCHMARKS
-from .controls import ControlsManager
-from .products import (
- get_profile_files_from_root,
- load_product_yaml,
- product_yaml_path,
-)
+from .profiles import get_profiles_from_products
from .yaml import open_and_macro_expand
@@ -25,8 +19,9 @@
from typing import Dict as dict_type
-# Cache variable files to avoid multiple reads
+# Cache variable files and respective content to avoid multiple reads
_var_files_cache = {}
+_vars_content_cache = {}
def get_variable_files_in_folder(content_dir: str, subfolder: str) -> list_type[str]:
@@ -69,26 +64,23 @@ def get_variable_files(content_dir: str) -> list_type[str]:
return variable_files
-def get_variable_options(content_dir: str, variable_id: str = None) -> dict_type:
+def _get_variables_content(content_dir: str) -> dict_type:
"""
- Retrieve the options for specific or all variables from the content root directory.
-
- If `variable_id` is provided, returns options for that variable only.
- If `variable_id` is not provided, returns a dictionary of all variable options.
+ Retrieve the content of all variable files from the specified content root directory.
Args:
content_dir (str): The root directory containing benchmark directories.
- variable_id (str, optional): The ID of the variable to retrieve options for.
- Defaults to None.
Returns:
- dict: If `variable_id` is None, a dictionary where keys are variable IDs and values are
- their options. Otherwise, a dictionary of options for the specified variable.
+ dict: A dictionary where keys are variable IDs and values are the content of the variable
+ files.
"""
- all_variable_files = get_variable_files(content_dir)
- all_options = {}
+ if content_dir in _vars_content_cache:
+ return _vars_content_cache[content_dir]
- for var_file in all_variable_files:
+ variables_content = {}
+
+ for var_file in get_variable_files(content_dir):
try:
yaml_content = open_and_macro_expand(var_file)
except Exception as e:
@@ -96,250 +88,70 @@ def get_variable_options(content_dir: str, variable_id: str = None) -> dict_type
continue
var_id = os.path.basename(var_file).split('.var')[0]
- options = yaml_content.get("options", {})
-
- if variable_id:
- if var_id == variable_id:
- return options
- else:
- all_options[var_id] = options
-
- if variable_id:
- print(f"Variable {variable_id} not found")
- return {}
-
- return all_options
-
-
-class ProfileVariables:
- """
- A class to represent profile variables.
-
- Attributes:
- -----------
- profile_id : str
- The unique identifier for the profile.
- product : str
- The product associated with the profile.
- variables : dict
- A dictionary containing the variables for the profile.
- """
- def __init__(self, profile_id, product, variables):
- self.profile_id = profile_id
- self.product = product
- self.variables = variables
-
-
-def _load_product_yaml(content_dir: str, product: str) -> object:
- """
- Load the product YAML file and return its content as a Python object.
-
- Args:
- content_dir (str): The directory where the content is stored.
- product (str): The name of the product.
-
- Returns:
- object: The loaded YAML content as a Python object.
- """
- file_yaml_path = product_yaml_path(content_dir, product)
- return load_product_yaml(file_yaml_path)
-
-
-def _load_yaml_profile_file(file_path: str) -> dict_type:
- """
- Load the content of a YAML file intended to profiles definitions.
-
- It is not necessary to process macros in this case.
-
- Args:
- file_path (str): The path to the YAML file.
-
- Returns:
- dict: The content of the YAML file as a dictionary.
- """
- with open(file_path, 'r') as file:
- try:
- return yaml.safe_load(file)
- except yaml.YAMLError as e:
- print(f"Error loading YAML profile file {file_path}: {e}")
- return {}
-
-
-def _get_extended_profile_path(profiles_files: list, profile_name: str) -> str:
- """
- Retrieve the full path of a profile file from a list of profile file paths.
-
- Args:
- profiles_files (list of str): A list of file paths where profile files are located.
- profile_name (str): The name of the profile to search for.
-
- Returns:
- str: The full path of the profile file if found, otherwise None.
- """
- profile_file = f"{profile_name}.profile"
- profile_path = next((path for path in profiles_files if profile_file in path), None)
- return profile_path
-
-
-def _process_profile_extension(profiles_files: list, profile_yaml: dict,
- profile_variables: dict, policies: dict) -> dict_type:
- """
- Processes the extension of a profile by recursively checking if the profile extends another
- profile and updating the profile variables accordingly.
-
- Args:
- profiles_files (list): List of profile file paths.
- profile_yaml (dict): The YAML content of the current profile.
- profile_variables (dict): The variables already defined in the current profile.
- policies (dict): The policies defined in the current profile.
-
- Returns:
- dict: The updated profile variables after processing the extended profile,
- or the original profile variables if no extension is found.
- """
- extended_profile = profile_yaml.get("extends")
- if isinstance(extended_profile, str):
- extended_profile = _get_extended_profile_path(profiles_files, extended_profile)
- if extended_profile is not None:
- return _process_profile(profiles_files, extended_profile, policies, profile_variables)
- return profile_variables
+ variables_content[var_id] = yaml_content
+ _vars_content_cache[content_dir] = variables_content
+ return variables_content
-def _process_controls(control_line: str, profile_variables: dict, policies: dict) -> dict_type:
- """
- Process a control file inheritance to update profile variables based on the given policies.
-
- Args:
- control_line (str): A string representing the control line, which contains a policy ID and
- optionally a level, separated by colons.
- profile_variables (dict): A dictionary of profile variables to be updated.
- policies (dict): A dictionary of policies, where each key is a policy ID and each value is
- a policy object containing the controls.
- Returns:
- dict: The updated profile variables dictionary.
-
- Raises:
- KeyError: If the policy ID from the control line is not found in the policies dictionary.
- """
- if control_line.count(":") == 2:
- policy_id, _, level = control_line.split(":")
- else:
- policy_id, _ = control_line.split(":")
- level = None
-
- try:
- policy = policies[policy_id]
- except KeyError:
- print(f"Policy {policy_id} not found")
- return profile_variables
-
- for control in policy.controls:
- if level in control.levels:
- for rule in control.rules:
- if "=" in rule:
- variable_name, variable_value = rule.split('=', 1)
- # When a profile extends a control file, the variables explicitly defined in
- # profiles files must be honored, so don't update variables already defined.
- if variable_name not in profile_variables:
- profile_variables[variable_name] = variable_value
- return profile_variables
-
-
-def _process_selections(profile_yaml: dict, profile_variables: dict, policies: dict) -> dict_type:
+def get_variable_property(content_dir: str, variable_id: str, property_name: str) -> str:
"""
- Processes the selections from the profile YAML and updates the profile variables accordingly.
+ Retrieve a specific property of a variable from the content root directory.
Args:
- profile_yaml (dict): A dictionary containing the profile YAML data.
- profile_variables (dict): A dictionary to store the profile variables.
- policies (dict): A dictionary containing policy information.
+ content_dir (str): The root directory containing benchmark directories.
+ variable_id (str): The ID of the variable to retrieve the property for.
+ property_name (str): The name of the property to retrieve.
Returns:
- dict: The updated profile variables dictionary.
- """
- selections = profile_yaml.get("selections")
- for selected in selections:
- if "=" in selected and "!" not in selected:
- variable_name, variable_value = selected.split('=', 1)
- profile_variables[variable_name] = variable_value
- elif ":" in selected:
- profile_variables = _process_controls(selected, profile_variables, policies)
- return profile_variables
-
-
-def _process_profile(profiles_files: list, file: str, policies: dict,
- profile_variables={}) -> dict_type:
+ str: The value of the specified property for the variable.
"""
- Processes a profile by loading its YAML file, handling profile extensions, and processing
- selections.
+ variables_content = _get_variables_content(content_dir)
+ variable_content = variables_content.get(variable_id, {})
+ return variable_content.get(property_name, '')
- Args:
- profiles_files (list): A list of profile file paths.
- file (str): The path to the profile file to be processed.
- policies (dict): A dictionary of policies defined by control files.
- profile_variables (dict, optional): A dictionary of profile variables. Defaults to empty.
- Returns:
- dict: A dictionary containing the processed profile variables.
+def get_variable_options(content_dir: str, variable_id: str = None) -> dict_type:
"""
- profile_yaml = _load_yaml_profile_file(file)
- profile_variables = _process_profile_extension(profiles_files, profile_yaml,
- profile_variables, policies)
- profile_variables = _process_selections(profile_yaml, profile_variables, policies)
- return profile_variables
-
+ Retrieve the options for specific or all variables from the content root directory.
-def _load_controls_manager(controls_dir: str, product_yaml: dict) -> object:
- """
- Loads and initializes a ControlsManager instance.
+ If `variable_id` is provided, returns options for that variable only.
+ If `variable_id` is not provided, returns a dictionary of all variables with their options.
Args:
- controls_dir (str): The directory containing control files.
- product_yaml (dict): The product configuration in YAML format.
+ content_dir (str): The root directory containing benchmark directories.
+ variable_id (str, optional): The ID of the variable to retrieve options for.
+ Defaults to None.
Returns:
- object: An instance of ControlsManager with loaded controls.
- """
- control_mgr = ControlsManager(controls_dir, product_yaml)
- control_mgr.load()
- return control_mgr
-
-
-def _get_profiles_from_products(content_dir: str, products: list) -> list_type:
+ dict: If `variable_id` is None, a dictionary where keys are variable IDs and values are
+ their options. Otherwise, a dictionary of options for the specified variable.
"""
- Retrieves profiles with respective variables from the given products.
+ variables_content = _get_variables_content(content_dir)
+ all_options = {}
- Args:
- content_dir (str): The directory containing the content.
- products (list): A list of product names to retrieve profiles from.
+ for var_id, var_yaml in variables_content.items():
+ options = var_yaml.get("options", {})
- Returns:
- list: A list of ProfileVariables objects containing profile variables for each product.
- """
- profiles = []
- controls_dir = os.path.join(content_dir, 'controls')
+ if variable_id:
+ if var_id == variable_id:
+ return options
+ else:
+ all_options[var_id] = options
- for product in products:
- product_yaml = _load_product_yaml(content_dir, product)
- profiles_files = get_profile_files_from_root(product_yaml, product_yaml)
- controls_manager = _load_controls_manager(controls_dir, product_yaml)
- for file in profiles_files:
- profile_id = os.path.basename(file).split('.profile')[0]
- profile_variables = _process_profile(profiles_files, file, controls_manager.policies)
- profile = ProfileVariables(profile_id, product, profile_variables)
- profiles.append(profile)
+ if variable_id:
+ print(f"Variable {variable_id} not found")
+ return {}
- return profiles
+ return all_options
-def _get_variables_from_profiles(profiles: list) -> dict_type:
+def get_variables_from_profiles(profiles: list) -> dict_type:
"""
Extracts variables from a list of profiles and organizes them into a nested dictionary.
Args:
- profiles (list): A list of profile objects, each containing variables, product, and id
- attributes.
+ profiles (list): A list of profile objects, each containing selections and id attributes.
Returns:
dict: A nested dictionary where the first level keys are variable names, the second level
@@ -349,8 +161,8 @@ def _get_variables_from_profiles(profiles: list) -> dict_type:
variables = defaultdict(lambda: defaultdict(dict))
for profile in profiles:
for variable, value in profile.variables.items():
- variables[variable][profile.product][profile.profile_id] = value
- return variables
+ variables[variable][profile.product_id][profile.profile_id] = value
+ return _convert_defaultdict_to_dict(variables)
def _convert_defaultdict_to_dict(dictionary: defaultdict) -> dict_type:
@@ -373,7 +185,8 @@ def get_variables_by_products(content_dir: str, products: list) -> dict_type[str
Retrieve variables by products from the specified content root directory.
This function collects profiles for the given products and extracts variables from these
- profiles.
+ profiles. If you already have a list of Profiles obtained by get_profiles_from_products()
+ defined in profiles.py, consider to use get_variables_from_profiles() instead.
Args:
content_dir (str): The root directory of the content.
@@ -383,8 +196,8 @@ def get_variables_by_products(content_dir: str, products: list) -> dict_type[str
dict: A dictionary where keys are variable names and values are dictionaries of
product-profile pairs.
"""
- profiles = _get_profiles_from_products(content_dir, products)
- profiles_variables = _get_variables_from_profiles(profiles)
+ profiles = get_profiles_from_products(content_dir, products)
+ profiles_variables = get_variables_from_profiles(profiles)
return _convert_defaultdict_to_dict(profiles_variables)
diff --git a/tests/data/profile_stability/rhel8/stig.profile b/tests/data/profile_stability/rhel8/stig.profile
index 7090a294f4d..eba79eae8f5 100644
--- a/tests/data/profile_stability/rhel8/stig.profile
+++ b/tests/data/profile_stability/rhel8/stig.profile
@@ -53,8 +53,6 @@ selections:
- accounts_password_pam_minclass
- accounts_password_pam_minlen
- accounts_password_pam_ocredit
-- accounts_password_pam_pwhistory_remember_password_auth
-- accounts_password_pam_pwhistory_remember_system_auth
- accounts_password_pam_pwquality_password_auth
- accounts_password_pam_pwquality_system_auth
- accounts_password_pam_retry
diff --git a/tests/data/profile_stability/rhel8/stig_gui.profile b/tests/data/profile_stability/rhel8/stig_gui.profile
index fcbe059e49b..c98305dc5a5 100644
--- a/tests/data/profile_stability/rhel8/stig_gui.profile
+++ b/tests/data/profile_stability/rhel8/stig_gui.profile
@@ -64,8 +64,6 @@ selections:
- accounts_password_pam_minclass
- accounts_password_pam_minlen
- accounts_password_pam_ocredit
-- accounts_password_pam_pwhistory_remember_password_auth
-- accounts_password_pam_pwhistory_remember_system_auth
- accounts_password_pam_pwquality_password_auth
- accounts_password_pam_pwquality_system_auth
- accounts_password_pam_retry
diff --git a/tests/unit/ssg-module/test_profiles.py b/tests/unit/ssg-module/test_profiles.py
new file mode 100644
index 00000000000..c1ac79afd64
--- /dev/null
+++ b/tests/unit/ssg-module/test_profiles.py
@@ -0,0 +1,40 @@
+import os
+import pytest
+
+from ssg.products import (
+ get_all,
+ get_profile_files_from_root,
+)
+from ssg.profiles import (
+ get_profiles_from_products,
+ _load_product_yaml,
+)
+
+
+# The get_profiles_from_products function interacts with many objects and other functions that
+# would be complex to mock. So it will be tested with a real content directory. To make it
+# predictable, all existing products will be collected and the first rhel product will be used
+# for testing. The decision to use a rhel product is that I am more used to them and I know their
+# profiles also use control files.
+content_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), "../../.."))
+
+def get_first_rhel_product_from_products_dir():
+ products = get_all(content_dir)
+ rhel_products = [product for product in products.linux if "rhel" in product]
+ return rhel_products[0]
+
+
+def count_profiles_in_products_dir(product):
+ product_yaml = _load_product_yaml(content_dir, product)
+ profiles_files = get_profile_files_from_root(product_yaml, product_yaml)
+ return len(profiles_files)
+
+
+def test_get_profiles_from_products():
+ products = [get_first_rhel_product_from_products_dir()]
+ profiles = get_profiles_from_products(content_dir, products, sorted=True)
+
+ assert len(profiles) == count_profiles_in_products_dir(products[0])
+ assert 'rhel' in profiles[0].product_id
+ assert len(profiles[0].rules) > 0
+ assert len(profiles[0].variables) > 0
diff --git a/tests/unit/ssg-module/test_variables.py b/tests/unit/ssg-module/test_variables.py
index 89e8c77a70b..1858b5d36bd 100644
--- a/tests/unit/ssg-module/test_variables.py
+++ b/tests/unit/ssg-module/test_variables.py
@@ -6,7 +6,9 @@
get_variable_files_in_folder,
get_variable_files,
get_variable_options,
+ get_variable_property,
get_variables_by_products,
+ get_variables_from_profiles,
get_variable_values,
)
@@ -24,7 +26,10 @@ def setup_test_files(base_dir, benchmark_dirs, create_txt_file=False):
path = base_dir / benchmark_dir
os.makedirs(path, exist_ok=True)
var_file = path / "test.var"
- var_file.write_text("options:\n default: value\n option1: value1\n option2: value2\n")
+ var_file.write_text(
+ "options:\n default: value\n option1: value1\n option2: value2\n"
+ "title: Test Title\ndescription: Test Description\n"
+ )
if create_txt_file:
txt_file = path / "test.txt"
txt_file.write_text("options:\n option: value\n")
@@ -79,3 +84,53 @@ def test_get_variable_values(tmp_path):
result = get_variable_values(str(content_dir), profiles_variables)
assert result["test"]["product1"]["profile1"] == "value1"
assert result["test"]["product2"]["profile2"] == "value2"
+
+
+def test_get_variables_from_profiles():
+ class MockProfile:
+ def __init__(self, product_id, profile_id, variables):
+ self.product_id = product_id
+ self.profile_id = profile_id
+ self.variables = variables
+
+ profiles = [
+ MockProfile("product1", "profile1", {"var1": "value1", "var2": "value2"}),
+ MockProfile("product1", "profile2", {"var1": "value3"}),
+ MockProfile("product2", "profile1", {"var2": "value4"}),
+ ]
+
+ expected_result = {
+ "var1": {
+ "product1": {
+ "profile1": "value1",
+ "profile2": "value3",
+ }
+ },
+ "var2": {
+ "product1": {
+ "profile1": "value2",
+ },
+ "product2": {
+ "profile1": "value4",
+ }
+ }
+ }
+
+ result = get_variables_from_profiles(profiles)
+ assert result == expected_result
+
+def test_get_variable_property(tmp_path):
+ content_dir = tmp_path / "content"
+ benchmark_dirs = ["app", "app/rules"]
+ setup_test_files(content_dir, benchmark_dirs)
+
+ result = get_variable_property(str(content_dir), "test", "title")
+ assert result == "Test Title"
+
+ # Test for a non-existent property
+ result = get_variable_property(str(content_dir), "test", "non_existent_property")
+ assert result == ""
+
+ # Test for a non-existent variable
+ result = get_variable_property(str(content_dir), "non_existent_variable", "property_name")
+ assert result == ""