diff --git a/features/notice_permission.feature b/features/notice_permission.feature deleted file mode 100644 index cd66384f8f..0000000000 --- a/features/notice_permission.feature +++ /dev/null @@ -1,33 +0,0 @@ -Feature: Notice Permission - - Scenario Outline: Check notice file read permission - Given a `` `` machine with ubuntu-advantage-tools installed - When I run `rm -rf /run/ubuntu-advantage` with sudo - When I run `mkdir /run/ubuntu-advantage` with sudo - When I run `mkdir /run/ubuntu-advantage/notices` with sudo - When I run `touch /run/ubuntu-advantage/notices/crasher` with sudo - When I run `chmod 0 /run/ubuntu-advantage/notices/crasher` with sudo - When I run `pro status` as non-root - Then stdout matches regexp: - """ - SERVICE +AVAILABLE +DESCRIPTION - (anbox-cloud +(yes|no) +.*)? - ?cc-eal +yes +Common Criteria EAL2 Provisioning Packages - cis +yes +Security compliance and audit tools - esm-apps +yes +Expanded Security Maintenance for Applications - esm-infra +yes +Expanded Security Maintenance for Infrastructure - fips +yes +NIST-certified FIPS crypto packages - fips-updates +yes +FIPS compliant crypto packages with stable security updates - livepatch +yes +(Canonical Livepatch service|Current kernel is not supported) - ros +yes +Security Updates for the Robot Operating System - ros-updates +yes +All Updates for the Robot Operating System - - For a list of all Ubuntu Pro services, run 'pro status --all' - - This machine is not attached to an Ubuntu Pro subscription. - See https://ubuntu.com/pro - """ - Examples: ubuntu release - | release | machine_type | - | xenial | lxd-container | - | bionic | lxd-container | \ No newline at end of file diff --git a/features/unattached_status.feature b/features/unattached_status.feature index d04609e2df..1b3eef967d 100644 --- a/features/unattached_status.feature +++ b/features/unattached_status.feature @@ -599,3 +599,38 @@ Feature: Unattached status Examples: ubuntu release | release | machine_type | | jammy | lxd-container | + + Scenario Outline: Check notice file read permission + Given a `` `` machine with ubuntu-advantage-tools installed + When I run `rm -rf /run/ubuntu-advantage` with sudo + When I run `mkdir -p /run/ubuntu-advantage/notices` with sudo + When I run `touch /run/ubuntu-advantage/notices/crasher` with sudo + When I run `chmod 0 /run/ubuntu-advantage/notices/crasher` with sudo + When I run `rm -rf /var/ubuntu-advantage` with sudo + When I run `mkdir -p /var/ubuntu-advantage/notices` with sudo + When I run `touch /var/ubuntu-advantage/notices/crasher` with sudo + When I run `chmod 0 /var/ubuntu-advantage/notices/crasher` with sudo + When I run `pro status` as non-root + Then stdout matches regexp: + """ + SERVICE +AVAILABLE +DESCRIPTION + (anbox-cloud +(yes|no) +.*)? + ?cc-eal +yes +Common Criteria EAL2 Provisioning Packages + cis +yes +Security compliance and audit tools + esm-apps +yes +Expanded Security Maintenance for Applications + esm-infra +yes +Expanded Security Maintenance for Infrastructure + fips +yes +NIST-certified FIPS crypto packages + fips-updates +yes +FIPS compliant crypto packages with stable security updates + livepatch +yes +(Canonical Livepatch service|Current kernel is not supported) + ros +yes +Security Updates for the Robot Operating System + ros-updates +yes +All Updates for the Robot Operating System + + For a list of all Ubuntu Pro services, run 'pro status --all' + + This machine is not attached to an Ubuntu Pro subscription. + See https://ubuntu.com/pro + """ + Examples: ubuntu release + | release | machine_type | + | xenial | lxd-container | + | bionic | lxd-container | \ No newline at end of file diff --git a/uaclient/files/notices.py b/uaclient/files/notices.py index 5bb10110d2..1485d58aca 100644 --- a/uaclient/files/notices.py +++ b/uaclient/files/notices.py @@ -181,17 +181,6 @@ def _is_readable(self, directory: str, file_name: str) -> bool: """ return os.access(os.path.join(directory, file_name), os.R_OK) - def _load_notice_file_contents( - self, directory: str, file_name: str - ) -> str: - """Loads the contents of the notice file. - - :param directory: The directory where the notice file is located. - :param file_name: The name of the notice file. - :returns: The contents of the notice file. - """ - return system.load_file(os.path.join(directory, file_name)) - def _get_default_message(self, file_name: str) -> str: """Gets the default message for a notice file. @@ -231,9 +220,15 @@ def list(self) -> List[str]: for notice_file_name in notice_file_names: if not self._is_readable(notice_directory, notice_file_name): continue - notice_file_contents = self._load_notice_file_contents( - notice_directory, notice_file_name - ) + try: + notice_file_contents = system.load_file( + os.path.join(notice_directory, notice_file_name) + ) + except PermissionError: + LOG.warning( + f"Permission error while reading {notice_file_name}" + ) + continue if notice_file_contents: notices.append(notice_file_contents) else: diff --git a/uaclient/files/tests/test_notices.py b/uaclient/files/tests/test_notices.py index f336cfdfaf..0edea463da 100644 --- a/uaclient/files/tests/test_notices.py +++ b/uaclient/files/tests/test_notices.py @@ -124,3 +124,38 @@ def test_notice_module( assert [mock.call(FakeNotice.a)] == notice_cls_remove.call_args_list notices.list() assert 1 == notice_cls_read.call_count + + @mock.patch("uaclient.files.notices.NoticesManager._get_notice_file_names") + def test_get_notice_file_names(self, m_get_notice_file_names): + notice = NoticesManager() + m_get_notice_file_names.return_value = [] + assert [] == notice._get_notice_file_names("directory") + m_get_notice_file_names.return_value = ["file1", "file2", "file3"] + assert ["file1", "file2", "file3"] == notice._get_notice_file_names( + "directory" + ) + + @mock.patch("uaclient.files.notices.os.access") + def test_is_readable(self, m_access): + notice = NoticesManager() + m_access.return_value = False + assert not notice._is_readable("directory", "file") + assert [] == notice.list() + m_access.assert_called_once_with("directory/file", os.R_OK) + + @mock.patch("uaclient.files.notices.NoticesManager._get_notice_file_names") + @mock.patch("uaclient.files.notices.NoticesManager._is_readable") + @mock.patch("uaclient.system.load_file") + def test_list(self, m_load_file, m_is_readable, m_get_notice_file_names): + notice = NoticesManager() + + m_get_notice_file_names.side_effect = ( + lambda directory: [] + if directory == defaults.NOTICES_TEMPORARY_DIRECTORY + else ["fakeNotice1", "fakeNotice2"] + ) + m_is_readable.side_effect = [True, False] + m_load_file.return_value = "test" + + assert ["test"] == notice.list() + assert 2 == notice._is_readable.call_count