{{#-
  We set defaults to "off", and products should enable relevant ones depending on how the product configures grub.
   - /boot/loader/entries/* may not exist.
   - If they exist, they can reference variables defined in grubenv, or they can contain literal args
   - The grub cfg may either use those loader entries, or it can contain literal values as well
   - Kernel opts can be stored in /etc/default/grub so they are persistent between kernel upgrades
-#}}
{{% set system_with_expanded_kernel_options_in_loader_entries = false -%}}
{{% set system_with_kernel_options_in_grubenv = false -%}}
{{% set system_with_expanded_kernel_options_in_loader_entries_or_with_options_in_grubenv = false -%}}
{{% set system_with_kernel_options_in_etc_default_grub = true -%}}
{{% set system_with_kernel_options_in_etc_default_grub_d = false -%}}
{{% set system_with_expanded_kernel_options_in_grub_cfg = false -%}}
{{% set system_with_bios_and_uefi_support = false -%}}

{{% if product in ["fedora", "ol9", "rhel9", "rhel10"] -%}}
{{% set system_with_expanded_kernel_options_in_loader_entries = true %}}
{{%- endif -%}}

{{% if product in ["ol8", "rhel8"] -%}}
{{% set system_with_expanded_kernel_options_in_loader_entries_or_with_options_in_grubenv = true -%}}
{{%- endif -%}}

{{% if product in ["ol7"] or 'ubuntu' in product -%}}
{{% set system_with_expanded_kernel_options_in_grub_cfg = true %}}
{{%- endif -%}}

{{% if 'ubuntu' in product -%}}
{{% set system_with_kernel_options_in_etc_default_grub_d = true -%}}
{{%- endif -%}}

{{% if grub2_uefi_boot_path and grub2_uefi_boot_path != grub2_boot_path -%}}
{{% set system_with_bios_and_uefi_support = true %}}
{{%- endif -%}}

<def-group>
  <definition class="compliance" id="{{{ _RULE_ID }}}" version="2">
    {{{ oval_metadata("Ensure " + ARG_NAME_VALUE + " is configured in the kernel line in /etc/default/grub.", rule_title=rule_title) }}}
    <criteria operator="OR">
    <criteria operator="AND">
      {{% if bootable_containers_supported == "true" %}}
        <extend_definition comment="The system is RHEL Image Mode" definition_ref="bootc" negate="true" />
      {{% endif %}}
      {{% if system_with_expanded_kernel_options_in_loader_entries_or_with_options_in_grubenv %}}
      <criterion test_ref="test_grub2_{{{ SANITIZED_ARG_NAME }}}_entries_expanded_or_referenced"
      comment="Check /boot/loader/entries/*.conf files if they contain direct reference to {{{ ARG_NAME_VALUE }}} or if they contain $kernelopts" />
      <criteria operator="OR"
      comment="Expressing implication">
        <criterion test_ref="test_grub2_{{{ SANITIZED_ARG_NAME }}}_at_least_one_entry_referenced" negate="true"
        comment="Negate the result of the test if there exists at least one $kernelopts in /boot/loader/entries" />
        {{% if system_with_bios_and_uefi_support -%}}
        <criteria operator="OR">
        {{%- endif %}}
        <criterion test_ref="test_grub2_{{{ SANITIZED_ARG_NAME }}}_argument_grub_env"
        comment="Check if {{{ ARG_NAME_VALUE }}} is present in the GRUB2 environment variable block in {{{ grub2_boot_path }}}/grubenv" />
      {{% if system_with_bios_and_uefi_support -%}}
        <criterion test_ref="test_grub2_{{{ SANITIZED_ARG_NAME }}}_argument_grub_env_uefi"
        comment="Check if {{{ ARG_NAME_VALUE }}} is present in the GRUB2 environment variable block in {{{ grub2_uefi_boot_path }}}/grubenv" />
        </criteria>
        {{%- endif %}}
      </criteria>
      {{% elif system_with_kernel_options_in_grubenv -%}}
        <extend_definition comment="check kernel command line parameters for referenced boot entries reference the $kernelopts variable" definition_ref="grub2_entries_reference_kernelopts" />
      {{% if system_with_bios_and_uefi_support -%}}
      <criteria operator="OR">
      {{%- endif %}}
        <criterion test_ref="test_grub2_{{{ SANITIZED_ARG_NAME }}}_argument_grub_env"
        comment="Check if {{{ ARG_NAME_VALUE }}} is present in the GRUB2 environment variable block in {{{ grub2_boot_path }}}/grubenv" />
      {{% if system_with_bios_and_uefi_support -%}}
        <criterion test_ref="test_grub2_{{{ SANITIZED_ARG_NAME }}}_argument_grub_env_uefi"
        comment="Check if {{{ ARG_NAME_VALUE }}} is present in the GRUB2 environment variable block in {{{ grub2_uefi_boot_path }}}/grubenv" />
      </criteria>
      {{%- endif %}}
      {{% elif system_with_expanded_kernel_options_in_loader_entries -%}}
          <criterion test_ref="test_grub2_{{{ SANITIZED_ARG_NAME }}}_entries"
                     comment="Check if {{{ ARG_NAME_VALUE }}} is present in the boot parameters in the /boot/loader/entries/*.conf" />
      {{%- endif %}}
      {{% if system_with_expanded_kernel_options_in_grub_cfg -%}}
          {{% if system_with_bios_and_uefi_support -%}}
          <criteria operator="OR">
          {{%- endif %}}
          <criterion test_ref="test_grub2_{{{ SANITIZED_ARG_NAME }}}_argument_grub_cfg"
          comment="Check if {{{ ARG_NAME_VALUE }}} is present in the boot parameters in the {{{ grub2_boot_path }}}/grub.cfg for all kernels" />
          {{% if system_with_bios_and_uefi_support -%}}
          <criterion test_ref="test_grub2_{{{ SANITIZED_ARG_NAME }}}_argument_grub_cfg_uefi"
          comment="Check if {{{ ARG_NAME_VALUE }}} is present in the boot parameters in the {{{ grub2_uefi_boot_path }}}/grub.cfg for all kernels" />
          </criteria>
          {{%- endif %}}
      {{%- endif %}}
      {{% if system_with_kernel_options_in_etc_default_grub -%}}
        <criteria operator="OR">
          <criteria operator="OR">
            <criterion test_ref="test_grub2_{{{ SANITIZED_ARG_NAME }}}_argument"
            comment="check for {{{ ARG_NAME_VALUE }}} in /etc/default/grub via GRUB_CMDLINE_LINUX" />
            {{% if system_with_kernel_options_in_etc_default_grub_d -%}}
            <criterion test_ref="test_grub2_{{{ SANITIZED_ARG_NAME }}}_argument_configdir"
            comment="check for {{{ ARG_NAME_VALUE }}} in /etc/default/grub.d/*cfg via GRUB_CMDLINE_LINUX" />
            {{%- endif %}}
          </criteria>
          <criteria operator="AND">
            <criteria operator="OR">
              <criterion test_ref="test_grub2_{{{ SANITIZED_ARG_NAME }}}_argument_default"
              comment="check for {{{ ARG_NAME_VALUE }}} in /etc/default/grub via GRUB_CMDLINE_LINUX_DEFAULT" />
              {{% if system_with_kernel_options_in_etc_default_grub_d -%}}
              <criterion test_ref="test_grub2_{{{ SANITIZED_ARG_NAME }}}_argument_default_configdir"
              comment="check for {{{ ARG_NAME_VALUE }}} in /etc/default/grub.d/*cfg via GRUB_CMDLINE_LINUX_DEFAULT" />
              {{%- endif %}}
            </criteria>
            <extend_definition definition_ref="bootloader_disable_recovery_set_to_true"
            comment="Check GRUB_DISABLE_RECOVERY=true in /etc/default/grub" />
          </criteria>
        </criteria>
      {{%- endif %}}
    </criteria>
    {{% if bootable_containers_supported == "true" %}}
      <criteria operator="AND">
        <extend_definition comment="The system is RHEL Image Mode" definition_ref="bootc" />
        <criterion comment="The {{{ ARG_NAME_VALUE }}} is present in the /usr/lib/bootc/kargs.d/*.toml files"  test_ref="test_grub2_{{{ SANITIZED_ARG_NAME }}}_usr_lib_bootc_kargs_d" />
      </criteria>
    {{% endif %}}
    </criteria>
  </definition>

{{% if system_with_expanded_kernel_options_in_loader_entries_or_with_options_in_grubenv %}}
  <ind:textfilecontent54_test id="test_grub2_{{{ SANITIZED_ARG_NAME }}}_entries_expanded_or_referenced"
  comment="check all /boot/loader/entries/*.conf for expanded entries of  {{{ ARG_NAME_VALUE }}}. Leave out rescue boot entries. Accept also references to $kernelopts."
  state_operator="OR" check="all" check_existence="all_exist" version="1">
    <ind:object object_ref="obj_grub2_{{{ SANITIZED_ARG_NAME }}}_entries_expanded_or_referenced" />
    <ind:state state_ref="state_grub2_{{{ SANITIZED_ARG_NAME }}}_argument" />
    <ind:state state_ref="state_grub2_{{{ SANITIZED_ARG_NAME }}}_argument_is_kernelopts" />
  </ind:textfilecontent54_test>

  <ind:textfilecontent54_object id="obj_grub2_{{{ SANITIZED_ARG_NAME }}}_entries_expanded_or_referenced" version="1">
    <ind:path>/boot/loader/entries/</ind:path>
    <ind:filename operation="pattern match">^.*\.conf$</ind:filename>
    <ind:pattern operation="pattern match">^options (.*)$</ind:pattern>
    <ind:instance datatype="int" operation="greater than or equal">1</ind:instance>
    <filter action="exclude">state_grub2_rescue_entry_for_{{{ _RULE_ID }}}</filter>
  </ind:textfilecontent54_object>

  <ind:textfilecontent54_state id="state_grub2_rescue_entry_for_{{{ _RULE_ID }}}" version="1">
    <ind:filename operation="pattern match">.*rescue\.conf$</ind:filename>
  </ind:textfilecontent54_state>

  <ind:textfilecontent54_test id="test_grub2_{{{ SANITIZED_ARG_NAME }}}_at_least_one_entry_referenced"
  comment="check all /boot/loader/entries/*.conf files if there is at least one entry referencing $kernelopts. Leave out rescue entries."
  check="all" check_existence="at_least_one_exists" version="1">
    <ind:object object_ref="obj_grub2_{{{ SANITIZED_ARG_NAME }}}_entries_expanded_or_referenced" />
    <ind:state state_ref="state_grub2_{{{ SANITIZED_ARG_NAME }}}_argument_is_kernelopts" />
  </ind:textfilecontent54_test>
{{% endif %}}


{{%- if system_with_kernel_options_in_etc_default_grub %}}
  <ind:textfilecontent54_test id="test_grub2_{{{ SANITIZED_ARG_NAME }}}_argument"
  comment="check for {{{ ARG_NAME_VALUE }}} in /etc/default/grub via GRUB_CMDLINE_LINUX"
  check="all" check_existence="all_exist" version="1">
    <ind:object object_ref="object_grub2_{{{ SANITIZED_ARG_NAME }}}_argument" />
    <ind:state state_ref="state_grub2_{{{ SANITIZED_ARG_NAME }}}_argument" />
  </ind:textfilecontent54_test>

  <ind:textfilecontent54_object id="object_grub2_{{{ SANITIZED_ARG_NAME }}}_argument" version="1">
    <ind:filepath>/etc/default/grub</ind:filepath>
    <ind:pattern operation="pattern match">^\s*GRUB_CMDLINE_LINUX="(.*)"$</ind:pattern>
    <ind:instance datatype="int" operation="greater than or equal">1</ind:instance>
  </ind:textfilecontent54_object>

  <ind:textfilecontent54_test id="test_grub2_{{{ SANITIZED_ARG_NAME }}}_argument_default"
  comment="check for {{{ ARG_NAME_VALUE }}} in /etc/default/grub via GRUB_CMDLINE_LINUX_DEFAULT"
  check="all" check_existence="all_exist" version="1">
    <ind:object object_ref="object_grub2_{{{ SANITIZED_ARG_NAME }}}_argument_default" />
    <ind:state state_ref="state_grub2_{{{ SANITIZED_ARG_NAME }}}_argument" />
  </ind:textfilecontent54_test>

  <ind:textfilecontent54_object id="object_grub2_{{{ SANITIZED_ARG_NAME }}}_argument_default"
  version="1">
    <ind:filepath>/etc/default/grub</ind:filepath>
    <ind:pattern operation="pattern match">^\s*GRUB_CMDLINE_LINUX_DEFAULT="(.*)"$</ind:pattern>
    <ind:instance datatype="int" operation="greater than or equal">1</ind:instance>
  </ind:textfilecontent54_object>
{{%- endif %}}

{{% if system_with_kernel_options_in_etc_default_grub_d -%}}
  <ind:textfilecontent54_test id="test_grub2_{{{ SANITIZED_ARG_NAME }}}_argument_configdir"
  comment="check for {{{ ARG_NAME_VALUE }}} in /etc/default/grub.d/*cfg via GRUB_CMDLINE_LINUX"
  check="at least one" check_existence="all_exist" version="1">
    <ind:object object_ref="object_grub2_{{{ SANITIZED_ARG_NAME }}}_argument_configdir" />
    <ind:state state_ref="state_grub2_{{{ SANITIZED_ARG_NAME }}}_argument" />
  </ind:textfilecontent54_test>

  <ind:textfilecontent54_test id="test_grub2_{{{ SANITIZED_ARG_NAME }}}_argument_default_configdir"
  comment="check for {{{ ARG_NAME_VALUE }}} in /etc/default/grub via GRUB_CMDLINE_LINUX_DEFAULT"
  check="all" check_existence="all_exist" version="1">
    <ind:object object_ref="object_grub2_{{{ SANITIZED_ARG_NAME }}}_argument_default_configdir" />
    <ind:state state_ref="state_grub2_{{{ SANITIZED_ARG_NAME }}}_argument" />
  </ind:textfilecontent54_test>

  <ind:textfilecontent54_object id="object_grub2_{{{ SANITIZED_ARG_NAME }}}_argument_configdir" version="1">
    <ind:filepath operation="pattern match">/etc/default/grub.d/[^/]+\.cfg</ind:filepath>
    <ind:pattern operation="pattern match">^\s*GRUB_CMDLINE_LINUX="(.*)"$</ind:pattern>
    <ind:instance datatype="int" operation="greater than or equal">1</ind:instance>
  </ind:textfilecontent54_object>

  <ind:textfilecontent54_object id="object_grub2_{{{ SANITIZED_ARG_NAME }}}_argument_default_configdir"
  version="1">
    <ind:filepath>/etc/default/grub.d/*.cfg</ind:filepath>
    <ind:pattern operation="pattern match">^\s*GRUB_CMDLINE_LINUX_DEFAULT="(.*)"$</ind:pattern>
    <ind:instance datatype="int" operation="greater than or equal">1</ind:instance>
  </ind:textfilecontent54_object>
{{%- endif %}}

{{%- if system_with_kernel_options_in_grubenv or system_with_expanded_kernel_options_in_loader_entries_or_with_options_in_grubenv %}}
{{%- macro test_and_object_for_kernel_options_grub_env(base_name, path) %}}
  <ind:textfilecontent54_test id="test_{{{ base_name }}}"
  comment="check for kernel command line parameters {{{ ARG_NAME_VALUE }}} in {{{ path }}} for all kernels"
  check="all" check_existence="all_exist" version="1">
    <ind:object object_ref="object_{{{ base_name }}}" />
    <ind:state state_ref="state_grub2_{{{ SANITIZED_ARG_NAME }}}_argument" />
  </ind:textfilecontent54_test>

  <ind:textfilecontent54_object id="object_{{{ base_name }}}"
  version="1">
    <ind:filepath>{{{ path }}}</ind:filepath>
    <ind:pattern operation="pattern match">^kernelopts=(.*)$</ind:pattern>
    <ind:instance datatype="int" operation="greater than or equal">1</ind:instance>
  </ind:textfilecontent54_object>
{{%- endmacro %}}

{{{ test_and_object_for_kernel_options_grub_env("grub2_" ~ SANITIZED_ARG_NAME ~ "_argument_grub_env", grub2_boot_path ~ "/grubenv") }}}
{{% if system_with_bios_and_uefi_support -%}}
{{{ test_and_object_for_kernel_options_grub_env("grub2_" ~ SANITIZED_ARG_NAME ~ "_argument_grub_env_uefi", grub2_uefi_boot_path ~ "/grubenv") }}}
{{%- endif %}}
{{%- endif %}}

{{%- if system_with_expanded_kernel_options_in_loader_entries %}}
    <ind:textfilecontent54_test id="test_grub2_{{{ SANITIZED_ARG_NAME }}}_entries"
                                comment="check kernel command line parameters for {{{ ARG_NAME_VALUE }}} for all boot entries."
                                check="all" check_existence="all_exist" version="1">
      <ind:object object_ref="obj_grub2_{{{ SANITIZED_ARG_NAME }}}_entries" />
      <ind:state state_ref="state_grub2_{{{ SANITIZED_ARG_NAME }}}_argument" />
    </ind:textfilecontent54_test>

  <ind:textfilecontent54_object id="obj_grub2_{{{ SANITIZED_ARG_NAME }}}_entries" version="1">
    <ind:path>/boot/loader/entries/</ind:path>
    <ind:filename operation="pattern match">^.*\.conf$</ind:filename>
    <ind:pattern operation="pattern match">^options (.*)$</ind:pattern>
    <ind:instance datatype="int" operation="greater than or equal">1</ind:instance>
    <filter action="exclude">state_grub2_rescue_entry_for_{{{ _RULE_ID }}}</filter>
  </ind:textfilecontent54_object>

  <ind:textfilecontent54_state id="state_grub2_rescue_entry_for_{{{ _RULE_ID }}}" version="1">
    <ind:filename operation="pattern match">.*rescue\.conf$</ind:filename>
  </ind:textfilecontent54_state>
{{%- endif %}}

{{%- if system_with_expanded_kernel_options_in_grub_cfg %}}
{{%- macro test_and_object_for_kernel_options_grub_cfg(base_name, path) %}}
  <ind:textfilecontent54_test id="test_{{{ base_name }}}"
  comment="check kernel command line parameters for {{{ ARG_NAME_VALUE }}} in {{{ path }}} for all kernels"
  check="all" check_existence="all_exist" version="1">
    <ind:object object_ref="object_{{{ base_name }}}" />
    <ind:state state_ref="state_grub2_{{{ SANITIZED_ARG_NAME }}}_argument" />
  </ind:textfilecontent54_test>

  <ind:textfilecontent54_object id="object_{{{ base_name }}}"
  version="1">
    <ind:filepath>{{{ path }}}</ind:filepath>
    {{% if product in ["ol7"] or 'ubuntu' in product %}}
      <ind:pattern operation="pattern match">^.*/vmlinuz.*(root=.*)$</ind:pattern>
    {{% else %}}
      <ind:pattern operation="pattern match">^set default_kernelopts=(.*)$</ind:pattern>
    {{% endif %}}
    <ind:instance datatype="int" operation="greater than or equal">1</ind:instance>
  </ind:textfilecontent54_object>
{{%- endmacro %}}

{{{ test_and_object_for_kernel_options_grub_cfg("grub2_" + SANITIZED_ARG_NAME + "_argument_grub_cfg", grub2_boot_path ~ "/grub.cfg") }}}
{{% if system_with_bios_and_uefi_support -%}}
{{{ test_and_object_for_kernel_options_grub_cfg("grub2_" + SANITIZED_ARG_NAME + "_argument_grub_cfg_uefi", grub2_uefi_boot_path ~ "/grub.cfg") }}}
{{%- endif %}}
{{%- endif %}}

{{% if system_with_expanded_kernel_options_in_loader_entries_or_with_options_in_grubenv %}}
  <ind:textfilecontent54_state id="state_grub2_{{{ SANITIZED_ARG_NAME }}}_argument_is_kernelopts"
  version="1">
    <ind:subexpression datatype="string" operation="pattern match">^(?:.*\s)?\$kernelopts(?:\s.*)?$</ind:subexpression>
  </ind:textfilecontent54_state>
{{% endif %}}

{{% if not ARG_VARIABLE %}}
  <ind:textfilecontent54_state id="state_grub2_{{{ SANITIZED_ARG_NAME }}}_argument"
  version="1">
    <ind:subexpression datatype="string" operation="pattern match">^(?:.*\s)?{{{ ESCAPED_ARG_NAME_VALUE }}}(?:\s.*)?$</ind:subexpression>
  </ind:textfilecontent54_state>
{{% else %}}
  <ind:textfilecontent54_state id="state_grub2_{{{ SANITIZED_ARG_NAME }}}_argument"
  version="1">
    <ind:subexpression datatype="string" operation="pattern match" var_ref="local_var_regex_{{{ SANITIZED_ARG_NAME }}}_{{{ ARG_VARIABLE }}}" />
  </ind:textfilecontent54_state>

  <local_variable id="local_var_regex_{{{ SANITIZED_ARG_NAME }}}_{{{ ARG_VARIABLE }}}"
  comment="Regex that matches {{{ ARG_NAME }}} with value {{{ ARG_VARIABLE }}}"
  datatype="string" version="1">
    <concat>
      <literal_component>^(?:.*\s)?{{{ ARG_NAME }}}=</literal_component>
      {{% if IS_SUBSTRING == "true" %}}
      <literal_component>\S*</literal_component>
      {{% endif %}}
      <variable_component var_ref="{{{ ARG_VARIABLE }}}" />
      {{% if IS_SUBSTRING == "true" %}}
      <literal_component>\S*</literal_component>
      {{% endif %}}
      <literal_component>(?:\s.*)?$</literal_component>
    </concat>
  </local_variable>

  <external_variable comment="Variable defining the value the argument should have" datatype="string" id="{{{ ARG_VARIABLE }}}" version="1" />
{{% endif %}}

{{% if bootable_containers_supported == "true" %}}
  <ind:textfilecontent54_test id="test_grub2_{{{ SANITIZED_ARG_NAME }}}_usr_lib_bootc_kargs_d"
                              comment="check kernel command line parameters for {{{ ARG_NAME_VALUE }}} for all boot entries."
                              check="at least one" check_existence="at_least_one_exists" version="1">
    <ind:object object_ref="object_grub2_{{{ SANITIZED_ARG_NAME }}}_usr_lib_bootc_kargs_d" />
    <ind:state state_ref="state_grub2_{{{ SANITIZED_ARG_NAME }}}_usr_lib_bootc_kargs_d" />
  </ind:textfilecontent54_test>
  <ind:textfilecontent54_object id="object_grub2_{{{ SANITIZED_ARG_NAME }}}_usr_lib_bootc_kargs_d" version="1">
    <ind:path>/usr/lib/bootc/kargs.d/</ind:path>
    <ind:filename operation="pattern match">^.*\.toml$</ind:filename>
    <ind:pattern operation="pattern match">^kargs = \[([^\]]+)\]$</ind:pattern>
    <ind:instance datatype="int" operation="greater than or equal">1</ind:instance>
  </ind:textfilecontent54_object>
{{% if not ARG_VARIABLE %}}
  <ind:textfilecontent54_state id="state_grub2_{{{ SANITIZED_ARG_NAME }}}_usr_lib_bootc_kargs_d" version="1">
    <ind:subexpression operation="pattern match">^.*"{{{ ESCAPED_ARG_NAME_VALUE }}}".*$</ind:subexpression>
  </ind:textfilecontent54_state>
{{% else %}}
  <ind:textfilecontent54_state id="state_grub2_{{{ SANITIZED_ARG_NAME }}}_usr_lib_bootc_kargs_d" version="1">
    <ind:subexpression operation="pattern match" var_ref="local_var_regex_{{{ SANITIZED_ARG_NAME }}}_{{{ ARG_VARIABLE }}}_bootc_kargs" />
  </ind:textfilecontent54_state>

  <local_variable id="local_var_regex_{{{ SANITIZED_ARG_NAME }}}_{{{ ARG_VARIABLE }}}_bootc_kargs"
  comment="Regex that matches {{{ ARG_NAME }}} with value {{{ ARG_VARIABLE }}}"
  datatype="string" version="1">
    <concat>
      <literal_component>^.*"{{{ ARG_NAME }}}=</literal_component>
      {{% if IS_SUBSTRING == "true" %}}
      <literal_component>\S*</literal_component>
      {{% endif %}}
      <variable_component var_ref="{{{ ARG_VARIABLE }}}" />
      {{% if IS_SUBSTRING == "true" %}}
      <literal_component>\S*</literal_component>
      {{% endif %}}
      <literal_component>".*$</literal_component>
    </concat>
  </local_variable>

  <external_variable comment="Variable defining the value the argument should have" datatype="string" id="{{{ ARG_VARIABLE }}}" version="1" />
{{% endif %}}
{{% endif %}}

</def-group>
