inspec-core 5.18.14 → 5.21.29
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +19 -16
- data/inspec-core.gemspec +22 -22
- data/lib/inspec/base_cli.rb +2 -0
- data/lib/inspec/cli.rb +6 -2
- data/lib/inspec/dsl.rb +10 -4
- data/lib/inspec/enhanced_outcomes.rb +19 -0
- data/lib/inspec/env_printer.rb +1 -1
- data/lib/inspec/exceptions.rb +2 -0
- data/lib/inspec/formatters/base.rb +69 -16
- data/lib/inspec/plugin/v2/loader.rb +19 -8
- data/lib/inspec/plugin/v2/plugin_types/reporter.rb +1 -0
- data/lib/inspec/plugin/v2/plugin_types/streaming_reporter.rb +54 -0
- data/lib/inspec/reporters/base.rb +1 -0
- data/lib/inspec/reporters/cli.rb +94 -3
- data/lib/inspec/reporters/json.rb +3 -1
- data/lib/inspec/reporters/yaml.rb +3 -1
- data/lib/inspec/reporters.rb +2 -1
- data/lib/inspec/resources/file.rb +1 -1
- data/lib/inspec/resources/http.rb +2 -2
- data/lib/inspec/resources/lxc.rb +65 -9
- data/lib/inspec/resources/oracledb_session.rb +13 -4
- data/lib/inspec/resources/podman.rb +353 -0
- data/lib/inspec/resources/podman_container.rb +84 -0
- data/lib/inspec/resources/podman_image.rb +108 -0
- data/lib/inspec/resources/podman_network.rb +81 -0
- data/lib/inspec/resources/podman_pod.rb +101 -0
- data/lib/inspec/resources/podman_volume.rb +87 -0
- data/lib/inspec/resources/service.rb +1 -1
- data/lib/inspec/rule.rb +54 -17
- data/lib/inspec/run_data/control.rb +6 -0
- data/lib/inspec/run_data/statistics.rb +8 -2
- data/lib/inspec/runner.rb +18 -8
- data/lib/inspec/runner_rspec.rb +3 -2
- data/lib/inspec/schema/exec_json.rb +78 -2
- data/lib/inspec/schema/output_schema.rb +4 -1
- data/lib/inspec/schema/profile_json.rb +46 -0
- data/lib/inspec/schema.rb +91 -0
- data/lib/inspec/utils/convert.rb +8 -0
- data/lib/inspec/utils/podman.rb +24 -0
- data/lib/inspec/utils/waivers/csv_file_reader.rb +34 -0
- data/lib/inspec/utils/waivers/excel_file_reader.rb +39 -0
- data/lib/inspec/utils/waivers/json_file_reader.rb +15 -0
- data/lib/inspec/version.rb +1 -1
- data/lib/inspec/waiver_file_reader.rb +61 -0
- data/lib/matchers/matchers.rb +7 -1
- data/lib/plugins/inspec-init/templates/profiles/alicloud/README.md +27 -0
- data/lib/plugins/inspec-init/templates/profiles/alicloud/controls/example.rb +10 -0
- data/lib/plugins/inspec-init/templates/profiles/alicloud/inputs.yml +1 -0
- data/lib/plugins/inspec-init/templates/profiles/alicloud/inspec.yml +14 -0
- data/lib/plugins/inspec-reporter-html2/README.md +1 -1
- data/lib/plugins/inspec-reporter-html2/templates/body.html.erb +7 -1
- data/lib/plugins/inspec-reporter-html2/templates/control.html.erb +10 -6
- data/lib/plugins/inspec-reporter-html2/templates/default.css +12 -0
- data/lib/plugins/inspec-reporter-html2/templates/selector.html.erb +7 -1
- data/lib/plugins/inspec-sign/lib/inspec-sign/base.rb +5 -2
- data/lib/plugins/inspec-streaming-reporter-progress-bar/lib/inspec-streaming-reporter-progress-bar/streaming_reporter.rb +39 -13
- metadata +25 -9
@@ -0,0 +1,353 @@
|
|
1
|
+
require "inspec/resources/command"
|
2
|
+
require "inspec/utils/filter"
|
3
|
+
require "hashie/mash"
|
4
|
+
|
5
|
+
module Inspec::Resources
|
6
|
+
class Podman < Inspec.resource(1)
|
7
|
+
# Resource requires an internal name.
|
8
|
+
name "podman"
|
9
|
+
|
10
|
+
# Restrict to only run on the below platforms (if none were given,
|
11
|
+
# all OS's and cloud API's supported)
|
12
|
+
supports platform: "unix"
|
13
|
+
|
14
|
+
desc "A resource to retrieve information about podman"
|
15
|
+
|
16
|
+
example <<~EXAMPLE
|
17
|
+
describe podman.containers do
|
18
|
+
its('images') { should include "docker.io/library/ubuntu:latest" }
|
19
|
+
end
|
20
|
+
|
21
|
+
describe podman.images do
|
22
|
+
its('names') { should_not include "docker.io/library/ubuntu:latest" }
|
23
|
+
end
|
24
|
+
|
25
|
+
describe podman.pods do
|
26
|
+
its("ids") { should include "95cadbb84df71e6374fceb3fd89ee3b8f2c7e1a831062cd9cea7d0e3e4b1dbcc" }
|
27
|
+
end
|
28
|
+
|
29
|
+
describe podman.info.host do
|
30
|
+
its("os") { should eq "linux"}
|
31
|
+
end
|
32
|
+
|
33
|
+
describe podman.version do
|
34
|
+
its("Client.Version") { should eq "4.1.0"}
|
35
|
+
end
|
36
|
+
|
37
|
+
podman.containers.ids.each do |id|
|
38
|
+
# call podman inspect for a specific container id
|
39
|
+
describe podman.object(id) do
|
40
|
+
its("State.OciVersion") { should eq "1.0.2-dev" }
|
41
|
+
its("State.Running") { should eq true}
|
42
|
+
end
|
43
|
+
end
|
44
|
+
EXAMPLE
|
45
|
+
|
46
|
+
def containers
|
47
|
+
PodmanContainerFilter.new(parse_containers)
|
48
|
+
end
|
49
|
+
|
50
|
+
def images
|
51
|
+
PodmanImageFilter.new(parse_images)
|
52
|
+
end
|
53
|
+
|
54
|
+
def networks
|
55
|
+
PodmanNetworkFilter.new(parse_networks)
|
56
|
+
end
|
57
|
+
|
58
|
+
def pods
|
59
|
+
PodmanPodFilter.new(parse_pods)
|
60
|
+
end
|
61
|
+
|
62
|
+
def volumes
|
63
|
+
PodmanVolumeFilter.new(parse_volumes)
|
64
|
+
end
|
65
|
+
|
66
|
+
def version
|
67
|
+
return @version if defined?(@version)
|
68
|
+
|
69
|
+
sub_cmd = "version --format json"
|
70
|
+
output = run_command(sub_cmd)
|
71
|
+
@version = Hashie::Mash.new(JSON.parse(output))
|
72
|
+
rescue JSON::ParserError => _e
|
73
|
+
Hashie::Mash.new({})
|
74
|
+
end
|
75
|
+
|
76
|
+
def info
|
77
|
+
return @info if defined?(@info)
|
78
|
+
|
79
|
+
sub_cmd = "info --format json"
|
80
|
+
output = run_command(sub_cmd)
|
81
|
+
@info = Hashie::Mash.new(JSON.parse(output))
|
82
|
+
rescue JSON::ParserError => _e
|
83
|
+
Hashie::Mash.new({})
|
84
|
+
end
|
85
|
+
|
86
|
+
# returns information about podman objects
|
87
|
+
def object(id)
|
88
|
+
return @inspect if defined?(@inspect)
|
89
|
+
|
90
|
+
output = run_command("inspect #{id} --format json")
|
91
|
+
data = JSON.parse(output)
|
92
|
+
data = data[0] if data.is_a?(Array)
|
93
|
+
@inspect = Hashie::Mash.new(data)
|
94
|
+
rescue JSON::ParserError => _e
|
95
|
+
Hashie::Mash.new({})
|
96
|
+
end
|
97
|
+
|
98
|
+
def to_s
|
99
|
+
"Podman"
|
100
|
+
end
|
101
|
+
|
102
|
+
private
|
103
|
+
|
104
|
+
# Calls the run_command method to get all podman containers and parse the command output.
|
105
|
+
# Returns the parsed command output.
|
106
|
+
def parse_containers
|
107
|
+
labels = %w{ID Image ImageID Command CreatedAt RunningFor Status Pod Ports Size Names Networks Labels Mounts}
|
108
|
+
parse_json_command(labels, "ps -a --no-trunc --size")
|
109
|
+
end
|
110
|
+
|
111
|
+
# Calls the run_command method to get all podman images and parse the command output.
|
112
|
+
# Returns the parsed command output.
|
113
|
+
def parse_images
|
114
|
+
labels = %w{ID Repository Tag Size Digest CreatedAt CreatedSince History}
|
115
|
+
parse_json_command(labels, "images -a --no-trunc")
|
116
|
+
end
|
117
|
+
|
118
|
+
# Calls the run_command method to get all podman network list and parse the command output.
|
119
|
+
# Returns the parsed command output.
|
120
|
+
def parse_networks
|
121
|
+
labels = %w{ID Name Driver Labels Options IPAMOptions Created Internal IPv6Enabled DNSEnabled NetworkInterface Subnets}
|
122
|
+
parse_json_command(labels, "network ls --no-trunc")
|
123
|
+
end
|
124
|
+
|
125
|
+
# Calls the run_command method to get all podman pod list and parse the command output.
|
126
|
+
# Returns the parsed command output.
|
127
|
+
def parse_pods
|
128
|
+
sub_cmd = "pod ps --no-trunc --format json"
|
129
|
+
output = run_command(sub_cmd)
|
130
|
+
parse(output)
|
131
|
+
end
|
132
|
+
|
133
|
+
# Calls the run_command method to get all podman volume list and parse the command output.
|
134
|
+
# Returns the parsed command output.
|
135
|
+
def parse_volumes
|
136
|
+
sub_cmd = "volume ls --format json"
|
137
|
+
output = run_command(sub_cmd)
|
138
|
+
parse(output)
|
139
|
+
end
|
140
|
+
|
141
|
+
# Runs the given podman command on the host machine on which podman is installed
|
142
|
+
# Returns the command output or raises the command execution error.
|
143
|
+
def run_command(subcommand)
|
144
|
+
result = inspec.command("podman #{subcommand}")
|
145
|
+
if result.stderr.empty?
|
146
|
+
result.stdout
|
147
|
+
else
|
148
|
+
raise "Error while running command \'podman #{subcommand}\' : #{result.stderr}"
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def parse_json_command(labels, subcommand)
|
153
|
+
# build command
|
154
|
+
format = labels.map { |label| "\"#{label}\": {{json .#{label}}}" }
|
155
|
+
raw = inspec.command("podman #{subcommand} --format '{#{format.join(", ")}}'").stdout
|
156
|
+
output = []
|
157
|
+
|
158
|
+
raw.each_line do |entry|
|
159
|
+
# convert all keys to lower_case to work well with ruby and filter table
|
160
|
+
row = JSON.parse(entry).map do |key, value|
|
161
|
+
[key.downcase, value]
|
162
|
+
end.to_h
|
163
|
+
|
164
|
+
# ensure all keys are there
|
165
|
+
row = ensure_keys(row, labels)
|
166
|
+
output.push(row)
|
167
|
+
end
|
168
|
+
|
169
|
+
output
|
170
|
+
rescue JSON::ParserError => _e
|
171
|
+
warn "Could not parse `podman #{subcommand}` output"
|
172
|
+
[]
|
173
|
+
end
|
174
|
+
|
175
|
+
def ensure_keys(entry, labels)
|
176
|
+
labels.each do |key|
|
177
|
+
entry[key.downcase] = nil unless entry.key?(key.downcase)
|
178
|
+
end
|
179
|
+
entry
|
180
|
+
end
|
181
|
+
|
182
|
+
# Method to parse JDON content.
|
183
|
+
# Returns: Parsed data.
|
184
|
+
def parse(content)
|
185
|
+
require "json" unless defined?(JSON)
|
186
|
+
output = JSON.parse(content)
|
187
|
+
parsed_output = []
|
188
|
+
output.each do |entry|
|
189
|
+
entry = entry.map do |k, v|
|
190
|
+
[k.downcase, v]
|
191
|
+
end.to_h
|
192
|
+
parsed_output << entry
|
193
|
+
end
|
194
|
+
parsed_output
|
195
|
+
rescue => e
|
196
|
+
raise Inspec::Exceptions::ResourceFailed, "Unable to parse command JSON output: #{e.message}"
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
# class for podman.containers plural resource
|
201
|
+
class PodmanContainerFilter
|
202
|
+
filter = FilterTable.create
|
203
|
+
filter.register_custom_matcher(:exists?) { |x| !x.entries.empty? }
|
204
|
+
filter.register_column(:commands, field: "command")
|
205
|
+
.register_column(:ids, field: "id")
|
206
|
+
.register_column(:created_at, field: "createdat")
|
207
|
+
.register_column(:images, field: "image")
|
208
|
+
.register_column(:names, field: "names")
|
209
|
+
.register_column(:status, field: "status")
|
210
|
+
.register_column(:image_ids, field: "image_id")
|
211
|
+
.register_column(:labels, field: "labels", style: :simple)
|
212
|
+
.register_column(:mounts, field: "mounts")
|
213
|
+
.register_column(:networks, field: "networks")
|
214
|
+
.register_column(:pods, field: "pod")
|
215
|
+
.register_column(:ports, field: "ports")
|
216
|
+
.register_column(:sizes, field: "size")
|
217
|
+
.register_column(:running_for, field: "running_for")
|
218
|
+
.register_custom_matcher(:running?) do |x|
|
219
|
+
x.where { status.downcase.start_with?("up") }
|
220
|
+
end
|
221
|
+
filter.install_filter_methods_on_resource(self, :containers)
|
222
|
+
|
223
|
+
attr_reader :containers
|
224
|
+
def initialize(containers)
|
225
|
+
@containers = containers
|
226
|
+
end
|
227
|
+
|
228
|
+
def to_s
|
229
|
+
"Podman Containers"
|
230
|
+
end
|
231
|
+
|
232
|
+
def resource_id
|
233
|
+
"Podman Containers"
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
# class for podman.images plural resource
|
238
|
+
class PodmanImageFilter
|
239
|
+
filter = FilterTable.create
|
240
|
+
filter.register_custom_matcher(:exists?) { |x| !x.entries.empty? }
|
241
|
+
filter.register_column(:ids, field: "id")
|
242
|
+
.register_column(:repositories, field: "repository")
|
243
|
+
.register_column(:tags, field: "tag")
|
244
|
+
.register_column(:sizes, field: "size")
|
245
|
+
.register_column(:digests, field: "digest")
|
246
|
+
.register_column(:created_at, field: "createdat")
|
247
|
+
.register_column(:created_since, field: "createdsince")
|
248
|
+
.register_column(:history, field: "history")
|
249
|
+
filter.install_filter_methods_on_resource(self, :images)
|
250
|
+
|
251
|
+
attr_reader :images
|
252
|
+
def initialize(images)
|
253
|
+
@images = images
|
254
|
+
end
|
255
|
+
|
256
|
+
def to_s
|
257
|
+
"Podman Images"
|
258
|
+
end
|
259
|
+
|
260
|
+
def resource_id
|
261
|
+
"Podman Images"
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
class PodmanNetworkFilter
|
266
|
+
filter = FilterTable.create
|
267
|
+
filter.register_custom_matcher(:exists?) { |x| !x.entries.empty? }
|
268
|
+
.register_column(:ids, field: "id")
|
269
|
+
.register_column(:names, field: "name")
|
270
|
+
.register_column(:drivers, field: "driver")
|
271
|
+
.register_column(:network_interfaces, field: "networkinterface")
|
272
|
+
.register_column(:created, field: "created")
|
273
|
+
.register_column(:subnets, field: "subnets")
|
274
|
+
.register_column(:ipv6_enabled, field: "ipv6enabled")
|
275
|
+
.register_column(:internal, field: "internal")
|
276
|
+
.register_column(:dns_enabled, field: "dnsenabled")
|
277
|
+
.register_column(:ipam_options, field: "ipamoptions")
|
278
|
+
.register_column(:options, field: "options")
|
279
|
+
.register_column(:labels, field: "labels")
|
280
|
+
filter.install_filter_methods_on_resource(self, :networks)
|
281
|
+
|
282
|
+
attr_reader :networks
|
283
|
+
def initialize(networks)
|
284
|
+
@networks = networks
|
285
|
+
end
|
286
|
+
|
287
|
+
def to_s
|
288
|
+
"Podman Networks"
|
289
|
+
end
|
290
|
+
|
291
|
+
def resource_id
|
292
|
+
"Podman Networks"
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
class PodmanPodFilter
|
297
|
+
filter = FilterTable.create
|
298
|
+
filter.register_custom_matcher(:exists?) { |x| !x.entries.empty? }
|
299
|
+
.register_column(:ids, field: "id")
|
300
|
+
.register_column(:cgroups, field: "cgroup")
|
301
|
+
.register_column(:containers, field: "containers")
|
302
|
+
.register_column(:created, field: "created")
|
303
|
+
.register_column(:infraids, field: "infraid")
|
304
|
+
.register_column(:names, field: "name")
|
305
|
+
.register_column(:namespaces, field: "namespace")
|
306
|
+
.register_column(:networks, field: "networks")
|
307
|
+
.register_column(:status, field: "status")
|
308
|
+
.register_column(:labels, field: "labels")
|
309
|
+
filter.install_filter_methods_on_resource(self, :pods)
|
310
|
+
|
311
|
+
attr_reader :pods
|
312
|
+
def initialize(pods)
|
313
|
+
@pods = pods
|
314
|
+
end
|
315
|
+
|
316
|
+
def to_s
|
317
|
+
"Podman Pods"
|
318
|
+
end
|
319
|
+
|
320
|
+
def resource_id
|
321
|
+
"Podman Pods"
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
class PodmanVolumeFilter
|
326
|
+
filter = FilterTable.create
|
327
|
+
filter.register_custom_matcher(:exists?) { |x| !x.entries.empty? }
|
328
|
+
.register_column(:names, field: "name")
|
329
|
+
.register_column(:drivers, field: "driver")
|
330
|
+
.register_column(:mountpoints, field: "mountpoint")
|
331
|
+
.register_column(:createdat, field: "createdat")
|
332
|
+
.register_column(:labels, field: "labels")
|
333
|
+
.register_column(:scopes, field: "scope")
|
334
|
+
.register_column(:options, field: "options")
|
335
|
+
.register_column(:mountcount, field: "mountcount")
|
336
|
+
.register_column(:needscopyup, field: "needscopyup")
|
337
|
+
.register_column(:needschown, field: "needschown")
|
338
|
+
filter.install_filter_methods_on_resource(self, :volumes)
|
339
|
+
|
340
|
+
attr_reader :volumes
|
341
|
+
def initialize(volumes)
|
342
|
+
@volumes = volumes
|
343
|
+
end
|
344
|
+
|
345
|
+
def to_s
|
346
|
+
"Podman Volumes"
|
347
|
+
end
|
348
|
+
|
349
|
+
def resource_id
|
350
|
+
"Podman Volumes"
|
351
|
+
end
|
352
|
+
end
|
353
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require "inspec/resources/podman"
|
2
|
+
require_relative "docker_object"
|
3
|
+
|
4
|
+
# Change module if required
|
5
|
+
module Inspec::Resources
|
6
|
+
class PodmanContainer < Inspec.resource(1)
|
7
|
+
include Inspec::Resources::DockerObject
|
8
|
+
name "podman_container"
|
9
|
+
supports platform: "unix"
|
10
|
+
|
11
|
+
desc "Inspec core resource to retrieve information about podman container"
|
12
|
+
|
13
|
+
example <<~EXAMPLE
|
14
|
+
describe podman_container("sweet_mendeleev") do
|
15
|
+
it { should exist }
|
16
|
+
it { should be_running }
|
17
|
+
its("id") { should eq "591270d8d80d26671fd6ed622f367fbe19004d16e3b519c292313feb5f22e7f7" }
|
18
|
+
its("image") { should eq "docker.io/library/nginx:latest" }
|
19
|
+
its("labels") { should include "maintainer"=>"NGINX Docker Maintainers <docker-maint@nginx.com>" }
|
20
|
+
its("ports") { should eq nil }
|
21
|
+
end
|
22
|
+
|
23
|
+
describe podman_container(id: "591270d8d80d2667") do
|
24
|
+
it { should exist }
|
25
|
+
it { should be_running }
|
26
|
+
end
|
27
|
+
EXAMPLE
|
28
|
+
|
29
|
+
def initialize(opts = {})
|
30
|
+
skip_resource "The `podman_container` resource is not yet available on your OS." unless inspec.os.unix?
|
31
|
+
|
32
|
+
# if a string is provided, we expect it is the name
|
33
|
+
if opts.is_a?(String)
|
34
|
+
@opts = { name: opts }
|
35
|
+
else
|
36
|
+
@opts = opts
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def running?
|
41
|
+
status.downcase.start_with?("up") if object_info.entries.length == 1
|
42
|
+
end
|
43
|
+
|
44
|
+
def status
|
45
|
+
object_info.status[0] if object_info.entries.length == 1
|
46
|
+
end
|
47
|
+
|
48
|
+
def labels
|
49
|
+
object_info.labels
|
50
|
+
end
|
51
|
+
|
52
|
+
def ports
|
53
|
+
object_info.ports[0] if object_info.entries.length == 1
|
54
|
+
end
|
55
|
+
|
56
|
+
def command
|
57
|
+
return unless object_info.entries.length == 1
|
58
|
+
|
59
|
+
object_info.commands[0]
|
60
|
+
end
|
61
|
+
|
62
|
+
def image
|
63
|
+
object_info.images[0] if object_info.entries.length == 1
|
64
|
+
end
|
65
|
+
|
66
|
+
def resource_id
|
67
|
+
object_info.ids[0] || @opts[:id] || @opts[:name] || ""
|
68
|
+
end
|
69
|
+
|
70
|
+
def to_s
|
71
|
+
name = @opts[:name] || @opts[:id]
|
72
|
+
"Podman Container #{name}"
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def object_info
|
78
|
+
return @info if defined?(@info)
|
79
|
+
|
80
|
+
opts = @opts
|
81
|
+
@info = inspec.podman.containers.where { names == opts[:name] || (!id.nil? && !opts[:id].nil? && (id == opts[:id] || id.start_with?(opts[:id]))) }
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require "inspec/resources/command"
|
2
|
+
require_relative "docker_object"
|
3
|
+
require "inspec/utils/podman"
|
4
|
+
|
5
|
+
module Inspec::Resources
|
6
|
+
class PodmanImage < Inspec.resource(1)
|
7
|
+
include Inspec::Resources::DockerObject
|
8
|
+
include Inspec::Utils::Podman
|
9
|
+
|
10
|
+
name "podman_image"
|
11
|
+
supports platform: "unix"
|
12
|
+
|
13
|
+
desc "InSpec core resource to retrieve information about podman image"
|
14
|
+
|
15
|
+
example <<~EXAMPLE
|
16
|
+
describe podman_image("docker.io/library/busybox") do
|
17
|
+
it { should exist }
|
18
|
+
its("repo_tags") { should include "docker.io/library/busybox:latest" }
|
19
|
+
its("size") { should eq 1636053 }
|
20
|
+
its("resource_id") { should eq "docker.io/library/busybox:latest" }
|
21
|
+
end
|
22
|
+
|
23
|
+
describe podman_image("docker.io/library/busybox:latest") do
|
24
|
+
it { should exist }
|
25
|
+
end
|
26
|
+
|
27
|
+
describe podman_image(repo: "docker.io/library/busybox", tag: "latest") do
|
28
|
+
it { should exist }
|
29
|
+
end
|
30
|
+
|
31
|
+
describe podman_image(id: "3c19bafed223") do
|
32
|
+
it { should exist }
|
33
|
+
end
|
34
|
+
EXAMPLE
|
35
|
+
|
36
|
+
attr_reader :opts, :image_info
|
37
|
+
|
38
|
+
def initialize(opts)
|
39
|
+
skip_resource "The `podman_image` resource is not yet available on your OS." unless inspec.os.unix?
|
40
|
+
opts = { image: opts } if opts.is_a?(String)
|
41
|
+
@opts = sanitize_options(opts)
|
42
|
+
raise Inspec::Exceptions::ResourceFailed, "Podman is not running. Please make sure it is installed and running." unless podman_running?
|
43
|
+
|
44
|
+
@image_info = get_image_info
|
45
|
+
end
|
46
|
+
|
47
|
+
LABELS = {
|
48
|
+
"id" => "ID",
|
49
|
+
"repo_tags" => "RepoTags",
|
50
|
+
"size" => "Size",
|
51
|
+
"digest" => "Digest",
|
52
|
+
"created_at" => "Created",
|
53
|
+
"version" => "Version",
|
54
|
+
"names_history" => "NamesHistory",
|
55
|
+
"repo_digests" => "RepoDigests",
|
56
|
+
"architecture" => "Architecture",
|
57
|
+
"os" => "Os",
|
58
|
+
"virtual_size" => "VirtualSize",
|
59
|
+
}.freeze
|
60
|
+
|
61
|
+
## This creates all the required properties methods dynamically.
|
62
|
+
LABELS.each do |k, v|
|
63
|
+
define_method(k) do
|
64
|
+
image_info[k.to_s]
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def exist?
|
69
|
+
! image_info.empty?
|
70
|
+
end
|
71
|
+
|
72
|
+
def resource_id
|
73
|
+
opts[:id] || opts[:image] || ""
|
74
|
+
end
|
75
|
+
|
76
|
+
def to_s
|
77
|
+
"podman_image #{resource_id}"
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
def sanitize_options(opts)
|
83
|
+
opts.merge!(parse_components_from_image(opts[:image]))
|
84
|
+
|
85
|
+
# assume a "latest" tag if we don't have one
|
86
|
+
opts[:tag] ||= "latest"
|
87
|
+
|
88
|
+
# Assemble/reassemble the image from the repo and tag
|
89
|
+
opts[:image] = "#{opts[:repo]}:#{opts[:tag]}" unless opts[:repo].nil?
|
90
|
+
|
91
|
+
opts
|
92
|
+
end
|
93
|
+
|
94
|
+
def get_image_info
|
95
|
+
current_image = opts[:id] || opts[:image] || opts[:repo] + ":" + opts[:tag]
|
96
|
+
json_key_label = generate_go_template(LABELS)
|
97
|
+
podman_inspect_cmd = inspec.command("podman image inspect #{current_image} --format '{#{json_key_label}}'")
|
98
|
+
|
99
|
+
if podman_inspect_cmd.exit_status == 0
|
100
|
+
parse_command_output(podman_inspect_cmd.stdout)
|
101
|
+
elsif podman_inspect_cmd.stderr =~ /failed to find image/
|
102
|
+
{}
|
103
|
+
else
|
104
|
+
raise Inspec::Exceptions::ResourceFailed, "Unable to retrieve podman image information for #{current_image}.\nError message: #{podman_inspect_cmd.stderr}"
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require "inspec/resources/command"
|
2
|
+
require "inspec/utils/podman"
|
3
|
+
module Inspec::Resources
|
4
|
+
class PodmanNetwork < Inspec.resource(1)
|
5
|
+
include Inspec::Utils::Podman
|
6
|
+
|
7
|
+
name "podman_network"
|
8
|
+
|
9
|
+
supports platform: "unix"
|
10
|
+
|
11
|
+
desc "InSpec core resource to retrive information about the given Podman network"
|
12
|
+
|
13
|
+
example <<~EXAMPLE
|
14
|
+
describe podman_network("podman") do
|
15
|
+
it { should exist }
|
16
|
+
end
|
17
|
+
describe podman_network("3a7c94d937d5f3a0f1a9b1610589945aedfbe56207fd5d32fc8154aa1a8b007f") do
|
18
|
+
its("driver") { should eq bridge }
|
19
|
+
end
|
20
|
+
EXAMPLE
|
21
|
+
|
22
|
+
LABELS = {
|
23
|
+
id: "ID",
|
24
|
+
name: "Name",
|
25
|
+
driver: "Driver",
|
26
|
+
labels: "Labels",
|
27
|
+
options: "Options",
|
28
|
+
ipam_options: "IPAMOptions",
|
29
|
+
internal: "Internal",
|
30
|
+
created: "Created",
|
31
|
+
ipv6_enabled: "IPv6Enabled",
|
32
|
+
dns_enabled: "DNSEnabled",
|
33
|
+
network_interface: "NetworkInterface",
|
34
|
+
subnets: "Subnets",
|
35
|
+
}.freeze
|
36
|
+
|
37
|
+
attr_reader :param, :network_info
|
38
|
+
def initialize(param)
|
39
|
+
skip_resource "The `podman_network` resource is not yet available on your OS." unless inspec.os.unix?
|
40
|
+
|
41
|
+
@param = param
|
42
|
+
raise Inspec::Exceptions::ResourceFailed, "Podman is not running. Please make sure it is installed and running." unless podman_running?
|
43
|
+
|
44
|
+
@network_info = get_network_info
|
45
|
+
end
|
46
|
+
|
47
|
+
## This creates all the required properties methods dynamically.
|
48
|
+
LABELS.each do |k, v|
|
49
|
+
define_method(k) do
|
50
|
+
network_info[k.to_s]
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def exist?
|
55
|
+
!network_info.empty?
|
56
|
+
end
|
57
|
+
|
58
|
+
def resource_id
|
59
|
+
id || param || ""
|
60
|
+
end
|
61
|
+
|
62
|
+
def to_s
|
63
|
+
"podman_network #{resource_id}"
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def get_network_info
|
69
|
+
go_template_format = generate_go_template(LABELS)
|
70
|
+
result = inspec.command("podman network inspect #{param} --format '{#{go_template_format}}'")
|
71
|
+
|
72
|
+
if result.exit_status == 0
|
73
|
+
parse_command_output(result.stdout)
|
74
|
+
elsif result.stderr =~ /network not found/
|
75
|
+
{}
|
76
|
+
else
|
77
|
+
raise Inspec::Exceptions::ResourceFailed, "Unable to retrieve podman network information for #{param}.\nError message: #{result.stderr}"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|