Release/1.9 (#73)
* 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:
Родитель
df5457dbe3
Коммит
0db78307ef
|
@ -126,7 +126,7 @@ Resources
|
||||||
---------
|
---------
|
||||||
|
|
||||||
- [ARD (Apple Remote Desktop)](https://github.com/Microsoft/macos-cookbook/blob/master/documentation/resource_ard.md)
|
- [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)
|
- [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)
|
- [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)
|
- [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
|
certfile String # certificate in .p12(PFX) or .cer(SSl certificate file) format
|
||||||
cert_passwd String # password for PFX format certificate file
|
cert_passwd String # password for PFX format certificate file
|
||||||
keychain String # keychain to install certificate to
|
keychain String # keychain to install certificate to
|
||||||
|
apps Array # list of apps that may access the imported key
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -70,3 +71,12 @@ certificate 'cert name' do
|
||||||
keychain '/User/edward/Library/Keychains/florida.keychain'
|
keychain '/User/edward/Library/Keychains/florida.keychain'
|
||||||
end
|
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 }
|
{ key_type: defaults_read_type_output.split.last, key_value: defaults_read_output.strip }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def plutil_format_map
|
||||||
|
{ 'us-ascii' => 'xml1',
|
||||||
|
'text/xml' => 'xml1',
|
||||||
|
'utf-8' => 'xml1',
|
||||||
|
'binary' => 'binary1' }
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def defaults_executable
|
def defaults_executable
|
||||||
|
@ -92,5 +99,6 @@ module MacOS
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
Chef::Recipe.include(MacOS::PlistHelpers)
|
Chef::Recipe.include MacOS::PlistHelpers
|
||||||
Chef::Resource.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]
|
@keychain == '' ? [@security_cmd, 'add-certificates', @cert] : [@security_cmd, 'add-certificates', @cert, '-k', @keychain]
|
||||||
end
|
end
|
||||||
|
|
||||||
def import(cert_passwd)
|
def import(cert_passwd, apps)
|
||||||
@keychain == '' ? [@security_cmd, 'import', @cert, '-P', cert_passwd] : [@security_cmd, 'import', @cert, '-P', cert_passwd, '-k', @keychain]
|
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
|
end
|
||||||
|
|
||||||
def install_certificate(cert_passwd)
|
def install_certificate(cert_passwd, apps)
|
||||||
valid_pkcs12 = ['.p12', '.pfx']
|
valid_pkcs12 = ['.p12', '.pfx']
|
||||||
valid_certs = ['.der', '.crt', '.cer']
|
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 }
|
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 }
|
elsif valid_certs.any? { |extension| ::File.extname(@cert).match? extension }
|
||||||
add_certificates
|
add_certificates
|
||||||
else
|
else
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
module MacOS
|
module MacOS
|
||||||
module SystemSetup
|
module SystemSetup
|
||||||
def running_in_a_vm?
|
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
|
end
|
||||||
|
|
||||||
def power_button_model?
|
def power_button_model?
|
||||||
|
|
|
@ -5,7 +5,7 @@ license 'MIT'
|
||||||
description 'Resources for configuring and provisioning macOS'
|
description 'Resources for configuring and provisioning macOS'
|
||||||
long_description IO.read(File.join(File.dirname(__FILE__), 'README.md'))
|
long_description IO.read(File.join(File.dirname(__FILE__), 'README.md'))
|
||||||
chef_version '~> 13.0' if respond_to?(:chef_version)
|
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'
|
source_url 'https://github.com/Microsoft/macos-cookbook'
|
||||||
issues_url 'https://github.com/Microsoft/macos-cookbook/issues'
|
issues_url 'https://github.com/Microsoft/macos-cookbook/issues'
|
||||||
|
|
|
@ -3,6 +3,7 @@ resource_name :certificate
|
||||||
property :certfile, String
|
property :certfile, String
|
||||||
property :cert_password, String
|
property :cert_password, String
|
||||||
property :keychain, String
|
property :keychain, String
|
||||||
|
property :apps, Array
|
||||||
|
|
||||||
action_class do
|
action_class do
|
||||||
def keychain
|
def keychain
|
||||||
|
@ -18,6 +19,6 @@ action :install do
|
||||||
end
|
end
|
||||||
|
|
||||||
execute 'install-certificate' do
|
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
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,7 +3,7 @@ resource_name :plist
|
||||||
property :path, String, name_property: true, desired_state: true
|
property :path, String, name_property: true, desired_state: true
|
||||||
property :entry, String, desired_state: true
|
property :entry, String, desired_state: true
|
||||||
property :value, [TrueClass, FalseClass, String, Integer, Float], 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|
|
load_current_value do |desired|
|
||||||
current_value_does_not_exist! unless ::File.exist? desired.path
|
current_value_does_not_exist! unless ::File.exist? desired.path
|
||||||
|
@ -52,17 +52,12 @@ EOF
|
||||||
|
|
||||||
converge_if_changed :encoding do
|
converge_if_changed :encoding do
|
||||||
converge_by 'change format' 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
|
execute ['/usr/bin/plutil', '-convert', plutil_format_map[new_resource.encoding], new_resource.path] do
|
||||||
action :run
|
action :run
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
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
|
converge_by "set #{new_resource.preference} to #{new_resource.setting}" do
|
||||||
set_pref = ['-set', new_resource.preference.to_s].join('')
|
set_pref = ['-set', new_resource.preference.to_s].join('')
|
||||||
execute ['/usr/sbin/systemsetup', set_pref, new_resource.setting]
|
execute ['/usr/sbin/systemsetup', set_pref, new_resource.setting]
|
||||||
|
ruby_block 'sleep one second' do
|
||||||
|
block do
|
||||||
|
sleep 1
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,7 +7,7 @@ property :ios_simulators, Array
|
||||||
|
|
||||||
action :setup do
|
action :setup do
|
||||||
chef_gem 'xcode-install' do
|
chef_gem 'xcode-install' do
|
||||||
options('--no-document')
|
options('--no-document --no-user-install')
|
||||||
end
|
end
|
||||||
|
|
||||||
CREDENTIALS_DATA_BAG = data_bag_item(:credentials, :apple_id)
|
CREDENTIALS_DATA_BAG = data_bag_item(:credentials, :apple_id)
|
||||||
|
|
|
@ -39,13 +39,19 @@ describe MacOS::SecurityCommand do
|
||||||
|
|
||||||
context 'importing a certificate (.p12)' do
|
context 'importing a certificate (.p12)' do
|
||||||
it 'imports a specified .p12 certificate file' 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
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'importing a certificate (.p12)' do
|
context 'importing a certificate (.p12)' do
|
||||||
it 'imports a specified .p12 certificate file to a specified keychain' 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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -63,13 +69,13 @@ describe MacOS::SecurityCommand do
|
||||||
|
|
||||||
context 'installing a certificate (.p12)' do
|
context 'installing a certificate (.p12)' do
|
||||||
it 'installs a specified .p12 certificate file' 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
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'installing a certificate (.cer)' do
|
context 'installing a certificate (.cer)' do
|
||||||
it 'adds a specified .cer certificate file' 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
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,13 +1,121 @@
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
describe 'macos::keep_awake' do
|
include MacOS::SystemSetup
|
||||||
context 'When all attributes are default, on macOS High Sierra 10.13' do
|
|
||||||
let(:chef_run) { ChefSpec::SoloRunner.new.converge(described_recipe) }
|
|
||||||
|
|
||||||
it 'converges successfully' do
|
shared_context 'when running on bare metal' do
|
||||||
allow_any_instance_of(Chef::Resource).to receive(:running_in_a_vm?).and_return(false)
|
shared_examples 'setting metal-specific power preferences' do
|
||||||
allow_any_instance_of(Chef::Resource).to receive(:power_button_model?).and_return(false)
|
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
|
expect { chef_run }.to_not raise_error
|
||||||
end
|
end
|
||||||
end
|
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'
|
certfile '/Users/vagrant/Test.p12'
|
||||||
cert_password 'test'
|
cert_password 'test'
|
||||||
keychain '/Users/vagrant/Library/Keychains/login.keychain'
|
keychain '/Users/vagrant/Library/Keychains/login.keychain'
|
||||||
|
apps ['/Applications/Mail.app', '/Applications/App Store.app']
|
||||||
action :install
|
action :install
|
||||||
end
|
end
|
||||||
|
|
|
@ -22,7 +22,7 @@ control 'new macOS users' do
|
||||||
its('groups') { should_not include 'admin' }
|
its('groups') { should_not include 'admin' }
|
||||||
end
|
end
|
||||||
|
|
||||||
describe groups.where { name == 'admin'} do
|
describe groups.where { name == 'admin' } do
|
||||||
it { should exist }
|
it { should exist }
|
||||||
its('gids') { should include 80 }
|
its('gids') { should include 80 }
|
||||||
end
|
end
|
||||||
|
|
Загрузка…
Ссылка в новой задаче