Skip to main content

command resource

Use the command Chef InSpec audit resource to test an arbitrary command that is run on the system.

Availability

Install

This resource is distributed with Chef InSpec and is automatically available for use.

Version

This resource first became available in v1.0.0 of InSpec.

Syntax

A command resource block declares a command to be run, one (or more) expected values, and the location to which that output is sent:

describe command('command') do
  it { should exist }
  its('property') { should eq 'value' }
end

where

  • 'command' must specify a command to be run
  • 'property' is one of exit_status, stderr, or stdout
  • 'output' tests the output of the command run on the system versus the output value stated in the test

Property Examples

The following examples show how to use this Chef InSpec audit resource.

exit_status

The exit_status property tests the exit status for the command:

its('exit_status') { should eq 123 }

stderr

The stderr property tests results of the command as returned in standard error (stderr):

its('stderr') { should eq 'error' }

stdout

The stdout property tests results of the command as returned in standard output (stdout). The following example shows matching output using a regular expression:

describe command('echo 1') do
   its('stdout') { should match (/[0-9]/) }
end

Test standard output (stdout)

describe command('echo hello') do
  its('stdout') { should eq "hello\n" }
  its('stderr') { should eq '' }
  its('exit_status') { should eq 0 }
end

Test standard error (stderr)

describe command('>&2 echo error') do
  its('stdout') { should eq '' }
  its('stderr') { should eq "error\n" }
  its('exit_status') { should eq 0 }
end

Test an exit status code

describe command('exit 123') do
  its('stdout') { should eq '' }
  its('stderr') { should eq '' }
  its('exit_status') { should eq 123 }
end

Test if the command shell exists

describe command('/bin/sh').exist? do
  it { should eq true }
end

Test for a command that should not exist

describe command('this is not existing').exist? do
  it { should eq false }
end

Test for PostgreSQL database running a RC, development, or beta release

describe command('psql -V') do
  its('stdout') { should eq '/RC/' }
  its('stdout') { should_not eq '/DEVEL/' }
  its('stdout') { should_not eq '/BETA/' }
end

Verify NTP

The following example shows how to use the file audit resource to verify if the ntp.conf and leap-seconds files are present, and then the command resource to verify if NTP is installed and running:

describe file('/etc/ntp.conf') do
   it { should be_file }
end

describe file('/etc/ntp.leapseconds') do
  it { should be_file }
end

describe command('pgrep ntp') do
   its('exit_status') { should eq 0 }
end

Verify WiX

Wix includes several tools – such as candle (preprocesses and compiles source files into object files), light (links and binds object files to an installer database), and heat (harvests files from various input formats). The following example uses a whitespace array and the file audit resource to verify if these three tools are present:

%w(
  candle.exe
  heat.exe
  light.exe
).each do |utility|
  describe file("C:/wix/##{utility}") do
    it { should be_file }
  end
end

Timing Out Long-Running Commands

On target platforms that support the feature, the command resource takes an optional timeout: parameter which specifies how long the command may run in seconds before erroring out and failing the control.

describe command("find / -owner badguy", timeout: 300) do
  its("stdout") { should be_empty }
end

This example would run the find command for up to 300 seconds, then give up and fail the control if it exceeded that time.

Aside from setting the value on a per-resource basis, you may also use the --command-timeout CLI option to globally set a command timeout. The CLI option takes precedence over any per-resource timeout: options.

Currently supported target platforms include:

  • Local Unix-like OSes, including macOS
  • SSH targets
  • Windows targets via WinRM

Any target platforms not listed are not supported at this time.

On unsupported platforms, the timeout value is ignored and the command will run indefinitely.

Redacting Sensitive Commands

By default the command that is ran is shown in the Chef 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 secret_password -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 secret_password -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

Matchers

For a full list of available matchers, see our Universal Matchers page.

This resource has the following special matchers.

exist

The exist matcher tests if a command may be run on the system:

it { should exist }
Edit this page on GitHub

Thank you for your feedback!

×