From 49ee29ce9ee371992225f5393f0f89811afdaeab Mon Sep 17 00:00:00 2001 From: Felipe Zipitria Date: Sun, 8 Dec 2019 19:18:52 -0500 Subject: [PATCH] feat(unattended): add newer options from upstream * upstream has new options now included in formula * updated pillar.example with new options * inspec tests for this new options are in place Also: * tests are included in travis Signed-off-by: Felipe Zipitria --- .travis.yml | 20 +++++--- apt/templates/unattended_config.jinja | 39 +++++++++++++-- kitchen.yml | 16 ++++++ pillar.example | 16 +++++- test/integration/unattended/README.md | 50 +++++++++++++++++++ .../unattended/controls/unattended_spec.rb | 46 +++++++++++++++++ test/integration/unattended/inspec.yml | 11 ++++ test/salt/pillar/unattended.pillar.sls | 33 ++++++++++++ 8 files changed, 220 insertions(+), 11 deletions(-) create mode 100644 test/integration/unattended/README.md create mode 100644 test/integration/unattended/controls/unattended_spec.rb create mode 100644 test/integration/unattended/inspec.yml create mode 100644 test/salt/pillar/unattended.pillar.sls diff --git a/.travis.yml b/.travis.yml index 326bb65..807f475 100644 --- a/.travis.yml +++ b/.travis.yml @@ -58,14 +58,22 @@ jobs: ## Define the rest of the matrix based on Kitchen testing # Make sure the instances listed below match up with # the `platforms` defined in `kitchen.yml` - - env: INSTANCE=repositories-debian-10-master-py3 - - env: INSTANCE=preferences-debian-10-master-py3 - # - env: INSTANCE=repositories-ubuntu-1804-master-py3 + # - env: INSTANCE=repositories-debian-10-master-py3 + # - env: INSTANCE=preferences-debian-10-master-py3 + # - env: INSTANCE=unattended-debian-10-master-py3 + - env: INSTANCE=debian-10-master-py3 + - env: INSTANCE=repositories-ubuntu-1804-master-py3 # - env: INSTANCE=preferences-ubuntu-1804-master-py3 - - env: INSTANCE=repositories-debian-9-2019-2-py3 + # - env: INSTANCE=unattended-ubuntu-1804-master-py3 + # - env: INSTANCE=ubuntu-1804-master-py3 + # - env: INSTANCE=repositories-debian-9-2019-2-py3 - env: INSTANCE=preferences-debian-9-2019-2-py3 - - env: INSTANCE=repositories-ubuntu-1804-2019-2-py3 - - env: INSTANCE=preferences-ubuntu-1804-2019-2-py3 + # - env: INSTANCE=unattended-debian-9-2019-2-py3 + # - env: INSTANCE=debian-9-2019-2-py3 + # - env: INSTANCE=repositories-ubuntu-1804-2019-2-py3 + # - env: INSTANCE=preferences-ubuntu-1804-2019-2-py3 + - env: INSTANCE=unattended-ubuntu-1804-2019-2-py3 + # - env: INSTANCE=ubuntu-1804-2019-2-py3 ## Define the release stage that runs `semantic-release` - stage: 'release' diff --git a/apt/templates/unattended_config.jinja b/apt/templates/unattended_config.jinja index ba97d00..3530b40 100644 --- a/apt/templates/unattended_config.jinja +++ b/apt/templates/unattended_config.jinja @@ -1,3 +1,8 @@ +######################################################################## +# File managed by Salt at <{{ source }}>. +# Your changes will be overwritten. +######################################################################## + {% set apt = pillar.get('apt', {}) -%} {% set unattended = apt.get('unattended', {}) -%} {% set allowed_origins = unattended.get('allowed_origins', ['${distro_id}:${distro_codename}-security']) -%} @@ -6,12 +11,28 @@ {% set auto_fix_interrupted_dpkg = unattended.get('auto_fix_interrupted_dpkg', 'true') -%} {% set minimal_steps = unattended.get('minimal_steps', 'false') -%} {% set install_on_shutdown = unattended.get('install_on_shutdown', 'false') -%} -{% set mail = unattended.get('mail', 'root') -%} +{% set mail = unattended.get('mail', '') -%} +{% set sender = unattended.get('sender', 'root') -%} {% set mail_only_on_error = unattended.get('mail_only_on_error', 'false') -%} -{% set remove_unused_dependencies = unattended.get('remove_unused_dependencies', 'true') -%} +{% set mail_report = unattended.get('mail_report', 'on-change') -%} +{% if mail_only_on_error -%} +{% set mail_report = 'only-on-error' -%} +{% endif -%} +{% if mail_report not in ['always', 'only-on-error', 'on-change'] -%} +{{ raise('apt-formula: mail_report should be one of "always", "only-on-error" or "on-change".') }} +{% endif -%} +{% set remove_unused_dependencies = unattended.get('remove_unused_dependencies', 'false') -%} +{% set remove_new_unused_dependencies = unattended.get('remove_new_unused_dependencies', 'true') -%} {% set automatic_reboot = unattended.get('automatic_reboot', 'false') -%} {% set automatic_reboot_time = unattended.get('automatic_reboot_time', 'now') -%} {% set dl_limit = unattended.get('dl_limit', '0') -%} +{% set syslog_enable = unattended.get('syslog_enable', 'false') -%} +{% set syslog_facility = unattended.get('syslog_facility', 'daemon') -%} +{% set package_whitelist_strict = unattended.get('package_whitelist_strict', 'false') -%} +{% set keep_debs_after_install = unattended.get('keep_debs_after_install', 'false') -%} +{% set dpkg_options = unattended.get('dpkg_options', '') -%} +{% set update_days = unattended.get('update_days', '') -%} + Unattended-Upgrade::Allowed-Origins { {%- for pattern in allowed_origins %} "{{ pattern }}"; @@ -31,8 +52,20 @@ Unattended-Upgrade::AutoFixInterruptedDpkg "{{ auto_fix_interrupted_dpkg }}"; Unattended-Upgrade::MinimalSteps "{{ minimal_steps }}"; Unattended-Upgrade::InstallOnShutdown "{{ install_on_shutdown }}"; Unattended-Upgrade::Mail "{{ mail }}"; -Unattended-Upgrade::MailOnlyOnError "{{ mail_only_on_error }}"; +Unattended-Upgrade::Sender "{{ sender }}"; +Unattended-Upgrade::MailReport "{{ mail_report }}"; Unattended-Upgrade::Remove-Unused-Dependencies "{{ remove_unused_dependencies }}"; +Unattended-Upgrade::Remove-New-Unused-Dependencies "{{ remove_new_unused_dependencies }}"; Unattended-Upgrade::Automatic-Reboot "{{ automatic_reboot }}"; Unattended-Upgrade::Automatic-Reboot-Time "{{ automatic_reboot_time }}"; +Unattended-Upgrade::SyslogEnable "{{ syslog_enable }}"; +Unattended-Upgrade::SyslogFacility "{{ syslog_facility }}"; +Unattended-Upgrade::Keep-Debs-After-Install "{{ keep_debs_after_install }}"; +Unattended-Upgrade::Package-Whitelist-Strict "{{ package_whitelist_strict }}"; +{% if update_days and update_days | is_list -%} +Unattended-Upgrade::Update-Days {"{{ update_days | join('";"') }}"}; +{% endif -%} Acquire::http::Dl-Limit "{{ dl_limit }}"; +{% if dpkg_options -%} +Dpkg::Options {"{{ dpkg_options }}"}; +{% endif -%} diff --git a/kitchen.yml b/kitchen.yml index 8d44ff7..9439176 100644 --- a/kitchen.yml +++ b/kitchen.yml @@ -85,3 +85,19 @@ suites: verifier: inspec_tests: - path: test/integration/preferences + - name: unattended + provisioner: + state_top: + base: + '*': + - apt.unattended + pillars: + top.sls: + base: + '*': + - apt + pillars_from_files: + apt.sls: test/salt/pillar/unattended.pillar.sls + verifier: + inspec_tests: + - path: test/integration/unattended diff --git a/pillar.example b/pillar.example index 7d5bef2..c8c6634 100644 --- a/pillar.example +++ b/pillar.example @@ -48,7 +48,11 @@ apt: minimal_steps: false install_on_shutdown: false mail: root - mail_only_on_error: false + sender: root + # Prefer using `mail_report: 'only-on-error'` over old syntax, + # mail_only_on_error: false` + # allowed values: 'always', 'only-on-error', 'on-change' + mail_report: 'only-on-error' remove_unused_dependencies: true automatic_reboot: false dl_limit: 0 @@ -58,6 +62,12 @@ apt: unattended_upgrade: 1 auto_clean_interval: 7 verbose: 2 + syslog_enable: true + syslog_facility: 'auth' + dpkg_options: '--force-confold' + update_days: ['Mon', 'Fri'] + package_whitelist_strict: false + keep_debs_after_install: false listchanges: profiles: @@ -78,12 +88,14 @@ apt: comps: [main, contrib, non-free] arch: [amd64, i386] type: [binary, source] + key_url: https://ftp-master.debian.org/keys/archive-key-10-security.asc updates: distro: stable-updates url: http://deb.debian.org/debian/ comps: [main, contrib, non-free] + key_url: https://ftp-master.debian.org/keys/archive-key-10.asc raspbian: - distro: wheezy + distro: stable url: http://archive.raspbian.org/raspbian type: [source] key_url: https://archive.raspbian.org/raspbian.public.key diff --git a/test/integration/unattended/README.md b/test/integration/unattended/README.md new file mode 100644 index 0000000..f4c979b --- /dev/null +++ b/test/integration/unattended/README.md @@ -0,0 +1,50 @@ +# InSpec Profile: `unattended` + +This shows the implementation of the `unattended` InSpec [profile](https://github.com/inspec/inspec/blob/master/docs/profiles.md). + +## Verify a profile + +InSpec ships with built-in features to verify a profile structure. + +```bash +$ inspec check unattended +Summary +------- +Location: unattended +Profile: profile +Controls: 4 +Timestamp: 2019-06-24T23:09:01+00:00 +Valid: true + +Errors +------ + +Warnings +-------- +``` + +## Execute a profile + +To run all **supported** controls on a local machine use `inspec exec /path/to/profile`. + +```bash +$ inspec exec unattended +.. + +Finished in 0.0025 seconds (files took 0.12449 seconds to load) +8 examples, 0 failures +``` + +## Execute a specific control from a profile + +To run one control from the profile use `inspec exec /path/to/profile --controls name`. + +```bash +$ inspec exec unattended --controls package +. + +Finished in 0.0025 seconds (files took 0.12449 seconds to load) +1 examples, 0 failures +``` + +See an [example control here](https://github.com/inspec/inspec/blob/master/examples/profile/controls/example.rb). diff --git a/test/integration/unattended/controls/unattended_spec.rb b/test/integration/unattended/controls/unattended_spec.rb new file mode 100644 index 0000000..93ef0e6 --- /dev/null +++ b/test/integration/unattended/controls/unattended_spec.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +audit = command( + "/usr/bin/apt-config dump --no-empty --format '%f=%v%n' Unattended-Upgrade" +).stdout + +options = { + assignment_regex: /^\s*([^=]*?)\s*=\s*(.*?)\s*$/, + multiple_values: true +} + +control 'Apt unattended upgrades' do + title 'should be configured' + + describe file('/etc/apt/apt.conf.d/50unattended-upgrades') do + it { should be_file } + it { should be_owned_by 'root' } + it { should be_grouped_into 'root' } + its('mode') { should cmp '0644' } + end + + describe file('/etc/apt/apt.conf.d/10periodic') do + it { should exist } + it { should be_owned_by 'root' } + it { should be_grouped_into 'root' } + its('mode') { should cmp '0644' } + its(:content) do + should match( + 'APT::Periodic::Enable "1";' + ) + end + end + + describe parse_config(audit, options) do + its('Unattended-Upgrade::Allowed-Origins::') { should include 'origin1' } + its('Unattended-Upgrade::Mail') { should include 'root' } + its('Unattended-Upgrade::MailReport') { should include 'only-on-error' } + its('Unattended-Upgrade::Package-Blacklist::') { should include 'salt-test' } + its('Unattended-Upgrade::Automatic-Reboot') { should include 'False' } + its('Unattended-Upgrade::SyslogEnable') { should include 'True' } + its('Unattended-Upgrade::SyslogFacility') { should include 'auth' } + its('Unattended-Upgrade::Remove-Unused-Dependencies') { should include 'True' } + its('Unattended-Upgrade::Keep-Debs-After-Install') { should include 'False' } + its('Unattended-Upgrade::Update-Days::') { should include 'Wed' } + end +end diff --git a/test/integration/unattended/inspec.yml b/test/integration/unattended/inspec.yml new file mode 100644 index 0000000..c832c01 --- /dev/null +++ b/test/integration/unattended/inspec.yml @@ -0,0 +1,11 @@ +# -*- coding: utf-8 -*- +# vim: ft=yaml +--- +name: unattended +title: apt formula +maintainer: SaltStack Formulas +license: Apache-2.0 +summary: Verify that the apt unattended preferences are configured correctly +supports: + - platform-name: debian + - platform-name: ubuntu diff --git a/test/salt/pillar/unattended.pillar.sls b/test/salt/pillar/unattended.pillar.sls new file mode 100644 index 0000000..b81bb1b --- /dev/null +++ b/test/salt/pillar/unattended.pillar.sls @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +# vim: ft=yaml +--- +apt: + unattended: + allowed_origins: + - origin1 + package_blacklist: + - salt-test + origins_patterns: + - origin=SaltStack + - origin=Debian,archive=stable,label=Debian-Security + auto_fix_interrupted_dpkg: true + minimal_steps: false + install_on_shutdown: false + mail: root + sender: root + mail_report: 'always' + remove_unused_dependencies: true + automatic_reboot: false + dl_limit: 0 + enabled: 1 + update_package_lists: 1 + download_upgradeable_packages: 1 + unattended_upgrade: 1 + auto_clean_interval: 7 + verbose: 2 + syslog_enable: true + syslog_facility: 'auth' + dpkg_options: '--force-confold' + update_days: ['Mon', 'Wed'] + package_whitelist_strict: false + keep_debs_after_install: false