inspec-core 4.56.17 → 5.7.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/etc/deprecations.json +12 -11
  3. data/inspec-core.gemspec +1 -1
  4. data/lib/inspec/base_cli.rb +14 -2
  5. data/lib/inspec/cli.rb +15 -0
  6. data/lib/inspec/dependency_installer.rb +74 -0
  7. data/lib/inspec/dependency_loader.rb +97 -0
  8. data/lib/inspec/dsl.rb +11 -2
  9. data/lib/inspec/errors.rb +7 -0
  10. data/lib/inspec/formatters/base.rb +23 -0
  11. data/lib/inspec/metadata.rb +36 -0
  12. data/lib/inspec/plugin/v2/plugin_types/streaming_reporter.rb +44 -1
  13. data/lib/inspec/profile.rb +63 -0
  14. data/lib/inspec/reporters/automate.rb +1 -1
  15. data/lib/inspec/reporters/cli.rb +1 -1
  16. data/lib/inspec/reporters/json.rb +31 -11
  17. data/lib/inspec/resource.rb +6 -0
  18. data/lib/inspec/resources/cron.rb +49 -0
  19. data/lib/inspec/resources/ipfilter.rb +59 -0
  20. data/lib/inspec/resources/ipnat.rb +58 -0
  21. data/lib/inspec/resources.rb +3 -16
  22. data/lib/inspec/runner.rb +18 -1
  23. data/lib/inspec/runner_rspec.rb +15 -0
  24. data/lib/inspec/schema/exec_json.rb +59 -58
  25. data/lib/inspec/schema/exec_json_min.rb +16 -16
  26. data/lib/inspec/schema/primitives.rb +68 -51
  27. data/lib/inspec/schema/profile_json.rb +27 -27
  28. data/lib/inspec/schema.rb +1 -0
  29. data/lib/inspec/ui.rb +1 -0
  30. data/lib/inspec/utils/deprecated_cloud_resources_list.rb +54 -0
  31. data/lib/inspec/version.rb +1 -1
  32. data/lib/inspec.rb +3 -0
  33. data/lib/plugins/inspec-init/lib/inspec-init/cli.rb +1 -0
  34. data/lib/plugins/inspec-init/lib/inspec-init/cli_plugin.rb +9 -0
  35. data/lib/plugins/inspec-init/lib/inspec-init/cli_resource.rb +126 -0
  36. data/lib/plugins/inspec-init/lib/inspec-init/renderer.rb +9 -8
  37. data/lib/plugins/inspec-init/templates/plugins/inspec-plugin-template/lib/inspec-plugin-template/plugin.erb +16 -0
  38. data/lib/plugins/inspec-init/templates/plugins/inspec-plugin-template/lib/inspec-plugin-template/streaming_reporter.erb +31 -0
  39. data/lib/plugins/inspec-init/templates/profiles/aws/inspec.yml +1 -1
  40. data/lib/plugins/inspec-init/templates/resources/basic/docs/resource-doc.erb +77 -0
  41. data/lib/plugins/inspec-init/templates/resources/basic/libraries/inspec-resource-template.erb +94 -0
  42. data/lib/plugins/inspec-init/templates/resources/plural/docs/resource-doc.erb +62 -0
  43. data/lib/plugins/inspec-init/templates/resources/plural/libraries/inspec-resource-template.erb +73 -0
  44. data/lib/plugins/inspec-reporter-html2/templates/body.html.erb +2 -0
  45. data/lib/plugins/inspec-reporter-html2/templates/control.html.erb +3 -0
  46. data/lib/plugins/inspec-reporter-html2/templates/profile.html.erb +1 -0
  47. data/lib/plugins/inspec-reporter-html2/templates/result.html.erb +1 -0
  48. data/lib/plugins/inspec-streaming-reporter-progress-bar/README.md +5 -0
  49. data/lib/plugins/inspec-streaming-reporter-progress-bar/lib/inspec-streaming-reporter-progress-bar/plugin.rb +13 -0
  50. data/lib/plugins/inspec-streaming-reporter-progress-bar/lib/inspec-streaming-reporter-progress-bar/streaming_reporter.rb +112 -0
  51. data/lib/plugins/inspec-streaming-reporter-progress-bar/lib/inspec-streaming-reporter-progress-bar/version.rb +8 -0
  52. data/lib/plugins/inspec-streaming-reporter-progress-bar/lib/inspec-streaming-reporter-progress-bar.rb +15 -0
  53. metadata +20 -3
@@ -35,7 +35,7 @@ module Inspec
35
35
  # Use this class to quickly add/use object types to/in a definition block
36
36
  class SchemaType
37
37
  attr_accessor :name, :depends
38
- def initialize(name, body, dependencies)
38
+ def initialize(name, body, dependencies, description = nil)
39
39
  # Validate the schema
40
40
  Primitives.validate_schema(body)
41
41
  # The title of the type
