spec/chef-vault/item_spec.rb in chef-vault-2.5.0 vs spec/chef-vault/item_spec.rb in chef-vault-2.6.0

- old
+ new

@@ -49,13 +49,88 @@ .and_raise(http_not_found) end end RSpec.describe ChefVault::Item do + before do + @orig_stdout = $stdout + $stdout = File.open(File::NULL, 'w') + end + + after do + $stdout = @orig_stdout + end + subject(:item) { ChefVault::Item.new("foo", "bar") } - describe '#new' do + describe 'vault probe predicates' do + before do + # a normal data bag item + @db = { 'foo' => '...' } + @dbi = Chef::DataBagItem.new + @dbi.data_bag('normal') + @dbi.raw_data = { 'id' => 'foo', 'foo' => 'bar' } + allow(@db).to receive(:load).with('foo').and_return(@dbi) + allow(Chef::DataBag).to receive(:load).with('normal').and_return(@db) + allow(Chef::DataBagItem).to receive(:load).with('normal', 'foo').and_return(@dbi) + + # an encrypted data bag item (non-vault) + @encdb = { 'foo' => '...' } + @encdbi = Chef::DataBagItem.new + @encdbi.data_bag('encrypted') + @encdbi.raw_data = { + 'id' => 'foo', + 'foo' => { 'encrypted_data' => '...' } + } + allow(@encdb).to receive(:load).with('foo').and_return(@encdbi) + allow(Chef::DataBag).to receive(:load).with('encrypted').and_return(@encdb) + allow(Chef::DataBagItem).to receive(:load).with('encrypted', 'foo').and_return(@encdbi) + + # two items that make up a vault + @vaultdb = { 'foo' => '...', 'foo_keys' => '...' } + @vaultdbi = Chef::DataBagItem.new + @vaultdbi.data_bag('vault') + @vaultdbi.raw_data = { + 'id' => 'foo', + 'foo' => { 'encrypted_data' => '...' } + } + allow(@vaultdb).to receive(:load).with('foo').and_return(@vaultdbi) + @vaultdbki = Chef::DataBagItem.new + @vaultdbki.data_bag('vault') + @vaultdbki.raw_data = { 'id' => 'foo_keys' } + allow(@vaultdb).to receive(:load).with('foo_keys').and_return(@vaultdbki) + allow(Chef::DataBag).to receive(:load).with('vault').and_return(@vaultdb) + allow(Chef::DataBagItem).to receive(:load).with('vault', 'foo').and_return(@vaultdbi) + end + + describe '::vault?' do + it 'should detect a vault item' do + expect(ChefVault::Item.vault?('vault', 'foo')).to be_truthy + end + + it 'should detect non-vault items' do + expect(ChefVault::Item.vault?('normal', 'foo')).not_to be_truthy + expect(ChefVault::Item.vault?('encrypted', 'foo')).not_to be_truthy + end + end + + describe '::data_bag_item_type' do + it 'should detect a vault item' do + expect(ChefVault::Item.data_bag_item_type('vault', 'foo')).to eq(:vault) + end + + it 'should detect an encrypted data bag item' do + expect(ChefVault::Item.data_bag_item_type('encrypted', 'foo')).to eq(:encrypted) + end + + it 'should detect a normal data bag item' do + expect(ChefVault::Item.data_bag_item_type('normal', 'foo')).to eq(:normal) + end + end + end + + describe '::new' do it { should be_an_instance_of ChefVault::Item } its(:keys) { should be_an_instance_of ChefVault::ItemKeys } its(:data_bag) { should eq "foo" } @@ -63,18 +138,84 @@ specify { expect(item['id']).to eq 'bar' } specify { expect(item.keys['id']).to eq 'bar_keys' } specify { expect(item.keys.data_bag).to eq 'foo' } + + it 'defaults the node name' do + item = ChefVault::Item.new('foo', 'bar') + expect(item.node_name).to eq(Chef::Config[:node_name]) + end + + it 'defaults the client key path' do + item = ChefVault::Item.new('foo', 'bar') + expect(item.client_key_path).to eq(Chef::Config[:client_key]) + end + + it 'allows for a node name override' do + item = ChefVault::Item.new('foo', 'bar', node_name: 'baz') + expect(item.node_name).to eq('baz') + end + + it 'allows for a client key path override' do + item = ChefVault::Item.new('foo', 'bar', client_key_path: '/foo/client.pem') + expect(item.client_key_path).to eq('/foo/client.pem') + end + + it 'allows for both node name and client key overrides' do + item = ChefVault::Item.new( + 'foo', 'bar', + node_name: 'baz', + client_key_path: '/foo/client.pem' + ) + expect(item.node_name).to eq('baz') + expect(item.client_key_path).to eq('/foo/client.pem') + end end + describe '::load' do + it 'allows for both node name and client key overrides' do + keys_db = Chef::DataBagItem.new + keys_db.raw_data = { + 'id' => 'bar_keys', + 'baz' => '...' + } + allow(ChefVault::ItemKeys) + .to receive(:load) + .and_return(keys_db) + fh = double 'private key handle' + allow(fh).to receive(:read).and_return('...') + allow(File).to receive(:open).and_return(fh) + privkey = double 'private key contents' + allow(privkey).to receive(:private_decrypt).and_return('sekrit') + allow(OpenSSL::PKey::RSA).to receive(:new).and_return(privkey) + allow(Chef::EncryptedDataBagItem).to receive(:load).and_return( + 'id' => 'bar', + 'password' => '12345' + ) + item = ChefVault::Item.load( + 'foo', 'bar', + node_name: 'baz', + client_key_path: '/foo/client.pem' + ) + expect(item.node_name).to eq('baz') + expect(item.client_key_path).to eq('/foo/client.pem') + end + end + describe '#save' do context 'when item["id"] is bar.bar' do let(:item) { ChefVault::Item.new("foo", "bar.bar") } - specify { expect { item.save }.to raise_error } end + + it 'should validate that the id of the vault matches the id of the keys data bag' do + item = ChefVault::Item.new('foo', 'bar') + item['id'] = 'baz' + item.keys['clients'] = %w(admin) + expect { item.save }.to raise_error(ChefVault::Exceptions::IdMismatch) + end end describe '#clients' do include BorkedNodeWithoutPublicKey @@ -85,18 +226,38 @@ end it 'should emit a warning if search returns a node without a public key' do # it should however emit a warning that you have a borked node expect { @vaultitem.clients('*:*') } - .to output(/node 'bar' has no private key; skipping/).to_stderr + .to output(/node 'bar' has no private key; skipping/).to_stdout end + + it 'should accept a client object and not perform a search' do + client = Chef::ApiClient.new + client.name 'foo' + privkey = OpenSSL::PKey::RSA.new(1024) + pubkey = privkey.public_key + client.public_key(pubkey.to_pem) + expect(Chef::Search::Query).not_to receive(:new) + expect(ChefVault::ChefPatch::User).not_to receive(:load) + @vaultitem.clients(client) + expect(@vaultitem.clients).to include('foo') + end end describe '#admins' do include BorkedNodeWithoutPublicKey it 'should blow up if you try to use a node without a public key as an admin' do expect { @vaultitem.admins('foo,bar') } .to raise_error(ChefVault::Exceptions::AdminNotFound) + end + end + + describe '#raw_keys' do + it 'should return the keys of the underlying data bag item' do + item = ChefVault::Item.new('foo', 'bar') + item['foo'] = 'bar' + expect(item.raw_keys).to eq(%w(id foo)) end end end