-
Notifications
You must be signed in to change notification settings - Fork 59
/
fetcher.rb
143 lines (118 loc) · 4.42 KB
/
fetcher.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# encoding: utf-8
# author: Christoph Hartmann
require 'uri'
require 'bundles/inspec-compliance/target'
require 'inspec/fetcher'
require 'inspec/errors'
# This class implements an InSpec fetcher for for Chef Server. The implementation
# is based on the Chef Compliance fetcher and only adapts the calls to redirect
# the requests via Chef Server.
#
# This implementation depends on chef-client runtime, therefore it is only executable
# inside of a chef-client run
module ChefServer
class Fetcher < Compliance::Fetcher
name 'chef-server'
# it positions itself before `compliance` fetcher
# only load it, if the Chef Server is integrated with Chef Compliance
priority 501
def self.resolve(target)
uri = if target.is_a?(String) && URI(target).scheme == 'compliance'
URI(target)
elsif target.respond_to?(:key?) && target.key?(:compliance)
URI("compliance://#{target[:compliance]}")
end
return nil if uri.nil?
profile = uri.host + uri.path
profile = uri.user + '@' + profile if uri.user
config = {
'insecure' => true,
}
if target.respond_to?(:key?) && target.key?(:version)
new(target_url(profile, config, target[:version]), config)
else
new(target_url(profile, config), config)
end
rescue URI::Error => _e
nil
end
def self.chef_server_url_base
cs = URI(Chef::Config[:chef_server_url])
cs.path = ''
cs.to_s
end
def self.chef_server_org
Chef::Config[:chef_server_url].split('/').last
end
def self.url_prefix
return '/compliance' if chef_server_reporter? || chef_server_fetcher?
''
end
def self.target_url(profile, config, version = nil)
o, p = profile.split('/')
reqpath = if version
"organizations/#{chef_server_org}/owners/#{o}/compliance/#{p}/version/#{version}/tar"
else
"organizations/#{chef_server_org}/owners/#{o}/compliance/#{p}/tar"
end
if config['insecure']
Chef::Config[:verify_api_cert] = false
Chef::Config[:ssl_verify_mode] = :verify_none
end
target_url = construct_url(chef_server_url_base + url_prefix + '/', reqpath)
Chef::Log.info("Fetching profile from: #{target_url}")
target_url
end
#
# We want to save compliance: in the lockfile rather than url: to
# make sure we go back through the ComplianceAPI handling.
#
def resolved_source
{ compliance: chef_server_url }
end
# Downloads archive to temporary file using a Chef::ServerAPI
# client so that Chef Server's header-based authentication can be
# used.
def download_archive_to_temp
return @temp_archive_path unless @temp_archive_path.nil?
Chef::Config[:verify_api_cert] = false # FIXME
Chef::Config[:ssl_verify_mode] = :verify_none # FIXME
rest = Chef::ServerAPI.new(@target, Chef::Config)
archive = with_http_rescue do
rest.streaming_request(@target)
end
@archive_type = '.tar.gz'
raise "Unable to find requested profile on path: '#{target_path}' on the Automate system." if archive.nil?
Inspec::Log.debug("Archive stored at temporary location: #{archive.path}")
@temp_archive_path = archive.path
end
def to_s
'Chef Server/Compliance Profile Loader'
end
# internal class methods
def self.chef_server_reporter?
return false unless defined?(Chef) && defined?(Chef.node) && defined?(Chef.node.attributes)
reporters = get_reporters(Chef.node.attributes['audit'])
# TODO: harmonize with audit_report.rb load_chef_fetcher
Chef.node.attributes['audit'] && (
reporters.include?('chef-server') ||
reporters.include?('chef-server-compliance') ||
reporters.include?('chef-server-visibility') ||
reporters.include?('chef-server-automate')
)
end
def self.chef_server_fetcher?
# TODO: harmonize with audit_report.rb load_chef_fetcher
%w(chef-server chef-server-compliance chef-server-visibility chef-server-automate).include?(Chef.node.attributes['audit']['fetcher'])
end
private
def chef_server_url
m = %r{^#{@config['server']}/owners/(?<owner>[^/]+)/compliance/(?<id>[^/]+)/tar$}.match(@target)
"#{m[:owner]}/#{m[:id]}"
end
def target_path
return @target.path if @target.respond_to?(:path)
@target
end
end
end