mirror of
https://github.com/inspec/inspec
synced 2024-11-10 15:14:23 +00:00
577688a3a0
Many of the resources are named as a top-level class with a fairly generic class name, such as "OS". This causes an issue specifically with kitchen-google which depends on a gem which depends on the "os" gem which itself defines an OS class with a different superclass. This prevents users from using TK, Google Compute, and Inspec without this fix. Some mocked commands had their digest changed as well due to the new indentation, specifically in the User and RegistryKey classes. I strongly recommend viewing this diff with `git diff --ignore-space-change` to see the *real* changes. :)
306 lines
14 KiB
Ruby
306 lines
14 KiB
Ruby
# encoding: utf-8
|
||
# author: Dominik Richter
|
||
# author: Christoph Hartmann
|
||
|
||
require 'minitest/autorun'
|
||
require 'minitest/spec'
|
||
require 'mocha/setup'
|
||
|
||
require 'simplecov'
|
||
SimpleCov.start do
|
||
add_filter '/test/'
|
||
add_group 'Resources', 'lib/resources'
|
||
add_group 'Matchers', 'lib/matchers'
|
||
add_group 'Backends', 'lib/inspec/backend'
|
||
end
|
||
|
||
require 'fileutils'
|
||
require 'pathname'
|
||
require 'tempfile'
|
||
require 'tmpdir'
|
||
require 'zip'
|
||
|
||
require 'utils/base_cli'
|
||
require 'inspec/fetcher'
|
||
require 'inspec/source_reader'
|
||
require 'inspec/resource'
|
||
require 'inspec/backend'
|
||
require 'inspec/profile'
|
||
require 'inspec/runner'
|
||
require 'inspec/runner_mock'
|
||
|
||
class MockLoader
|
||
# collects emulation operating systems
|
||
OPERATING_SYSTEMS = {
|
||
arch: { family: 'arch', release: nil, arch: nil },
|
||
centos5: { family: 'redhat', release: '5.11', arch: 'x86_64' },
|
||
centos6: { family: 'redhat', release: '6.6', arch: 'x86_64' },
|
||
centos7: { family: 'redhat', release: '7.1.1503', arch: 'x86_64' },
|
||
debian6: { family: 'debian', release: '6', arch: 'x86_64' },
|
||
debian7: { family: 'debian', release: '7', arch: 'x86_64' },
|
||
debian8: { family: 'debian', release: '8', arch: 'x86_64' },
|
||
freebsd9: { family: 'freebsd', release: '9', arch: 'amd64' },
|
||
freebsd10: { family: 'freebsd', release: '10', arch: 'amd64' },
|
||
osx104: { family: 'darwin', release: '10.10.4', arch: nil, name: 'mac_os_x' },
|
||
ubuntu1204: { family: 'ubuntu', release: '12.04', arch: 'x86_64' },
|
||
ubuntu1404: { family: 'ubuntu', release: '14.04', arch: 'x86_64' },
|
||
ubuntu1504: { family: 'ubuntu', release: '15.04', arch: 'x86_64' },
|
||
windows: { family: 'windows', release: nil, arch: nil },
|
||
wrlinux: { family: 'wrlinux', release: '7.0(3)I2(2)', arch: 'x86_64' },
|
||
solaris11: { family: "solaris", release: '11', arch: 'i386'},
|
||
solaris10: { family: "solaris", release: '10', arch: 'i386'},
|
||
undefined: { family: nil, release: nil, arch: nil },
|
||
}
|
||
|
||
# pass the os identifier to emulate a specific operating system
|
||
def initialize(os = nil)
|
||
# selects operating system
|
||
@os = OPERATING_SYSTEMS[os || :ubuntu1404]
|
||
end
|
||
|
||
def backend
|
||
return @backend if defined?(@backend)
|
||
scriptpath = ::File.realpath(::File.dirname(__FILE__))
|
||
|
||
# create mock backend
|
||
@backend = Inspec::Backend.create({ backend: :mock })
|
||
mock = @backend.backend
|
||
|
||
# set os emulation
|
||
mock.mock_os(@os)
|
||
|
||
# create all mock files
|
||
local = Train.create('local').connection
|
||
mockfile = lambda { |x|
|
||
path = ::File.join(scriptpath, '/unit/mock/files', x)
|
||
local.file(path)
|
||
}
|
||
mockdir = lambda { |x|
|
||
md = Object.new
|
||
|
||
class << md
|
||
attr_accessor :isdir
|
||
end
|
||
md.isdir = x
|
||
|
||
def md.directory?
|
||
isdir
|
||
end
|
||
md
|
||
}
|
||
|
||
mock.files = {
|
||
'/proc/net/bonding/bond0' => mockfile.call('bond0'),
|
||
'/etc/ssh/ssh_config' => mockfile.call('ssh_config'),
|
||
'/etc/ssh/sshd_config' => mockfile.call('sshd_config'),
|
||
'/etc/passwd' => mockfile.call('passwd'),
|
||
'/etc/shadow' => mockfile.call('shadow'),
|
||
'/etc/ntp.conf' => mockfile.call('ntp.conf'),
|
||
'/etc/login.defs' => mockfile.call('login.defs'),
|
||
'/etc/security/limits.conf' => mockfile.call('limits.conf'),
|
||
'/etc/inetd.conf' => mockfile.call('inetd.conf'),
|
||
'/etc/group' => mockfile.call('etcgroup'),
|
||
'/etc/audit/auditd.conf' => mockfile.call('auditd.conf'),
|
||
'/etc/mysql/my.cnf' => mockfile.call('mysql.conf'),
|
||
'/etc/mysql/mysql2.conf' => mockfile.call('mysql2.conf'),
|
||
'kitchen.yml' => mockfile.call('kitchen.yml'),
|
||
'example.csv' => mockfile.call('example.csv'),
|
||
'policyfile.lock.json' => mockfile.call('policyfile.lock.json'),
|
||
'/sys/class/net/br0/bridge' => mockdir.call(true),
|
||
'rootwrap.conf' => mockfile.call('rootwrap.conf'),
|
||
'/etc/apache2/apache2.conf' => mockfile.call('apache2.conf'),
|
||
'/etc/apache2/ports.conf' => mockfile.call('ports.conf'),
|
||
'/etc/apache2/conf-enabled/serve-cgi-bin.conf' => mockfile.call('serve-cgi-bin.conf'),
|
||
'/etc/xinetd.conf' => mockfile.call('xinetd.conf'),
|
||
'/etc/xinetd.d' => mockfile.call('xinetd.d'),
|
||
'/etc/xinetd.d/chargen-stream' => mockfile.call('xinetd.d_chargen-stream'),
|
||
'/etc/xinetd.d/chargen-dgram' => mockfile.call('xinetd.d_chargen-dgram'),
|
||
}
|
||
|
||
# create all mock commands
|
||
cmd = lambda {|x|
|
||
stdout = ::File.read(::File.join(scriptpath, '/unit/mock/cmd/'+x))
|
||
mock.mock_command('', stdout, '', 0)
|
||
}
|
||
|
||
empty = lambda {
|
||
mock.mock_command('', '', '', 0)
|
||
}
|
||
|
||
mock.commands = {
|
||
'ps aux' => cmd.call('ps-aux'),
|
||
'Get-Content win_secpol.cfg' => cmd.call('secedit-export'),
|
||
'secedit /export /cfg win_secpol.cfg' => cmd.call('success'),
|
||
'Remove-Item win_secpol.cfg' => cmd.call('success'),
|
||
'env' => cmd.call('env'),
|
||
'$Env:PATH' => cmd.call('$env-PATH'),
|
||
# registry key test (winrm 1.6.0, 1.6.1)
|
||
'2790db1e88204a073ed7fd3493f5445e5ce531afd0d2724a0e36c17110c535e6' => cmd.call('reg_schedule'),
|
||
'25a1a38fafc289a646d30f7aa966ce0901c267798f47abf2f9440e27d31a5b7d' => cmd.call('reg_schedule'),
|
||
'Auditpol /get /subcategory:\'User Account Management\' /r' => cmd.call('auditpol'),
|
||
'/sbin/auditctl -l' => cmd.call('auditctl'),
|
||
'/sbin/auditctl -s' => cmd.call('auditctl-s'),
|
||
'yum -v repolist all' => cmd.call('yum-repolist-all'),
|
||
'dpkg -s curl' => cmd.call('dpkg-s-curl'),
|
||
'rpm -qia curl' => cmd.call('rpm-qia-curl'),
|
||
'pacman -Qi curl' => cmd.call('pacman-qi-curl'),
|
||
'gem list --local -a -q ^rubocop$' => cmd.call('gem-list-local-a-q-rubocop'),
|
||
'npm ls -g --json bower' => cmd.call('npm-ls-g--json-bower'),
|
||
'pip show jinja2' => cmd.call('pip-show-jinja2'),
|
||
"Get-Package -Name 'Mozilla Firefox' | ConvertTo-Json" => cmd.call('get-package-firefox'),
|
||
"Get-Package -Name 'Ruby 2.1.6-p336-x64' | ConvertTo-Json" => cmd.call('get-package-ruby'),
|
||
"New-Object -Type PSObject | Add-Member -MemberType NoteProperty -Name Service -Value (Get-Service -Name dhcp| Select-Object -Property Name, DisplayName, Status) -PassThru | Add-Member -MemberType NoteProperty -Name WMI -Value (Get-WmiObject -Class Win32_Service | Where-Object {$_.Name -eq 'dhcp' -or $_.DisplayName -eq 'dhcp'} | Select-Object -Property StartMode) -PassThru | ConvertTo-Json" => cmd.call('get-service-dhcp'),
|
||
"Get-WindowsFeature | Where-Object {$_.Name -eq 'dhcp' -or $_.DisplayName -eq 'dhcp'} | Select-Object -Property Name,DisplayName,Description,Installed,InstallState | ConvertTo-Json" => cmd.call('get-windows-feature'),
|
||
'lsmod' => cmd.call('lsmod'),
|
||
'/sbin/sysctl -q -n net.ipv4.conf.all.forwarding' => cmd.call('sbin_sysctl'),
|
||
# ports on windows
|
||
'Get-NetTCPConnection | Select-Object -Property State, Caption, Description, LocalAddress, LocalPort, RemoteAddress, RemotePort, DisplayName, Status | ConvertTo-Json' => cmd.call('get-net-tcpconnection'),
|
||
# lsof formatted list of ports (should be quite cross platform)
|
||
'lsof -nP -i -FpctPn' => cmd.call('lsof-nP-i-FpctPn'),
|
||
# ports on linux
|
||
'netstat -tulpen' => cmd.call('netstat-tulpen'),
|
||
# ports on freebsd
|
||
'sockstat -46l' => cmd.call('sockstat'),
|
||
# packages on windows
|
||
"Get-WmiObject -Class Win32_Product | Where-Object {$_.Name -eq 'Microsoft Visual C++ 2008 Redistributable - x64 9.0.30729.6161'} | Select-Object -Property Name,Version,Vendor,PackageCode,Caption,Description | ConvertTo-Json" => cmd.call('win32_product'),
|
||
# service status upstart on ubuntu
|
||
'initctl status ssh' => cmd.call('initctl-status-ssh'),
|
||
# service config for upstart on ubuntu
|
||
'initctl show-config ssh' => cmd.call('initctl-show-config-ssh'),
|
||
# upstart version on ubuntu
|
||
'initctl --version' => cmd.call('initctl--version'),
|
||
# show ssh service Centos 7
|
||
'systemctl show --all sshd' => cmd.call('systemctl-show-all-sshd'),
|
||
'/path/to/systemctl show --all sshd' => cmd.call('systemctl-show-all-sshd'),
|
||
# services on macos
|
||
'launchctl list' => cmd.call('launchctl-list'),
|
||
# services on freebsd 10
|
||
'service -e' => cmd.call('service-e'),
|
||
'service sendmail onestatus' => cmd.call('service-sendmail-onestatus'),
|
||
# services for system 5 e.g. centos6, debian 6
|
||
'service sshd status' => cmd.call('service-sshd-status'),
|
||
'find /etc/rc*.d -name S*' => cmd.call('find-etc-rc-d-name-S'),
|
||
'ls -1 /etc/init.d/' => cmd.call('ls-1-etc-init.d'),
|
||
# user information for linux
|
||
'id root' => cmd.call('id-root'),
|
||
'getent passwd root' => cmd.call('getent-passwd-root'),
|
||
'chage -l root' => cmd.call('chage-l-root'),
|
||
# user information for ldap test
|
||
'id jfolmer' => cmd.call('id-jfolmer'),
|
||
'getent passwd jfolmer' => cmd.call('getent-passwd-jfolmer'),
|
||
'chage -l jfolmer' => cmd.call('chage-l-root'),
|
||
# user info for mac
|
||
'id chartmann' => cmd.call('id-chartmann'),
|
||
'dscl -q . -read /Users/chartmann NFSHomeDirectory PrimaryGroupID RecordName UniqueID UserShell' => cmd.call('dscl'),
|
||
# user info for freebsd
|
||
'pw usershow root -7' => cmd.call('pw-usershow-root-7'),
|
||
# user info for windows (winrm 1.6.0, 1.6.1)
|
||
'650b6b72a66316418b25421a54afe21a230704558082914c54711904bb10e370' => cmd.call('GetUserAccount'),
|
||
'174686f0441b8dd387b35cf1cbeed3f98441544351de5d8fb7b54f655e75583f' => cmd.call('GetUserAccount'),
|
||
# group info for windows
|
||
'Get-WmiObject Win32_Group | Select-Object -Property Caption, Domain, Name, SID, LocalAccount | ConvertTo-Json' => cmd.call('GetWin32Group'),
|
||
# network interface
|
||
'9e80f048a1af5a0f6ab8a465e46ea5ed5ba6587e9b5e54a7a0c0a1a02bb6f663' => cmd.call('find-net-interface'),
|
||
'c33821dece09c8b334e03a5bb9daefdf622007f73af4932605e758506584ec3f' => empty.call,
|
||
'Get-NetAdapter | Select-Object -Property Name, InterfaceDescription, Status, State, MacAddress, LinkSpeed, ReceiveLinkSpeed, TransmitLinkSpeed, Virtual | ConvertTo-Json' => cmd.call('Get-NetAdapter'),
|
||
# bridge on linux
|
||
'ls -1 /sys/class/net/br0/brif/' => cmd.call('ls-sys-class-net-br'),
|
||
# bridge on Windows
|
||
'Get-NetAdapterBinding -ComponentID ms_bridge | Get-NetAdapter | Select-Object -Property Name, InterfaceDescription | ConvertTo-Json' => cmd.call('get-netadapter-binding-bridge'),
|
||
# host for Windows
|
||
'Resolve-DnsName –Type A microsoft.com | ConvertTo-Json' => cmd.call('Resolve-DnsName'),
|
||
'Test-NetConnection -ComputerName microsoft.com | Select-Object -Property ComputerName, PingSucceeded | ConvertTo-Json' => cmd.call('Test-NetConnection'),
|
||
# host for Linux
|
||
'getent hosts example.com' => cmd.call('getent-hosts-example.com'),
|
||
'ping -w 1 -c 1 example.com' => cmd.call('ping-example.com'),
|
||
# apt
|
||
"find /etc/apt/ -name *.list -exec sh -c 'cat {} || echo -n' \\;" => cmd.call('etc-apt'),
|
||
# iptables
|
||
'iptables -S' => cmd.call('iptables-s'),
|
||
# apache_conf
|
||
'find /etc/apache2/ports.conf -maxdepth 1 -type f' => cmd.call('find-apache2-ports-conf'),
|
||
'find /etc/apache2/conf-enabled/*.conf -maxdepth 1 -type f' => cmd.call('find-apache2-conf-enabled'),
|
||
# mount
|
||
"mount | grep -- ' on /'" => cmd.call("mount"),
|
||
"mount | grep -- ' on /mnt/iso-disk'" => cmd.call("mount-multiple"),
|
||
# solaris 10 package manager
|
||
'pkginfo -l SUNWzfsr' => cmd.call('pkginfo-l-SUNWzfsr'),
|
||
# solaris 11 package manager
|
||
'pkg info system/file-system/zfs' => cmd.call('pkg-info-system-file-system-zfs'),
|
||
# port netstat on solaris 10 & 11
|
||
'netstat -an -f inet -f inet6' => cmd.call('s11-netstat-an-finet-finet6'),
|
||
# xinetd configuration
|
||
'find /etc/xinetd.d -type f' => cmd.call('find-xinetd.d'),
|
||
}
|
||
|
||
@backend
|
||
end
|
||
|
||
# loads a resource class and instantiates the class with the given arguments
|
||
def load_resource(resource, *args)
|
||
# initialize resource with backend and parameters
|
||
@resource_class = Inspec::Resource.registry[resource]
|
||
@resource = @resource_class.new(backend, resource, *args)
|
||
end
|
||
|
||
def self.mock_os(resource, name)
|
||
osinfo = OPERATING_SYSTEMS[name] ||
|
||
fail("Can't find operating system to mock: #{name}")
|
||
resource.inspec.backend.mock_os(osinfo)
|
||
end
|
||
|
||
def self.mock_command(resource, cmd, res = {})
|
||
resource.inspec.backend
|
||
.mock_command(cmd, res[:stdout], res[:stderr], res[:exit_status])
|
||
end
|
||
|
||
def self.home
|
||
File.join(File.dirname(__FILE__), 'unit')
|
||
end
|
||
|
||
def self.profile_path(name)
|
||
dst = name
|
||
dst = "#{home}/mock/profiles/#{name}" unless name.start_with?(home)
|
||
dst
|
||
end
|
||
|
||
def self.load_profile(name, opts = {})
|
||
opts[:test_collector] = Inspec::RunnerMock.new
|
||
Inspec::Profile.for_target(profile_path(name), opts)
|
||
end
|
||
|
||
def self.profile_tgz(name)
|
||
path = File.join(home, 'mock', 'profiles', name)
|
||
dst = File.join(Dir.tmpdir, Dir::Tmpname.make_tmpname(name, '.tar.gz'))
|
||
|
||
# generate relative paths
|
||
files = Dir.glob("#{path}/**/*")
|
||
relatives = files.map { |e| Pathname.new(e).relative_path_from(Pathname.new(path)).to_s }
|
||
|
||
require 'inspec/archive/tar'
|
||
tag = Inspec::Archive::TarArchiveGenerator.new
|
||
tag.archive(path, relatives, dst)
|
||
|
||
dst
|
||
end
|
||
|
||
def self.profile_zip(name, opts = {})
|
||
path = File.join(home, 'mock', 'profiles', name)
|
||
dst = File.join(Dir.tmpdir, Dir::Tmpname.make_tmpname(name, '.zip'))
|
||
|
||
# rubyzip only works relative paths
|
||
files = Dir.glob("#{path}/**/*")
|
||
relatives = files.map { |e| Pathname.new(e).relative_path_from(Pathname.new(path)).to_s }
|
||
|
||
require 'inspec/archive/zip'
|
||
zag = Inspec::Archive::ZipArchiveGenerator.new
|
||
zag.archive(path, relatives, dst)
|
||
|
||
dst
|
||
end
|
||
end
|
||
|
||
def load_resource(*args)
|
||
m = MockLoader.new(:ubuntu1404)
|
||
m.send('load_resource', *args)
|
||
end
|