Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #11872 - Compliance status for hosts #131

Merged
merged 1 commit into from Oct 13, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -66,6 +66,7 @@ def create
arf_bzip2 = request.body.read
arf_bzip2_size = request.body.size
ForemanOpenscap::ArfReport.create_arf(asset, params, arf_bzip2, arf_bzip2_size)
asset.host.refresh_statuses if asset.host
render :json => { :result => :OK, :received => arf_bzip2_size }
end

Expand Down
17 changes: 17 additions & 0 deletions app/models/concerns/foreman_openscap/host_extensions.rb
Expand Up @@ -8,11 +8,16 @@ module HostExtensions
has_many :asset_policies, :through => :asset, :class_name => "::ForemanOpenscap::AssetPolicy"
has_many :policies, :through => :asset_policies, :class_name => "::ForemanOpenscap::Policy"
has_many :arf_reports, :through => :asset, :class_name => '::ForemanOpenscap::ArfReport'
has_one :compliance_status_object, :class_name => '::ForemanOpenscap::ComplianceStatus', :foreign_key => 'host_id'

scoped_search :in => :policies, :on => :name, :complete_value => true, :rename => :'compliance_policy',
:only_explicit => true, :operators => ['= ', '!= '], :ext_method => :search_by_policy_name
scoped_search :in => :policies, :on => :name, :complete_value => true, :rename => :'compliance_report_missing_for',
:only_explicit => true, :operators => ['= ', '!= '], :ext_method => :search_by_missing_arf
scoped_search :in => :compliance_status_object, :on => :status, :rename => :compliance_status,
:complete_value => {:compliant => ::ForemanOpenscap::ComplianceStatus::COMPLIANT,
:incompliant => ::ForemanOpenscap::ComplianceStatus::INCOMPLIANT,
:inconclusive => ::ForemanOpenscap::ComplianceStatus::INCONCLUSIVE}
end

def get_asset
Expand All @@ -34,6 +39,10 @@ def scap_status_changed?(policy)
!last_reports.first.equal? last_reports.last
end

def last_report_for_policy(policy)
reports_for_policy(policy, 1)
end

def reports_for_policy(policy, limit = nil)
if limit
ForemanOpenscap::ArfReport.where(:asset_id => asset.id, :policy_id => policy.id).limit limit
Expand All @@ -42,6 +51,14 @@ def reports_for_policy(policy, limit = nil)
end
end

def compliance_status(options = {})
@compliance_status ||= get_status(ForemanOpenscap::ComplianceStatus).to_status(options)
end

def compliance_status_label(options = {})
@compliance_status_label ||= get_status(ForemanOpenscap::ComplianceStatus).to_label(options)
end

module ClassMethods
def search_by_policy_name(key, operator, policy_name)
cond = sanitize_sql_for_conditions(["foreman_openscap_policies.name #{operator} ?", value_to_sql(operator, policy_name)])
Expand Down
6 changes: 5 additions & 1 deletion app/models/foreman_openscap/arf_report.rb
Expand Up @@ -122,7 +122,11 @@ def failed?
end

def passed?
passed > 0 && !failed?
passed > 0 && failed == 0 && othered == 0
end

def othered?
!passed? && !failed?
end

def equal?(other)
Expand Down
46 changes: 46 additions & 0 deletions app/models/foreman_openscap/compliance_status.rb
@@ -0,0 +1,46 @@
module ForemanOpenscap
class ComplianceStatus < ::HostStatus::Status
COMPLIANT = 0
INCONCLUSIVE = 1
INCOMPLIANT = 2

def self.status_name
N_('Compliance')
end

def to_label(options = {})
case to_status
when COMPLIANT
N_('Compliant')
when INCONCLUSIVE
N_('Inconclusive')
when INCOMPLIANT
N_('Incompliant')
else
N_('Unknown Compliance status')
end
end