@@ -44,14 +44,17 @@ module Inspec
44
44
  @body = body
45
45
  # What SchemaType[]s it depends on. In essence, any thing that you .ref in the body
46
46
  @depends = Set.new(dependencies)
47
+ # The description of the type
48
+ @description = description
47
49
  end
48
50
 
49
51
  # Produce this schema types generated body.
50
52
  # Use to actually define the ref!
51
53
  def body
52
54
  @body.merge({
55
+ "description" => @description,
53
56
  "title" => @name,
54
- })
57
+ }).compact
55
58
  end
56
59
 
57
60
  # Formats this to have a JSON pointer compatible title
@@ -89,22 +92,32 @@ module Inspec
89
92
  URL = { "type" => "string" }.freeze
90
93
 
91
94
  # A controls tags can have any number of properties, and any sorts of values
92
- TAGS = { "type" => "object", "additionalProperties" => true }.freeze
95
+ TAGS = {
96
+ "type" => "object",
97
+ "additionalProperties" => true,
98
+ "description" => "A set of any number of tags - they can have any sort of value and are usually metadata. Example: 'nist' => ['AC-10'].",
99
+ }.freeze
93
100
 
94
101
  # Attributes/Inputs specify the inputs to a profile.
95
- INPUT = { "type" => "object", "additionalProperties" => true }.freeze
102
+ INPUT = {
103
+ "type" => "object",
104
+ "additionalProperties" => true,
105
+ "description" => "An input or attribute used in the run.",
106
+ }.freeze
96
107
 
97
- # Within a control file, impacts can be numeric 0-1 or string in [none,low,medium,high,critical]
98
- # However, when they are output, the string types are automatically converted as follows:
99
- # none -> 0 to 0.01
100
- # low -> 0.01 to 0.4
101
- # medium -> 0.4 to 0.7
102
- # high -> 0.7 to 0.9
103
- # Critical -> 0.9 to 1.0 (inclusive)
104
108
  IMPACT = {
105
109
  "type" => "number",
106
110
  "minimum" => 0.0,
107
111
  "maximum" => 1.0,
112
+ "description" => %q{
113
+ Within a control file, impacts can be a decimal number in the range [0,1] or a string that is one of [none,low,medium,high,critical].
114
+ However, the string will be automatically converted as follows:
115
+ none -> 0 to 0.01
116
+ low -> 0.01 to 0.4
117
+ medium -> 0.4 to 0.7
118
+ high -> 0.7 to 0.9
119
+ critical -> 0.9 to 1.0
120
+ },
108
121
  }.freeze
109
122
 
110
123
  # A status for a control
@@ -123,9 +136,9 @@ module Inspec
123
136
  "additionalProperties" => true,
124
137
  "required" => ["total"],
125
138
  "properties" => {
126
- "total" => desc(NUMBER, "Total number of controls (in this category) for this inspec execution."),
139
+ "total" => desc(NUMBER, "The total. Example: the total number of controls in a given category for a run."),
127
140
  },
128
- }, [])
141
+ }, [], "Statistics for a given item, such as the total.")
129
142
 
130
143
  # Bundles several results statistics, representing distinct groups of controls
131
144
  STATISTIC_GROUPING = SchemaType.new("Statistic Hash", {
@@ -133,11 +146,11 @@ module Inspec
133
146
  "additionalProperties" => true,
134
147
  "required" => [],
135
148
  "properties" => {
136
- "passed" => STATISTIC_ITEM.ref,
137
- "skipped" => STATISTIC_ITEM.ref,
138
- "failed" => STATISTIC_ITEM.ref,
149
+ "passed" => desc(STATISTIC_ITEM.ref, "Statistics for the controls that passed."),
150
+ "skipped" => desc(STATISTIC_ITEM.ref, "Statistics for the controls that were skipped."),
151
+ "failed" => desc(STATISTIC_ITEM.ref, "Statistics for the controls that failed."),
139
152
  },
140
- }, [STATISTIC_ITEM])
153
+ }, [STATISTIC_ITEM], "Statistics for the control results.")
141
154
 
142
155
  # Contains statistics of an exec run.
143
156
  STATISTICS = SchemaType.new("Statistics", {
@@ -145,10 +158,10 @@ module Inspec
145
158
  "additionalProperties" => true,
146
159
  "required" => ["duration"],
147
160
  "properties" => {
148
- "duration" => desc(NUMBER, "How long (in seconds) this inspec exec ran for."),
161
+ "duration" => desc(NUMBER, "How long (in seconds) this run by the tool was."),
149
162
  "controls" => desc(STATISTIC_GROUPING.ref, "Breakdowns of control statistics by result"),
150
163
  },
151
- }, [STATISTIC_GROUPING])
164
+ }, [STATISTIC_GROUPING], "Statistics for the run(s) such as how long it took.")
152
165
 
153
166
  # Profile dependencies
