Project: Chef InSpec (Provisioning / Security & Compliance)
File: shell.md

+++ title = "Chef InSpec Shell" draft = false gh_repo = "inspec" [menu] [menu.inspec] title = "InSpec Shell" identifier = "inspec/Chef InSpec Shell" parent = "inspec" weight = 70 +++ The Chef InSpec interactive shell is a pry-based REPL that can be used to quickly run Chef InSpec controls and tests without having to write it to a file. Its functionality is similar to as it provides a way to exercise the Chef InSpec Language, its resources, tests, and plugins without having to create a profile or write a test file. See for an introduction to what pry is and what it can do. See on Learn Chef for a hands-on example that uses Chef InSpec shell. If you are using Chef InSpec from a platform-specific package (rpm, msi, etc.) or from a Chef prepared shell in Chef Workstation, you can directly launch Chef InSpec shell against your local machine using the `inspec shell` command. ```bash inspec shell inspec help shell # This will describe inspec shell usage ``` If you wish to connect to a remote machine (called a target within InSpec), you can use the `-t` flag. We support connecting using SSH, WinRM, Docker, Podman and many other target types. If no target is provided, we implicitly support the "local" target - i.e. tests running on the current machine running InSpec. For an SSH connection, use `-i` for specifying SSH key files, and the `--sudo*` commands for requesting a privilege escalation after logging in. For a WinRM connection, use `--path` to change the login path, `--ssl` to use SSL for transport layer encryption. ```bash inspec shell -t ssh://root@192.168.64.2:11022 # Login to remote machine using ssh as root. inspec shell -t ssh://user@hostname:1234 -i /path/to/user_key # Login to hostname on port 1234 as user using given ssh key. inspec shell -t winrm://UserName:Password@windowsmachine:1234 # Login to windowsmachine over WinRM as UserName. inspec shell -t winrm://windowsmachine --user 'UserName@domain' --password 'Secret123!' # Login to windowsmachine as UserName@domain.org. inspec shell -t docker://container_id # Login to a Docker container. inspec shell -t podman://container_id --podman-url "unix:///run/user/$UID/podman/podman.sock" #Login to Podman rootless container. ``` Use resource packs to share custom resources with other Chef InSpec users. A resource pack is a Chef InSpec profile that contains only custom resources and no other controls or tests. For example, the profile in in the Chef InSpec GitHub repository defines an . To use these resources within the Chef InSpec shell, you will need to download and specify them as a dependency. Once you have local access to the profile, you can use the `example_config` custom resource provided in the `examples/profile` GitHub repo in your local environment : ```bash inspec shell --depends examples/profile ``` Once inside the shell your resource will be available: ```ruby inspec> example_config ``` Since Chef InSpec shell is pry based, you can treat the shell as an interactive Ruby session. You can write Ruby expressions and evaluate them. Source high-lighting, automatic indentation and command history (using the up and down arrow keys) are available to make your experience more delightful. You can exit the shell using `exit`. ```bash $ inspec shell Welcome to the interactive InSpec Shell To find out how to use it, type: help inspec> 1 + 2 => 3 inspec> exit ``` The Chef InSpec shell automatically evaluates the result of every command as if it were a test file. If you type in a Ruby command that is not an Chef InSpec control or test, the shell will evaluate it as if it were a regular Ruby