def to_global(options = {})
case to_status
when COMPLIANT
::HostStatus::Global::OK
when INCONCLUSIVE
::HostStatus::Global::WARN
else
::HostStatus::Global::ERROR
end
end

def relevant?
host.policies.present?
end

def to_status(options = {})
latest_reports = host.policies.map { |p| host.last_report_for_policy p }.flatten
return INCOMPLIANT if latest_reports.any?(&:failed?)
return INCONCLUSIVE if latest_reports.any?(&:othered?)
COMPLIANT
end
end
end
5 changes: 0 additions & 5 deletions app/overrides/hosts/index/host_arf_report.rb

This file was deleted.

8 changes: 4 additions & 4 deletions app/overrides/hosts/overview/host_compliance_status.rb
@@ -1,4 +1,4 @@
Deface::Override.new(:virtual_path => "hosts/_overview",
:name => "add_compliance_check",
:insert_after => "#properties_table",
:partial => "compliance_hosts/host_status")
Deface::Override.new(:virtual_path => "hosts/show",
:name => "add_compliance_link_to_host",
:insert_bottom => 'td:last',
:partial => 'compliance_hosts/compliance_status')
6 changes: 6 additions & 0 deletions app/views/compliance_hosts/_compliance_status.erb
@@ -0,0 +1,6 @@
<%= link_to(
_('Compliance'),
compliance_host_path(@host.id),
:title => _("Host compliance details"),
:class => 'btn btn-default') if @host.arf_reports.any?
%>
11 changes: 8 additions & 3 deletions lib/foreman_openscap/engine.rb
Expand Up @@ -19,7 +19,7 @@ class Engine < ::Rails::Engine
f.split(File::SEPARATOR, 4).last
end
end

initializer 'foreman_openscap.assets.precompile' do |app|
app.config.assets.precompile += assets_to_precompile
end
Expand All @@ -39,6 +39,9 @@ class Engine < ::Rails::Engine

apipie_documented_controllers ["#{ForemanOpenscap::Engine.root}/app/controllers/api/v2/compliance/*.rb"]

version = SETTINGS[:version]
register_custom_status ForemanOpenscap::ComplianceStatus if version.major.to_i >= 1 && version.minor.to_i >= 10