154
167
  DEPENDENCY = SchemaType.new("Dependency", {
@@ -156,17 +169,17 @@ module Inspec
156
169
  "additionalProperties" => true, # Weird stuff shows up here sometimes
157
170
  "required" => [], # Mysteriously even in a run profile we can have no status
158
171
  "properties" => {
159
- "name" => STRING,
160
- "url" => URL,
161
- "branch" => STRING,
162
- "path" => STRING,
163
- "status_message" => STRING,
164
- "status" => STRING,
165
- "git" => URL,
166
- "supermarket" => STRING,
167
- "compliance" => STRING,
172
+ "name" => desc(STRING, "The name/assigned alias."),
173
+ "url" => desc(URL, "The address of the dependency."),
174
+ "branch" => desc(STRING, "The branch name for a git repo."),
175
+ "path" => desc(STRING, "The relative path if the dependency is locally available."),
176
+ "status_message" => desc(STRING, "The reason for the status if it is 'failed' or 'skipped'."),
177
+ "status" => desc(STRING, "The status. Should be: 'loaded', 'failed', or 'skipped'."), # NOTE: enum?
178
+ "git" => desc(URL, "The location of the git repo. Example: 'https://github.com/mitre/canonical-ubuntu-18.04-lts-stig-baseline.git'."),
179
+ "supermarket" => desc(STRING, "The 'user/profilename' attribute for a Supermarket server."),
180
+ "compliance" => desc(STRING, "The 'user/profilename' attribute for an Automate server."),
168
181
  },
169
- }, [])
182
+ }, [], "A dependency for a profile. Can include relative paths or urls for where to find the dependency.")
170
183
 
171
184
  # Represents the platform the test was run on
172
185
  PLATFORM = SchemaType.new("Platform", {
@@ -176,9 +189,9 @@ module Inspec
176
189
  "properties" => {
177
190
  "name" => desc(STRING, "The name of the platform this was run on."),
178
191
  "release" => desc(STRING, "The version of the platform this was run on."),
179
- "target_id" => STRING,
192
+ "target_id" => desc(STRING, "The id of the target. Example: the name and version of the operating system were not sufficient to identify the platform so a release identifier can additionally be provided like '21H2' for the release version of MS Windows 10."),
180
193
  },
181
- }, [])
194
+ }, [], "Platform information such as its name.")
182
195
 
183
196
  # Explains what software ran the inspec profile/made this file. Typically inspec but could in theory be a different software
184
197
  GENERATOR = SchemaType.new("Generator", {
@@ -186,10 +199,10 @@ module Inspec
186
199
  "additionalProperties" => true,
187
200
  "required" => %w{name version},
188
201
  "properties" => {
189
- "name" => desc(STRING, "The name of the software that generated this report."),
190
- "version" => desc(STRING, "The version of the software that generated this report."),
202
+ "name" => desc(STRING, "The name. Example: Chef Inspec."),
203
+ "version" => desc(STRING, "The version. Example: 4.18.108."),
191
204
  },
192
- }, [])
205
+ }, [], "The tool that generated this file. Example: Chef Inspec.")
193
206
 
194
207
  # Occurs from "exec --reporter json" and "inspec json"
195
208
  # Denotes what file this control comes from, and where within
@@ -197,11 +210,11 @@ module Inspec
197
210
  "type" => "object",
198
211
  "additionalProperties" => true,
199
212
  "properties" => {
200
- "ref" => desc(STRING, "Path to the file that this statement originates from"),
201
- "line" => desc(NUMBER, "The line at which this statement is located in the file"),
213
+ "ref" => desc(STRING, "Path to the file that this control originates from."),
214
+ "line" => desc(NUMBER, "The line on which this control is located."),
202
215
  },
203
216
  "required" => %w{ref line},
204
- }, [])
217
+ }, [], "The explicit location of the control.")
205
218
 
206
219
  # References an external document
207
220
  REFERENCE = SchemaType.new("Reference", {
@@ -211,26 +224,30 @@ module Inspec
211
224
  "type" => "object",
212
225
  "required" => ["ref"],
213
226
  "properties" => { "ref" => STRING },
227
+ "description" => "A human readable/meaningful reference. Example: a book title.",
214
228
  },
215
229
  {
216
230
  "type" => "object",
217
231
  "required" => ["url"],
218
- "properties" => { "url" => STRING },
232
+ "properties" => { "url" => STRING }, # NOTE: should this be a URL?
233
+ "description" => "A url pointing at the reference.",
219
234
  },
220
235
  {
221
236
  "type" => "object",
222
237
  "required" => ["uri"],
223
- "properties" => { "uri" => STRING },
238
+ "properties" => { "uri" => STRING }, # NOTE: should this be a URL?
239
+ "description" => "A uri pointing at the reference.",
224
240
  },
225
241
  # I am of the opinion that this is just an error in the codebase itself. See profiles/wrapper-override to uncover new mysteries!
226
242
  {
227
243
  "type" => "object",
228
244
  "required" => ["ref"],
229
245
  "properties" => { "ref" => array(OBJECT) },
246
+ "description" => "", # TODO: I'm not sure what goes here. Maybe it's supposed to be objects similar to { "title" => "blah", "text" => "blah" }?
230
247
 
231
248
  },
232
249
  ],
