command resource: Allow redacting #to_s (#3207)

* command resource: Allow redacting `#to_s`
* Respond to feedback

Signed-off-by: Jerry Aldrich <jerryaldrichiii@gmail.com>
This commit is contained in:
Jerry Aldrich 2018-07-16 05:20:57 -07:00 committed by Jared Quick
parent 409a71b28e
commit 706493f2f3
3 changed files with 66 additions and 5 deletions

View file

@ -124,6 +124,34 @@ Wix includes several tools -- such as `candle` (preprocesses and compiles source
end
end
### Redacting Sensitive Commands
By default the command that is ran is shown in the InSpec output. This can be problematic if the command contains sensitive arguments such as a password. These sensitive parts can be redacted by passing in `redact_regex` and a regular expression to redact. Optionally, you can use 2 capture groups to fine tune what is redacted.
The following examples show how to use `redact_regex`:
# Example without capture groups
describe command('myapp -p secretpassword -d no_redact', redact_regex: /-p .* -d/) do
its('exit_status') { should cmp 0 }
end
# Result (no capture groups used)
Command: `myapp REDACTED no_redact`
✔ exit_status should cmp == 0
# Example with capture groups
# Each set of parenthesis is a capture group.
# Anything in the two capture groups will not be 'REDACTED'
describe command('myapp -p secretpassword -d no_redact', redact_regex: /(-p ).*( -d)/) do
its('exit_status') { should cmp 0 }
end
# Result (capture groups used)
Command: `myapp -p REDACTED -d no_redact`
✔ exit_status should cmp == 0
> For more info/help on regular expressions, we recommend [RegExr](https://regexr.com/)
<br>
## Matchers

View file

@ -22,11 +22,22 @@ module Inspec::Resources
attr_reader :command
def initialize(cmd)
def initialize(cmd, options = {})
if cmd.nil?
raise 'InSpec `command` was called with `nil` as the argument. This is not supported. Please provide a valid command instead.'
end
@command = cmd
if options[:redact_regex]
unless options[:redact_regex].is_a?(Regexp)
# Make sure command is replaced so sensitive output isn't shown
@command = 'ERROR'
raise Inspec::Exceptions::ResourceFailed,
'The `redact_regex` option must be a regular expression'
end
@redact_regex = options[:redact_regex]
end
end
def result
@ -67,7 +78,11 @@ module Inspec::Resources
end
def to_s
"Command #{@command}"
output = "Command: `#{@command}`"
# Redact output if the `redact_regex` option is passed
# If no capture groups are passed then `\1` and `\2` are ignored
output.gsub!(@redact_regex, '\1REDACTED\2') unless @redact_regex.nil?
output
end
end
end

View file

@ -7,12 +7,12 @@ require 'inspec/resource'
describe Inspec::Resources::Cmd do
let(:x) { rand.to_s }
def resource(y)
load_resource('command', y)
def resource(command, options = {} )
load_resource('command', command, options)
end
it 'prints as a bash command' do
resource(x).to_s.must_equal 'Command '+x
resource(x).to_s.must_equal "Command: `#{x}`"
end
it 'runs a valid mocked command' do
@ -35,4 +35,22 @@ describe Inspec::Resources::Cmd do
it 'raises when called with nil as a command' do
proc { resource(nil).result }.must_raise StandardError
end
it 'fails the resource if `redact_regex` is not a regular expression' do
result = resource('env', redact_regex: 'string')
result.resource_failed?.must_equal true
result.resource_exception_message.must_match /must be a regular expression/
end
it 'redacts output if `redact_regex` is passed with caputure groups' do
cmd = 'command_with_password -p supersecret -d no_redact'
expected_to_s = 'Command: `command_with_password -p REDACTED -d no_redact`'
resource(cmd, redact_regex: /(-p ).*( -d)/).to_s.must_equal(expected_to_s)
end
it 'redacts output if `redact_regex` is passed without a caputure group' do
cmd = 'command_with_password -p supersecret -d no_redact'
expected_to_s = 'Command: `command_with_password REDACTED no_redact`'
resource(cmd, redact_regex: /-p .* -d/).to_s.must_equal(expected_to_s)
end
end