diff options
Diffstat (limited to 'poky/meta/lib/oeqa/selftest')
-rw-r--r-- | poky/meta/lib/oeqa/selftest/cases/cve_check.py | 159 | ||||
-rw-r--r-- | poky/meta/lib/oeqa/selftest/cases/devtool.py | 129 | ||||
-rw-r--r-- | poky/meta/lib/oeqa/selftest/cases/git.py | 15 | ||||
-rw-r--r-- | poky/meta/lib/oeqa/selftest/cases/imagefeatures.py | 2 | ||||
-rw-r--r-- | poky/meta/lib/oeqa/selftest/cases/multiconfig.py | 13 | ||||
-rw-r--r-- | poky/meta/lib/oeqa/selftest/cases/oescripts.py | 3 | ||||
-rw-r--r-- | poky/meta/lib/oeqa/selftest/cases/overlayfs.py | 36 | ||||
-rw-r--r-- | poky/meta/lib/oeqa/selftest/cases/runtime_test.py | 2 |
8 files changed, 328 insertions, 31 deletions
diff --git a/poky/meta/lib/oeqa/selftest/cases/cve_check.py b/poky/meta/lib/oeqa/selftest/cases/cve_check.py index d1947baffc..d0b2213703 100644 --- a/poky/meta/lib/oeqa/selftest/cases/cve_check.py +++ b/poky/meta/lib/oeqa/selftest/cases/cve_check.py @@ -1,9 +1,13 @@ -from oe.cve_check import Version +import json +import os from oeqa.selftest.case import OESelftestTestCase +from oeqa.utils.commands import bitbake, get_bb_vars class CVECheck(OESelftestTestCase): def test_version_compare(self): + from oe.cve_check import Version + result = Version("100") > Version("99") self.assertTrue( result, msg="Failed to compare version '100' > '99'") result = Version("2.3.1") > Version("2.2.3") @@ -42,3 +46,156 @@ class CVECheck(OESelftestTestCase): self.assertTrue( result ,msg="Failed to compare version with suffix '1.0p2' > '1.0p1'") result = Version("1.0_patch2","patch") < Version("1.0_patch3","patch") self.assertTrue( result ,msg="Failed to compare version with suffix '1.0_patch2' < '1.0_patch3'") + + + def test_recipe_report_json(self): + config = """ +INHERIT += "cve-check" +CVE_CHECK_FORMAT_JSON = "1" +""" + self.write_config(config) + + vars = get_bb_vars(["CVE_CHECK_SUMMARY_DIR", "CVE_CHECK_SUMMARY_FILE_NAME_JSON"]) + summary_json = os.path.join(vars["CVE_CHECK_SUMMARY_DIR"], vars["CVE_CHECK_SUMMARY_FILE_NAME_JSON"]) + recipe_json = os.path.join(vars["CVE_CHECK_SUMMARY_DIR"], "m4-native_cve.json") + + try: + os.remove(summary_json) + os.remove(recipe_json) + except FileNotFoundError: + pass + + bitbake("m4-native -c cve_check") + + def check_m4_json(filename): + with open(filename) as f: + report = json.load(f) + self.assertEqual(report["version"], "1") + self.assertEqual(len(report["package"]), 1) + package = report["package"][0] + self.assertEqual(package["name"], "m4-native") + found_cves = { issue["id"]: issue["status"] for issue in package["issue"]} + self.assertIn("CVE-2008-1687", found_cves) + self.assertEqual(found_cves["CVE-2008-1687"], "Patched") + + self.assertExists(summary_json) + check_m4_json(summary_json) + self.assertExists(recipe_json) + check_m4_json(recipe_json) + + + def test_image_json(self): + config = """ +INHERIT += "cve-check" +CVE_CHECK_FORMAT_JSON = "1" +""" + self.write_config(config) + + vars = get_bb_vars(["CVE_CHECK_DIR", "CVE_CHECK_SUMMARY_DIR", "CVE_CHECK_SUMMARY_FILE_NAME_JSON"]) + report_json = os.path.join(vars["CVE_CHECK_SUMMARY_DIR"], vars["CVE_CHECK_SUMMARY_FILE_NAME_JSON"]) + print(report_json) + try: + os.remove(report_json) + except FileNotFoundError: + pass + + bitbake("core-image-minimal-initramfs") + self.assertExists(report_json) + + # Check that the summary report lists at least one package + with open(report_json) as f: + report = json.load(f) + self.assertEqual(report["version"], "1") + self.assertGreater(len(report["package"]), 1) + + # Check that a random recipe wrote a recipe report to deploy/cve/ + recipename = report["package"][0]["name"] + recipe_report = os.path.join(vars["CVE_CHECK_DIR"], recipename + "_cve.json") + self.assertExists(recipe_report) + with open(recipe_report) as f: + report = json.load(f) + self.assertEqual(report["version"], "1") + self.assertEqual(len(report["package"]), 1) + self.assertEqual(report["package"][0]["name"], recipename) + + + def test_recipe_report_json_unpatched(self): + config = """ +INHERIT += "cve-check" +CVE_CHECK_FORMAT_JSON = "1" +CVE_CHECK_REPORT_PATCHED = "0" +""" + self.write_config(config) + + vars = get_bb_vars(["CVE_CHECK_SUMMARY_DIR", "CVE_CHECK_SUMMARY_FILE_NAME_JSON"]) + summary_json = os.path.join(vars["CVE_CHECK_SUMMARY_DIR"], vars["CVE_CHECK_SUMMARY_FILE_NAME_JSON"]) + recipe_json = os.path.join(vars["CVE_CHECK_SUMMARY_DIR"], "m4-native_cve.json") + + try: + os.remove(summary_json) + os.remove(recipe_json) + except FileNotFoundError: + pass + + bitbake("m4-native -c cve_check") + + def check_m4_json(filename): + with open(filename) as f: + report = json.load(f) + self.assertEqual(report["version"], "1") + self.assertEqual(len(report["package"]), 1) + package = report["package"][0] + self.assertEqual(package["name"], "m4-native") + #m4 had only Patched CVEs, so the issues array will be empty + self.assertEqual(package["issue"], []) + + self.assertExists(summary_json) + check_m4_json(summary_json) + self.assertExists(recipe_json) + check_m4_json(recipe_json) + + + def test_recipe_report_json_ignored(self): + config = """ +INHERIT += "cve-check" +CVE_CHECK_FORMAT_JSON = "1" +CVE_CHECK_REPORT_PATCHED = "1" +""" + self.write_config(config) + + vars = get_bb_vars(["CVE_CHECK_SUMMARY_DIR", "CVE_CHECK_SUMMARY_FILE_NAME_JSON"]) + summary_json = os.path.join(vars["CVE_CHECK_SUMMARY_DIR"], vars["CVE_CHECK_SUMMARY_FILE_NAME_JSON"]) + recipe_json = os.path.join(vars["CVE_CHECK_SUMMARY_DIR"], "logrotate_cve.json") + + try: + os.remove(summary_json) + os.remove(recipe_json) + except FileNotFoundError: + pass + + bitbake("logrotate -c cve_check") + + def check_m4_json(filename): + with open(filename) as f: + report = json.load(f) + self.assertEqual(report["version"], "1") + self.assertEqual(len(report["package"]), 1) + package = report["package"][0] + self.assertEqual(package["name"], "logrotate") + found_cves = { issue["id"]: issue["status"] for issue in package["issue"]} + # m4 CVE should not be in logrotate + self.assertNotIn("CVE-2008-1687", found_cves) + # logrotate has both Patched and Ignored CVEs + self.assertIn("CVE-2011-1098", found_cves) + self.assertEqual(found_cves["CVE-2011-1098"], "Patched") + self.assertIn("CVE-2011-1548", found_cves) + self.assertEqual(found_cves["CVE-2011-1548"], "Ignored") + self.assertIn("CVE-2011-1549", found_cves) + self.assertEqual(found_cves["CVE-2011-1549"], "Ignored") + self.assertIn("CVE-2011-1550", found_cves) + self.assertEqual(found_cves["CVE-2011-1550"], "Ignored") + + self.assertExists(summary_json) + check_m4_json(summary_json) + self.assertExists(recipe_json) + check_m4_json(recipe_json) diff --git a/poky/meta/lib/oeqa/selftest/cases/devtool.py b/poky/meta/lib/oeqa/selftest/cases/devtool.py index 3eea2b1a0e..34fc791f3a 100644 --- a/poky/meta/lib/oeqa/selftest/cases/devtool.py +++ b/poky/meta/lib/oeqa/selftest/cases/devtool.py @@ -218,6 +218,34 @@ class DevtoolTestCase(OESelftestTestCase): filelist.append(' '.join(splitline)) return filelist + def _check_diff(self, diffoutput, addlines, removelines): + """Check output from 'git diff' matches expectation""" + remaining_addlines = addlines[:] + remaining_removelines = removelines[:] + for line in diffoutput.splitlines(): + if line.startswith('+++') or line.startswith('---'): + continue + elif line.startswith('+'): + matched = False + for item in addlines: + if re.match(item, line[1:].strip()): + matched = True + remaining_addlines.remove(item) + break + self.assertTrue(matched, 'Unexpected diff add line: %s' % line) + elif line.startswith('-'): + matched = False + for item in removelines: + if re.match(item, line[1:].strip()): + matched = True + remaining_removelines.remove(item) + break + self.assertTrue(matched, 'Unexpected diff remove line: %s' % line) + if remaining_addlines: + self.fail('Expected added lines not found: %s' % remaining_addlines) + if remaining_removelines: + self.fail('Expected removed lines not found: %s' % remaining_removelines) + class DevtoolBase(DevtoolTestCase): @@ -444,7 +472,7 @@ class DevtoolAddTests(DevtoolBase): checkvars['S'] = '${WORKDIR}/MarkupSafe-%s' % testver checkvars['SRC_URI'] = url self._test_recipe_contents(recipefile, checkvars, []) - + def test_devtool_add_fetch_git(self): tempdir = tempfile.mkdtemp(prefix='devtoolqa') self.track_for_cleanup(tempdir) @@ -544,6 +572,19 @@ class DevtoolAddTests(DevtoolBase): # Test devtool build result = runCmd('devtool build %s' % pn) + def test_devtool_add_python_egg_requires(self): + # Fetch source + tempdir = tempfile.mkdtemp(prefix='devtoolqa') + self.track_for_cleanup(tempdir) + testver = '0.14.0' + url = 'https://files.pythonhosted.org/packages/e9/9e/25d59f5043cf763833b2581c8027fa92342c4cf8ee523b498ecdf460c16d/uvicorn-%s.tar.gz' % testver + testrecipe = 'python3-uvicorn' + srcdir = os.path.join(tempdir, testrecipe) + # Test devtool add + self.track_for_cleanup(self.workspacedir) + self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') + result = runCmd('devtool add %s %s -f %s' % (testrecipe, srcdir, url)) + class DevtoolModifyTests(DevtoolBase): def test_devtool_modify(self): @@ -705,6 +746,7 @@ class DevtoolModifyTests(DevtoolBase): self.assertTrue(bbclassextended, 'None of these recipes are BBCLASSEXTENDed to native - need to adjust testrecipes list: %s' % ', '.join(testrecipes)) self.assertTrue(inheritnative, 'None of these recipes do "inherit native" - need to adjust testrecipes list: %s' % ', '.join(testrecipes)) + def test_devtool_modify_localfiles_only(self): # Check preconditions testrecipe = 'base-files' @@ -917,23 +959,7 @@ class DevtoolUpdateTests(DevtoolBase): srcurilines[0] = 'SRC_URI = "' + srcurilines[0] srcurilines.append('"') removelines = ['SRCREV = ".*"'] + srcurilines - for line in result.output.splitlines(): - if line.startswith('+++') or line.startswith('---'): - continue - elif line.startswith('+'): - matched = False - for item in addlines: - if re.match(item, line[1:].strip()): - matched = True - break - self.assertTrue(matched, 'Unexpected diff add line: %s' % line) - elif line.startswith('-'): - matched = False - for item in removelines: - if re.match(item, line[1:].strip()): - matched = True - break - self.assertTrue(matched, 'Unexpected diff remove line: %s' % line) + self._check_diff(result.output, addlines, removelines) # Now try with auto mode runCmd('cd %s; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, os.path.basename(recipefile))) result = runCmd('devtool update-recipe %s' % testrecipe) @@ -1303,6 +1329,73 @@ class DevtoolUpdateTests(DevtoolBase): expected_status = [] self._check_repo_status(os.path.dirname(recipefile), expected_status) + def test_devtool_finish_modify_git_subdir(self): + # Check preconditions + testrecipe = 'dos2unix' + bb_vars = get_bb_vars(['SRC_URI', 'S', 'WORKDIR', 'FILE'], testrecipe) + self.assertIn('git://', bb_vars['SRC_URI'], 'This test expects the %s recipe to be a git recipe' % testrecipe) + workdir_git = '%s/git/' % bb_vars['WORKDIR'] + if not bb_vars['S'].startswith(workdir_git): + self.fail('This test expects the %s recipe to be building from a subdirectory of the git repo' % testrecipe) + subdir = bb_vars['S'].split(workdir_git, 1)[1] + # Clean up anything in the workdir/sysroot/sstate cache + bitbake('%s -c cleansstate' % testrecipe) + # Try modifying a recipe + tempdir = tempfile.mkdtemp(prefix='devtoolqa') + self.track_for_cleanup(tempdir) + self.track_for_cleanup(self.workspacedir) + self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe) + self.add_command_to_tearDown('bitbake-layers remove-layer */workspace') + result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir)) + testsrcfile = os.path.join(tempdir, subdir, 'dos2unix.c') + self.assertExists(testsrcfile, 'Extracted source could not be found') + self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. devtool output: %s' % result.output) + self.assertNotExists(os.path.join(tempdir, subdir, '.git'), 'Subdirectory has been initialised as a git repo') + # Check git repo + self._check_src_repo(tempdir) + # Modify file + runCmd("sed -i '1s:^:/* Add a comment */\\n:' %s" % testsrcfile) + result = runCmd('git commit -a -m "Add a comment"', cwd=tempdir) + # Now try updating original recipe + recipefile = bb_vars['FILE'] + recipedir = os.path.dirname(recipefile) + self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (recipedir, testrecipe)) + result = runCmd('devtool update-recipe %s' % testrecipe) + expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)), + ('??', '.*/%s/%s/$' % (testrecipe, testrecipe))] + self._check_repo_status(os.path.dirname(recipefile), expected_status) + result = runCmd('git diff %s' % os.path.basename(recipefile), cwd=os.path.dirname(recipefile)) + removelines = ['SRC_URI = "git://.*"'] + addlines = [ + 'SRC_URI = "git://.* \\\\', + 'file://0001-Add-a-comment.patch;patchdir=.. \\\\', + '"' + ] + self._check_diff(result.output, addlines, removelines) + # Put things back so we can run devtool finish on a different layer + runCmd('cd %s; rm -f %s/*.patch; git checkout .' % (recipedir, testrecipe)) + # Run devtool finish + res = re.search('recipes-.*', recipedir) + self.assertTrue(res, 'Unable to find recipe subdirectory') + recipesubdir = res[0] + self.add_command_to_tearDown('rm -rf %s' % os.path.join(self.testlayer_path, recipesubdir)) + result = runCmd('devtool finish %s meta-selftest' % testrecipe) + # Check bbappend file contents + appendfn = os.path.join(self.testlayer_path, recipesubdir, '%s_%%.bbappend' % testrecipe) + with open(appendfn, 'r') as f: + appendlines = f.readlines() + expected_appendlines = [ + 'FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"\n', + '\n', + 'SRC_URI += "file://0001-Add-a-comment.patch;patchdir=.."\n', + '\n' + ] + self.assertEqual(appendlines, expected_appendlines) + self.assertExists(os.path.join(os.path.dirname(appendfn), testrecipe, '0001-Add-a-comment.patch')) + # Try building + bitbake('%s -c patch' % testrecipe) + + class DevtoolExtractTests(DevtoolBase): def test_devtool_extract(self): diff --git a/poky/meta/lib/oeqa/selftest/cases/git.py b/poky/meta/lib/oeqa/selftest/cases/git.py new file mode 100644 index 0000000000..f12874dc7d --- /dev/null +++ b/poky/meta/lib/oeqa/selftest/cases/git.py @@ -0,0 +1,15 @@ +from oeqa.selftest.case import OESelftestTestCase +from oeqa.utils.commands import bitbake + +class GitCheck(OESelftestTestCase): + def test_git_intercept(self): + """ + Git binaries with CVE-2022-24765 fixed will refuse to operate on a + repository which is owned by a different user. This breaks our + do_install task as that runs inside pseudo, so the git repository is + owned by the build user but git is running as (fake)root. + + We have an intercept which disables pseudo, so verify that it works. + """ + bitbake("git-submodule-test -c test_git_as_user") + bitbake("git-submodule-test -c test_git_as_root") diff --git a/poky/meta/lib/oeqa/selftest/cases/imagefeatures.py b/poky/meta/lib/oeqa/selftest/cases/imagefeatures.py index 6b94ace4eb..6d010b3e3a 100644 --- a/poky/meta/lib/oeqa/selftest/cases/imagefeatures.py +++ b/poky/meta/lib/oeqa/selftest/cases/imagefeatures.py @@ -235,7 +235,7 @@ USERADD_GID_TABLES += "files/static-group" DISTRO_FEATURES:append = " pam opengl wayland" # Switch to systemd -DISTRO_FEATURES += "systemd" +DISTRO_FEATURES:append = " systemd" VIRTUAL-RUNTIME_init_manager = "systemd" VIRTUAL-RUNTIME_initscripts = "" VIRTUAL-RUNTIME_syslog = "" diff --git a/poky/meta/lib/oeqa/selftest/cases/multiconfig.py b/poky/meta/lib/oeqa/selftest/cases/multiconfig.py index baae9b456f..83cbd1345d 100644 --- a/poky/meta/lib/oeqa/selftest/cases/multiconfig.py +++ b/poky/meta/lib/oeqa/selftest/cases/multiconfig.py @@ -70,3 +70,16 @@ TMPDIR = "${TOPDIR}/tmp-mc-tiny" result = bitbake('mc:test:multiconfig-test-parse -c showvar') self.assertIn('MCTESTVAR=test2', result.output.splitlines()) + + def test_multiconfig_inlayer(self): + """ + Test that a multiconfig from meta-selftest works. + """ + + config = """ +BBMULTICONFIG = "muslmc" +""" + self.write_config(config) + + # Build a core-image-minimal, only dry run needed to check config is present + bitbake('mc:muslmc:bash -n') diff --git a/poky/meta/lib/oeqa/selftest/cases/oescripts.py b/poky/meta/lib/oeqa/selftest/cases/oescripts.py index cd687816c8..bd84f151cb 100644 --- a/poky/meta/lib/oeqa/selftest/cases/oescripts.py +++ b/poky/meta/lib/oeqa/selftest/cases/oescripts.py @@ -129,7 +129,8 @@ class OEListPackageconfigTests(OEScriptTests): def check_endlines(self, results, expected_endlines): for line in results.output.splitlines(): for el in expected_endlines: - if line.split() == el.split(): + if line and line.split()[0] == el.split()[0] and \ + ' '.join(sorted(el.split())) in ' '.join(sorted(line.split())): expected_endlines.remove(el) break diff --git a/poky/meta/lib/oeqa/selftest/cases/overlayfs.py b/poky/meta/lib/oeqa/selftest/cases/overlayfs.py index 472746a64f..96beb8b869 100644 --- a/poky/meta/lib/oeqa/selftest/cases/overlayfs.py +++ b/poky/meta/lib/oeqa/selftest/cases/overlayfs.py @@ -55,18 +55,36 @@ inherit overlayfs config = """ IMAGE_INSTALL:append = " overlayfs-user" -DISTRO_FEATURES += "systemd overlayfs" +DISTRO_FEATURES:append = " systemd overlayfs" """ self.write_config(config) self.add_overlay_conf_to_machine() res = bitbake('core-image-minimal', ignore_status=True) - line = getline(res, " Mount path /mnt/overlay not found in fstat and unit mnt-overlay.mount not found in systemd unit directories") + line = getline(res, " Mount path /mnt/overlay not found in fstab and unit mnt-overlay.mount not found in systemd unit directories") self.assertTrue(line and line.startswith("WARNING:"), msg=res.output) line = getline(res, "Not all mount paths and units are installed in the image") self.assertTrue(line and line.startswith("ERROR:"), msg=res.output) + def test_not_all_units_installed_but_qa_skipped(self): + """ + Summary: Test skipping the QA check + Expected: Image is created successfully + Author: Claudius Heine <ch@denx.de> + """ + + config = """ +IMAGE_INSTALL:append = " overlayfs-user" +DISTRO_FEATURES += "systemd overlayfs" +OVERLAYFS_QA_SKIP[mnt-overlay] = "mount-configured" +""" + + self.write_config(config) + self.add_overlay_conf_to_machine() + + bitbake('core-image-minimal') + def test_mount_unit_not_set(self): """ Summary: Test whether mount unit was set properly @@ -76,7 +94,7 @@ DISTRO_FEATURES += "systemd overlayfs" config = """ IMAGE_INSTALL:append = " overlayfs-user" -DISTRO_FEATURES += "systemd overlayfs" +DISTRO_FEATURES:append = " systemd overlayfs" """ self.write_config(config) @@ -94,7 +112,7 @@ DISTRO_FEATURES += "systemd overlayfs" config = """ IMAGE_INSTALL:append = " overlayfs-user" -DISTRO_FEATURES += "systemd overlayfs" +DISTRO_FEATURES:append = " systemd overlayfs" """ wrong_machine_config = """ @@ -118,7 +136,7 @@ OVERLAYFS_MOUNT_POINT[usr-share-overlay] = "/usr/share/overlay" config = """ IMAGE_INSTALL:append = " overlayfs-user systemd-machine-units" -DISTRO_FEATURES += "systemd overlayfs" +DISTRO_FEATURES:append = " systemd overlayfs" # Use systemd as init manager VIRTUAL-RUNTIME_init_manager = "systemd" @@ -253,7 +271,7 @@ class OverlayFSEtcRunTimeTests(OESelftestTestCase): """ configBase = """ -DISTRO_FEATURES += "systemd" +DISTRO_FEATURES:append = " systemd" # Use systemd as init manager VIRTUAL-RUNTIME_init_manager = "systemd" @@ -295,7 +313,7 @@ OVERLAYFS_ETC_DEVICE = "/dev/mmcblk0p1" """ config = """ -DISTRO_FEATURES += "systemd" +DISTRO_FEATURES:append = " systemd" # Use systemd as init manager VIRTUAL-RUNTIME_init_manager = "systemd" @@ -331,7 +349,7 @@ INHERIT += "overlayfs-etc" """ config = f""" -DISTRO_FEATURES += "systemd" +DISTRO_FEATURES:append = " systemd" # Use systemd as init manager VIRTUAL-RUNTIME_init_manager = "systemd" @@ -373,7 +391,7 @@ OVERLAYFS_ETC_DEVICE = "/dev/sda3" """ config = """ -DISTRO_FEATURES += "systemd" +DISTRO_FEATURES:append = " systemd" # Use systemd as init manager VIRTUAL-RUNTIME_init_manager = "systemd" diff --git a/poky/meta/lib/oeqa/selftest/cases/runtime_test.py b/poky/meta/lib/oeqa/selftest/cases/runtime_test.py index 3ece617cb0..857737f730 100644 --- a/poky/meta/lib/oeqa/selftest/cases/runtime_test.py +++ b/poky/meta/lib/oeqa/selftest/cases/runtime_test.py @@ -252,7 +252,7 @@ class TestImage(OESelftestTestCase): import subprocess, os distro = oe.lsb.distro_identifier() - if distro and distro in ['debian-9', 'debian-10', 'centos-7', 'centos-8', 'ubuntu-16.04', 'ubuntu-18.04', 'almalinux-8.5']: + if distro and (distro in ['debian-9', 'debian-10', 'centos-7', 'centos-8', 'ubuntu-16.04', 'ubuntu-18.04'] or distro.startswith('almalinux')): self.skipTest('virgl headless cannot be tested with %s' %(distro)) render_hint = """If /dev/dri/renderD* is absent due to lack of suitable GPU, 'modprobe vgem' will create one suitable for mesa llvmpipe software renderer.""" |