Skip to content

Using InSpec with the GCP transport crashes when used with file() resources #61

Closed
@adrienthebo

Description

@adrienthebo

When when the GCP transport is used with an InSpec profile using the file() resource, InSpec raises an exception and exits.

This comes up frequently as inspec init profile my-profile generates a simple InSpec control that uses the file().

Expected behavior

The file() resource is built with the assumption that the system under test
is a host, but when the GCP transport is used the semantics of file() get a
little fuzzy. There are two reasonable scenarios I can think of for expected
behavior:

  • Option 1: Read a local file
  • Option 2: Exit gracefully

Actual behavior

InSpec assumes that the backend can read files, calls #source_path on nil, raises an exception, and crashes.

Steps to reproduce

Example Gemfile:

source 'https://rubygems.org'

gem 'inspec', '~> 2.3.0'

Generate a new InSpec profile:

└> bundle exec inspec init profile gcp-file
Create new profile at /Users/thebo/lagrange/projects/inspec/inspec-gcp-file/gcp-file
 * Create directory libraries
 * Create file README.md
 * Create directory controls
 * Create file controls/example.rb
 * Create file inspec.yml
 * Create file libraries/.gitkeep

Amend the inspec.yml to match the configuration given in the inspec-gcp README:

name: my-profile
title: My GCP InSpec Profile
version: 0.1.0
inspec_version: '>= 2.2.10'
depends:
  - name: inspec-gcp
    url: https://github.com/inspec/inspec-gcp/archive/master.tar.gz
supports:
  - platform: gcp

Attempt to run the newly generated profile with the gcp transport:

