-
Notifications
You must be signed in to change notification settings - Fork 59
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
fix reporting files #134
Merged
Merged
fix reporting files #134
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
95506c4
save report to variable instead of file by default
2c5d191
write to json file to ensure interval timing
d544e1e
tests and cleanup
0b466bc
refactor to make json-file its own reporter, write timestamp file
ad07cfa
support multiple reporters
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,27 +6,44 @@ class Handler | |
# Creates a compliance audit report | ||
class AuditReport < ::Chef::Handler | ||
def report | ||
reporter = node['audit']['collector'] | ||
# ensure reporters is array | ||
reporters = handle_reporters(node['audit']['collector']) | ||
|
||
# collect attribute values | ||
server = node['audit']['server'] | ||
user = node['audit']['owner'] | ||
token = node['audit']['token'] | ||
refresh_token = node['audit']['refresh_token'] | ||
interval = node['audit']['interval'] | ||
interval_enabled = node['audit']['interval']['enabled'] | ||
interval_time = node['audit']['interval']['time'] | ||
report_file = node['audit']['output'] | ||
profiles = node['audit']['profiles'] | ||
quiet = node['audit']['quiet'] | ||
|
||
# create a file with a timestamp to | ||
create_timestamp_file if interval_enabled | ||
|
||
# load inspec, supermarket bundle and compliance bundle | ||
load_needed_dependencies | ||
|
||
# ensure authentication for Chef Compliance is in place | ||
login_to_compliance(server, user, token, refresh_token) if reporter == 'chef-compliance' | ||
# iterate through reporters | ||
reporters.each do |reporter| | ||
# ensure authentication for Chef Compliance is in place, see libraries/compliance.rb | ||
login_to_compliance(server, user, token, refresh_token) if reporter == 'chef-compliance' | ||
|
||
if check_interval_settings(interval, interval_enabled, interval_time, report_file) | ||
call(reporter, profiles) | ||
send_report(reporter, server, user, profiles) | ||
else | ||
Chef::Log.error 'Please take a look at your interval settings' | ||
# true if profile is due to run (see libraries/helper.rb) | ||
if check_interval_settings(interval, interval_enabled, interval_time) | ||
# return hash of opts to be used by runner | ||
opts = get_opts(reporter, quiet) | ||
|
||
# instantiate inspec runner with given options and run profiles; return report | ||
report = call(opts, profiles) | ||
|
||
# send report to the correct reporter (visibility, compliance, chef-server) | ||
send_report(reporter, server, user, profiles, report) | ||
else | ||
Chef::Log.error 'Please take a look at your interval settings' | ||
end | ||
end | ||
end | ||
|
||
|
@@ -44,55 +61,27 @@ def load_needed_dependencies | |
require 'bundles/inspec-compliance/target' | ||
end | ||
|
||
# TODO: temporary, we should not use this | ||
# TODO: harmonize with CLI login_refreshtoken method | ||
def login_to_compliance(server, user, access_token, refresh_token) | ||
if !refresh_token.nil? | ||
success, msg, access_token = Compliance::API.get_token_via_refresh_token(server, refresh_token, true) | ||
else | ||
success = true | ||
end | ||
|
||
if success | ||
config = Compliance::Configuration.new | ||
config['user'] = user | ||
config['server'] = server | ||
config['token'] = access_token | ||
config['insecure'] = true | ||
config['version'] = Compliance::API.version(server, true) | ||
config.store | ||
else | ||
Chef::Log.error msg | ||
raise('Could not store authentication token') | ||
end | ||
end | ||
|
||
def check_interval_settings(interval, interval_enabled, interval_time, report_file) | ||
# handle intervals | ||
interval_seconds = 0 # always run this by default, unless interval is defined | ||
if !interval.nil? && interval_enabled | ||
interval_seconds = interval_time * 60 # seconds in interval | ||
Chef::Log.debug "Auditing this machine every #{interval_seconds} seconds " | ||
end | ||
# returns true if profile is overdue to run | ||
profile_overdue_to_run?(interval_seconds, report_file) | ||
# sets format to json-min when chef-compliance, json when chef-visibility | ||
def get_opts(reporter, quiet) | ||
format = reporter == 'chef-visibility' ? 'json' : 'json-min' | ||
output = quiet ? ::File::NULL : $stdout | ||
Chef::Log.warn "Format is #{format}" | ||
{ 'report' => true, 'format' => format, 'output' => output } | ||
end | ||
|
||
def call(reporter, profiles) | ||
# run profiles and return report | ||
def call(opts, profiles) | ||
Chef::Log.debug 'Initialize InSpec' | ||
format = reporter == 'chef-visibility' ? 'json' : 'json-min' | ||
Chef::Log.warn "Format is #{format}" | ||
# TODO: for now we need to store the report to a file we expect that to | ||
# get from the runner | ||
Chef::Log.warn "*********** Directory is #{node['audit']['output']}" | ||
opts = { 'format' => format, 'output' => node['audit']['output'] } | ||
Chef::Log.debug "Options are set to: #{opts}" | ||
runner = ::Inspec::Runner.new(opts) | ||
|
||
# parse profile hashes for runner, see libraries/helper.rb | ||
tests = tests_for_runner(profiles) | ||
tests.each { |target| runner.add_target(target, opts) } | ||
|
||
Chef::Log.info "Running tests from: #{tests.inspect}" | ||
runner.run | ||
runner.report.to_json | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. +1 |
||
end | ||
|
||
# extracts relevant node data | ||
|
@@ -109,41 +98,46 @@ def gather_nodeinfo | |
} | ||
end | ||
|
||
def send_report(reporter, server, user, profiles) | ||
# send report to the collector (see libraries/collector_classes.rb) | ||
def send_report(reporter, server, user, profiles, report) | ||
Chef::Log.info "Reporting to #{reporter}" | ||
|
||
# TODO: harmonize reporter interface | ||
if reporter == 'chef-visibility' | ||
Collector::ChefVisibility.new(entity_uuid, run_id, gather_nodeinfo[:node]).send_report | ||
Collector::ChefVisibility.new(entity_uuid, run_id, gather_nodeinfo, report).send_report | ||
|
||
elsif reporter == 'chef-compliance' | ||
raise_if_unreachable = node['audit']['raise_if_unreachable'] | ||
url = construct_url(server, File.join('/owners', user, 'inspec')) | ||
if server | ||
# TODO: we should not send the profiles to the reporter, all the information | ||
# should be available in inspec reports out-of-the-box | ||
# TODO: Chef Compliance can only handle reports for profiles it knows | ||
profiles = tests_for_runner(profiles).map { |profile| profile[:compliance] }.uniq | ||
# TODO: raise warning when not a compliance-known profile | ||
profiles = tests_for_runner(profiles).map { |profile| profile[:compliance] if profile[:compliance] }.uniq.compact | ||
compliance_profiles = profiles.map { |profile| | ||
owner, profile_id = profile.split('/') | ||
{ | ||
owner: owner, | ||
profile_id: profile_id, | ||
} | ||
} | ||
Collector::ChefCompliance.new(url, gather_nodeinfo, raise_if_unreachable, compliance_profiles).send_report | ||
Collector::ChefCompliance.new(url, gather_nodeinfo, raise_if_unreachable, compliance_profiles, report).send_report | ||
else | ||
Chef::Log.warn "'server' and 'token' properties required by inspec report collector #{reporter}. Skipping..." | ||
end | ||
|
||
elsif reporter == 'chef-server' | ||
chef_url = server || base_chef_server_url | ||
if chef_url | ||
url = construct_url(chef_url + '/compliance/', File.join('organizations', user, 'inspec')) | ||
Collector::ChefServer.new(url).send_report | ||
else | ||
Chef::Log.warn "unable to determine chef-server url required by inspec report collector '#{reporter}'. Skipping..." | ||
end | ||
# elsif reporter == 'chef-server' | ||
# chef_url = server || base_chef_server_url | ||
# if chef_url | ||
# url = construct_url(chef_url + '/compliance/', File.join('organizations', user, 'inspec')) | ||
# Collector::ChefServer.new(url).send_report | ||
# else | ||
# Chef::Log.warn "unable to determine chef-server url required by inspec report collector '#{reporter}'. Skipping..." | ||
# end | ||
|
||
elsif reporter == 'json-file' | ||
timestamp = Time.now.utc.to_s.tr(' ', '_') | ||
Collector::JsonFile.new(report, timestamp).send_report | ||
else | ||
Chef::Log.warn "#{reporter} is not a supported InSpec report collector" | ||
end | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it would be perfect to iterate only over
send_report(reporter, server, user, profiles)
, but we needjson-min
for Chef Compliance ... so it looks like we need to iterate over the scan as well for now