233
- }, [])
250
+ }, [], "A reference to an external document.")
234
251
 
235
252
  # Represents a group of controls within a profile/.rb file
236
253
  CONTROL_GROUP = SchemaType.new("Control Group", {
@@ -238,11 +255,11 @@ module Inspec
238
255
  "additionalProperties" => true,
239
256
  "required" => %w{id controls},
240
257
  "properties" => {
241
- "id" => desc(STRING, "The unique identifier of the group"),
242
- "title" => desc({ type: %w{string null} }, "The name of the group"),
243
- "controls" => desc(array(STRING), "The control IDs in this group"),
258
+ "id" => desc(STRING, "The unique identifier for the group. Example: the relative path to the file specifying the controls."),
259
+ "title" => desc({ type: %w{string null} }, "The title of the group - should be human readable."), # NOTE: pretty unique type like this - wouldn't it be better to have it be a STRING and then continue to not make it required?
260
+ "controls" => desc(array(STRING), "The set of controls as specified by their ids in this group. Example: 'V-75443'."),
244
261
  },
245
- }, [])
262
+ }, [], "Descriptions for controls in a group, such as the list of all the controls.")
246
263
 
247
264
  # Occurs from "inspec exec --reporter json" and "inspec json"
248
265
  # Represents a platfrom or group of platforms that this profile supports
@@ -251,15 +268,15 @@ module Inspec
251
268
  "additionalProperties" => true, # NOTE: This should really be false, and inspec should validate profiles to ensure people don't make dumb mistakes like platform_family
252
269
  "required" => [],
253
270
  "properties" => {
254
- "platform-family" => STRING,
255
- "platform-name" => STRING,
256
- "platform" => STRING,
257
- "release" => STRING,
271
+ "platform-family" => desc(STRING, "The platform family. Example: 'redhat'."),
272
+ "platform-name" => desc(STRING, "The platform name - can include wildcards. Example: 'debian'."),
273
+ "platform" => desc(STRING, "The location of the platform. Can be: 'os', 'aws', 'azure', or 'gcp'."), # NOTE: enum?
274
+ "release" => desc(STRING, "The release of the platform. Example: '20.04' for 'ubuntu'."),
258
275
  # os-* supports are being deprecated
259
- "os-family" => STRING,
260
- "os-name" => STRING,
276
+ "os-family" => desc(STRING, "Deprecated in favor of platform-family."),
277
+ "os-name" => desc(STRING, "Deprecated in favor of platform-name."),
261
278
  },
262
- }, [])
279
+ }, [], "A supported platform target. Example: the platform name being 'ubuntu'.")
263
280
 
264
281
  end
265
282
  end
@@ -8,9 +8,9 @@ module Inspec
8
8
  # Represents descriptions. Can have any string => string pairing
9
9
  CONTROL_DESCRIPTIONS = Primitives::SchemaType.new("Profile JSON Control Descriptions", {
10
10
  "type" => "object",
11
- "aditionalProperties" => Primitives::STRING,
11
+ "additionalProperties" => Primitives::STRING,
12
12
  "required" => [],
13
- }, [])
13
+ }, [], "An arbitrary set of descriptions for a control.")
14
14
 
15
15
  # Represents a control that hasn't been run
16
16
  # Differs slightly from a normal control, in that it lacks results, and its descriptions are different
@@ -19,17 +19,17 @@ module Inspec
19
19
  "additionalProperties" => true,
20
20
  "required" => %w{id title desc impact tags code},
21
21
  "properties" => {
22
- "id" => Primitives.desc(Primitives::STRING, "The ID of this control"),
23
- "title" => { "type" => %w{string null} },
24
- "desc" => { "type" => %w{string null} },
25
- "descriptions" => CONTROL_DESCRIPTIONS.ref,
26
- "impact" => Primitives::IMPACT,
27
- "refs" => Primitives.array(Primitives::REFERENCE.ref),
28
- "tags" => Primitives::TAGS,
29
- "code" => Primitives.desc(Primitives::STRING, "The raw source code of the control. Note that if this is an overlay control, it does not include the underlying source code"),
30
- "source_location" => Primitives::SOURCE_LOCATION.ref,
22
+ "id" => Primitives.desc(Primitives::STRING, "The id."),
23
+ "title" => Primitives.desc({ "type" => %w{string null} }, "The title - is nullable."),
24
+ "desc" => Primitives.desc({ "type" => %w{string null} }, "The description for the overarching control."),
25
+ "descriptions" => Primitives.desc(CONTROL_DESCRIPTIONS.ref, "A set of additional descriptions. Example: the 'fix' text."),
26
+ "impact" => Primitives.desc(Primitives::IMPACT, "The impactfulness or severity."),
27
+ "refs" => Primitives.desc(Primitives.array(Primitives::REFERENCE.ref), "The set of references to external documents."),
28
+ "tags" => Primitives.desc(Primitives::TAGS, "A set of tags - usually metadata."),
29
+ "code" => Primitives.desc(Primitives::STRING, "The raw source code of the control. Note that if this is an overlay control, it does not include the underlying source code."),
30
+ "source_location" => Primitives.desc(Primitives::SOURCE_LOCATION.ref, "The explicit location of the control within the source code."),
31
31
  },