Bare Chef InSpec resources are instantiated and their help text is presented. You may also access the resource contents or other matchers that they define. Run `help <resource>` to get more help on using a particular resource or see the Chef InSpec resources documentation online. ```bash $ inspec shell Welcome to the interactive InSpec Shell To find out how to use it, type: help inspec> file('/Users/username').directory? => true inspec> os_env('HOME') => Environment variable HOME inspec> os_env('HOME').content => /Users/username inspec> exit ``` Chef InSpec tests are immediately executed. ```bash inspec> describe file('/Users') # Empty test. Summary: 0 successful, 0 failures, 0 skipped inspec> describe file('/Users') do # Test with one check. inspec> it { should exist } inspec> end File /Users should exist Summary: 1 successful, 0 failures, 0 skipped ``` All tests in a control are immediately executed as well. If a control is redefined in the shell, the old control's tests are destroyed and replaced with the redefinition and the control is re-run. ```bash inspec> control 'my_control' do inspec> describe os_env('HOME') do inspec> its('content') { should eq '/Users/username' } inspec> end inspec> end my_control: Environment variable HOME content should eq "/Users/username" Summary: 1 successful, 0 failures, 0 skipped ``` Syntax errors are illegal tests are also detected and reported. ```bash inspec> control 'foo' do inspec> thisisnonsense inspec> end NameError: undefined local variable or method `thisisnonsense' for #<#<Class:0x007fd63b571f98>:0x007fd639825cc8> from /usr/local/lib/ruby/gems/2.3.0/gems/rspec-expectations-3.5.0/lib/rspec/matchers.rb:967:in `method_missing' inspec> control 'foo' do inspec> describe file('wut') do inspec> its('thismakesnosense') { should cmp 'fail' } inspec> end inspec> end foo: File wut thismakesnosense (undefined method `thismakesnosense' for File wut:Inspec::Resource::Registry::File) Summary: 0 successful, 1 failures, 0 skipped ``` You can run a single Chef InSpec command and fetch its results using the `-c` flag. This is similar to using `bash -c`. ```bash $ inspec shell -c 'describe file("/Users/username") do it { should exist } end' Target: local:// File /Users/username should exist Summary: 1 successful, 0 failures, 0 skipped ``` ```bash $ inspec shell --format json -c 'describe file("/Users/test") do it { should exist } end' { "version": "1.49.2", "controls": [{ "status": "passed", "code_desc": "File /Users/test should exist", "run_time": 0.002374, "start_time": "2018-01-06 18:32:38 -0500" }], "other_checks": [], "profiles": [{ "name": "inspec-shell", "supports": [], "controls": [{ "title": null, "desc": null, "impact": 0.5, "refs": [], "tags": {}, "code": "", "source_location": { "ref": "/usr/local/lib/ruby/gems/2.4.0/gems/inspec-1.49.2/lib/inspec/controlevalcontext.rb", "line": 89 }, "id": "(generated from (eval):1 7b6f82c2cc5e4205b3e2c97c8e855f2d)", "results": [{ "status": "passed", "code_desc": "File /Users/test should exist", "run_time": 0.002374, "start_time": "2018-01-06 18:32:38 -0500" }] }], "groups": [{ "title": null, "controls": ["(generated from (eval):1 7b6f82c2cc5e4205b3e2c97c8e855f2d)"], "id": "unknown" }], "attributes": [], "sha256": "29c070a90b7e3521babf618215573284a790d92907783d5b2c138f411bfd2e74" }], "platform": { "name": "macosx", "release": "17.3.0" }, "statistics": { "duration": 0.003171 } } ``` With InSpec , you can set inputs using the InSpec `shell` command. This allows you to work more consistently with InSpec profiles when switching between the `shell` and `exec` commands. For more details on inputs, see the . The `shell` command accepts one or more inputs in the command line as single-quoted YAML or JSON structures. ```bash $ inspec shell --input=inputname=inputvalue Welcome to the interactive InSpec Shell To find out how to use it, type: help inspec> control 'my_control' do inspec> describe input('input_name') do inspec> it { should cmp 'input_value' } inspec> end inspec> end Profile: inspec-shell mycontrol: inputvalue inputvalue is expected to cmp == "inputvalue" Profile Summary: 1 successful control, 0 control failures, 0 controls skipped Test Summary: 1 successful, 0 failures, 0 skipped inspec> exit ``` You can also save inputs and values to one or more YAML files and pass them to `shell` in the command line. For example: ```yaml inputname: inputvalue anotherinput: anothervalue ``` ```bash inspec shell --input-file=<path> ```