Merge ~ahasenack/ubuntu/+source/ubuntu-advantage-tools:disco-v18-update into ubuntu/+source/ubuntu-advantage-tools:ubuntu/devel

Proposed by Andreas Hasenack on 2019-01-14
Status: Merged
Approved by: Robie Basak on 2019-01-22
Approved revision: 7245b89d3e844a8bf836199330308920dfdc84fe
Merged at revision: 7245b89d3e844a8bf836199330308920dfdc84fe
Proposed branch: ~ahasenack/ubuntu/+source/ubuntu-advantage-tools:disco-v18-update
Merge into: ubuntu/+source/ubuntu-advantage-tools:ubuntu/devel
Diff against target: 994 lines (+705/-12)
16 files modified
README.md (+2/-0)
debian/changelog (+13/-0)
keyrings/ubuntu-securitybenchmarks-keyring.gpg (+0/-0)
modules/service-cc.sh (+75/-0)
modules/service-cis.sh (+75/-0)
modules/service-livepatch.sh (+14/-2)
modules/service.sh (+9/-1)
tests/fakes.py (+20/-0)
tests/test_cc.py (+186/-0)
tests/test_cisaudit.py (+187/-0)
tests/test_livepatch_motd.py (+14/-0)
tests/test_script.py (+20/-0)
tests/testing.py (+26/-1)
ubuntu-advantage (+23/-7)
ubuntu-advantage.1 (+35/-1)
update-motd.d/80-livepatch (+6/-0)
Reviewer Review Type Date Requested Status
Christian Ehrhardt  2019-01-14 Approve on 2019-01-22
Canonical Server Team 2019-01-14 Pending
Review via email: mp+361749@code.launchpad.net

Description of the change

Bileto ticket and ppa: https://bileto.ubuntu.com/#/ticket/3593

The package build runs unit tests, way more comprehensive than the dep8 tests.

This contains all the changes since v17 (available in disco) to what is in the master branch on github, effectively bringing the code in sync. I used git rebase to transport the github commits onto the ubuntu package git repo.

If reviewing each commit, what will complicate things a bit is the revert of "Merge pull request #147 from panlinux/switch-kernel-for-lp".

To post a comment you must log in.
Christian Ehrhardt  (paelzer) wrote :

Considering that the content was already reviewed on the actual project I can't find an issue from the packaging perspective.
So Ack?

I took a look at the rest (high level only) and found a few worth to mention:

I was wondering why the Readme.md didn't get an entry for "Canonical CIS Ubuntu Benchmark Audit tool", but all other elements got one - intentional?

Furthermore "FIPS PPA repository" got changed to "FIPS repository", but all the commoncriteria/CIS entries still call it "PPA repository" that feels a bit inconsistent.

How do you want to continue, do you want to fix up the mentioned issues and/or a deeper review of what was changed upstream?
Or would you want to upload v18 as-is (it is a correctly packaged v18) and work on those things fro v19 at the source?

review: Needs Information
Andreas Hasenack (ahasenack) wrote :

I'll fix that here.

Andreas Hasenack (ahasenack) wrote :

Updated and pushed. There are other mentions of "PPA" elsewhere in the code (status messages, that kind of thing), but changing those is a bigger chunk of work as it also affects tests and UI. I would prefer to change that in a later version. The PPA change you noted in the help output was indeed an oversight and what I did is just a continuation of https://github.com/CanonicalLtd/ubuntu-advantage-script/pull/153, so that's OK to do here.

I also updated the README.md file regarding the CIS audit tool. No URL for it yet, though, so I'll just leave it mentioned.

Christian Ehrhardt  (paelzer) wrote :

Thanks, the packaging and the changes in general LGTM

review: Approve
Andreas Hasenack (ahasenack) wrote :