32
- }, [CONTROL_DESCRIPTIONS, Primitives::REFERENCE, Primitives::SOURCE_LOCATION])
32
+ }, [CONTROL_DESCRIPTIONS, Primitives::REFERENCE, Primitives::SOURCE_LOCATION], "The set of all tests within the control.")
33
33
 
34
34
  # A profile that has not been run.
35
35
  PROFILE = Primitives::SchemaType.new("Profile JSON Profile", {
@@ -37,24 +37,24 @@ module Inspec
37
37
  "additionalProperties" => true, # Anything in the yaml will be put in here. LTTODO: Make this stricter!
38
38
  "required" => %w{name supports controls groups sha256},
39
39
  "properties" => {
40
- "name" => Primitives::STRING,
41
- "supports" => Primitives.array(Primitives::SUPPORT.ref),
42
- "controls" => Primitives.array(CONTROL.ref),
43
- "groups" => Primitives.array(Primitives::CONTROL_GROUP.ref),
44
- "inputs" => Primitives.array(Primitives::INPUT),
45
- "sha256" => Primitives::STRING,
46
- "status" => Primitives::STRING,
47
- "generator" => Primitives::GENERATOR.ref,
48
- "version" => Primitives::STRING,
40
+ "name" => Primitives.desc(Primitives::STRING, "The name - must be unique."),
41
+ "supports" => Primitives.desc(Primitives.array(Primitives::SUPPORT.ref), "The set of supported platform targets."),
42
+ "controls" => Primitives.desc(Primitives.array(CONTROL.ref), "The set of controls - contains no findings as the assessment has not yet occurred."),
43
+ "groups" => Primitives.desc(Primitives.array(Primitives::CONTROL_GROUP.ref), "A set of descriptions for the control groups. Example: the ids of the controls."),
44
+ "inputs" => Primitives.desc(Primitives.array(Primitives::INPUT), "The input(s) or attribute(s) used to be in the run."),
45
+ "sha256" => Primitives.desc(Primitives::STRING, "The checksum of the profile."),
46
+ "status" => Primitives.desc(Primitives::STRING, "The status. Example: skipped."),
47
+ "generator" => Primitives.desc(Primitives::GENERATOR.ref, "The tool that generated this file. Example: Chef Inspec."),
48
+ "version" => Primitives.desc(Primitives::STRING, "The version of the profile."),
49
49
 
50
50
  # Other properties possible in inspec docs, but that aren"t guaranteed
51
- "title" => Primitives::STRING,
52
- "maintainer" => Primitives::STRING,
53
- "copyright" => Primitives::STRING,
54
- "copyright_email" => Primitives::STRING,
55
- "depends" => Primitives.array(Primitives::DEPENDENCY.ref), # Can have depends, but NOT a parentprofile
51
+ "title" => Primitives.desc(Primitives::STRING, "The title - should be human readable."),
52
+ "maintainer" => Primitives.desc(Primitives::STRING, "The maintainer(s)."),
53
+ "copyright" => Primitives.desc(Primitives::STRING, "The copyright holder(s)."),
54
+ "copyright_email" => Primitives.desc(Primitives::STRING, "The email address or other contract information of the copyright holder(s)."),
55
+ "depends" => Primitives.desc(Primitives.array(Primitives::DEPENDENCY.ref), "The set of dependencies this profile depends on. Example: an overlay profile is dependent on another profile."), # Can have depends, but NOT a parentprofile
56
56
  },
57
- }, [Primitives::SUPPORT, CONTROL, Primitives::CONTROL_GROUP, Primitives::DEPENDENCY, Primitives::GENERATOR])
57
+ }, [Primitives::SUPPORT, CONTROL, Primitives::CONTROL_GROUP, Primitives::DEPENDENCY, Primitives::GENERATOR], "Information on the set of controls that can be assessed. Example: it can include the name of the Inspec profile.")
58
58
  end
59
59
  end
60
60
  end
data/lib/inspec/schema.rb CHANGED
@@ -57,6 +57,7 @@ module Inspec
57
57
  "run_time" => { "type" => "number" },
58
58
  "start_time" => { "type" => "string" },
59
59
  "resource_class" => { "type" => "string", "optional" => true },
60
+ "resource_id" => { "type" => "string", "optional" => true },
60
61
  "skip_message" => { "type" => "string", "optional" => true },