# Add permissions
security_block :foreman_openscap do
permission :view_arf_reports, {:arf_reports => [:index, :show, :parse, :auto_complete_search],
Expand Down Expand Up @@ -99,8 +102,10 @@ class Engine < ::Rails::Engine
:parent => :hosts_menu

# add dashboard widget
widget 'foreman_openscap_host_reports_widget', :name => N_('OpenSCAP Host reports widget'), :sizex => 4, :sizey => 1
widget 'foreman_openscap_reports_breakdown_widget', :name => N_('OpenSCAP Reports breakdown widget'), :sizex => 4, :sizey => 1
widget 'compliance_host_reports_widget',
:name => N_('OpenSCAP Host reports widget'), :sizex => 4, :sizey => 1
widget 'compliance_reports_breakdown_widget',
:name => N_('OpenSCAP Reports breakdown widget'), :sizex => 4, :sizey => 1

# As 'arf_report_breakdowns' is a view and does not appear in schema.rb, db:test:prepare will not create the view
# which will make the following tests fail.
Expand Down
7 changes: 7 additions & 0 deletions test/factories/arf_report_breakdown_factory.rb
@@ -0,0 +1,7 @@
FactoryGirl.define do
factory :arf_report_breakdown, :class => 'ForemanOpenscap::ArfReportBreakdown' do
passed 0
failed 0
othered 0
end
end
3 changes: 2 additions & 1 deletion test/factories/arf_report_factory.rb
Expand Up @@ -2,8 +2,9 @@
factory :arf_report, :class => ::ForemanOpenscap::ArfReport do |f|
f.asset
f.policy
f.sequence(:digest) { |n| "#{n}1212aa#{n}"}
f.sequence(:digest) { |n| "#{n}1212aa#{n}" }
date '1973-01-13'
xccdf_rule_results []
f.arf_report_breakdown
end
end
8 changes: 8 additions & 0 deletions test/factories/compliance_host_factory.rb
@@ -0,0 +1,8 @@
FactoryGirl.define do
factory :compliance_host, :class => Host::Managed do
sequence(:name) { |n| "host#{n}" }
sequence(:hostname) { |n| "host#{n}" }
root_pass 'xybxa6JUkz63w'
policies []
end
end
2 changes: 1 addition & 1 deletion test/factories/policy_factory.rb
Expand Up @@ -9,4 +9,4 @@
cron_line '* * * * 30'
hosts []
end
end
end
2 changes: 1 addition & 1 deletion test/factories/xccdf_rule_result_factory.rb
Expand Up @@ -3,4 +3,4 @@
xccdf_result_id 1
xccdf_rule_id 1
end
end
end
18 changes: 18 additions & 0 deletions test/unit/arf_report_test.rb
Expand Up @@ -53,5 +53,23 @@ class ArfReportTest < ActiveSupport::TestCase

refute(report_1.equal? report_2)
end

test 'should recognize report that failed' do
breakdown = FactoryGirl.build(:arf_report_breakdown, :passed => 1, :failed => 1, :othered => 1)
report = FactoryGirl.create(:arf_report, :arf_report_breakdown => breakdown)
assert report.failed?
end

test 'should recognize report that othered' do
breakdown = FactoryGirl.build(:arf_report_breakdown, :passed => 1, :failed => 0, :othered => 1)
report = FactoryGirl.create(:arf_report, :arf_report_breakdown => breakdown)
assert report.othered?
end

test 'should recognize report that passed' do
breakdown = FactoryGirl.build(:arf_report_breakdown, :passed => 1, :failed => 0, :othered => 0)
report = FactoryGirl.create(:arf_report, :arf_report_breakdown => breakdown)
assert report.passed?
end
end
end
43 changes: 43 additions & 0 deletions test/unit/compliance_status_test.rb
@@ -0,0 +1,43 @@
require 'test_plugin_helper'

class ComplianceStatusTest < ActiveSupport::TestCase
def setup
disable_orchestration
User.current = users :admin
ForemanOpenscap::Policy.any_instance.stubs(:ensure_needed_puppetclasses).returns(true)
@policy_a = FactoryGirl.create(:policy)
@policy_b = FactoryGirl.create(:policy)
@failed_report = FactoryGirl.create(:arf_report).stubs(:failed?).returns(true)
@passed_report = FactoryGirl.create(:arf_report).stubs(:failed?).returns(false)
@passed_report.stubs(:othered?).returns(:false)
@othered_report = FactoryGirl.create(:arf_report).stubs(:failed?).returns(false)
@othered_report.stubs(:othered?).returns(true)
end

test 'status should be incompliant' do
status = ForemanOpenscap::ComplianceStatus.new
host = FactoryGirl.create(:compliance_host, :policies => [@policy_a, @policy_b])
host.stubs(:last_report_for_policy).returns(@failed_report, @passed_report)
status.host = host
assert_equal 2, status.to_status
end

test 'status should be inconclusive' do
status = ForemanOpenscap::ComplianceStatus.new
host = FactoryGirl.create(:compliance_host, :policies => [@policy_a, @policy_b])
host.stubs(:last_report_for_policy).returns(@othered_report, @passed_report)
status.host = host
assert_equal 1, status.to_status
end

test 'status should be compliant' do
status = ForemanOpenscap::ComplianceStatus.new
host = FactoryGirl.create(:compliance_host, :policies => [@policy_a, @policy_b])
passed_report = FactoryGirl.create(:arf_report).stubs(:failed?).returns(false)
passed_report.stubs(:othered?).returns(:false)
host.stubs(:last_report_for_policy).returns(passed_report, @passed_report)
status.host = host
assert_equal 0, status.to_status
end

end