Tagged and uploaded.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/README.md b/README.md
2index f18d214..b217889 100644
3--- a/README.md
4+++ b/README.md
5@@ -9,6 +9,8 @@ Currently it supports the following:
6 - [Ubuntu Extended Security Maintenance](https://ubuntu.com/esm) archive.
7 - [Canonical Livepatch](https://www.ubuntu.com/server/livepatch) service for managed live kernel patching.
8 - Canonical FIPS 140-2 Certified Modules. Install Configure and Enable FIPS modules.
9+- Canonical Common Criteria EAL2 certification artifacts provisioning
10+- Canonical CIS Ubuntu Benchmark Audit tool
11
12 Run
13
14diff --git a/debian/changelog b/debian/changelog
15index 39ea084..6b4db06 100644
16--- a/debian/changelog
17+++ b/debian/changelog
18@@ -1,3 +1,16 @@
19+ubuntu-advantage-tools (18) disco; urgency=medium
20+
21+ [ Andreas Hasenack ]
22+ * Have ua status cope with the additional livepatch status of running a
23+ kernel that is not supported for livepatches.
24+
25+ [ Vineetha Kamath ]
26+ * Add support to common criteria EAL2 artifacts installation #144
27+ * Add new flag enable-cisaudit to support cis audit
28+ * Add support for disable-cc-provisioning
29+
30+ -- Andreas Hasenack <andreas@canonical.com> Mon, 14 Jan 2019 16:39:31 -0200
31+
32 ubuntu-advantage-tools (17) bionic; urgency=medium
33
34 * New upstream release (LP: #1759280):
35diff --git a/keyrings/ubuntu-cc-keyring.gpg b/keyrings/ubuntu-cc-keyring.gpg
36new file mode 100644
37index 0000000..d00f63f
38Binary files /dev/null and b/keyrings/ubuntu-cc-keyring.gpg differ
39diff --git a/keyrings/ubuntu-securitybenchmarks-keyring.gpg b/keyrings/ubuntu-securitybenchmarks-keyring.gpg
40new file mode 100644
41index 0000000..e69de29
42--- /dev/null
43+++ b/keyrings/ubuntu-securitybenchmarks-keyring.gpg
44diff --git a/modules/service-cc.sh b/modules/service-cc.sh
45new file mode 100644
46index 0000000..2995c33
47--- /dev/null
48+++ b/modules/service-cc.sh
49@@ -0,0 +1,75 @@
50+# shellcheck disable=SC2034,SC2039
51+
52+CC_PROVISIONING_SERVICE_TITLE="Canonical Common Criteria EAL2 Provisioning"
53+CC_PROVISIONING_SUPPORTED_SERIES="xenial"
54+CC_PROVISIONING_SUPPORTED_ARCHS="x86_64 ppc64le s390x"
55+
56+CC_PROVISIONING_REPO_URL="https://private-ppa.launchpad.net/ubuntu-advantage/commoncriteria"
57+CC_PROVISIONING_REPO_KEY_FILE="ubuntu-cc-keyring.gpg"
58+CC_PROVISIONING_REPO_LIST=${CC_PROVISIONING_REPO_LIST:-"/etc/apt/sources.list.d/ubuntu-cc-${SERIES}.list"}
59+CC_PROVISIONING_UBUNTU_COMMONCRITERIA="ubuntu-commoncriteria"
60+
61+cc_provisioning_enable() {
62+ local token="$1"
63+ local result=0
64+
65+ _cc_is_installed || result=$?
66+ if [ $result -eq 0 ]; then
67+ error_msg "Common Criteria artifacts are already installed and available in /usr/lib/common-criteria."
68+ error_exit service_already_enabled
69+ fi
70+
71+ check_token "$CC_PROVISIONING_REPO_URL" "$token"
72+ apt_add_repo "$CC_PROVISIONING_REPO_LIST" "$CC_PROVISIONING_REPO_URL" "$token" \
73+ "${KEYRINGS_DIR}/${CC_PROVISIONING_REPO_KEY_FILE}"
74+ apt_install_package_if_missing_file "$APT_METHOD_HTTPS" apt-transport-https
75+ apt_install_package_if_missing_file "$CA_CERTIFICATES" ca-certificates
76+ echo -n 'Running apt-get update... '
77+ check_result apt_get update
78+ echo 'Ubuntu Common Criteria PPA repository enabled.'
79+
80+ echo -n 'Installing Common Criteria artifacts (this may take a while)... '
81+ # shellcheck disable=SC2086
82+ check_result apt_get install $CC_PROVISIONING_UBUNTU_COMMONCRITERIA
83+
84+ echo "Successfully prepared this machine to host the Common Criteria artifacts."
85+ echo "Please follow instructions in /usr/share/doc/ubuntu-commoncriteria/README to configure EAL2 on the target machine(s)."
86+}
87+
88+cc_provisioning_disable() {
89+ if [ -f "$CC_PROVISIONING_REPO_LIST" ]; then
90+ apt_remove_repo "$CC_PROVISIONING_REPO_LIST" "$CC_PROVISIONING_REPO_URL" \
91+ "$APT_KEYS_DIR/$CC_PROVISIONING_REPO_KEY_FILE"
92+ echo -n 'Running apt-get update... '
93+ check_result apt_get update
94+ echo 'Canonical Common Criteria EAL2 Provisioning Disabled.'
95+ else
96+ echo 'Canonical Common Criteria EAL2 Provisioning is not Enabled.'
97+ fi
98+
99+ if apt_is_package_installed $CC_PROVISIONING_UBUNTU_COMMONCRITERIA; then
100+ check_result apt_get remove $CC_PROVISIONING_UBUNTU_COMMONCRITERIA
101+ echo 'Canonical Common Criteria EAL2 Artifacts Removed.'
102+ fi
103+}
104+
105+cc_provisioning_is_enabled() {
106+ _cc_is_installed
107+}
108+
109+cc_provisioning_print_status() {
110+ echo "cc-provisioning: artifacts are in /usr/lib/common-criteria"
111+}
112+
113+_cc_is_installed() {
114+ apt_is_package_installed ubuntu-commoncriteria && return 0
115+}
116+
117+cc_provisioning_validate_token() {
118+ local token="$1"
119+
120+ if ! validate_user_pass_token "$token"; then
121+ error_msg 'Invalid token, it must be in the form "user:password"'
122+ return 1
123+ fi
124+}
125diff --git a/modules/service-cis.sh b/modules/service-cis.sh
126new file mode 100644
127index 0000000..12fb3e4
128--- /dev/null
129+++ b/modules/service-cis.sh
130@@ -0,0 +1,75 @@
131+# shellcheck disable=SC2034,SC2039
132+
133+CISAUDIT_SERVICE_TITLE="Canonical CIS Benchmark 16.04 Audit Tool"
134+CISAUDIT_SUPPORTED_SERIES="xenial"
135+CISAUDIT_SUPPORTED_ARCHS="x86_64 ppc64le s390x"
136+
137+CISAUDIT_REPO_URL="https://private-ppa.launchpad.net/ubuntu-advantage/security-benchmarks"
138+CISAUDIT_REPO_KEY_FILE="ubuntu-securitybenchmarks-keyring.gpg"
139+CISAUDIT_REPO_LIST=${CISAUDIT_REPO_LIST:-"/etc/apt/sources.list.d/ubuntu-cis-${SERIES}.list"}
140+CISAUDIT_UBUNTU_CISBENCHMARK="ubuntu-cisbenchmark-16.04"
141+
142+cisaudit_enable() {
143+ local token="$1"
144+ local result=0
145+
146+ _cisaudit_is_installed || result=$?
147+ if [ $result -eq 0 ]; then
148+ error_msg "CIS benchmark audit package is already installed and files are available in /usr/share/ubuntu-securityguides/$CISAUDIT_UBUNTU_CISBENCHMARK."
149+ error_exit service_already_enabled
150+ fi
151+
152+ check_token "$CISAUDIT_REPO_URL" "$token"
153+ apt_add_repo "$CISAUDIT_REPO_LIST" "$CISAUDIT_REPO_URL" "$token" \
154+ "${KEYRINGS_DIR}/${CISAUDIT_REPO_KEY_FILE}"
155+ apt_install_package_if_missing_file "$APT_METHOD_HTTPS" apt-transport-https
156+ apt_install_package_if_missing_file "$CA_CERTIFICATES" ca-certificates
157+ echo -n 'Running apt-get update... '
158+ check_result apt_get update
159+ echo 'Ubuntu Security Benchmarks PPA repository enabled.'
160+
161+ echo -n 'Installing CIS audit benchmark tool (this may take a while)... '
162+ # shellcheck disable=SC2086
163+ check_result apt_get install $CISAUDIT_UBUNTU_CISBENCHMARK
164+
165+ echo "Successfully installed the CIS audit tool."
166+ echo "Please follow instructions in /usr/share/doc/$CISAUDIT_UBUNTU_CISBENCHMARK/README to run the CIS audit tool on the target machine(s)."
167+}
168+
169+cisaudit_disable() {
170+ if [ -f "$CISAUDIT_REPO_LIST" ]; then
171+ apt_remove_repo "$CISAUDIT_REPO_LIST" "$CISAUDIT_REPO_URL" \
172+ "$APT_KEYS_DIR/$CISAUDIT_REPO_KEY_FILE"
173+ echo -n 'Running apt-get update... '
174+ check_result apt_get update
175+ echo "Canonical CIS Benchmark 16.04 Audit Tool Repository Disabled."
176+ else
177+ echo 'Canonical CIS Benchmark 16.04 Audit Tool Repository is not Enabled.'
178+ fi
179+
180+ if apt_is_package_installed $CISAUDIT_UBUNTU_CISBENCHMARK; then
181+ check_result apt_get remove $CISAUDIT_UBUNTU_CISBENCHMARK
182+ echo 'Canonical CIS Benchmark 16.04 Audit Tool Removed.'
183+ fi
184+}
185+
186+cisaudit_is_enabled() {
187+ _cisaudit_is_installed
188+}
189+
190+cisaudit_print_status() {
191+ echo "cisaudit: files are in /usr/share/ubuntu-securityguides/$CISAUDIT_UBUNTU_CISBENCHMARK"
192+}
193+
194+_cisaudit_is_installed() {
195+ apt_is_package_installed $CISAUDIT_UBUNTU_CISBENCHMARK && return 0
196+}
197+
198+cisaudit_validate_token() {
199+ local token="$1"
200+
201+ if ! validate_user_pass_token "$token"; then
202+ error_msg 'Invalid token, it must be in the form "user:password"'
203+ return 1
204+ fi
205+}
206diff --git a/modules/service-livepatch.sh b/modules/service-livepatch.sh
207index 0e35020..d7e920d 100644
208--- a/modules/service-livepatch.sh
209+++ b/modules/service-livepatch.sh
210@@ -45,7 +45,7 @@ livepatch_disable() {
211
212 echo 'Disabling Livepatch...'
213 canonical-livepatch disable
214- if [ "$remove_snap" ]; then
215+ if [ -n "$remove_snap" ]; then
216 echo 'Removing the canonical-livepatch snap...'
217 snap remove canonical-livepatch
218 else
219@@ -59,8 +59,20 @@ livepatch_is_enabled() {
220 canonical-livepatch status >/dev/null 2>&1 || return 1
221 }
222
223+livepatch_disabled_reason() {
224+ local output
225+ local result=0
226+ local unsupported_kernel_msg="is not eligible for livepatch updates"
227+
228+ output=$(canonical-livepatch status 2>&1) || result=$?
229+ if echo "${output}" | grep -q "${unsupported_kernel_msg}"; then
230+ echo " (unsupported kernel)"
231+ fi
232+}
233+
234 livepatch_print_status() {
235- canonical-livepatch status
236+ # remove empty lines
237+ canonical-livepatch status | grep -vE '^[[:blank:]]*$'
238 }
239
240 livepatch_validate_token() {
241diff --git a/modules/service.sh b/modules/service.sh
242index 26dc63e..f8e8d80 100644
243--- a/modules/service.sh
244+++ b/modules/service.sh
245@@ -49,15 +49,23 @@ service_print_status() {
246 status="disabled"
247 if ! is_supported "$series" "$archs"; then
248 status+=" (not available)"
249+ else
250+ status+=$(service_disabled_reason "${service}")
251 fi
252 fi
253
254- echo "$service: $status"
255+ echo "${service//_/-}: $status"
256 if [ "$status" = enabled ]; then
257 _service_print_detailed_status "$service"
258 fi
259 }
260
261+service_disabled_reason() {
262+ local service="$1"
263+
264+ call_if_defined "${service}_disabled_reason"
265+}
266+
267 service_check_user() {
268 if [ "$(id -u)" -ne 0 ]; then
269 error_msg "This command must be run as root (try using sudo)"
270diff --git a/tests/fakes.py b/tests/fakes.py
271index 0075504..ca6566d 100644
272--- a/tests/fakes.py
273+++ b/tests/fakes.py
274@@ -30,6 +30,16 @@ EOF
275 fi
276 """
277
278+# regardless of the command, canonical-livepatch will always exit with
279+# status 1 and a message like this
280+LIVEPATCH_UNSUPPORTED_KERNEL = """
281+cat <<EOF
282+2018/05/24 18:51:29 cannot use livepatch: your kernel "4.15.0-1010-kvm" \
283+is not eligible for livepatch updates
284+EOF
285+exit 1
286+"""
287+
288 LIVEPATCH_ENABLED = """
289 if [ "$1" = "status" ]; then
290 cat <<EOF
291@@ -50,6 +60,10 @@ status:
292 * CVE-2015-7837 LP: #1509563
293 * CVE-2016-0758 LP: #1581202
294 EOF
295+# empty lines, for regression testing of
296+# https://github.com/CanonicalLtd/ubuntu-advantage-script/issues/145
297+echo
298+echo
299 elif [ "$1" = "enable" ]; then
300 echo -n "2017/08/04 18:03:47 Error executing enable?auth-token="
301 echo "deafbeefdeadbeefdeadbeefdeadbeef."
302@@ -159,6 +173,12 @@ fips: disabled (not available)
303 livepatch: disabled (not available)
304 """
305
306+STATUS_CACHE_LIVEPATCH_DISABLED_UNSUPPORTED = """\
307+esm: disabled (not available)
308+fips: disabled (not available)
309+livepatch: disabled (unsupported kernel)
310+"""
311+
312 STATUS_CACHE_MIXED_CONTENT = """\
313 esm: enabled
314 patchState: should-not-be-here
315diff --git a/tests/test_cc.py b/tests/test_cc.py
316new file mode 100644
317index 0000000..04ab50b
318--- /dev/null
319+++ b/tests/test_cc.py
320@@ -0,0 +1,186 @@
321+"""Tests for CC-related commands."""
322+
323+from testing import UbuntuAdvantageTest
324+
325+
326+class CCTest(UbuntuAdvantageTest):
327+
328+ SERIES = 'xenial'
329+ ARCH = 'x86_64'
330+
331+ def setUp(self):
332+ super().setUp()
333+ self.setup_cc()
334+
335+ def test_enable_cc_provisioning(self):
336+ """The enable-cc-provisioning enables commoncriteria repository."""
337+ process = self.script('enable-cc-provisioning', 'user:pass')
338+ self.assertEqual(0, process.returncode)
339+ self.assertIn(
340+ 'Ubuntu Common Criteria PPA repository enabled.',
341+ process.stdout)
342+ expected = (
343+ 'deb https://private-ppa.launchpad.net/ubuntu-advantage/'
344+ 'commoncriteria/ubuntu xenial main\n'
345+ '# deb-src https://private-ppa.launchpad.net/'
346+ 'ubuntu-advantage/commoncriteria/ubuntu xenial main\n')
347+ self.assertEqual(expected, self.cc_repo_list.read_text())
348+ self.assertEqual(
349+ self.apt_auth_file.read_text(),
350+ 'machine private-ppa.launchpad.net/ubuntu-advantage/'
351+ 'commoncriteria/ubuntu/'
352+ ' login user password pass\n')
353+ self.assertEqual(self.apt_auth_file.stat().st_mode, 0o100600)
354+ keyring_file = self.trusted_gpg_dir / 'ubuntu-cc-keyring.gpg'
355+ self.assertEqual('GPG key', keyring_file.read_text())
356+ self.assertIn(
357+ 'Successfully prepared this machine to host'
358+ ' the Common Criteria artifacts',
359+ process.stdout)
360+ # the apt-transport-https dependency is already installed
361+ self.assertNotIn(
362+ 'Installing missing dependency apt-transport-https',
363+ process.stdout)
364+
365+ def test_enable_cc_provisioning_auth_if_other_entries(self):
366+ """Existing auth.conf entries are preserved."""
367+ auth = 'machine example.com login user password pass\n'
368+ self.apt_auth_file.write_text(auth)
369+ process = self.script('enable-cc-provisioning', 'user:pass')
370+ self.assertEqual(0, process.returncode)
371+ self.assertIn(auth, self.apt_auth_file.read_text())
372+
373+ def test_enable_cc_provisioning_install_apt_transport_https(self):
374+ """enable-cc-provisioning installs apt-transport-https if needed."""
375+ self.apt_method_https.unlink()
376+ process = self.script('enable-cc-provisioning', 'user:pass')
377+ self.assertEqual(0, process.returncode)
378+ self.assertIn(
379+ 'Installing missing dependency apt-transport-https',
380+ process.stdout)
381+
382+ def test_enable_cc_provisioning_install_apt_transport_https_fails(self):
383+ """Stderr is printed if apt-transport-https install fails."""
384+ self.apt_method_https.unlink()
385+ self.make_fake_binary('apt-get', command='echo failed >&2; false')
386+ process = self.script('enable-cc-provisioning', 'user:pass')
387+ self.assertEqual(1, process.returncode)
388+ self.assertIn('failed', process.stderr)
389+
390+ def test_enable_cc_provisioning_install_ca_certificates(self):
391+ """enable-fips installs ca-certificates if needed."""
392+ self.ca_certificates.unlink()
393+ process = self.script('enable-cc-provisioning', 'user:pass')
394+ self.assertEqual(0, process.returncode)
395+ self.assertIn(
396+ 'Installing missing dependency ca-certificates',
397+ process.stdout)
398+
399+ def test_enable_cc_provisioning_install_ca_certificates_fails(self):
400+ """Stderr is printed if ca-certificates install fails."""
401+ self.ca_certificates.unlink()
402+ self.make_fake_binary('apt-get', command='echo failed >&2; false')
403+ process = self.script('enable-cc-provisioning', 'user:pass')
404+ self.assertEqual(1, process.returncode)
405+ self.assertIn('failed', process.stderr)
406+
407+ def test_enable_cc_provisioning_missing_token(self):
408+ """The token must be specified when using enable-fips."""
409+ process = self.script('enable-cc-provisioning')
410+ self.assertEqual(3, process.returncode)
411+ self.assertIn(
412+ 'Invalid token, it must be in the form "user:password"',
413+ process.stderr)
414+
415+ def test_enable_cc_provisioning_invalid_token_format(self):
416+ """The CC token must be specified as "user:password"."""
417+ process = self.script('enable-cc-provisioning', 'foo-bar')
418+ self.assertEqual(3, process.returncode)
419+ self.assertIn(
420+ 'Invalid token, it must be in the form "user:password"',
421+ process.stderr)
422+
423+ def test_enable_cc_provisioning_invalid_token(self):
424+ """If token is invalid, an error is returned."""
425+ message = (
426+ 'E: Failed to fetch https://esm.ubuntu.com/'
427+ ' 401 Unauthorized [IP: 1.2.3.4]')
428+ self.make_fake_binary(
429+ 'apt-helper', command='echo "{}"; exit 1'.format(message))
430+ process = self.script('enable-cc-provisioning', 'user:pass')
431+ self.assertEqual(3, process.returncode)
432+ self.assertIn('Checking token... ERROR', process.stdout)
433+ self.assertIn('Invalid token', process.stderr)
434+
435+ def test_enable_cc_provisioning_error_checking_token(self):
436+ """If token check fails, an error is returned."""
437+ message = (
438+ 'E: Failed to fetch https://esm.ubuntu.com/'
439+ ' 404 Not Found [IP: 1.2.3.4]')
440+ self.make_fake_binary(
441+ 'apt-helper', command='echo "{}"; exit 1'.format(message))
442+ process = self.script('enable-cc-provisioning', 'user:pass')
443+ self.assertEqual(3, process.returncode)
444+ self.assertIn('Checking token... ERROR', process.stdout)
445+ self.assertIn(
446+ 'Failed checking token (404 Not Found [IP: 1.2.3.4])',
447+ process.stderr)
448+
449+ def test_enable_cc_provisioning_skip_token_check_no_helper(self):
450+ """If apt-helper is not found, the token check is skipped."""
451+ self.apt_helper.unlink()
452+ process = self.script('enable-cc-provisioning', 'user:pass')
453+ self.assertEqual(0, process.returncode)
454+ self.assertIn('Checking token... SKIPPED', process.stdout)
455+
456+ def test_enable_cc_provisioning_only_supported_on_xenial(self):
457+ """The enable-cc-provisioning option fails if not on Xenial."""
458+ self.SERIES = 'zesty'
459+ process = self.script('enable-cc-provisioning', 'user:pass')
460+ self.assertEqual(4, process.returncode)
461+ self.assertIn(
462+ 'Canonical Common Criteria EAL2 Provisioning is '
463+ 'not supported on zesty',
464+ process.stderr)
465+
466+ def test_unsupported_on_i686(self):
467+ """CC is unsupported on i686 arch."""
468+ self.ARCH = 'i686'
469+ process = self.script('enable-cc-provisioning', 'user:pass')
470+ self.assertEqual(7, process.returncode)
471+ self.assertIn(
472+ 'Sorry, but Canonical Common Criteria EAL2 Provisioning '
473+ 'is not supported on i686',
474+ process.stderr)
475+
476+ def test_unsupported_on_arm64(self):
477+ """CC is unsupported on arm64 arch."""
478+ self.ARCH = 'arm64'
479+ process = self.script('enable-cc-provisioning', 'user:pass')
480+ self.assertEqual(7, process.returncode)
481+ self.assertIn(
482+ 'Sorry, but Canonical Common Criteria EAL2 Provisioning '
483+ 'is not supported on arm64',
484+ process.stderr)
485+
486+ def test_disable_cc_provisioning(self):
487+ """The disable-cc-provisioning option disables commoncriteria repo."""
488+ self.setup_cc(enabled=True)
489+ other_auth = 'machine example.com login user password pass\n'
490+ self.apt_auth_file.write_text(other_auth)
491+ process = self.script('disable-cc-provisioning')
492+ self.assertEqual(0, process.returncode)
493+ self.assertFalse(self.cc_repo_list.exists())
494+ # the keyring file is removed
495+ keyring_file = self.trusted_gpg_dir / 'ubuntu-cc-keyring.gpg'
496+ self.assertFalse(keyring_file.exists())
497+ # credentials are removed
498+ self.assertEqual(self.apt_auth_file.read_text(), other_auth)
499+
500+ def test_disable_cc_provisioning_fails_already_disabled(self):
501+ """If commoncriteria repo is not enabled, disable fails."""
502+ process = self.script('disable-cc-provisioning')
503+ self.assertEqual(8, process.returncode)
504+ self.assertIn(
505+ 'Canonical Common Criteria EAL2 Provisioning is not enabled\n',
506+ process.stderr)
507diff --git a/tests/test_cisaudit.py b/tests/test_cisaudit.py
508new file mode 100644
509index 0000000..47b2784
510--- /dev/null
511+++ b/tests/test_cisaudit.py
512@@ -0,0 +1,187 @@
513+"""Tests for CISAudit-related commands."""
514+
515+from testing import UbuntuAdvantageTest
516+
517+
518+class CISAUDITTest(UbuntuAdvantageTest):
519+
520+ SERIES = 'xenial'
521+ ARCH = 'x86_64'
522+
523+ def setUp(self):
524+ super().setUp()
525+ self.setup_cisaudit()
526+
527+ def test_enable_cisaudit(self):
528+ """The enable-cisaudit enables security benchmarks repository."""
529+ process = self.script('enable-cisaudit', 'user:pass')
530+ self.assertEqual(0, process.returncode)
531+ self.assertIn(
532+ 'Ubuntu Security Benchmarks PPA repository enabled.',
533+ process.stdout)
534+ expected = (
535+ 'deb https://private-ppa.launchpad.net/ubuntu-advantage/'
536+ 'security-benchmarks/ubuntu xenial main\n'
537+ '# deb-src https://private-ppa.launchpad.net/'
538+ 'ubuntu-advantage/security-benchmarks/ubuntu xenial main\n')
539+ self.assertEqual(expected, self.cisaudit_repo_list.read_text())
540+ self.assertEqual(
541+ self.apt_auth_file.read_text(),
542+ 'machine private-ppa.launchpad.net/ubuntu-advantage/'
543+ 'security-benchmarks/ubuntu/'
544+ ' login user password pass\n')
545+ self.assertEqual(self.apt_auth_file.stat().st_mode, 0o100600)
546+ cis_keyring = 'ubuntu-securitybenchmarks-keyring.gpg'
547+ keyring_file = self.trusted_gpg_dir / cis_keyring
548+ self.assertEqual('GPG key', keyring_file.read_text())
549+ self.assertIn(
550+ 'Successfully installed the CIS audit tool.',
551+ process.stdout)
552+ # the apt-transport-https dependency is already installed
553+ self.assertNotIn(
554+ 'Installing missing dependency apt-transport-https',
555+ process.stdout)
556+
557+ def test_enable_cisaudit_auth_if_other_entries(self):
558+ """Existing auth.conf entries are preserved."""
559+ auth = 'machine example.com login user password pass\n'
560+ self.apt_auth_file.write_text(auth)
561+ process = self.script('enable-cisaudit', 'user:pass')
562+ self.assertEqual(0, process.returncode)
563+ self.assertIn(auth, self.apt_auth_file.read_text())
564+
565+ def test_enable_cisaudit_install_apt_transport_https(self):
566+ """enable-cisaudit installs apt-transport-https if needed."""
567+ self.apt_method_https.unlink()
568+ process = self.script('enable-cisaudit', 'user:pass')
569+ self.assertEqual(0, process.returncode)
570+ self.assertIn(
571+ 'Installing missing dependency apt-transport-https',
572+ process.stdout)
573+
574+ def test_enable_cisaudit_install_apt_transport_https_fails(self):
575+ """Stderr is printed if apt-transport-https install fails."""
576+ self.apt_method_https.unlink()
577+ self.make_fake_binary('apt-get', command='echo failed >&2; false')
578+ process = self.script('enable-cisaudit', 'user:pass')
579+ self.assertEqual(1, process.returncode)
580+ self.assertIn('failed', process.stderr)
581+
582+ def test_enable_cisaudit_install_ca_certificates(self):
583+ """enable-cisaudit installs ca-certificates if needed."""
584+ self.ca_certificates.unlink()
585+ process = self.script('enable-cisaudit', 'user:pass')
586+ self.assertEqual(0, process.returncode)
587+ self.assertIn(
588+ 'Installing missing dependency ca-certificates',
589+ process.stdout)
590+
591+ def test_enable_cisaudit_install_ca_certificates_fails(self):
592+ """Stderr is printed if ca-certificates install fails."""
593+ self.ca_certificates.unlink()
594+ self.make_fake_binary('apt-get', command='echo failed >&2; false')
595+ process = self.script('enable-cisaudit', 'user:pass')
596+ self.assertEqual(1, process.returncode)
597+ self.assertIn('failed', process.stderr)
598+
599+ def test_enable_cisaudit_missing_token(self):
600+ """The token must be specified when using enable-cisaudit."""
601+ process = self.script('enable-cisaudit')
602+ self.assertEqual(3, process.returncode)
603+ self.assertIn(
604+ 'Invalid token, it must be in the form "user:password"',
605+ process.stderr)
606+
607+ def test_enable_cisaudit_invalid_token_format(self):
608+ """The cisaudit token must be specified as "user:password"."""
609+ process = self.script('enable-cisaudit', 'foo-bar')
610+ self.assertEqual(3, process.returncode)
611+ self.assertIn(
612+ 'Invalid token, it must be in the form "user:password"',
613+ process.stderr)
614+
615+ def test_enable_cisaudit_invalid_token(self):
616+ """If token is invalid, an error is returned."""
617+ message = (
618+ 'E: Failed to fetch https://esm.ubuntu.com/'
619+ ' 401 Unauthorized [IP: 1.2.3.4]')
620+ self.make_fake_binary(
621+ 'apt-helper', command='echo "{}"; exit 1'.format(message))
622+ process = self.script('enable-cisaudit', 'user:pass')
623+ self.assertEqual(3, process.returncode)
624+ self.assertIn('Checking token... ERROR', process.stdout)
625+ self.assertIn('Invalid token', process.stderr)
626+
627+ def test_enable_cisaudit_error_checking_token(self):
628+ """If token check fails, an error is returned."""
629+ message = (
630+ 'E: Failed to fetch https://esm.ubuntu.com/'
631+ ' 404 Not Found [IP: 1.2.3.4]')
632+ self.make_fake_binary(
633+ 'apt-helper', command='echo "{}"; exit 1'.format(message))
634+ process = self.script('enable-cisaudit', 'user:pass')
635+ self.assertEqual(3, process.returncode)
636+ self.assertIn('Checking token... ERROR', process.stdout)
637+ self.assertIn(
638+ 'Failed checking token (404 Not Found [IP: 1.2.3.4])',
639+ process.stderr)
640+
641+ def test_enable_cisaudit_skip_token_check_no_helper(self):
642+ """If apt-helper is not found, the token check is skipped."""
643+ self.apt_helper.unlink()
644+ process = self.script('enable-cisaudit', 'user:pass')
645+ self.assertEqual(0, process.returncode)
646+ self.assertIn('Checking token... SKIPPED', process.stdout)
647+
648+ def test_enable_cisaudit_only_supported_on_xenial(self):
649+ """The enable-cisaudit option fails if not on Xenial."""
650+ self.SERIES = 'zesty'
651+ process = self.script('enable-cisaudit', 'user:pass')
652+ self.assertEqual(4, process.returncode)
653+ self.assertIn(
654+ 'Sorry, but Canonical CIS Benchmark 16.04 '
655+ 'Audit Tool is not supported on zesty\n',
656+ process.stderr)
657+
658+ def test_unsupported_on_i686(self):
659+ """CISAudit is unsupported on i686 arch."""
660+ self.ARCH = 'i686'
661+ process = self.script('enable-cisaudit', 'user:pass')
662+ self.assertEqual(7, process.returncode)
663+ self.assertIn(
664+ 'Sorry, but Canonical CIS Benchmark 16.04 Audit Tool '
665+ 'is not supported on i686',
666+ process.stderr)
667+
668+ def test_unsupported_on_arm64(self):
669+ """CISAudit is unsupported on arm64 arch."""
670+ self.ARCH = 'arm64'
671+ process = self.script('enable-cisaudit', 'user:pass')
672+ self.assertEqual(7, process.returncode)
673+ self.assertIn(
674+ 'Sorry, but Canonical CIS Benchmark 16.04 Audit Tool '
675+ 'is not supported on arm64',
676+ process.stderr)
677+
678+ def test_disable_cisaudit(self):
679+ """The disable-cisaudit option disables security-benchmarks repo."""
680+ self.setup_cisaudit(enabled=True)
681+ other_auth = 'machine example.com login user password pass\n'
682+ self.apt_auth_file.write_text(other_auth)
683+ process = self.script('disable-cisaudit')
684+ self.assertEqual(0, process.returncode)
685+ self.assertFalse(self.cisaudit_repo_list.exists())
686+ # the keyring file is removed
687+ cis_keyring = 'ubuntu-securitybenchmarks-keyring.gpg'
688+ keyring_file = self.trusted_gpg_dir / cis_keyring
689+ self.assertFalse(keyring_file.exists())
690+ # credentials are removed
691+ self.assertEqual(self.apt_auth_file.read_text(), other_auth)
692+
693+ def test_disable_cisaudit_fails_already_disabled(self):
694+ """If security-benchmarks repo is not enabled, disable fails."""
695+ process = self.script('disable-cisaudit')
696+ self.assertEqual(8, process.returncode)
697+ self.assertIn(
698+ 'Canonical CIS Benchmark 16.04 Audit Tool is not enabled\n',
699+ process.stderr)
700diff --git a/tests/test_livepatch_motd.py b/tests/test_livepatch_motd.py
701index c8beeda..a934f4c 100644
702--- a/tests/test_livepatch_motd.py
703+++ b/tests/test_livepatch_motd.py
704@@ -9,6 +9,7 @@ from fakes import (
705 STATUS_CACHE_LIVEPATCH_ENABLED_NO_CONTENT,
706 STATUS_CACHE_LIVEPATCH_DISABLED_AVAILABLE,
707 STATUS_CACHE_LIVEPATCH_DISABLED_UNAVAILABLE,
708+ STATUS_CACHE_LIVEPATCH_DISABLED_UNSUPPORTED,
709 STATUS_CACHE_MIXED_CONTENT)
710 from random import randrange
711
712@@ -98,6 +99,19 @@ class LivepatchMOTDTest(UbuntuAdvantageTest):
713 self.assertEqual(0, process.returncode)
714 self.assertEqual('', process.stdout)
715
716+ def test_disabled_unsupported(self):
717+ """Livepatch is disabled and unsupported."""
718+ self.KERNEL_VERSION = '4.15.0-1010-kvm'
719+ self.ua_status_cache.write_text(
720+ STATUS_CACHE_LIVEPATCH_DISABLED_UNSUPPORTED)
721+ process = self.script()
722+ self.assertEqual(0, process.returncode)
723+ self.assertIn('Canonical Livepatch is installed but disabled',
724+ process.stdout)
725+ self.assertIn('Kernel {} is not supported (https://bit.ly/'
726+ 'livepatch-faq)'.format(self.KERNEL_VERSION),
727+ process.stdout)
728+
729 def test_other_state_fields_ignored(self):
730 """The MOTD script ignores *State fields not from livepatch."""
731 self.ua_status_cache.write_text(STATUS_CACHE_MIXED_CONTENT)
732diff --git a/tests/test_script.py b/tests/test_script.py
733index 4e7da93..ec4be19 100644
734--- a/tests/test_script.py
735+++ b/tests/test_script.py
736@@ -1,6 +1,7 @@
737 """Tests for the ubuntu-advantage script."""
738
739 from testing import UbuntuAdvantageTest
740+from fakes import LIVEPATCH_UNSUPPORTED_KERNEL
741
742
743 class UbuntuAdvantageScriptTest(UbuntuAdvantageTest):
744@@ -54,6 +55,14 @@ class UbuntuAdvantageScriptTest(UbuntuAdvantageTest):
745 self.assertIn("livepatch: disabled (not available)", process.stdout)
746 self.assertIn("esm: enabled", process.stdout)
747
748+ def test_livepatch_status_no_empty_line(self):
749+ """The status output has no empty lines when livepatch is enabled."""
750+ self.setup_livepatch(installed=True, enabled=True)
751+ process = self.script('status', 'livepatch')
752+ lines = process.stdout.split('\n')[:-1]
753+ for line in lines:
754+ self.assertNotEqual('', line.strip())
755+
756 def test_status_xenial(self):
757 """The status command shows only livepatch available on xenial."""
758 self.SERIES = 'xenial'
759@@ -91,6 +100,17 @@ class UbuntuAdvantageScriptTest(UbuntuAdvantageTest):
760 process = self.script('status', 'unknown')
761 self.assertEqual(process.returncode, 1)
762
763+ def test_status_livepatch_unsupported_kernel(self):
764+ """Livepatch is unavailable on an unsupported kernel."""
765+ self.SERIES = 'xenial'
766+ self.ARCH = 'x86_64'
767+ self.setup_livepatch(
768+ installed=True, enabled=False,
769+ livepatch_command=LIVEPATCH_UNSUPPORTED_KERNEL)
770+ process = self.script('status')
771+ self.assertIn('livepatch: disabled (unsupported kernel)',
772+ process.stdout)
773+
774 def test_version(self):
775 """The version command shows the package version."""
776 self.make_fake_binary('dpkg-query', command='echo 123')
777diff --git a/tests/testing.py b/tests/testing.py
778index c684f48..17fc080 100644
779--- a/tests/testing.py
780+++ b/tests/testing.py
781@@ -57,6 +57,8 @@ class UbuntuAdvantageTest(TestWithFixtures):
782 self.fips_repo_list = Path(self.tempdir.join('fips-repo.list'))
783 self.fips_updates_repo_list = Path(
784 self.tempdir.join('fips-updates-repo.list'))
785+ self.cc_repo_list = Path(self.tempdir.join('cc-repo.list'))
786+ self.cisaudit_repo_list = Path(self.tempdir.join('cisaudit-repo.list'))
787 self.fips_repo_preferences = Path(
788 self.tempdir.join('preferences-fips'))
789 self.fips_updates_repo_preferences = Path(
790@@ -82,6 +84,9 @@ class UbuntuAdvantageTest(TestWithFixtures):
791 (self.keyrings_dir / 'ubuntu-fips-keyring.gpg').write_text('GPG key')
792 (self.keyrings_dir / 'ubuntu-fips-updates-keyring.gpg').write_text(
793 'GPG key')
794+ (self.keyrings_dir / 'ubuntu-cc-keyring.gpg').write_text('GPG key')
795+ (self.keyrings_dir /
796+ 'ubuntu-securitybenchmarks-keyring.gpg').write_text('GPG key')
797 self.cpuinfo.write_text('flags\t\t: fpu apic')
798 self.make_fake_binary('apt-get')
799 self.make_fake_binary('apt-helper')
800@@ -117,12 +122,14 @@ class UbuntuAdvantageTest(TestWithFixtures):
801 'ESM_REPO_LIST': str(self.esm_repo_list),
802 'FIPS_REPO_LIST': str(self.fips_repo_list),
803 'FIPS_UPDATES_REPO_LIST': str(self.fips_updates_repo_list),
804+ 'CC_PROVISIONING_REPO_LIST': str(self.cc_repo_list),
805+ 'CISAUDIT_REPO_LIST': str(self.cisaudit_repo_list),
806 'FIPS_BOOT_CFG': str(self.boot_cfg),
807 'FIPS_BOOT_CFG_DIR': str(self.etc_dir),
808 'FIPS_ENABLED_FILE': str(self.fips_enabled_file),
809 'FIPS_REPO_PREFERENCES': str(self.fips_repo_preferences),
810 'FIPS_UPDATES_REPO_PREFERENCES': str(
811- self.fips_updates_repo_preferences),
812+ self.fips_updates_repo_preferences),
813 'KEYRINGS_DIR': str(self.keyrings_dir),
814 'APT_HELPER': str(self.apt_helper),
815 'APT_AUTH_FILE': str(self.apt_auth_file),
816@@ -174,3 +181,21 @@ class UbuntuAdvantageTest(TestWithFixtures):
817 return
818 self.make_fake_binary('dpkg-query')
819 self.fips_enabled_file.write_text('1' if enabled else '0')
820+
821+ def setup_cc(self, enabled=False):
822+ """Setup the CC repository."""
823+ if enabled is True:
824+ self.make_fake_binary(
825+ 'dpkg-query', command='[ $2 = ubuntu-commoncriteria ]')
826+ else:
827+ self.make_fake_binary(
828+ 'dpkg-query', command='[ $2 != ubuntu-commoncriteria ]')
829+
830+ def setup_cisaudit(self, enabled=False):
831+ """Setup the CISAudit repository."""
832+ if enabled is True:
833+ self.make_fake_binary(
834+ 'dpkg-query', command='[ $2 = ubuntu-cisbenchmark-16.04 ]')
835+ else:
836+ self.make_fake_binary(
837+ 'dpkg-query', command='[ $2 != ubuntu-cisbenchmark-16.04 ]')
838diff --git a/ubuntu-advantage b/ubuntu-advantage
839index 1ad03a5..19293f2 100755
840--- a/ubuntu-advantage
841+++ b/ubuntu-advantage
842@@ -4,7 +4,7 @@
843 SCRIPTNAME=$(basename "$0")
844
845 # Services managed by the script (in alphabetical order)
846-SERVICES="esm fips livepatch"
847+SERVICES="cc-provisioning esm fips livepatch cisaudit"
848
849 # system details
850 SERIES=${SERIES:-$(lsb_release -cs)}
851@@ -41,13 +41,13 @@ print_status() {
852 local service="$1"
853
854 local services="$SERVICES"
855- if [ "$service" ]; then
856- name_in_list "$service" "$SERVICES" || error_exit invalid_command
857+ if [ -n "$service" ]; then
858+ name_in_list "${service//_/-}" "$SERVICES" || error_exit invalid_command
859 services="$service"
860 fi
861
862 for service in $services; do
863- service_print_status "$service"
864+ service_print_status "${service//-/_}"
865 done
866 }
867
868@@ -63,6 +63,8 @@ Currently available are:
869 - Canonical FIPS 140-2 Certified Modules
870 - Canonical FIPS 140-2 Non-Certified Module Updates
871 - Canonical Livepatch Service (https://www.ubuntu.com/server/livepatch)
872+- Canonical Common Criteria EAL2 certification artifacts provisioning
873+- Canonical CIS Ubuntu Benchmark Audit tool
874
875 Commands:
876 version show the tool version
877@@ -70,16 +72,26 @@ Commands:
878 offerings (or of a specific one if provided)
879 enable-esm <TOKEN> enable the ESM repository
880 disable-esm disable the ESM repository
881- enable-fips <TOKEN> enable the FIPS PPA repository and install,
882+ enable-fips <TOKEN> enable the FIPS repository and install,
883 configure and enable FIPS certified modules
884 disable-fips currently not supported
885- enable-fips-updates <TOKEN> [-y] enable non-certified FIPS-UPDATES PPA
886+ enable-fips-updates <TOKEN> [-y] enable non-certified FIPS-UPDATES
887 repository and install updates. With an
888 optional "-y" the user prompt will be
889 bypassed.
890 enable-livepatch <TOKEN> enable the Livepatch service
891 disable-livepatch [-r] disable the Livepatch service. With "-r", the
892 canonical-livepatch snap will also be removed
893+ enable-cc-provisioning <TOKEN> enable the commoncriteria repository and
894+ install the ubuntu-commoncriteria DEB package
895+ disable-cc-provisioning disable the commoncriteria repository and
896+ remove the ubuntu-commoncriteria DEB package
897+ enable-cisaudit <TOKEN> enable the security benchmarks repository
898+ and install the ubuntu-cisbenchmark-16.04 DEB
899+ package.
900+ disable-cisaudit disable the security benchmarks repository
901+ and uninstall the ubuntu-cisbenchmark-16.04 DEB
902+ package.
903 EOF
904 error_exit invalid_command
905 }
906@@ -91,11 +103,15 @@ main() {
907 local service
908 service=$(service_from_command "$command")
909 # if the command contains a service name, check that it's valid
910- if [ "$service" ] && ! name_in_list "$service" "$SERVICES" \
911+ if [ -n "$service" ] && ! name_in_list "$service" "$SERVICES" \
912 && [ "$service" != "fips-updates" ]; then
913 error_msg "Invalid command: \"$command\""
914 usage
915 fi
916+ # replace -(hyphen) in service commands with _(underscore) (eg: cc-provisioning) to
917+ # use in generic service function invocations. Adding it here so the name_in_list
918+ # function call above uses the original command.
919+ service=${service//-/_}
920
921 case "$command" in
922 status)
923diff --git a/ubuntu-advantage.1 b/ubuntu-advantage.1
924index e86b85d..e53a774 100644
925--- a/ubuntu-advantage.1
926+++ b/ubuntu-advantage.1
927@@ -86,8 +86,42 @@ https://ubuntu.com/livepatch
928 .B
929 disable-livepatch \fR[\fB\-r\fR]
930 Disable the Livepatch service. If the \fB\-r\fR option is given, the
931-canonical-livepatch snap will be removed after the sevice is disabled.
932+canonical-livepatch snap will be removed after the service is disabled.
933
934+.SH CC (Canonical Common Critieria EAL2 Provisioning)
935+Enable Common Criteria PPA and install Common Criteria EAL2 artifacts
936+.TP
937+.B
938+enable-cc-provisioning \fItoken\fR
939+Enables the Commoncriteria PPA repository, installs the ubuntu-commoncriteria
940+package which has the common criteria artifacts. The artifacts include a
941+configure script, a tarball with additional packages and post install scripts.
942+The artifacts will be installed in /usr/lib/common-criteria directory. The
943+evaluated configuration guide and README instructions on how to set up a
944+system to be Common Criteria compliant are available in
945+/usr/share/doc/ubuntu-commoncriteria directory.
946+.TP
947+.B
948+disable-cc-provisioning
949+Disables the commoncriteria PPA repository and removes the ubuntu-commoncriteria
950+DEB package.
951+.SH CIS (Canonical CIS Audit tooling)
952+Enable CIS Auditing PPA and install CIS audit tool package
953+.TP
954+.B
955+enable-cisaudit \fItoken\fR
956+Enables the Security Benchmarks PPA, installs the ubuntu-cisbenchmark-16.04
957+package which has the CIS Audit tooling files. They include the xccdf and xml
958+files and scripts to check compliance against the CIS 16.04 benchmark. The
959+files will be installed in
960+/usr/share/ubuntu-securityguides/ubuntu-cisbenchmark-16.04.
961+The documentation for the tool is available in
962+/usr/share/doc/ubuntu-cisbenchmark-16.04.
963+.TP
964+.B
965+disable-cisaudit
966+Disables the security benchmarks PPA repository and removes the
967+ubuntu-cisbenchmark-16.04 DEB package installed on the machine.
968 .SH EXIT STATUS
969 .TP
970 .B
971diff --git a/update-motd.d/80-livepatch b/update-motd.d/80-livepatch
972index de59bf1..ee09a73 100755
973--- a/update-motd.d/80-livepatch
974+++ b/update-motd.d/80-livepatch
975@@ -2,6 +2,7 @@
976
977 UA=${UA:-"/usr/bin/ubuntu-advantage"}
978 UA_STATUS_CACHE=${UA_STATUS_CACHE:-"/var/cache/ubuntu-advantage-tools/ubuntu-advantage-status.cache"}
979+KERNEL_VERSION=${KERNEL_VERSION:-"$(uname -r)"}
980
981 [ -x "$UA" ] || exit 0
982
983@@ -73,6 +74,11 @@ case "$livepatch_status" in
984 "disabled (not available)")
985 # do nothing
986 ;;
987+ "disabled (unsupported kernel)")
988+ echo
989+ echo " * Canonical Livepatch is installed but disabled"
990+ echo " - Kernel ${KERNEL_VERSION} is not supported (https://bit.ly/livepatch-faq)"
991+ ;;
992 "enabled")
993 echo
994 echo " * Canonical Livepatch is enabled."

Subscribers

People subscribed via source and target branches