61
62
  "resource" => { "type" => "string", "optional" => true },
62
63
  "message" => { "type" => "string", "optional" => true },
data/lib/inspec/ui.rb CHANGED
@@ -30,6 +30,7 @@ module Inspec
30
30
  EXIT_USAGE_ERROR = 1
31
31
  EXIT_PLUGIN_ERROR = 2
32
32
  EXIT_FATAL_DEPRECATION = 3
33
+ EXIT_GEM_DEPENDENCY_LOAD_ERROR = 4
33
34
  EXIT_LICENSE_NOT_ACCEPTED = 172
34
35
  EXIT_FAILED_TESTS = 100
35
36
  EXIT_SKIPPED_TESTS = 101
@@ -0,0 +1,54 @@
1
+ module DeprecatedCloudResourcesList
2
+ CLOUD_RESOURCES_DEPRECATED = %i{
3
+ aws_billing_report
4
+ aws_billing_reports
5
+ aws_cloudtrail_trail
6
+ aws_cloudtrail_trails
7
+ aws_cloudwatch_alarm
8
+ aws_cloudwatch_log_metric_filter
9
+ aws_config_delivery_channel
10
+ aws_config_recorder
11
+ aws_ec2_instance
12
+ aws_ebs_volume
13
+ aws_ebs_volumes
14
+ aws_flow_log
15
+ aws_ec2_instances
16
+ aws_ecs_cluster
17
+ aws_eks_cluster
18
+ aws_elb
19
+ aws_elbs
20
+ aws_iam_access_key
21
+ aws_iam_access_keys
22
+ aws_iam_group
23
+ aws_iam_groups
24
+ aws_iam_password_policy
25
+ aws_iam_policies
26
+ aws_iam_policy
27
+ aws_iam_role
28
+ aws_iam_root_user
29
+ aws_iam_user
30
+ aws_iam_users
31
+ aws_kms_key
32
+ aws_kms_keys
33
+ aws_rds_instance
34
+ aws_route_table
35
+ aws_route_tables
36
+ aws_s3_bucket
37
+ aws_s3_bucket_object
38
+ aws_s3_buckets
39
+ aws_security_group
40
+ aws_security_groups
41
+ aws_sns_subscription
42
+ aws_sns_topic
43
+ aws_sns_topics
44
+ aws_sqs_queue
45
+ aws_subnet
46
+ aws_subnets
47
+ aws_vpc
48
+ aws_vpcs
49
+ azure_generic_resource
50
+ azure_resource_group
51
+ azure_virtual_machine
52
+ azure_virtual_machine_data_disk
53
+ }.freeze
54
+ end
@@ -1,3 +1,3 @@
1
1
  module Inspec
2
- VERSION = "4.56.17".freeze
2
+ VERSION = "5.7.9".freeze
3
3
  end
data/lib/inspec.rb CHANGED
@@ -28,3 +28,6 @@ require "inspec/base_cli"
28
28
  require "inspec/fetcher"
29
29
  require "inspec/source_reader"
30
30
  require "inspec/resource"
31
+
32
+ require "inspec/dependency_loader"
33
+ require "inspec/dependency_installer"
@@ -10,6 +10,7 @@ module InspecPlugins
10
10
 
11
11
  require_relative "cli_profile"
12
12
  require_relative "cli_plugin"
13
+ require_relative "cli_resource"
13
14
  end
14
15
  end
15
16
  end
@@ -81,6 +81,7 @@ module InspecPlugins
81
81
  File.join("lib", "inspec-plugin-template.erb") => File.join("lib", plugin_name + ".rb"),
82
82
  File.join("lib", "inspec-plugin-template", "cli_command.erb") => File.join("lib", plugin_name, "cli_command.rb"),
83
83
  File.join("lib", "inspec-plugin-template", "reporter.erb") => File.join("lib", plugin_name, "reporter.rb"),
84
+ File.join("lib", "inspec-plugin-template", "streaming_reporter.erb") => File.join("lib", plugin_name, "streaming_reporter.rb"),
84
85
  File.join("lib", "inspec-plugin-template", "plugin.erb") => File.join("lib", plugin_name, "plugin.rb"),
85
86
  File.join("lib", "inspec-plugin-template", "version.erb") => File.join("lib", plugin_name, "version.rb"),
86
87
  File.join("test", "functional", "inspec_plugin_template_test.erb") => File.join("test", "functional", snake_case + "_test.rb"),
@@ -183,6 +184,9 @@ module InspecPlugins
183
184
  elsif activators_by_type.key?(:reporter)
184
185
  vars[:reporter_name_dashes] = activators_by_type[:reporter].tr("_", "-")
185
186
  vars[:reporter_name_snake] = activators_by_type[:reporter].tr("-", "_")
187
+ elsif activators_by_type.key?(:streaming_reporter)
188
+ vars[:streaming_reporter_name_dashes] = activators_by_type[:streaming_reporter].tr("_", "-")
189
+ vars[:streaming_reporter_name_snake] = activators_by_type[:streaming_reporter].tr("-", "_")
186
190
  end
