SCAP Reporting (Proposed new functionality)

That makes perfect sense. If I wanted to add that, would something like this be enough for my extension?

app/models/concerns/foreman_plugin_ex/arf_report_extensions.rb:

module ForemanPlugin_ex
  module ArfReportExtensions
    extend ActiveSupport::Concern
    def ArfReport_create_arf(asset, proxy, params)
      arf_report = nil
      policy = Policy.find_by :id => params[:policy_id]
      return unless policy

      ArfReport.transaction do
        arf_report = ArfReport.create(:host => asset.host,
                                      :reported_at => Time.at(params[:date].to_i),
                                      :status => params[:metrics],
                                      :metrics => params[:metrics],
                                      :openscap_proxy => proxy)
        return arf_report unless arf_report.persisted?
        PolicyArfReport.where(:arf_report_id => arf_report.id, :policy_id => policy.id, :digest => params[:digest]).first_or_create!
        if params[:logs]
          params[:logs].each do |log|
            src = Source.find_or_create_by(value: log[:source])
            msg = nil
            if src.logs.count > 0
              msg = Log.where(:source_id => src.id).order(:id => :desc).first.message
              update_msg_with_changes(msg, log)
            else
              if (msg = Message.find_by(:value => log[:title]))
                msg.attributes = {
                  :value => N_(log[:title]),
                  :severity => log[:severity],
                  :description => newline_to_space(log[:description]),
                  :rationale => newline_to_space(log[:rationale]),
                  :scap_references => references_links(log[:references]),
                  :fixes => JSON.fast_generate(log[:fixes])
                }
              else
                msg = Message.new(:value => N_(log[:title]),
                                  :severity => log[:severity],
                                  :description => newline_to_space(log[:description]),
                                  :rationale => newline_to_space(log[:rationale]),
                                  :scap_references => references_links(log[:references]),
                                  :fixes => JSON.fast_generate(log[:fixes]))
              end
              msg.save!
            end
            # TODO: log level
            Log.create!(:source_id => src.id,
                        :message_id => msg.id,
                        :level => :info,
                        :result => log[:result],
                        :report => arf_report)
          end
        end
      end
      arf_report
    end
  end
end
module ForemanPluginEx
  module ArfReportExtensions
    extend ActiveSupport::Concern

    #included do
      # execute callbacks
    #end

    # create or overwrite instance methods...
    #def instance_method_name
    #end

      # create or overwrite class methods...
      #def class_method_name
      #end
    module ClassMethods

      def ArfReport_create_arf(asset, proxy, params)
        arf_report = nil
        policy = Policy.find_by :id => params[:policy_id]
        return unless policy

        ArfReport.transaction do
          arf_report = ArfReport.create(:host => asset.host,
                                        :reported_at => Time.at(params[:date].to_i),
                                        :status => params[:metrics],
                                        :metrics => params[:metrics],
                                        :openscap_proxy => proxy)
          return arf_report unless arf_report.persisted?
          PolicyArfReport.where(:arf_report_id => arf_report.id, :policy_id => policy.id, :digest => params[:digest]).first_or_create!
          if params[:logs]
            params[:logs].each do |log|
              src = Source.find_or_create_by(value: log[:source])
              msg = nil
              if src.logs.count > 0
                msg = Log.where(:source_id => src.id).order(:id => :desc).first.message
                update_msg_with_changes(msg, log)
              else
                if (msg = Message.find_by(:value => log[:title]))
                  msg.attributes = {
                    :value => N_(log[:title]),
                    :severity => log[:severity],
                    :description => newline_to_space(log[:description]),
                    :rationale => newline_to_space(log[:rationale]),
                    :scap_references => references_links(log[:references]),
                    :fixes => JSON.fast_generate(log[:fixes])
                  }
                else
                  msg = Message.new(:value => N_(log[:title]),
                                    :severity => log[:severity],
                                    :description => newline_to_space(log[:description]),
                                    :rationale => newline_to_space(log[:rationale]),
                                    :scap_references => references_links(log[:references]),
                                    :fixes => JSON.fast_generate(log[:fixes]))
                end
                msg.save!
              end
              # TODO: log level
              Log.create!(:source_id => src.id,
                          :message_id => msg.id,
                          :level => :info,
                          :result => log[:result],
                          :report => arf_report)
            end
          end
        end
        arf_report
      end
    end
  end
end

Seen the “Fix Me” column and “Solution” button sorta gave me some hope that you can actually use the Ansible code that comes with each test to fix the hosts for failed tests, but I guess that is not the case?
Since I am using ansible to setup the hosts and perform the tests, it would be a great feature to also be able to remediate failed tests using the ansible code that comes with the security guide.
Thinking a “Fix” button and then the selection of Ansible or Remote Execution (Bash) or Manually.

That should work, but don’t forget that you’d need to add a new migration that adds :fixes column to the Message table: Fixes #36738 - Add remediation wizard by ofedoren · Pull Request #546 · theforeman/foreman_openscap · GitHub

Hello @tedevil,

That’s what I’m actually adding in my PR (Fixes #36738 - Add remediation wizard by ofedoren · Pull Request #546 · theforeman/foreman_openscap · GitHub). You can see on the video attached that it’s possible to observe all the available fixes you can use manually. Ansible will be supported as automated remediation. It will use Ansible fix (snippet) and Remote Execution with Ansible provider to run against selected hosts.

Sorry, missed the attached video. Looking good!
One feature to add (if possible) could be to automatically run that specific failed test again after remediation, and flag that test as passed if it did pass this time. Little unsure if those tests are possible to run individually or if you just are forced to run all tests again to get them check again.
Could be as easy as to maybe just have a check box on the remediation page to “Run OpenSCAP scan after remediation”.