Properly handle held packages on dpkg-flavored OS (#2087)

* check the proper field for dpkg installation state fixes #2006

Signed-off-by: Mathieu Sauve-Frankel <msf@kisoku.net>

* Properly handle held packages on dpkg-flavored OS

InSpec was looking at the wrong field in `dpkg -s` output to determine
whether a package was installed or not. An installed, held package was
incorrectly reported as uninstalled.

This adds the proper unit tests and also adds a `be_held` matcher.

Thanks to @kisoku for the initial work in #2007.

Signed-off-by: Adam Leff <adam@leff.co>
This commit is contained in:
Adam Leff 2017-08-18 11:29:23 -04:00 committed by Dominik Richter
parent 88ee548551
commit 367d42fb3a
5 changed files with 46 additions and 3 deletions

View file

@ -28,6 +28,13 @@ This InSpec audit resource has the following matchers:
<%= partial "/shared/matcher_be" %>
### be_held
The `be_held` matcher tests if the named package is "held". On dpkg platforms, a "held" package
will not be upgraded to a later version.
it { should be_held }
### be_installed
The `be_installed` matcher tests if the named package is installed on the system:

View file

@ -15,6 +15,7 @@ module Inspec::Resources
example "
describe package('nginx') do
it { should be_installed }
it { should_not be_held } # for dpkg platforms that support holding a version from being upgraded
its('version') { should eq 1.9.5 }
end
"
@ -56,6 +57,13 @@ module Inspec::Resources
info[:installed] == true
end
# returns true it the package is held (if the OS supports it)
def held?(_provider = nil, _version = nil)
return false if info.nil?
return false unless info.key?(:held)
info[:held] == true
end
# returns the package description
def info
return @cache if !@cache.nil?
@ -107,11 +115,14 @@ module Inspec::Resources
assignment_regex: /^\s*([^:]*?)\s*:\s*(.*?)\s*$/,
multiple_values: false,
).params
# If the package is installed, Status is "install ok installed"
# If the package is installed and marked hold, Status is "hold ok installed"
# If the package is removed and not purged, Status is "deinstall ok config-files" with exit_status 0
# If the package is purged cmd fails with non-zero exit status
{
name: params['Package'],
installed: params['Status'].split(' ').first == 'install',
installed: params['Status'].split(' ')[2] == 'installed',
held: params['Status'].split(' ')[0] == 'hold',
version: params['Version'],
type: 'deb',
}

View file

@ -189,6 +189,7 @@ class MockLoader
'/sbin/auditctl -s' => cmd.call('auditctl-s'),
'yum -v repolist all' => cmd.call('yum-repolist-all'),
'dpkg -s curl' => cmd.call('dpkg-s-curl'),
'dpkg -s held-package' => cmd.call('dpkg-s-held-package'),
'rpm -qia curl' => cmd.call('rpm-qia-curl'),
'rpm -qia --dbpath /var/lib/fake_rpmdb curl' => cmd.call('rpm-qia-curl'),
'rpm -qia --dbpath /var/lib/rpmdb_does_not_exist curl' => cmd_exit_1,

View file

@ -0,0 +1,14 @@
Package: held-package
Status: hold ok installed
Priority: optional
Section: web
Installed-Size: 306
Maintainer: Fake User <fake@user.biz)
Architecture: amd64
Multi-Arch: foreign
Version: 1.2.3-1
Depends: libc6 (>= 2.17), libcurl3 (= 7.35.0-1ubuntu2), zlib1g (>= 1:1.1.4)
Description: Totally a fake package
Can you believe this is fake?
I can.
Homepage: http://chef.io

View file

@ -18,16 +18,26 @@ describe 'Inspec::Resources::Package' do
# ubuntu
it 'verify ubuntu package parsing' do
resource = MockLoader.new(:ubuntu1404).load_resource('package', 'curl')
pkg = { name: 'curl', installed: true, version: '7.35.0-1ubuntu2', type: 'deb' }
pkg = { name: 'curl', installed: true, held: false, version: '7.35.0-1ubuntu2', type: 'deb' }
_(resource.installed?).must_equal true
_(resource.held?).must_equal false
_(resource.version).must_equal '7.35.0-1ubuntu2'
_(resource.info).must_equal pkg
end
it 'verify ubuntu package which is held' do
resource = MockLoader.new(:ubuntu1404).load_resource('package', 'held-package')
pkg = { name: 'held-package', installed: true, held: true, version: '1.2.3-1', type: 'deb' }
_(resource.installed?).must_equal true
_(resource.held?).must_equal true
_(resource.version).must_equal '1.2.3-1'
_(resource.info).must_equal pkg
end
# mint
it 'verify mint package parsing' do
resource = MockLoader.new(:mint17).load_resource('package', 'curl')
pkg = { name: 'curl', installed: true, version: '7.35.0-1ubuntu2', type: 'deb' }
pkg = { name: 'curl', installed: true, held: false, version: '7.35.0-1ubuntu2', type: 'deb' }
_(resource.installed?).must_equal true
_(resource.version).must_equal '7.35.0-1ubuntu2'
_(resource.info).must_equal pkg