* Add documentation detailing new certificate resource changes incorporating the -T option

* modify security library and certificate resource to accomodate -T option

* Testing for new and improved certificate resource

* Fix Chef Spec tests

* bump version to 1.9.0

* hotfix for plist encoding type utf-8

* move plutil_format_map to libraries

* using Chef::Application.fatal to enforce encoding types

* add one second after each systemsetup call

* Add support for more hypervisors in keep_awake

- Leverage the node['virtualization']['systems'] ohai attribute to
determine whether we are a guest or a host
- Add appropriate chefspec tests

* Add another context for empty virtualization hash

* bump to 1.8.1

* ensure xcode-install gem is in Chef embedded even if ChefDK is present

* adjust implementation of running_in_a_vm?

* fix rspec shared context

* re-arrange chefspec keep_awake unit tests
This commit is contained in:
Eric Hanko 2018-03-21 15:20:39 -07:00 коммит произвёл GitHub
Родитель df5457dbe3
Коммит 0db78307ef
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
14 изменённых файлов: 178 добавлений и 31 удалений

Просмотреть файл

@ -126,7 +126,7 @@ Resources
---------
- [ARD (Apple Remote Desktop)](https://github.com/Microsoft/macos-cookbook/blob/master/documentation/resource_ard.md)
- [Certificate](https://github.com/Microsoft/macos-cookbook/blob/master/documentation/resource_certificate.md)
- [Certificate (security)](https://github.com/Microsoft/macos-cookbook/blob/master/documentation/resource_certificate.md)
- [Machine Name](https://github.com/Microsoft/macos-cookbook/blob/master/documentation/resource_machine_name.md)
- [Plist](https://github.com/Microsoft/macos-cookbook/blob/master/documentation/resource_plist.md)
- [Spotlight (mdutil)](https://github.com/Microsoft/macos-cookbook/blob/master/documentation/resource_spotlight.md)

Просмотреть файл

@ -20,6 +20,7 @@ certificate 'cert name' do
certfile String # certificate in .p12(PFX) or .cer(SSl certificate file) format
cert_passwd String # password for PFX format certificate file
keychain String # keychain to install certificate to
apps Array # list of apps that may access the imported key
end
```
@ -69,4 +70,13 @@ certificate 'cert name' do
certfile '/User/edward/Documents/cert.p12'
keychain '/User/edward/Library/Keychains/florida.keychain'
end
```
**Install PFX format certificate to default keychain, accessible by certain app**
```ruby
certificate 'cert name' do
certfile '/User/edward/Documents/cert.p12'
cert_passwd 'teach'
apps ['/Applications/Maps.app', '/Applications/Time Machine.app']
end
```

Просмотреть файл

@ -80,6 +80,13 @@ module MacOS
{ key_type: defaults_read_type_output.split.last, key_value: defaults_read_output.strip }
end
def plutil_format_map
{ 'us-ascii' => 'xml1',
'text/xml' => 'xml1',
'utf-8' => 'xml1',
'binary' => 'binary1' }
end
private
def defaults_executable
@ -92,5 +99,6 @@ module MacOS
end
end
Chef::Recipe.include(MacOS::PlistHelpers)
Chef::Resource.include(MacOS::PlistHelpers)
Chef::Recipe.include MacOS::PlistHelpers
Chef::Resource.include MacOS::PlistHelpers
Chef::DSL::Recipe.include MacOS::MachineName

Просмотреть файл

@ -20,16 +20,28 @@ module MacOS
@keychain == '' ? [@security_cmd, 'add-certificates', @cert] : [@security_cmd, 'add-certificates', @cert, '-k', @keychain]
end
def import(cert_passwd)
@keychain == '' ? [@security_cmd, 'import', @cert, '-P', cert_passwd] : [@security_cmd, 'import', @cert, '-P', cert_passwd, '-k', @keychain]
def import(cert_passwd, apps)
app_array = []
apps.each do |app|
app_array.push('-T')
app_array.push(app)
end
@keychain == '' ? [@security_cmd, 'import', @cert, '-P', cert_passwd, *app_array] : [@security_cmd, 'import', @cert, '-P', cert_passwd, '-k', @keychain, *app_array]
end
def install_certificate(cert_passwd)
def install_certificate(cert_passwd, apps)
valid_pkcs12 = ['.p12', '.pfx']
valid_certs = ['.der', '.crt', '.cer']
apps.each do |app|
unless app.is_a? String
Chef::Exception.fatal("Invalid application: #{@app}.")
end
end
if valid_pkcs12.any? { |extension| ::File.extname(@cert).match? extension }
import(cert_passwd)
import(cert_passwd, apps)
elsif valid_certs.any? { |extension| ::File.extname(@cert).match? extension }
add_certificates
else

Просмотреть файл

@ -1,7 +1,8 @@
module MacOS
module SystemSetup
def running_in_a_vm?
Chef.node['hardware']['machine_model'].match?(/Parallels/) # TODO: cover more hypervisors
virtualization_systems = Chef.node['virtualization']['systems']
virtualization_systems.empty? || virtualization_systems.values.include?('guest') ? true : false
end
def power_button_model?

Просмотреть файл

@ -5,7 +5,7 @@ license 'MIT'
description 'Resources for configuring and provisioning macOS'
long_description IO.read(File.join(File.dirname(__FILE__), 'README.md'))
chef_version '~> 13.0' if respond_to?(:chef_version)
version '1.8.2'
version '1.9.0'
source_url 'https://github.com/Microsoft/macos-cookbook'
issues_url 'https://github.com/Microsoft/macos-cookbook/issues'

Просмотреть файл

@ -3,6 +3,7 @@ resource_name :certificate
property :certfile, String
property :cert_password, String
property :keychain, String
property :apps, Array
action_class do
def keychain
@ -18,6 +19,6 @@ action :install do
end
execute 'install-certificate' do
command [*cert.install_certificate(new_resource.cert_password)]
command [*cert.install_certificate(new_resource.cert_password, new_resource.apps)]
end
end

Просмотреть файл

@ -3,7 +3,7 @@ resource_name :plist
property :path, String, name_property: true, desired_state: true
property :entry, String, desired_state: true
property :value, [TrueClass, FalseClass, String, Integer, Float], desired_state: true
property :encoding, String, desired_state: true, default: 'binary', equal_to: ['text/xml', 'binary', 'us-ascii']
property :encoding, String, desired_state: true, default: 'binary'
load_current_value do |desired|
current_value_does_not_exist! unless ::File.exist? desired.path
@ -52,17 +52,12 @@ EOF
converge_if_changed :encoding do
converge_by 'change format' do
Chef::Application.fatal!(
"Option encoding must be equal to one of: #{plutil_format_map.keys}! You passed \"#{new_resource.encoding}\"."
) unless plutil_format_map.keys.include? new_resource.encoding
execute ['/usr/bin/plutil', '-convert', plutil_format_map[new_resource.encoding], new_resource.path] do
action :run
end
end
end
end
action_class do
def plutil_format_map
{ 'us-ascii' => 'xml1',
'text/xml' => 'xml1',
'binary' => 'binary1' }
end
end

Просмотреть файл

@ -20,6 +20,11 @@ action :set do
converge_by "set #{new_resource.preference} to #{new_resource.setting}" do
set_pref = ['-set', new_resource.preference.to_s].join('')
execute ['/usr/sbin/systemsetup', set_pref, new_resource.setting]
ruby_block 'sleep one second' do
block do
sleep 1
end
end
end
end
end

Просмотреть файл

@ -7,7 +7,7 @@ property :ios_simulators, Array
action :setup do
chef_gem 'xcode-install' do
options('--no-document')
options('--no-document --no-user-install')
end
CREDENTIALS_DATA_BAG = data_bag_item(:credentials, :apple_id)

Просмотреть файл

@ -39,13 +39,19 @@ describe MacOS::SecurityCommand do
context 'importing a certificate (.p12)' do
it 'imports a specified .p12 certificate file' do
expect(p12_cert.import('password')).to eq ['/usr/bin/security', 'import', '/Users/vagrant/Test.p12', '-P', 'password']
expect(p12_cert.import('password', [])).to eq ['/usr/bin/security', 'import', '/Users/vagrant/Test.p12', '-P', 'password']
end
end
context 'importing a certificate (.p12)' do
it 'imports a specified .p12 certificate file to a specified keychain' do
expect(p12_cert_kc.import('password')).to eq ['/usr/bin/security', 'import', '/Users/vagrant/Test.p12', '-P', 'password', '-k', 'test.keychain']
expect(p12_cert_kc.import('password', [])).to eq ['/usr/bin/security', 'import', '/Users/vagrant/Test.p12', '-P', 'password', '-k', 'test.keychain']
end
end
context 'importing a certificate (.p12) accessible by Mail and App Store ' do
it 'imports a specified .p12 certificate file to a specified keychain' do
expect(p12_cert_kc.import('password', ['/Applications/Mail.app', '/Applications/App Store.app'])).to eq ['/usr/bin/security', 'import', '/Users/vagrant/Test.p12', '-P', 'password', '-k', 'test.keychain', '-T', '/Applications/Mail.app', '-T', '/Applications/App Store.app']
end
end
@ -63,13 +69,13 @@ describe MacOS::SecurityCommand do
context 'installing a certificate (.p12)' do
it 'installs a specified .p12 certificate file' do
expect(p12_cert.install_certificate('password')).to eq ['/usr/bin/security', 'import', '/Users/vagrant/Test.p12', '-P', 'password']
expect(p12_cert.install_certificate('password', [])).to eq ['/usr/bin/security', 'import', '/Users/vagrant/Test.p12', '-P', 'password']
end
end
context 'installing a certificate (.cer)' do
it 'adds a specified .cer certificate file' do
expect(cer_cert.install_certificate('password')).to eq ['/usr/bin/security', 'add-certificates', '/Users/vagrant/Test.cer']
expect(cer_cert.install_certificate('password', [])).to eq ['/usr/bin/security', 'add-certificates', '/Users/vagrant/Test.cer']
end
end
end

Просмотреть файл

@ -1,13 +1,121 @@
require 'spec_helper'
describe 'macos::keep_awake' do
context 'When all attributes are default, on macOS High Sierra 10.13' do
let(:chef_run) { ChefSpec::SoloRunner.new.converge(described_recipe) }
include MacOS::SystemSetup
it 'converges successfully' do
allow_any_instance_of(Chef::Resource).to receive(:running_in_a_vm?).and_return(false)
allow_any_instance_of(Chef::Resource).to receive(:power_button_model?).and_return(false)
shared_context 'when running on bare metal' do
shared_examples 'setting metal-specific power preferences' do
before(:each) do
allow_any_instance_of(Chef::Resource).to receive(:power_button_model?).and_return(true)
chef_run.node.normal['virtualization']['systems'] = { 'vbox' => 'host', 'parallels' => 'host' }
stub_command('which git').and_return('/usr/bin/git')
end
it 'returns false' do
expect(running_in_a_vm?).to be false
end
it 'sets wake on lan' do
chef_run.converge(described_recipe)
expect(chef_run).to set_system_preference('wake the computer when accessed using a network connection')
end
it 'disables power button sleep' do
chef_run.converge(described_recipe)
expect(chef_run).to set_system_preference('pressing power button does not sleep computer')
end
it 'sets restart after a power failure' do
chef_run.converge(described_recipe)
expect(chef_run).to set_system_preference('restart after a power failure')
end
it 'converges successfully on bare metal' do
expect { chef_run }.to_not raise_error
end
end
end
shared_context 'running in a parallels virtual machine' do
before(:each) do
allow_any_instance_of(Chef::Resource).to receive(:power_button_model?).and_return(false)
chef_run.node.normal['virtualization']['systems'] = { 'parallels' => 'guest' }
stub_command('which git').and_return('/usr/bin/git')
end
shared_examples 'not setting metal-specific power prefs' do
it 'confirms we are in a vm' do
expect(running_in_a_vm?).to be true
end
it 'does not set wake on lan' do
chef_run.converge(described_recipe)
expect(chef_run).to_not set_system_preference('wake the computer when accessed using a network connection')
end
it 'skips disabling power button sleep' do
chef_run.converge(described_recipe)
expect(chef_run).to_not set_system_preference('pressing power button does not sleep computer')
end
it 'does not set restart after a power failure' do
chef_run.converge(described_recipe)
expect(chef_run).to_not set_system_preference('restart after a power failure')
end
it 'converges successfully in a vm' do
expect { chef_run }.to_not raise_error
end
end
end
shared_context 'running in an undetermined virtualization system' do
before(:each) do
allow_any_instance_of(Chef::Resource).to receive(:power_button_model?).and_return(false)
chef_run.node.override['virtualization']['systems'] = {}
stub_command('which git').and_return('/usr/bin/git')
end
shared_examples 'not setting metal-specific power prefs' do
it 'assumes we are in a vm' do
expect(running_in_a_vm?).to be true
end
it 'does not set wake on lan' do
chef_run.converge(described_recipe)
expect(chef_run).to_not set_system_preference('wake the computer when accessed using a network connection')
end
it 'skips disabling power button sleep' do
chef_run.converge(described_recipe)
expect(chef_run).to_not set_system_preference('pressing power button does not sleep computer')
end
it 'does not set restart after a power failure' do
chef_run.converge(described_recipe)
expect(chef_run).to_not set_system_preference('restart after a power failure')
end
it 'converges successfully in a vm' do
expect { chef_run }.to_not raise_error
end
end
end
describe 'macos::keep_awake' do
let(:chef_run) { ChefSpec::SoloRunner.new }
describe 'keep_awake in a parallels vm' do
include_context 'running in a parallels virtual machine'
it_behaves_like 'not setting metal-specific power prefs'
end
describe 'keep_awake in an undetermined virtualization system' do
include_context 'running in an undetermined virtualization system'
it_behaves_like 'not setting metal-specific power prefs'
end
describe 'keep_awake on bare metal' do
include_context 'when running on bare metal'
it_behaves_like 'setting metal-specific power preferences'
end
end

Просмотреть файл

@ -8,5 +8,6 @@ certificate 'install a PFX format certificate file' do
certfile '/Users/vagrant/Test.p12'
cert_password 'test'
keychain '/Users/vagrant/Library/Keychains/login.keychain'
apps ['/Applications/Mail.app', '/Applications/App Store.app']
action :install
end

Просмотреть файл

@ -22,7 +22,7 @@ control 'new macOS users' do
its('groups') { should_not include 'admin' }
end
describe groups.where { name == 'admin'} do
describe groups.where { name == 'admin' } do
it { should exist }
its('gids') { should include 80 }
end