187
191
  vars
188
192
  end
@@ -267,6 +271,11 @@ module InspecPlugins
267
271
  File.join("lib", "inspec-plugin-template", "reporter.erb"),
268
272
  ]
269
273
  end
274
+ unless requested_activators.include?(:streaming_reporter)
275
+ skips += [
276
+ File.join("lib", "inspec-plugin-template", "streaming_reporter.erb"),
277
+ ]
278
+ end
270
279
 
271
280
  skips.uniq
272
281
  end
@@ -0,0 +1,126 @@
1
+ require_relative "renderer"
2
+
3
+ module InspecPlugins
4
+ module Init
5
+ class CLI < Inspec.plugin(2, :cli_command)
6
+ #-------------------------------------------------------------------#
7
+ # inspec init resource
8
+ #-------------------------------------------------------------------#
9
+ desc "resource RESOURCE_NAME [options]", "Generates an InSpec resource, which can extend the scope of InSpec resources support"
10
+ # General options
11
+ option :prompt, type: :boolean, default: true, desc: "Interactively prompt for information to put in your generated resource."
12
+ option :overwrite, type: :boolean, default: false, desc: "Overwrite existing files"
13
+ option :layout, type: :string, default: "resource-pack", desc: "File layout, either 'resource-pack' or 'core'"
14
+ option :template, type: :string, default: "basic", desc: "Which type of resource template to use"
15
+
16
+ # Templating vars
17
+ option :supports_platform, type: :string, default: "linux", desc: "the platform supported by this resource"
18
+ option :description, type: :string, default: "Resource description ...", desc: "the description of this resource"
19
+ option :class_name, type: :string, default: "MyCustomResource", desc: "Class Name for your resource."
20
+ option :path, type: :string, default: ".", desc: "Subdirectory under which to create files"
21
+
22
+ # Wishlist:
23
+ # Make make_rename_map_resource dynamic:
24
+ # + Add a --path option which defaults to ., which will create the tree under that path
25
+ # + Add a --layout option which changes all the tree to act as placing the files in core inspec (lib/inspec/resources, docs-chef-io/)
26
+ # - Add a --template=plural option which changes the templates to use a set of Filtertable based templates
27
+ # - Add a --template=inherit option which provides a template for inheriting from the core resources
28
+ # - Add a template=aws
29
+ # + Generate properties and matchers:
30
+ # + generate a has_bells? matcher => it { should have_bells }
31
+ # + generate a is_purple? matcher => it { should be_purple }
32
+ # + generate a shoe_size => its('shoe_size') { should cmp 10 }
33
+ # + Generate unit tests for above properties and matchers
34
+ # + Generate docs for properties and matchers
35
+ # + Add --overwrite option
36
+
37
+ def resource(resource_name)
38
+ resource_vars_from_opts_resource
39
+ template_vars = {
40
+ name: options[:path], # This is used for the path prefix
41
+ resource_name: resource_name,
42
+ }
43
+ template_vars.merge!(options)
44
+ template_path = File.join("resources", template_vars["template"])
45
+
46
+ render_opts = {
47
+ templates_path: TEMPLATES_PATH,
48
+ overwrite: options[:overwrite],
49
+ file_rename_map: make_rename_map_resource(template_vars),
50
+ }
51
+ renderer = InspecPlugins::Init::Renderer.new(ui, render_opts)
52
+ renderer.render_with_values(template_path, "resource", template_vars)
53
+ end
54
+
55
+ private
56
+
57
+ def make_rename_map_resource(vars)
58
+ if vars["layout"] == "resource-pack"
59
+ {
60
+ File.join("libraries", "inspec-resource-template.erb") => File.join("libraries", vars[:resource_name] + ".rb"),
61
+ File.join("docs", "resource-doc.erb") => File.join("docs", vars[:resource_name] + ".md"),
62
+ File.join("test", "unit", "inspec-resource-test-template.erb") => File.join("test", "unit", vars[:resource_name] + "_test.rb"),
63
+ }
64
+ elsif vars["layout"] == "core"
65
+ {
66
+ File.join("libraries", "inspec-resource-template.erb") => File.join("lib", "inspec", "resources", vars[:resource_name] + ".rb"),
67
+ File.join("docs", "resource-doc.erb") => File.join("docs-chef-io", "content", "inspec", "resources", vars[:resource_name] + ".md"),
68
+ File.join("test", "unit", "inspec-resource-test-template.erb") => File.join("test", "unit", "resources", vars[:resource_name] + "_test.rb"),
69
+ }
70
+ else
71
+ ui.error("Unrecognized value for 'layout' - please enter either 'resource-pack' or 'core'")
72
+ ui.exit(:usage_error)
73
+ end
74
+ end
75
+
76
+ def resource_vars_from_opts_resource
77
+ if options[:prompt] && ui.interactive?
78
+ options.dup.merge(prompt_for_options_resource)
79
+ elsif !options[:prompt]
80
+ # Nothing to do - unless we need to calculate dynamic defaults in the future
81
+ else
82
+ ui.error("You requested interactive prompting for the template variables, but this does not seem to be an interactive terminal.")
83
+ ui.exit(:usage_error)
84
+ end
85
+ end
86
+
87
+ def prompt_for_options_resource # rubocop: disable Metrics/AbcSize
88
+ option_defs = self.class.all_commands["resource"].options
89
+ options_order = {
90
+ path: {},
91
+ layout: {
92
+ mode: :select,
93
+ choices: [
94
+ { name: "Resource Pack", value: "resource-pack", default: true },
95
+ { name: "InSpec Core", value: "core" },
96
+ ],
97
+ },
98
+ template: {
99
+ mode: :select,
100
+ choices: [
101
+ { name: "Basic", value: "basic", default: true },
102
+ { name: "Plural", value: "plural" },
103
+ ],
104
+ },
105
+ supports_platform: {},
106
+ description: {},
107
+ class_name: {},
108
+ }
109
+
110
+ options_order.each do |opt_name, prompt_options|
111
+ opt_def = option_defs[opt_name]
112
+
113
+ case prompt_options[:mode]
114
+ when :select
115
+ options[opt_name] = ui.prompt.select("Choose " + opt_def.description + ":", prompt_options[:choices])
116
+ when :multiline
117
+ options[opt_name] = ui.prompt.multiline("Enter " + opt_def.description + ". Press Control-D to end.", default: options[opt_name])
118
+ else
119
+ # Assume plain ask
120
+ options[opt_name] = ui.prompt.ask("Enter " + opt_def.description + ":", default: options[opt_name])
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
@@ -38,8 +38,8 @@ module InspecPlugins
38
38
  full_destination_path = Pathname.new(Dir.pwd).join(relative_destination_path)
39
39
 
40
40
  # check that the directory does not exist
41
- if File.exist?(full_destination_path) && !overwrite_mode
42
- ui.plain_line "#{ui.emphasis(full_destination_path)} exists already, use --overwrite"
41
+ if File.exist?(full_destination_path) && !overwrite_mode && template_values[:name] != "."
42
+ ui.plain_line "#{ui.emphasis(full_destination_path)} exists already, use --overwrite or move to #{ui.emphasis(full_destination_path)} to create the resource"
43
43
  ui.exit(:usage_error)
44
44
  end
45
45
 
@@ -57,18 +57,19 @@ module InspecPlugins
57
57
 
58
58
  relative_destination_item_path = file_rename_map[relative_destination_item_path] || relative_destination_item_path
59
59
  full_destination_item_path = Pathname.new(full_destination_path).join(relative_destination_item_path)
60
- if File.directory?(source_file)
61
- ui.list_item "Creating directory #{ui.emphasis(relative_destination_item_path)}"
62
- FileUtils.mkdir_p(full_destination_item_path)
63
- elsif File.file?(source_file)
60
+ if File.file?(source_file)
61
+ # Be git-like and only create directories if they contain a file
62
+ containing_directory = full_destination_item_path.dirname
63
+ unless File.exist?(containing_directory)
64
+ ui.list_item "Creating directory #{ui.emphasis(containing_directory)}"
65
+ FileUtils.mkdir_p(containing_directory)
66
+ end
64
67
  ui.list_item "Creating file #{ui.emphasis(relative_destination_item_path)}"
65
68
  # read & render content
66
69
  content = render(File.read(source_file), template_values)
67
70
  # write file content
68
71
 
69
72
  File.write(full_destination_item_path, content)
70
- else
71
- ui.warning "Ignoring #{ui.emphasis(source_file)}, because its not an file or directoy"
72
73
  end
73
74
  end
74
75
 
@@ -66,6 +66,22 @@ module InspecPlugins
66
66
  InspecPlugins::<%= module_name %>::Reporter
67
67
  end
68
68
  <% end %>
69
+
70
+ <% if activators[:streaming_reporter] %>
71
+ # Define a new Streaming Reporter.
72
+ # The argument here will be used to match against the CLI --reporter option.
73
+ # `--reporter <%= streaming_reporter_name_snake %>` will load your streaming reporter and perform streaming real-time on each passing, failing or pending test.
74
+ streaming_reporter :<%= streaming_reporter_name_snake %> do
75
+ # Calling this activator doesn't mean the reporter is being executed - just
76
+ # that we should be ready to do so. So, load the file that defines the
77
+ # functionality.
78
+ require "<%= plugin_name %>/streaming_reporter"
79
+
80
+ # Having loaded our functionality, return a class that will let the
81
+ # reporting engine tap into it.
82
+ InspecPlugins::<%= module_name %>::StreamingReporter
83
+ end
84
+ <% end %>
69
85
  end
70
86
  end
71
87
  end