# bundle exec inspec exec gcp-file -t gcp://
Your application has authenticated using end user credentials from Google Cloud SDK. We recommend that most server applications use service accounts instead. If your application continues to use end user credentials from Cloud SDK, you might receive a "quota exceeded" or "API not enabled" error. For more information about service accounts, see https://cloud.google.com/docs/authentication/.
bundler: failed to load command: inspec (/Users/thebo/lagrange/projects/inspec/inspec-gcp-file/.bundle/ruby/2.4.0/bin/inspec)
NameError: undefined method `source_path' for class `NilClass'
  /Users/thebo/lagrange/projects/inspec/inspec-gcp-file/.bundle/ruby/2.4.0/gems/inspec-2.3.10/lib/resources/file.rb:52:in `method'
  /Users/thebo/lagrange/projects/inspec/inspec-gcp-file/.bundle/ruby/2.4.0/gems/inspec-2.3.10/lib/resources/file.rb:52:in `block (2 levels) in <class:FileResource>'
  /Users/thebo/lagrange/projects/inspec/inspec-gcp-file/.bundle/ruby/2.4.0/gems/inspec-2.3.10/lib/resources/file.rb:137:in `to_s'
  /Users/thebo/lagrange/projects/inspec/inspec-gcp-file/.bundle/ruby/2.4.0/gems/rspec-core-3.8.0/lib/rspec/core/metadata.rb:180:in `build_description_from'
  /Users/thebo/lagrange/projects/inspec/inspec-gcp-file/.bundle/ruby/2.4.0/gems/rspec-core-3.8.0/lib/rspec/core/metadata.rb:133:in `populate'
  /Users/thebo/lagrange/projects/inspec/inspec-gcp-file/.bundle/ruby/2.4.0/gems/rspec-core-3.8.0/lib/rspec/core/metadata.rb:258:in `create'
  /Users/thebo/lagrange/projects/inspec/inspec-gcp-file/.bundle/ruby/2.4.0/gems/rspec-core-3.8.0/lib/rspec/core/example_group.rb:422:in `set_it_up'
  /Users/thebo/lagrange/projects/inspec/inspec-gcp-file/.bundle/ruby/2.4.0/gems/rspec-core-3.8.0/lib/rspec/core/example_group.rb:386:in `subclass'
  /Users/thebo/lagrange/projects/inspec/inspec-gcp-file/.bundle/ruby/2.4.0/gems/rspec-core-3.8.0/lib/rspec/core/example_group.rb:260:in `block in define_example_group_method'
  /Users/thebo/lagrange/projects/inspec/inspec-gcp-file/.bundle/ruby/2.4.0/gems/inspec-2.3.10/lib/inspec/runner_rspec.rb:27:in `example_group'
  /Users/thebo/lagrange/projects/inspec/inspec-gcp-file/.bundle/ruby/2.4.0/gems/inspec-2.3.10/lib/inspec/runner.rb:310:in `rspec_failed_block'
  /Users/thebo/lagrange/projects/inspec/inspec-gcp-file/.bundle/ruby/2.4.0/gems/inspec-2.3.10/lib/inspec/runner.rb:268:in `get_check_example'
  /Users/thebo/lagrange/projects/inspec/inspec-gcp-file/.bundle/ruby/2.4.0/gems/inspec-2.3.10/lib/inspec/runner.rb:280:in `block in register_rule'
  /Users/thebo/lagrange/projects/inspec/inspec-gcp-file/.bundle/ruby/2.4.0/gems/inspec-2.3.10/lib/inspec/runner.rb:279:in `each'
  /Users/thebo/lagrange/projects/inspec/inspec-gcp-file/.bundle/ruby/2.4.0/gems/inspec-2.3.10/lib/inspec/runner.rb:279:in `flat_map'
  /Users/thebo/lagrange/projects/inspec/inspec-gcp-file/.bundle/ruby/2.4.0/gems/inspec-2.3.10/lib/inspec/runner.rb:279:in `register_rule'
  /Users/thebo/lagrange/projects/inspec/inspec-gcp-file/.bundle/ruby/2.4.0/gems/inspec-2.3.10/lib/inspec/runner.rb:96:in `block in load'
  /Users/thebo/lagrange/projects/inspec/inspec-gcp-file/.bundle/ruby/2.4.0/gems/inspec-2.3.10/lib/inspec/runner.rb:95:in `each'
  /Users/thebo/lagrange/projects/inspec/inspec-gcp-file/.bundle/ruby/2.4.0/gems/inspec-2.3.10/lib/inspec/runner.rb:95:in `load'
  /Users/thebo/lagrange/projects/inspec/inspec-gcp-file/.bundle/ruby/2.4.0/gems/inspec-2.3.10/lib/inspec/runner.rb:102:in `run'
  /Users/thebo/lagrange/projects/inspec/inspec-gcp-file/.bundle/ruby/2.4.0/gems/inspec-2.3.10/lib/inspec/cli.rb:184:in `exec'
  /Users/thebo/lagrange/projects/inspec/inspec-gcp-file/.bundle/ruby/2.4.0/gems/thor-0.20.0/lib/thor/command.rb:27:in `run'
  /Users/thebo/lagrange/projects/inspec/inspec-gcp-file/.bundle/ruby/2.4.0/gems/thor-0.20.0/lib/thor/invocation.rb:126:in `invoke_command'
  /Users/thebo/lagrange/projects/inspec/inspec-gcp-file/.bundle/ruby/2.4.0/gems/thor-0.20.0/lib/thor.rb:387:in `dispatch'
  /Users/thebo/lagrange/projects/inspec/inspec-gcp-file/.bundle/ruby/2.4.0/gems/thor-0.20.0/lib/thor/base.rb:466:in `start'
  /Users/thebo/lagrange/projects/inspec/inspec-gcp-file/.bundle/ruby/2.4.0/gems/inspec-2.3.10/bin/inspec:12:in `<top (required)>'
  /Users/thebo/lagrange/projects/inspec/inspec-gcp-file/.bundle/ruby/2.4.0/bin/inspec:23:in `load'
  /Users/thebo/lagrange/projects/inspec/inspec-gcp-file/.bundle/ruby/2.4.0/bin/inspec:23:in `<top (required)>'

Workarounds

When a local file is under test, the file can be read directly through File.read or a Pathname object can be used.

control 'gcp-file-workaround' do
  # the `file()` resource fails when the GCP transport is in use; to work around this issue we
  # intentionally interact with the local filesystem to perform our tests
  describe Pathname.new("credentials.json") do
    it { should exist }

    it "contains valid JSON" do
      JSON.parse(subject.read)
    end
  end
end

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions