mirror of
https://github.com/inspec/inspec
synced 2024-12-13 06:42:40 +00:00
8269d0da9e
This change adds support in Habitat-packaged profiles for profiles that depend on other profiles. When `inspec habitat profile create` or `inspec habitat profile upload` is run, it will see if the profile's dependencies have been vendored yet, and if not, it will vendor them before creating the habitat artifact. For the git and URL fetchers, more explicit creation of the target directories for the vendored profiles is done. This is implicitly done via normal CLI interactions a user may go through, but in our case, we want to ensure those directories are there before the fetchers try to write out content. By adding this support, we also fix a bug experienced in Habitat where a profile that was packaged before an `inspec exec` was run for the profile would cause a failure in Habitat. This is caused by `inspec exec` doing a vendor of the dependencies if necessary and generating the inspec.lock file. In Habitat, the package dir is not writable by the hab user and InSpec would fail to run due to an inability to write out an inspec.lock. Signed-off-by: Adam Leff <adam@leff.co>
185 lines
5.9 KiB
Ruby
185 lines
5.9 KiB
Ruby
require 'helper'
|
|
require 'mixlib/log'
|
|
require 'ostruct'
|
|
|
|
describe Habitat::Profile do
|
|
let(:profile) do
|
|
OpenStruct.new(
|
|
name: 'my_profile',
|
|
version: '1.2.3',
|
|
files: %w(file1 file2)
|
|
)
|
|
end
|
|
|
|
let(:subject) { Habitat::Profile.new('/path/to/profile', { 'log_level' => 'fatal' }) }
|
|
|
|
before do
|
|
Habitat::Log.level(:fatal)
|
|
end
|
|
|
|
describe '#verify_profile' do
|
|
it 'exits if the profile is not valid' do
|
|
profile = mock
|
|
profile.stubs(:check).returns(summary: { valid: false })
|
|
subject.expects(:profile).returns(profile)
|
|
proc { subject.send(:verify_profile) }.must_raise SystemExit
|
|
end
|
|
|
|
it 'does not exist if the profile is valid' do
|
|
profile = mock
|
|
profile.stubs(:check).returns(summary: { valid: true })
|
|
subject.expects(:profile).returns(profile)
|
|
subject.send(:verify_profile)
|
|
end
|
|
end
|
|
|
|
describe '#vendor_profile_dependencies' do
|
|
let(:cache) { '/path/to/cache' }
|
|
let(:lockfile) { '/path/to/lock' }
|
|
let(:profile) do
|
|
profile = mock
|
|
profile.stubs(:generate_lockfile).returns(foo: 'bar')
|
|
profile
|
|
end
|
|
|
|
before do
|
|
subject.expects(:cache_path).at_least_once.returns(cache)
|
|
subject.expects(:inspec_lockfile).at_least_once.returns(lockfile)
|
|
end
|
|
|
|
describe 'when lockfile exists and cache dir exists' do
|
|
it 'does not generate the lockfile' do
|
|
File.expects(:exist?).with(lockfile).returns(true)
|
|
Dir.expects(:exist?).with(cache).returns(true)
|
|
subject.expects(:profile).returns(profile).never
|
|
profile.expects(:generate_lockfile).never
|
|
subject.send(:vendor_profile_dependencies)
|
|
end
|
|
end
|
|
|
|
describe 'when the lockfile exists but the cache dir does not' do
|
|
it 'deletes the lockfile, generates the lockfile, and refreshes the profile object' do
|
|
File.expects(:exist?).with(lockfile).returns(true).at_least_once
|
|
Dir.expects(:exist?).with(cache).returns(false).at_least_once
|
|
FileUtils.expects(:rm_rf).with(cache)
|
|
File.expects(:delete).with(lockfile)
|
|
subject.expects(:profile).returns(profile)
|
|
File.expects(:write).with(lockfile, "---\n:foo: bar\n")
|
|
subject.expects(:create_profile_object)
|
|
|
|
subject.send(:vendor_profile_dependencies)
|
|
end
|
|
end
|
|
|
|
describe 'when the lockfile does not exist' do
|
|
it 'generates the lockfile, and refreshes the profile object' do
|
|
File.expects(:exist?).with(lockfile).returns(false).at_least_once
|
|
FileUtils.expects(:rm_rf).with(cache)
|
|
subject.expects(:profile).returns(profile)
|
|
File.expects(:write).with(lockfile, "---\n:foo: bar\n")
|
|
subject.expects(:create_profile_object)
|
|
|
|
subject.send(:vendor_profile_dependencies)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe '#validate_habitat_installed' do
|
|
it 'exits if hab --version fails' do
|
|
cmd = mock
|
|
cmd.stubs(:error?).returns(true)
|
|
cmd.stubs(:run_command)
|
|
cmd.stubs(:stdout)
|
|
cmd.stubs(:stderr)
|
|
Mixlib::ShellOut.expects(:new).with('hab --version').returns(cmd)
|
|
proc { subject.send(:validate_habitat_installed) }.must_raise SystemExit
|
|
end
|
|
end
|
|
|
|
describe '#validate_habitat_origin' do
|
|
it 'does not exit if the origin key exists' do
|
|
subject.expects(:habitat_origin).returns('12345')
|
|
subject.send(:validate_habitat_origin)
|
|
end
|
|
|
|
it 'exits if no origin key exists' do
|
|
subject.expects(:habitat_origin).returns(nil)
|
|
proc { subject.send(:validate_habitat_origin) }.must_raise SystemExit
|
|
end
|
|
end
|
|
|
|
describe '#validate_habitat_auth_token' do
|
|
it 'does not exit if the auth_token exists' do
|
|
subject.expects(:habitat_auth_token).returns('12345')
|
|
subject.send(:validate_habitat_auth_token)
|
|
end
|
|
|
|
it 'exits if no auth_token exists' do
|
|
subject.expects(:habitat_auth_token).returns(nil)
|
|
proc { subject.send(:validate_habitat_auth_token) }.must_raise SystemExit
|
|
end
|
|
end
|
|
|
|
describe '#build_hart' do
|
|
before do
|
|
subject.expects(:work_dir).at_least_once.returns(Dir.tmpdir)
|
|
end
|
|
|
|
it 'exits if the build fails' do
|
|
subject.expects(:system).returns(false)
|
|
proc { subject.send(:build_hart) }.must_raise SystemExit
|
|
end
|
|
|
|
it 'exits if more than one hart is created' do
|
|
subject.expects(:system).returns(true)
|
|
Dir.expects(:glob).returns(%w(hart1 hart2))
|
|
proc { subject.send(:build_hart) }.must_raise SystemExit
|
|
end
|
|
|
|
it 'exits if more than no hart is created' do
|
|
subject.expects(:system).returns(true)
|
|
Dir.expects(:glob).returns([])
|
|
proc { subject.send(:build_hart) }.must_raise SystemExit
|
|
end
|
|
|
|
it 'returns the hart filename' do
|
|
subject.expects(:system).returns(true)
|
|
Dir.expects(:glob).returns(%w(hart1))
|
|
subject.send(:build_hart).must_equal('hart1')
|
|
end
|
|
end
|
|
|
|
describe '#upload_hart' do
|
|
it 'exits if the upload failed' do
|
|
env = {
|
|
'TERM' => 'vt100',
|
|
'HAB_AUTH_TOKEN' => 'my_token',
|
|
'HAB_NONINTERACTIVE' => 'true',
|
|
}
|
|
|
|
cmd = mock
|
|
cmd.stubs(:run_command)
|
|
cmd.stubs(:error?).returns(true)
|
|
cmd.stubs(:stdout)
|
|
cmd.stubs(:stderr)
|
|
|
|
subject.expects(:habitat_auth_token).returns('my_token')
|
|
Mixlib::ShellOut.expects(:new).with("hab pkg upload my_hart", env: env).returns(cmd)
|
|
proc { subject.send(:upload_hart, 'my_hart') }.must_raise SystemExit
|
|
end
|
|
end
|
|
|
|
describe '#habitat_cli_config' do
|
|
it 'returns an empty hash if the CLI config does not exist' do
|
|
File.expects(:exist?).with(File.join(ENV['HOME'], '.hab', 'etc', 'cli.toml')).returns(false)
|
|
subject.send(:habitat_cli_config).must_equal({})
|
|
end
|
|
|
|
it 'returns parsed TOML from the hab config file' do
|
|
config_file = File.join(ENV['HOME'], '.hab', 'etc', 'cli.toml')
|
|
File.expects(:exist?).with(config_file).returns(true)
|
|
TOML.expects(:load_file).with(config_file).returns(foo: 1)
|
|
subject.send(:habitat_cli_config).must_equal(foo: 1)
|
|
end
|
|
end
|
|
end
|