mirror of
https://github.com/inspec/inspec
synced 2024-11-10 15:14:23 +00:00
Merge pull request #4401 from inspec/cw/input-from-cli
inputs: Accept bare input from the command line
This commit is contained in:
commit
a6bd7ec4b5
7 changed files with 132 additions and 12 deletions
|
@ -44,13 +44,9 @@ When the above profile is executed by using `inspec exec rock_critic`, you would
|
|||
Test Summary: 0 successful, 1 failure, 0 skipped
|
||||
```
|
||||
|
||||
That result clearly won't do. Let's override the input's default value. Create a file, `custom_amps.yml`:
|
||||
That result clearly won't do. Let's override the input's default value.
|
||||
|
||||
```yaml
|
||||
amplifier_max_volume: 11
|
||||
```
|
||||
|
||||
We can now run that profile with `inspec exec rock_critic --input-file custom_amps.yaml`:
|
||||
We can now run that profile with `inspec exec rock_critic --input amplifier_max_volume=11`:
|
||||
|
||||
```
|
||||
11
|
||||
|
@ -67,11 +63,12 @@ That said, any profile that uses the DSL keyword `input()` (or the deprecated `a
|
|||
|
||||
### How can I set Inputs?
|
||||
|
||||
As installed (without specialized plugins), Chef InSpec supports five ways of setting inputs:
|
||||
As installed (without specialized plugins), Chef InSpec supports several ways of setting inputs:
|
||||
|
||||
* Inline in control code, using `input('input_name', value: 42)`.
|
||||
* In profile `inspec.yml` metadata files
|
||||
* Using the CLI option `--input-file somefile.yaml`
|
||||
* Using the CLI option `--input name1=value1 name2=value2...` to read directly from the command line
|
||||
* Using the CLI option `--input-file somefile.yaml` to read inputs from files
|
||||
* In kitchen-inspec, using the `verifier/inputs` settings
|
||||
* In the Audit Cookbook, using the `node[:audit][:inputs]`
|
||||
|
||||
|
@ -83,7 +80,7 @@ In addition, Chef InSpec supports Input Plugins, which can provide optional inte
|
|||
|
||||
Briefly:
|
||||
|
||||
inline DSL < metadata < ( cli-input-file or kitchen-inspec or audit-cookbook )
|
||||
inline DSL < metadata < ( cli-input-file or kitchen-inspec or audit-cookbook ) < cli --input
|
||||
|
||||
In addition, for inherited profiles:
|
||||
|
||||
|
@ -122,7 +119,7 @@ As packaged, Chef InSpec uses the following priority values:
|
|||
| CLI `--input-file` option | 40 | No |
|
||||
| inspec-kitchen `inputs:` section | 40 | No |
|
||||
| audit cookbook `node[:audit][:inputs]` | 40 | No |
|
||||
|
||||
| CLI `--input` option | 50 | No |
|
||||
|
||||
### What happened to "Attributes"?
|
||||
|
||||
|
@ -246,13 +243,35 @@ an_input: a_value
|
|||
another_input: another_value
|
||||
```
|
||||
|
||||
CLI-set inputs have a priority of 40.
|
||||
CLI-input-file-set inputs have a priority of 40.
|
||||
|
||||
As of Chef InSpec 4.3.2, this mechanism has the following limitations:
|
||||
|
||||
1. No [input options](#input-options-reference) may be set - only the name and value.
|
||||
2. Because the CLI is outside the scope of any individual profile and the inputs don't take options, the inputs are clumsily copied into every profile, effectively making the CLI mechanism global.
|
||||
|
||||
## Setting Input values using `--input`
|
||||
|
||||
You may also provide inputs and values directly on the command line:
|
||||
|
||||
```yaml
|
||||
inspec exec my_profile --input input_name=input_value
|
||||
```
|
||||
|
||||
To set multiple inputs, say:
|
||||
```yaml
|
||||
inspec exec my_profile --input input_name1=input_value1 name2=value2
|
||||
```
|
||||
|
||||
Do not repeat the `--input` flag; that will override the previous setting.
|
||||
|
||||
CLI-set inputs have a priority of 50.
|
||||
|
||||
As of Chef InSpec 4.12, this mechanism has the following limitations:
|
||||
|
||||
1. No [input options](#input-options-reference) may be set - only the name and value.
|
||||
2. Because the CLI is outside the scope of any individual profile and the inputs don't take options, the inputs are clumsily copied into every profile, effectively making the CLI mechanism global.
|
||||
|
||||
## Input Options Reference
|
||||
|
||||
### Name
|
||||
|
|
|
@ -133,6 +133,8 @@ module Inspec
|
|||
option :reporter, type: :array,
|
||||
banner: "one two:/output/file/path",
|
||||
desc: "Enable one or more output reporters: cli, documentation, html, progress, json, json-min, json-rspec, junit, yaml"
|
||||
option :input, type: :array, banner: "name1=value1 name2=value2",
|
||||
desc: "Specify one or more inputs directly on the command line, as --input NAME=VALUE"
|
||||
option :input_file, type: :array,
|
||||
desc: "Load one or more input files, a YAML file with values for the profile to use"
|
||||
option :attrs, type: :array,
|
||||
|
|
|
@ -135,10 +135,37 @@ module Inspec
|
|||
bind_inputs_from_metadata(profile_name, sources[:profile_metadata])
|
||||
bind_inputs_from_input_files(profile_name, sources[:cli_input_files])
|
||||
bind_inputs_from_runner_api(profile_name, sources[:runner_api])
|
||||
bind_inputs_from_cli_args(profile_name, sources[:cli_input_arg])
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def bind_inputs_from_cli_args(profile_name, input_list)
|
||||
# TODO: move this into a core plugin
|
||||
|
||||
return if input_list.nil?
|
||||
return if input_list.empty?
|
||||
|
||||
# These arrive as an array of "name=value" strings
|
||||
# If the user used a comma, we'll see unfortunately see it as "name=value," pairs
|
||||
input_list.each do |pair|
|
||||
unless pair.include?("=")
|
||||
if pair.end_with?(".yaml")
|
||||
raise ArgumentError, "ERROR: --input is used for individual input values, as --input name=value. Use --input-file to load a YAML file."
|
||||
else
|
||||
raise ArgumentError, "ERROR: An '=' is required when using --input. Usage: --input input_name1=input_value1 input2=value2"
|
||||
end
|
||||
end
|
||||
input_name, input_value = pair.split("=")
|
||||
evt = Inspec::Input::Event.new(
|
||||
value: input_value.chomp(","), # Trim trailing comma if any
|
||||
provider: :cli,
|
||||
priority: 50
|
||||
)
|
||||
find_or_register_input(input_name, profile_name, event: evt)
|
||||
end
|
||||
end
|
||||
|
||||
def bind_inputs_from_runner_api(profile_name, input_hash)
|
||||
# TODO: move this into a core plugin
|
||||
|
||||
|
|
|
@ -137,7 +137,8 @@ module Inspec
|
|||
# Remaining args are possible sources of inputs
|
||||
cli_input_files: options[:runner_conf][:input_file], # From CLI --input-file
|
||||
profile_metadata: metadata,
|
||||
runner_api: options[:runner_conf][:inputs] # This is the route the audit_cookbook and kitchen-inspec take
|
||||
runner_api: options[:runner_conf][:inputs], # This is the route the audit_cookbook and kitchen-inspec take
|
||||
cli_input_arg: options[:runner_conf][:input] # The --input name=value CLI option
|
||||
)
|
||||
|
||||
@runner_context =
|
||||
|
|
|
@ -43,6 +43,11 @@ describe "inputs" do
|
|||
line = lines.detect { |l| l.include? "--attrs" }
|
||||
line.wont_be_nil
|
||||
end
|
||||
|
||||
it "includes the --input option" do
|
||||
result = run_inspec_process("exec help", lock: true) # --no-create-lockfile option breaks usage help
|
||||
assert_match(/--input\s/, result.stdout) # Careful not to match --input-file
|
||||
end
|
||||
end
|
||||
|
||||
describe "when using a cli-specified file" do
|
||||
|
@ -142,6 +147,56 @@ describe "inputs" do
|
|||
end
|
||||
end
|
||||
|
||||
describe "when using the --input inline raw input flag CLI option" do
|
||||
let(:result) { run_inspec_process("exec #{inputs_profiles_path}/cli #{input_opt} #{control_opt}", json: true) }
|
||||
let(:control_opt) { "" }
|
||||
|
||||
describe "when the --input is used once with one value" do
|
||||
let(:input_opt) { "--input test_input_01=value_from_cli_01" }
|
||||
let(:control_opt) { "--controls test_control_01" }
|
||||
it("correctly reads the input") { result.must_have_all_controls_passing }
|
||||
end
|
||||
|
||||
describe "when the --input is used once with two values" do
|
||||
let(:input_opt) { "--input test_input_01=value_from_cli_01 test_input_02=value_from_cli_02" }
|
||||
it("correctly reads the input") { result.must_have_all_controls_passing }
|
||||
end
|
||||
|
||||
describe "when the --input is used once with two values and a comma" do
|
||||
let(:input_opt) { "--input test_input_01=value_from_cli_01, test_input_02=value_from_cli_02" }
|
||||
it("correctly reads the input") { result.must_have_all_controls_passing }
|
||||
end
|
||||
|
||||
describe "when the --input is used twice with one value each" do
|
||||
let(:input_opt) { "--input test_input_01=value_from_cli_01 --input test_input_02=value_from_cli_02" }
|
||||
let(:control_opt) { "--controls test_control_02" }
|
||||
# Expected, though unfortunate, behavior is to only notice the second input
|
||||
it("correctly reads the input") { result.must_have_all_controls_passing }
|
||||
end
|
||||
|
||||
describe "when the --input is used with no equal sign" do
|
||||
let(:input_opt) { "--input value_from_cli_01" }
|
||||
it "does not run and provides an error message" do
|
||||
output = result.stdout
|
||||
assert_includes "ERROR", output
|
||||
assert_includes "An '=' is required", output
|
||||
assert_includes "input_name_1=input_value_1", output
|
||||
assert_equal 1, result.exit_status
|
||||
end
|
||||
end
|
||||
|
||||
describe "when the --input is used with a .yaml extension" do
|
||||
let(:input_opt) { "--input myfile.yaml" }
|
||||
it "does not run and provides an error message" do
|
||||
output = result.stdout
|
||||
assert_includes "ERROR", output
|
||||
assert_includes "individual input values", output
|
||||
assert_includes "Use --input-file", output
|
||||
assert_equal 1, result.exit_status
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "when accessing inputs in a variety of scopes using the DSL" do
|
||||
it "is able to read the inputs using the input keyword" do
|
||||
cmd = "exec #{inputs_profiles_path}/scoping"
|
||||
|
|
10
test/unit/mock/profiles/inputs/cli/controls/cli.rb
Normal file
10
test/unit/mock/profiles/inputs/cli/controls/cli.rb
Normal file
|
@ -0,0 +1,10 @@
|
|||
control "test_control_01" do
|
||||
describe input("test_input_01", value: "value_from_dsl") do
|
||||
it { should cmp "value_from_cli_01"}
|
||||
end
|
||||
end
|
||||
control "test_control_02" do
|
||||
describe input("test_input_02", value: "value_from_dsl") do
|
||||
it { should cmp "value_from_cli_02"}
|
||||
end
|
||||
end
|
6
test/unit/mock/profiles/inputs/cli/inspec.yml
Normal file
6
test/unit/mock/profiles/inputs/cli/inspec.yml
Normal file
|
@ -0,0 +1,6 @@
|
|||
name: cli
|
||||
license: Apache-2.0
|
||||
summary: Profile to exercise setting inputs using the --input CLI option
|
||||
version: 0.1.0
|
||||
supports:
|
||||
platform: os
|
Loading…
Reference in a new issue