master: subtree updates oct 4 2023

poky: 61531cd395..e444d2bed0:
  Adrian Freihofer (3):
        lib/oe/utils: Refactor to make multiprocess_launch callable without d
        lib/oe/package: Refactor to make strip_execs callable without d
        oeqa/selftest/devtool: Refactor runqemu pre-requisites

  Alexander Kanavin (69):
        cargo-c-native: fix version check
        igt-gpu-tools: do not write shortened git commit hash into binaries
        curl: build and run the full set of ptests
        ptest: report tests that were killed on timeout
        perl: use 64 bit integers across all targets
        perl: ensure all failures are caught
        strace: parallelize ptest
        strace: remove from time64.inc exception list
        busybox: enable 64 bit shell arithmetic (via long long type)
        openssl: parallelize tests
        openssl: ensure all ptest fails are caught
        glibc-tests: rename to glibc-y2038-tests
        sysstat: merge .inc into .bb
        sysstat: update 12.6.2 -> 12.7.4
        glib-2.0: update 2.76.4 -> 2.78.0
        ovmf: update edk2-stable202305 -> edk2-stable202308
        libdnf: update 0.70.1 -> 0.71.0
        liburi-perl: update 5.17 -> 5.21
        python3-pygobject: update 3.44.1 -> 3.46.0
        go-helloworld: update to latest revision
        gzip: update 1.12 -> 1.13
        procps: update 4.0.3 -> 4.0.4
        screen: update 4.9.0 -> 4.9.1
        gobject-introspection: update 1.76.1 -> 1.78.0
        igt-gpu-tools: update 1.27.1 -> 1.28
        libva-utils: update 2.19.0 -> 2.20.0
        piglit: update to latest revision
        groff: add a patch to resolve build races
        groff: fix another build race via backport
        systemd: upgrade 254 -> 254.4
        util-linux: upgrade 2.39.1 -> 2.39.2
        cmake: upgrade 3.27.4 -> 3.27.5
        jquery: upgrade 3.7.0 -> 3.7.1
        python3-setuptools-rust: upgrade 1.6.0 -> 1.7.0
        vulkan: upgrade 1.3.250.0 -> 1.3.261.1
        libxcb: upgrade 1.15 -> 1.16
        xcb-proto: upgrade 1.15.2 -> 1.16.0
        boost: upgrade 1.82.0 -> 1.83.0
        btrfs-tools: upgrade 6.3.3 -> 6.5.1
        createrepo-c: upgrade 0.21.1 -> 1.0.0
        debianutils: upgrade 5.12 -> 5.13
        diffoscope: upgrade 244 -> 249
        ethtool: upgrade 6.3 -> 6.5
        font-util: upgrade 1.4.0 -> 1.4.1
        freetype: upgrade 2.13.1 -> 2.13.2
        ghostscript: upgrade 10.01.2 -> 10.02.0
        iproute2: upgrade 6.4.0 -> 6.5.0
        json-c: upgrade 0.16 -> 0.17
        kmscube: upgrade to latest revision
        libarchive: upgrade 3.7.1 -> 3.7.2
        libsdl2: upgrade 2.28.0 -> 2.28.3
        libsolv: upgrade 0.7.24 -> 0.7.25
        man-pages: upgrade 6.04 -> 6.05.01
        meson: upgrade 1.1.1 -> 1.2.1
        mmc-utils: upgrade to latest revision
        mtd-utils: upgrade 2.1.5 -> 2.1.6
        puzzles: upgrade to latest revision
        python3-dtschema: upgrade 2023.6.1 -> 2023.7
        python3-git: upgrade 3.1.35 -> 3.1.36
        python3-libarchive-c: upgrade 4.0 -> 5.0
        python3-setuptools: upgrade 68.2.1 -> 68.2.2
        python3-sphinx: upgrade 7.2.5 -> 7.2.6
        seatd: upgrade 0.7.0 -> 0.8.0
        sqlite3: upgrade 3.43.0 -> 3.43.1
        tiff: upgrade 4.5.1 -> 4.6.0
        vala: upgrade 0.56.8 -> 0.56.13
        xf86-input-libinput: upgrade 1.3.0 -> 1.4.0
        xwayland: upgrade 23.1.2 -> 23.2.1
        python3-setuptools-scm: fix upstream version check

  Alexandre Belloni (1):
        python3: fix SoB on patch

  Antoine Lubineau (1):
        cve-check: add CVSS vector string to CVE database and reports

  Bruce Ashfield (9):
        linux-yocto/6.4: update to v6.4.15
        linux-yocto/6.1: update to v6.1.52
        linux-yocto/6.4: update to v6.4.16
        linux-yocto/6.1: update to v6.1.53
        linux-yocto/6.1: update to v6.1.55
        linux-yocto-dev: update to v6.6-rcX
        linux-yocto: introduce 6.5 reference kernel recipes
        linux-libc-headers: uprev to v6.5
        linux-libc-headers: default to 6.5

  Charles-Antoine Couret (1):
        systemd-boot-cfg: add .conf suffix to default entry label

  Chen Qi (1):
        python3: add cpython to CVE_PRODUCT

  Daniel Semkowicz (2):
        wic: bootimg-partition: Fix file name in debug message
        uboot-extlinux-config.bbclass: Add missing variable descriptions

  Deepthi Hemraj (2):
        binutils: stable 2.41 branch updates.
        glibc: stable 2.38 branch updates.

  Denys Dmytriyenko (2):
        bitbake.conf: add MACHINE to SDK_NAME
        spdx: use TOOLCHAIN_OUTPUTNAME for SDK filename prefix

  Derek Straka (1):
        pypi.bbclass: Update the upstream checks to automatically replace '_' with '-'

  Eilís 'pidge' Ní Fhlannagáin (2):
        lib/oe/package_managegment: Add nativesdk-intercept PATH
        update_mandb: deb fails due to missing man cache

  Etienne Cordonnier (1):
        bitbake: bitbake-worker/runqueue: Avoid unnecessary bytes object copies

  Insu Park (1):
        bitbake: data: Add missing dependency handling of remove operator

  Jan Garcia (1):
        insane.bbclass: Count raw bytes in shebang-size

  Joshua Watt (6):
        classes/create-spdx-2.2: Add extra debugging for missing package files
        nfs-utils: Don't start nfs-statsd.service without exports
        nfs-utils: Add StateDirectory for systemd services
        bitbake: utils: Add path_is_descendant()
        bitbake: fetch2: git: Use path_is_descendant() instead of path for repo check
        classes/create-spdx-2.2: Show error if document is not found

  Julien Stephan (1):
        bitbake: bitbake: cooker: add a new function to retrieve task signatures

  Kai Kang (2):
        goarch.bbclass: not compatible with riscv32
        adwaita-icon-theme: 43 -> 45.0

  Khem Raj (25):
        perl: Add packageconfig for setlocale functionality differences
        libc-test: Run as non-root user
        coreutils: Upgrade to 9.4
        coreutils: Add config.h to ptest package
        gettext: Add missing dependency on gawk autoconf
        util-linux: Disable failing tests on musl
        Revert "util-linux: scanf_cv_alloc_modifier changed from 'as' -> 'ms'"
        util-linux: Fix lscpu on musl
        qemu: Add PACKAGECONFIG for dax
        llvm: Upgrade to 17.0.1
        oeqa: Use 2.14 release of cpio instead of 2.13
        musl: Update to latest
        bsd-headers: Define __CONCAT and __STRING
        mesa: Update clang-17 patch to upstream v2
        musl-legacy-error: Add recipe
        elfutils: Depend on musl-legacy-error for musl targets
        debugedit: Use musl-legacy-error
        systemd: Drop two upstreamed musl patches
        systemd: Refresh patches to avoid patch-fuzz
        glib-2.0: Enable possible locales with musl for ptests
        glib-2.0: Remove failing ptests on musl
        llvm: Upgrade to 17.0.2
        createrepo-c: Fix function declaration bug found with clang
        mesa: Simplify llvm-17 patch
        mesa: Fix native build on hosts with llvm-dev installed

  Lee Chee Yang (2):
        bind: update to 9.18.19
        cups: fix CVE-2023-4504

  Markus Volk (8):
        mesa: upgrade 23.1.3 -> 23.1.7
        libportal: upgrade 0.6 -> 0.7.1
        appstream: import recipe from meta-oe
        libadwaita: upgrade 1.3.4 -> 1.4.0
        maintainers.inc: add missing entries for appstream and libxmlb
        libxmlb: import recipe from meta-oe
        pulseaudio: dont include consolekit for systemd
        mesa: Upgrade 23.1.7 -> 23.1.8

  Marta Rybczynska (3):
        python3-ply: add to nativesdk
        python3-isodate: add homepage
        python3-rdflib: add homepage

  Martin Jansa (3):
        gcc: backport a fix for ICE caused by CVE-2023-4039.patch
        fontcache.bbclass: avoid native recipes depending on target fontconfig
        multilib_script.bbclass: expand script name as well

  Matthias Schnelte (1):
        bitbake: fetch2: Adds vscode devcontainer support

  Michael Opdenacker (18):
        base: add newline before LICENSE_FLAGS_DETAILS
        dev-manual: new-recipe.rst fix inconsistency with contributor guide
        contributor-guide: recipe-style-guide: add Upstream-Status
        dev-manual: licenses: update license manifest location
        dev-manual: licenses: mention SPDX for license compliance
        dev-manual: disk-space: improve wording for obsolete sstate cache files
        sdk-manual: extensible.rst: fix multiple formatting issues
        alsa-lib: upgrade 1.2.9 -> 1.2.10
        alsa-utils: upgrade 1.2.9 -> 1.2.10
        shadow: fix patch Upstream-Status
        libevent: fix patch Upstream-Status
        alsa-utils: update patch Upstream-Status
        alsa-lib: fix patch Upstream-Status
        lib/oe/qa: remove obsolete "Accepted" string for Upstream-Status
        lib/oe/qa: update guidelines link for Upstream-Status
        bsp-guide: bsp.rst: replace reference to wiki
        dev-manual: new-recipe.rst: replace reference to wiki
        maintainers.inc: add self for flac recipe

  Mikko Rapeli (9):
        openssh: update Upstream-Status to Denied in test logging patch
        openssh: improve banner ptest failure logging
        testimage.bbclass: detect slirp from TEST_RUNQEMUPARAMS
        oeqa dnf_runtime.py: fix HTTP server IP address and port
        oeqa selftest runtime_test.py: append to TEST_RUNQEMUPARAMS
        selftest runtime_test.py: add testimage.bbclass slirp test
        openssh: capture logs in run-ptest
        testimage.bbclass: remove QEMU_USE_SLIRP variable
        oeqa/selftest/context.py: check git command return values

  Ninad Palsule (1):
        kernel-fitImage: Strip path component from dtb

  Peter Kjellerstedt (7):
        libsoup-2.4: Only specify --cross-file when building for target
        libsoup: Only specify --cross-file when building for target
        bitbake: tinfoil: Do not fail when logging is disabled and full config is used
        bitbake: bitbake-getvar: Make --quiet work with --recipe
        bitbake: bitbake-getvar: Make --value imply --quiet
        bitbake: bitbake-getvar: Add a (suppressable) error for undefined variables
        bitbake: bitbake-getvar: Treat undefined variables as empty with --value

  Peter Marko (2):
        openssl: Upgrade 3.1.2 -> 3.1.3
        json-c: define CVE_VERSION

  Qiu Tingting (1):
        tar: add ptest support

  Richard Purdie (34):
        bitbake.conf: Add IMAGE_BASENAME to SDK_NAME
        vim: Upgrade 9.0.1664 -> 9.0.1894
        defaultsetup: Inherit create-spdx by default
        oeqa/selftest/runtime_test: No need to use append with TEST_RUNQEMUPARAMS
        devtool/build_sdk: Drop unused imports
        bitbake: lib: Drop inotify support and replace with mtime checks
        bitbake: server/process: Disable the flush() call in server logging
        recipetool/devtool: Ensure server knows about changed files
        lttng-tools: Upgrade 2.13.10 -> 2.13.11
        oeqa/selftest/wic: Improve assertTrue calls
        elfutils: Fix reproducibility issue with bunzip2
        bitbake: cooker: Drop unneeded flush calls
        sstate: Fix nativesdk entry in SSTATE_ARCHS
        multilib: fix SSTATE_ARCHS for multilib usage
        license/license_image: Fix license file layout to avoid overlapping files
        oeqa/selftest/bbtests: Improve and update test_non_gplv3
        create-spdx/sbom: Ensure files don't overlap between machines
        sstate: Stop allowing overlapping symlinks from sstate
        recipes: Drop remaining PR values from recipes
        bitbake.conf: No longer support PR from filename
        oeqa/selftest: Fix broken symlink removal handling
        oeqa/selftest/reproducible: Avoid oe-selftest startup delays
        oeqa: Streamline oe-selftest startup time
        oeqa/selftest/oescripts: Avoid variable access at module load
        bitbake: codeparser: Update debug variable reference
        contributor-guide/style-guide: Refer to recipes, not packages
        contributor-guide/style-guide: Add a note about task idempotence
        lib: Import packagedata oe module by default
        oeqa/runner: Ensure class setup errors are shown to bitbake logging
        create-spdx: Ensure it is clear where the message comes from
        oeqa/utils/gitarchive: Handle broken commit counts in results repo
        python3-numpy: Fix reproducibility issue
        scritps/runqemu: Ensure we only have two serial ports
        glibc: Pull in stable branch fixes

  Robert Joslyn (2):
        curl: Update from 8.2.1 to 8.3.0
        curl: Skip tests marked flaky

  Robert Yang (1):
        libxcrypt-compat: Remove libcrypt.so to fix conflict with libcrypt

  Roland Hieber (7):
        template: fix typo in section header
        ref-manual: point outdated link to the new location
        contributor-guide: recipe-style-guide: add more patch tagging examples
        contributor-guide: recipe-style-guide: add section about CVE patches
        contributor-guide: discourage marking patches as Inappropriate
        contributor-guide: deprecate "Accepted" patch status
        contributor-guide: style-guide: discourage using Pending patch status

  Ross Burton (19):
        packagegroup-core-x11-xserver: add modesetting driver to default XSERVER
        machine/qemu*: add modesetting drivers to XSERVER
        beaglebone-yocto: remove redundant XSERVER assignment
        gcc: Fix -fstack-protector issue on aarch64
        testimage: respect target/server IPs when using slirp
        manuals: document LICENSE_FLAGS_DETAILS
        linux-yocto: update CVE ignores
        libwebp: upgrade to 1.3.2
        oeqa/runtime/parselogs: remove unused imports
        oeqa/runtime/parselogs: don't bother to show target hardware information
        oeqa/runtime/parselogs: remove obsolete LSB testing support
        oeqa/runtime/parselogs: inline single-caller functions
        oeqa/runtime/parselogs: improve find call
        oeqa/runtime/parselogs: don't pass around members
        oeqa/runtime/parselogs: move some variables out of global scope
        oeqa/runtime/parselogs: select the correct machine-specific ignores early
        oeqa/runtime/parselogs: parse the logs with Python, not grep
        webkitgtk: reduce size of -dbg package
        bitbake: bitbake/lib: spawn server/worker using the current Python interpreter

  Samantha Jalabert (14):
        python3-isodate: Copy recipe from meta-python
        python3-booleanpy: Copy recipe from meta-python
        python3-beartype: add recipe
        python3-click: Copy recipe from meta-python
        ptest-packagelists.inc: add python test click
        python3-license-expression: Copy recipe from meta-python
        ptest-packagelists.inc: add python test license-expression
        python3-rdflib: Copy recipe from meta-python
        python3-uritools: add recipe
        python3-xmltodict: Copy recipe from meta-python
        ptest-packagelists.inc: add python test xmltodict
        python3-spdx-tools: add recipe
        qa: Add selftest for python3-spdx-tools
        maintainers.inc: add python3-spdx-tools and dependencies

  Sean Nyekjaer (1):
        gcc: depend on zstd

  Stefan Tauner (1):
        gdb: fix RDEPENDS for PACKAGECONFIG[tui]

  Stephan Wurm (1):
        python3-jsonschema: Update homepage URL

  Tim Orling (1):
        python3-cryptography{-vectors}: upgrade to 41.0.4

  Trevor Gamblin (6):
        patchtest: Add tests from patchtest oe repo
        patchtest/selftest: remove configurable target
        patchtest: add requirements.txt
        patchtest: Add README.md for selftests
        python3-ptest: skip test_input_no_stdout_fileno
        patchtest/selftest: only split resultlines once

  Ulrich Ölmann (1):
        packagegroup-base: clean up setting packagegroup-machine-base's SUMMARY

  Wang Mingyu (36):
        alsa-ucm-conf: upgrade 1.2.9 -> 1.2.10
        at-spi2-core: upgrade 2.48.3 -> 2.48.4
        dbus: upgrade 1.14.8 -> 1.14.10
        debianutils: upgrade 5.8 -> 5.12
        dnf: upgrade 4.16.1 -> 4.17.0
        harfbuzz: upgrade 8.1.1 -> 8.2.0
        kexec-tools: upgrade 2.0.26 -> 2.0.27
        libinput: upgrade 1.23.0 -> 1.24.0
        libnl: upgrade 3.7.0 -> 3.8.0
        nghttp2: upgrade 1.55.1 -> 1.56.0
        ccache: upgrade 4.8.2 -> 4.8.3
        pkgconf: upgrade 2.0.2 -> 2.0.3
        python3-git: upgrade 3.1.34 -> 3.1.35
        python3-hypothesis: upgrade 6.84.0 -> 6.84.3
        python3-pyelftools: upgrade 0.29 -> 0.30
        python3-pytest: upgrade 7.4.1 -> 7.4.2
        python3-setuptools: upgrade 68.1.2 -> 68.2.1
        strace: upgrade 6.4 -> 6.5
        stress-ng: upgrade 0.16.04 -> 0.16.05
        wayland-utils: upgrade 1.1.0 -> 1.2.0
        wireless-regdb: upgrade 2023.05.03 -> 2023.09.01
        at-spi2-core: upgrade 2.48.4 -> 2.50.0
        enchant2: upgrade 2.5.0 -> 2.6.1
        harfbuzz: upgrade 8.2.0 -> 8.2.1
        kbd: upgrade 2.6.2 -> 2.6.3
        libsecret: upgrade 0.21.0 -> 0.21.1
        gobject-introspection: upgrade 1.78.0 -> 1.78.1
        python3-numpy: upgrade 1.25.2 -> 1.26.0
        python3-hypothesis: upgrade 6.84.3 -> 6.86.2
        python3-pycryptodome: upgrade 3.18.0 -> 3.19.0
        python3-pycryptodomex: upgrade 3.18.0 -> 3.19.0
        python3-smmap: upgrade 5.0.0 -> 6.0.0
        python3-trove-classifiers: upgrade 2023.8.7 -> 2023.9.19
        python3-typing-extensions: upgrade 4.7.1 -> 4.8.0
        python3-urllib3: upgrade 2.0.4 -> 2.0.5
        python3-zipp: upgrade 3.16.2 -> 3.17.0

  Yash Shinde (1):
        glibc: fix CVE-2023-4527

  Yogita Urade (2):
        tiff: fix CVE-2023-40745
        tiff: fix CVE-2023-41175

meta-openembedded: eff1b182c1..ea42cec2ec:
  Alex Kiernan (2):
        mdns: Upgrade 1790.80.10 -> 2200.0.8
        jq: Upgrade 1.6+git -> 1.7

  Archana Polampalli (2):
        python3-appdirs: print ptest results in unified format
        nodejs: upgrade 18.17.1 -> 20.5.1

  Armin Kuster (1):
        openldap: update to 2.5.16.

  Bruce Ashfield (2):
        zfs: update to v2.2.0-rc4
        vboxguestdrivers: fix kernel v6.5 build

  Chi Xu (1):
        mariadb: Add ptest support

  Clément Péron (6):
        etcd-cpp-apiv3: upgrade 0.14.3 -> 0.15.3
        devtools: grpc: bump to 1.56.2
        protobuf: upgrade 4.22.2 -> 4.23.4
        protobuf-c: bump to next release to support protobuf 4.23.x
        mariadb: add missing <cstdint> in rocksdb string_util.h
        etcd-cpp-apiv3: fix build when gRPC is cross compiled

  Daniel Semkowicz (2):
        cockpit: Move packagekit to a separate package
        cockpit: Move apps to a separate package

  Derek Straka (54):
        python3-absl: Update version 1.4.0 -> 2.0.0
        python3-brotli: Update version 1.0.9 -> 1.1.0
        python3-cachecontrol: Update version 0.13.0 -> 0.13.1
        python3-cantools: Update version 38.0.2 -> 39.2.0
        python3-cerberus: Update version 1.3.4 -> 1.3.5
        python3-configshell-fb: Update version 1.1.29 -> 1.1.30
        python3-custom-inherit: Update version 2.3.1 -> 2.4.1
        python3-distlib: Update version 0.3.6 -> 0.3.7
        python3-fasteners: Update version 0.18 -> 0.19
        python3-filelock: Update version 3.12.0 -> 3.12.4
        python3-bleak: Update version 0.20.2 -> 0.21.1
        python3-dynamic-dispatch: Correct the upstream regex check for version upgrades
        python3-google-api-python-client: Update version 2.99.0 -> 2.100.0
        python3-sqlalchemy: Upgrade 2.0.20 -> 2.0.21
        python3-netaddr: Update version 0.8.0 -> 0.9.0
        python3-msgpack: Update version 1.0.5 -> 1.0.6
        python3-protobuf: Update version 4.24.2 -> 4.24.3
        python3-gevent: Update version 23.7.0 -> 23.9.1
        python3-langtable: Update version 0.0.63 -> 0.0.64
        python3-posix-ipc: Update version 1.0.5 -> 1.1.1
        python3-websocket-client: Update version 1.5.3 -> 1.6.3
        python3-web3: Update version 6.9.0 -> 6.10.0
        python3-apiflask: Update version 2.0.1 -> 2.0.2
        python3-argh: Update version 0.29.3 -> 0.29.4
        python3-async-timeout: remove old version of the library
        python3-pydantic: Update version 1.10.7 -> 2.4.1
        python3-pyhamcrest: Fix upstream check by specifying the UPSTREAM_CHECK_URI and UPSTREAM_CHECK_REGEX
        python3-pyasn1-modules: Update version 0.2.8 -> 0.3.0
        python-pyiface: Update version from git -> 0.0.11
        python3-pymysql: Fix upstream check by specifying the UPSTREAM_CHECK_URI and UPSTREAM_CHECK_REGEX
        python3-pymysql: update verion 1.0.2 -> 1.1.0
        python3-pyproj: update version 3.6.0 -> 3.6.1
        python3-pyproject-api: update version 1.5.1 -> 1.6.1
        python3-redis: update version 5.0.0 -> 5.0.1
        python3-traitlets: update version 5.9.0 -> 5.10.1
        python3-xxhash: update version 3.2.0 -> 3.3.0
        python3-pyzmq: update version 25.0.0 -> 25.1.1
        python3-cachecontrol: Fix upstream check by specifying the UPSTREAM_CHECK_URI and UPSTREAM_CHECK_REGEX
        python3-flask-babel: update version 2.0.0 -> 3.1.0
        python3-idna-ssl: Fix upstream check by specifying the UPSTREAM_CHECK_URI and UPSTREAM_CHECK_REGEX
        python3-ninja-syntax: Fix upstream check by specifying the UPSTREAM_CHECK_URI and UPSTREAM_CHECK_REGEX
        python3-prettytable: update version 3.6.0 -> 3.9.0
        python3-pytz-deprecation-shim: Remove outdated recipe meant to be a short lived shim
        python3-tzlocal: Remove dependency on pytz_deprecation_shim removed in release 5.0
        python3-astroid: update version 2.16.6 -> 3.0.0
        python3-flask: update version 2.3.2 -> 2.3.3
        python3-google-api-core: update version 2.12.0
        python3-google-api-python-client: update version 2.100.0 -> 2.101.0
        python3-google-auth: update version 2.23.0 -> 2.23.1
        python3-parse-type: update version 0.5.2 -> 0.6.2
        python3-nacl: Add recipe for the latest release of PyNaCl
        python3-botocore: add recipe for latest version of botocore
        python3-boto3: add recipe for latest version of boto3
        python3-flask-cors: add initial version of the recipe for 4.0.0

  Etienne Cordonnier (1):
        uutils-coreutils: upgrade 0.0.20 -> 0.0.21

  Gianfranco Costamagna (3):
        mosquitto: do not automatically depend on dlt-daemon, it's a non-mandatory logging system
        mosquitto: upgrade 2.0.15 -> 2.0.17
        mosquitto: upgrade 2.0.17 -> 2.0.18

  Jeffrey Pautler (1):
        bolt: disable CVE checking for this recipe

  Jonas Gorski (1):
        frr: upgrade 8.4.4 -> 9.0.1

  Julian Haller (1):
        openct: Fix typo in SUMMARY variable

  Kai Kang (1):
        ostree: not compatible with riscv32 when ptest enabled

  Khem Raj (25):
        vlc: Fix build with gettext 0.22+
        usbguard: Enable seccomp if distro features have it
        sharutils: Check for intmax_t using configure
        poco: Add pass/fail ststus into logs
        mongodb: Add rdep on tzdata-core
        mongodb: Upgrade to 4.4.24
        meta-oe-ptest-image-poco: Increase size tp 1G
        poco: Fix ptest runtime errors
        poco: Do not enable MongoDB packageconfig by default
        plocate: Upgrade to 1.1.19 release
        xscreensaver: Add osuosl backup MIRROR
        mozjs-115: Apply autoconf tuple mismatch fix
        cpp-netlib: Fix build with boost 1.80+
        cpp-netlib: Fix buildpaths in generated cmake files
        python3-pybluez: Fix patch upstream-status
        python3-pynetlinux: Fix patch upstream-status
        libnet-idn-encode: Add recipe
        libio-socket-ssl-perl: Change libnet-libidn-perl->libnet-idn-encode rdep for ptests
        libnfs: Drop -Wno-implicit-function-declaration
        webkitgtk3: Do not use musttail with clang on arm
        fftw: Fix ptest result reporting
        nodejs: Fix ptest result reporting
        relayd: Update to latest tip of trunk
        relayd: Fix build with clang
        kernel-selftest: Build headers before compiling tests

  Lee Chee Yang (8):
        libsdl: fix CVE-2022-34568
        keepalived: 2.2.2 -> 2.2.8
        irssi: 1.4.2 -> 1.4.4
        iniparser: Fix CVE-2023-33461
        opensc: fix CVE-2023-2977
        x11vnc: Fix CVE-2020-29074
        libvncserver: update to 0.9.14
        ntpsec: 1.2.2 -> 1.2.2a

  Markus Volk (48):
        libei: add recipe
        libxmlb: update 0.3.10 -> 0.3.14
        appstream: update 0.16.2 -> 0.16.3
        webrtc-audio-processing: add recipe for 1.x
        pipewire: upgrade 0.3.79 -> 0.3.80
        evolution-data-server: upgrade 3.48.3 -> 3.50.0
        appstream: remove workaround for cross-compile
        libxmlb: fix a reproducibility and runtime issue with ptest
        tracker-miners: upgrade 3.5.0 -> 3.6.0
        mozjs: upgrade 102.9.0 -> 102.15.0
        tecla: add recipe
        polkit: upgrade 122 -> 123
        tracker: upgrade 3.5.1 -> 3.6.0
        libxmlb: remove recipe
        appstream: remove recipe
        gvfs: upgrade 1.51.90 -> 1.52.0
        mutter: upgrade 44.3 -> 45.0
        xdg-desktop-portal: upgrade 1.16.0 -> 1.18.0
        gnome-boxes: upgrade 44.2 -> 45.0
        gnome-session: upgrade 44.0 -> 45.0
        gnome-text-editor: upgrade 44.0 -> 45.0
        gnome-shell: upgrade 44.3 -> 45.0
        eog: upgrade 44.3 -> 45.0
        gnome-calculator: upgrade 44.0 -> 45.0
        xdg-desktop-portal-gnome: upgrade 44.1 -> 45.0
        gnome-calendar: upgrade 44.0 -> 45.0
        gnome-software: upgrade 44.4 -> 45.0
        zenity: upgrade 3.44.0 -> 3.44.2
        gnome-system-monitor: upgrade 44.0 -> 45.0
        webkitgtk: upgrade 2.40.5 -> 2.42.0
        gnome-control-center: upgrade 44.3 -> 45.0
        gnome-settings-daemon: upgrade 44.1 -> 45.0
        tracker: add missing Upstream-Status
        gdm: upgrade 44.1 -> 45.0.1
        gnome-calendar: fix reproducibility issue
        exiv2: Upgrade 0.27.6 -> 0.28.0
        gexiv: Upgrade 0.14.0 -> 0.14.2
        gjs: Upgrade 1.76.1 -> 1.78.0
        mozjs: add recipe for v115
        evince: Upgrade 44.2 -> 45.0
        Nautilus: Upgrade 44.2.1 -> 45.0
        gedit: Upgrade 44.2 -> 46.1
        tepl: Upgrade 6.4.0 -> 6.8.0
        libblockdev: Upgrade 2.28 -> 3.03
        udisks2: Upgrade 2.9.4 -> 2.10.1
        mozjs: Upgrade 102.15.0 -> 102.15.1
        libnfs: dont install libnfs-config.cmake
        gnome-remote-desktop: Upgrade 44.2 -> 45.0

  Martin Jansa (20):
        webrtc-audio-processing: Fix build with -Werror=return-type
        freeglut: return x11 to REQUIRED_DISTRO_FEATURES
        packagegroup-meta-multimedia: restore x11 restriction for projucer
        btrfsmaintenance: move btrfs-tools dependency from build-time to run-time
        btrfsmaintenance: drop allarch
        ttf-google-fira: exclude siggen dependency on fontconfig
        cukinia: drop allarch
        mdio-tools: exclude siggen dependency on mdio-netlink
        ot-br-posix: exclude siggen dependency on ipset
        mongodb: add and fix Upstream-Status
        mongodb: Fix build on 32bit
        gupnp: fix build with meson-1.2.0
        minifi-cpp, mozjs-115, redis-7.2.1, pv: add missing Upstream-Status
        mozjs: fix filename in MULTILIB_SCRIPTS
        gupnp-tools: fix build with meson-1.2.0
        gnome-tweaks, networkmanager-fortisslvpn, libesmtp, json-schema-validator, python3-pybluez, python3-pynetlinux, apache2: Fix Malformed Upstream-Status
        mozjs: use PV in MULTILIB_SCRIPTS
        mosquitto, etcd-cpp-apiv3: add missing Upstream-Status
        meta-oe/dynamic-layers: add Upstream-Status where missing
        meta-oe/dynamic-layers: add one more missing Upstream-Status and fix one malformed

  Michał Iwanicki (1):
        python3-pyu2f: add recipe

  Mingli Yu (4):
        minifi-cpp: Remove the buildpath issue
        hdf5: Upgrade to 1.14.2
        vlock: Use EXTRA_CFLAGS
        mozjs-102: Remove the buildpath

  Richard Leitner (2):
        python3-shellingham: add recipe for v1.5.3
        python3-autoflake: add recipe for v2.2.1

  Ross Burton (1):
        webkitgtk3: reduce size of -dbg package

  Sam Van Den Berge (6):
        python3-flask-jwt-extended: add recipe
        python3-flask-marshmallow: add recipe
        python3-apispec: add recipe
        python3-flask-httpauth: add recipe
        python3-webargs: add recipe
        python3-apiflask: add recipe

  Samantha Jalabert (6):
        Remove python3-rdflib
        Remove python3-license-expression
        Remove python3-xmltodict
        Remove python3-booleanpy
        Remove python3-click
        Remove python3-isodate

  Samuli Piippo (1):
        protobuf: stage protoc binary to sysroot

  Sanjay Chitroda (1):
        netkit-telnet: Fix CVE-2022-39028

  Trevor Gamblin (1):
        python3-aiofiles: upgrade 23.1.0 -> 23.2.1

  Vyacheslav Yurkov (3):
        overlayfs-tools: Drop unneeded dependency
        overlayfs-tools: Bump up the version
        overlayfs-tools: Install fsck binary

  Wang Mingyu (42):
        freerdp: upgrade 2.10.0 -> 2.11.0
        boost-sml: upgrade 1.1.8 -> 1.1.9
        ctags: upgrade 6.0.20230827.0 -> 6.0.20230917.0
        dovecot: upgrade 2.3.20 -> 2.3.21
        freerdp: upgrade 2.11.0 -> 2.11.1
        gensio: upgrade 2.7.5 -> 2.7.6
        geoclue: upgrade 2.7.0 -> 2.7.1
        hwloc: upgrade 2.9.2 -> 2.9.3
        iperf3: upgrade 3.14 -> 3.15
        libcloudproviders: upgrade 0.3.2 -> 0.3.4
        libdeflate: upgrade 1.18 -> 1.19
        libglvnd: upgrade 1.6.0 -> 1.7.0
        libtommath: upgrade 1.2.0 -> 1.2.1
        libcoap: upgrade 4.3.1 -> 4.3.3
        python3-antlr4-runtime: upgrade 4.13.0 -> 4.13.1
        python3-lazy: upgrade 1.5 -> 1.6
        python3-pyfanotify: upgrade 0.2.0 -> 0.2.1
        psqlodbc: upgrade 15.00.0000 -> 16.00.0000
        python3-argcomplete: upgrade 3.1.1 -> 3.1.2
        python3-bitstring: upgrade 4.1.1 -> 4.1.2
        python3-cmake: upgrade 3.27.4.1 -> 3.27.5
        python3-coverage: upgrade 7.3.0 -> 7.3.1
        python3-engineio: upgrade 4.7.0 -> 4.7.1
        python3-eth-utils: upgrade 2.2.0 -> 2.2.1
        python3-flask-migrate: upgrade 4.0.4 -> 4.0.5
        python3-flask-socketio: upgrade 5.3.5 -> 5.3.6
        python3-google-api-python-client: upgrade 2.97.0 -> 2.99.0
        python3-google-auth: upgrade 2.22.0 -> 2.23.0
        python3-pillow: upgrade 10.0.0 -> 10.0.1
        python3-pymisp: upgrade 2.4.175 -> 2.4.176
        python3-pymodbus: upgrade 3.5.0 -> 3.5.2
        python3-rapidjson: upgrade 1.10 -> 1.11
        python3-rich: upgrade 13.5.2 -> 13.5.3
        python3-term: upgrade 2.4 -> 2.5
        python3-tox: upgrade 4.11.1 -> 4.11.3
        python3-typeguard: upgrade 4.1.3 -> 4.1.5
        python3-types-setuptools: upgrade 68.1.0.1 -> 68.2.0.0
        python3-virtualenv: upgrade 20.24.4 -> 20.24.5
        python3-xlsxwriter: upgrade 3.1.2 -> 3.1.3
        python3-zeroconf: upgrade 0.97.0 -> 0.112.0
        redis: upgrade 7.2.0 -> 7.2.1
        remmina: upgrade 1.4.31 -> 1.4.32

  Xiangyu Chen (3):
        mosh: add support of protobuf 4.22.x
        protobuf: upgrade 3.21.12 -> 4.22.2
        protobuf-c: add support of protobuf 4.22.x

  Yi Zhao (1):
        audit: upgrade 3.1.1 -> 3.1.2

meta-arm: bd0953cc60..95789365f7:
  Abdellatif El Khlifi (2):
        arm-bsp/trusted-firmware-a: corstone1000: enable ERRATA_A35_855472
        arm-bsp/u-boot: corstone1000: purge U-Boot specific DT nodes before Linux

  Adam Johnston (1):
        arm-bsp/trusted-firmware-a: Fix BL32 path if usrmerge enabled

  Divin Raj (1):
        ci,doc,kas,arm-bsp,arm: Remove support for fvp-baser-aemv8r64 machine

  Emekcan Aras (6):
        arm-bsp/optee-os: corstone1000: Handling logging syscall correctly
        CI: Add meta-secure-core
        CI: Include meta-secure-core in corstone1000
        kas: corstone1000: add meta-secure-core
        arm-bsp/u-boot: corstone1000: introduce authenticated capsule update
        arm-bsp/trusted-firmware-m: Enable authenticated capsule update

  Javier Tia (2):
        optee-client: start tee-supplicant.service when teeprivX dev is detected
        libts: tee-udev.rules: Change ownership to tee group

  Jon Mason (5):
        arm/edk2: update to edk2-stable202308
        arm/trusted-firmware-m: update to 1.8.1
        arm/opencsd: update to v1.4.1
        arm/scp-firmware: update to v2.13.0
        README: remove reference to meta-arm-autonomy

  Khem Raj (1):
        layer.conf: update LAYERSERIES_COMPAT for nanbield

  Mariam Elshakfy (2):
        arm-bsp/optee-os: N1SDP upgrade optee-os to 3.22
        arm-bsp/optee-os: N1SDP upgrade tadevkit and optee-test to 3.22

  Peter Hoyes (2):
        CI: Allow a GitHub container registry mirror to be specified
        CI: Make update-repos more resilient to network issues

  Ross Burton (15):
        arm/generic-arm64: move SERIAL_CONSOLES to generic-arm64
        arm/qemu-generic-arm64: force off KVM in qemu
        arm/generic-arm64: set XSERVER to install the modesetting driver
        CI: remove redundant variables in testimage.yml
        arm-bsp: change port mapping for SSH to port 2222
        arm/apply_local_src_patches: allow use in multiple directories
        arm/trusted-services: pass through CMake generator
        arm/trusted-services: add missing pkgconfig inherit
        arm/trusted-services/ts-remote-test: move binary to $bindir
        arm/trusted-services/ts-sp-env-test: add missing DEPENDS
        arm/trusted-services/ts-sp-env-test: remove
        arm/trusted-services: use apply_local_src_patches
        arm/trusted-services: upgrade nanopb and fix build races
        CI: use a venv for sphinx
        CI: upgrade to Kas 4 container

  Xueliang Zhong (2):
        arm-bsp/n1sdp: update to linux yocto kernel 6.4
        arm-bsp/corstone1000: bump kernel version to v6.4

meta-security: 1856a7cf43..aca6d4a9e7:
  Armin Kuster (10):
        suricata: fix build issue.
        suricata: Update to 7.0.0
        sssd: Update to 2.9.2
        openscap: update to 1.3.9
        python3-privacyidea: update to 3.8.1
        lkrg-module: update to 0.9.7
        libhtp: update to 0.5.45
        swtpm: update 0.8.1
        lynis: Update to 3.0.9
        scap-security-guide: Drop Poky patch and update to tip

  John Broadbent (1):
        libhoth: Update

meta-raspberrypi: 6501ec892c..482d864b8f:
  Joshua Watt (1):
        rpi-base: Fix wic image kernel dependency

  Khem Raj (5):
        userland: Update to trunk from 20230419
        linux-raspberrypi: Upgrade 6.1 release to latest point release 6.1.54
        linux-firmware-rpidistro: Update to 20230210-5_bpo11+1
        bluez-firmware-rpidistro: Update to 1.2-4+rpt10
        raspberrypi-firmware: Update to 20230509~buster

  Martin Jansa (1):
        layer.conf: update LAYERSERIES_COMPAT for nanbield

Change-Id: Id75112a3b0be4bd150dc5d9a28c01982ed48200e
Signed-off-by: Andrew Geissler <geissonator@yahoo.com>
diff --git a/poky/meta/lib/oe/__init__.py b/poky/meta/lib/oe/__init__.py
index 47be7b5..da7cbab 100644
--- a/poky/meta/lib/oe/__init__.py
+++ b/poky/meta/lib/oe/__init__.py
@@ -7,6 +7,6 @@
 from pkgutil import extend_path
 __path__ = extend_path(__path__, __name__)
 
-BBIMPORTS = ["data", "path", "utils", "types", "package", \
+BBIMPORTS = ["data", "path", "utils", "types", "package", "packagedata", \
              "packagegroup", "sstatesig", "lsb", "cachedpath", "license", \
              "qa", "reproducible", "rust", "buildcfg"]
diff --git a/poky/meta/lib/oe/package.py b/poky/meta/lib/oe/package.py
index 9d70925..1dd20f8 100644
--- a/poky/meta/lib/oe/package.py
+++ b/poky/meta/lib/oe/package.py
@@ -114,7 +114,7 @@
             return start == magic
     return False
 
-def strip_execs(pn, dstdir, strip_cmd, libdir, base_libdir, d, qa_already_stripped=False):
+def strip_execs(pn, dstdir, strip_cmd, libdir, base_libdir, max_process, qa_already_stripped=False):
     """
     Strip executable code (like executables, shared libraries) _in_place_
     - Based on sysroot_strip in staging.bbclass
@@ -122,6 +122,7 @@
     :param strip_cmd: Strip command (usually ${STRIP})
     :param libdir: ${libdir} - strip .so files in this directory
     :param base_libdir: ${base_libdir} - strip .so files in this directory
+    :param max_process: number of stripping processes started in parallel
     :param qa_already_stripped: Set to True if already-stripped' in ${INSANE_SKIP}
     This is for proper logging and messages only.
     """
@@ -164,7 +165,7 @@
                 # ...but is it ELF, and is it already stripped?
                 checkelf.append(file)
                 inodecache[file] = s.st_ino
-    results = oe.utils.multiprocess_launch(is_elf, checkelf, d)
+    results = oe.utils.multiprocess_launch_mp(is_elf, checkelf, max_process)
     for (file, elf_file) in results:
                 #elf_file = is_elf(file)
                 if elf_file & 1:
@@ -192,7 +193,7 @@
         elf_file = int(elffiles[file])
         sfiles.append((file, elf_file, strip_cmd))
 
-    oe.utils.multiprocess_launch(runstrip, sfiles, d)
+    oe.utils.multiprocess_launch_mp(runstrip, sfiles, max_process)
 
 
 def file_translate(file):
diff --git a/poky/meta/lib/oe/package_manager/deb/sdk.py b/poky/meta/lib/oe/package_manager/deb/sdk.py
index 653e42a..6f30050 100644
--- a/poky/meta/lib/oe/package_manager/deb/sdk.py
+++ b/poky/meta/lib/oe/package_manager/deb/sdk.py
@@ -69,7 +69,12 @@
 
         self.target_pm.run_pre_post_installs()
 
+        env_bkp = os.environ.copy()
+        os.environ['PATH'] = self.d.expand("${COREBASE}/scripts/nativesdk-intercept") + \
+                             os.pathsep + os.environ["PATH"]
+
         self.target_pm.run_intercepts(populate_sdk='target')
+        os.environ.update(env_bkp)
 
         execute_pre_post_process(self.d, self.d.getVar("POPULATE_SDK_POST_TARGET_COMMAND"))
 
diff --git a/poky/meta/lib/oe/package_manager/ipk/sdk.py b/poky/meta/lib/oe/package_manager/ipk/sdk.py
index 6a1f167..cc7a7ed 100644
--- a/poky/meta/lib/oe/package_manager/ipk/sdk.py
+++ b/poky/meta/lib/oe/package_manager/ipk/sdk.py
@@ -63,7 +63,12 @@
 
         self.target_pm.install_complementary(self.d.getVar('SDKIMAGE_INSTALL_COMPLEMENTARY'))
 
+        env_bkp = os.environ.copy()
+        os.environ['PATH'] = self.d.expand("${COREBASE}/scripts/nativesdk-intercept") + \
+                             os.pathsep + os.environ["PATH"]
+
         self.target_pm.run_intercepts(populate_sdk='target')
+        os.environ.update(env_bkp)
 
         execute_pre_post_process(self.d, self.d.getVar("POPULATE_SDK_POST_TARGET_COMMAND"))
 
diff --git a/poky/meta/lib/oe/package_manager/rpm/sdk.py b/poky/meta/lib/oe/package_manager/rpm/sdk.py
index 85df6e9..ea79fe0 100644
--- a/poky/meta/lib/oe/package_manager/rpm/sdk.py
+++ b/poky/meta/lib/oe/package_manager/rpm/sdk.py
@@ -67,7 +67,12 @@
 
         self.target_pm.install_complementary(self.d.getVar('SDKIMAGE_INSTALL_COMPLEMENTARY'))
 
+        env_bkp = os.environ.copy()
+        os.environ['PATH'] = self.d.expand("${COREBASE}/scripts/nativesdk-intercept") + \
+                             os.pathsep + os.environ["PATH"]
+
         self.target_pm.run_intercepts(populate_sdk='target')
+        os.environ.update(env_bkp)
 
         execute_pre_post_process(self.d, self.d.getVar("POPULATE_SDK_POST_TARGET_COMMAND"))
 
diff --git a/poky/meta/lib/oe/qa.py b/poky/meta/lib/oe/qa.py
index de98063..f8ae3c7 100644
--- a/poky/meta/lib/oe/qa.py
+++ b/poky/meta/lib/oe/qa.py
@@ -216,8 +216,8 @@
 def check_upstream_status(fullpath):
     import re
     kinda_status_re = re.compile(r"^.*upstream.*status.*$", re.IGNORECASE | re.MULTILINE)
-    strict_status_re = re.compile(r"^Upstream-Status: (Pending|Submitted|Denied|Accepted|Inappropriate|Backport|Inactive-Upstream)( .+)?$", re.MULTILINE)
-    guidelines = "https://www.openembedded.org/wiki/Commit_Patch_Message_Guidelines#Patch_Header_Recommendations:_Upstream-Status"
+    strict_status_re = re.compile(r"^Upstream-Status: (Pending|Submitted|Denied|Inappropriate|Backport|Inactive-Upstream)( .+)?$", re.MULTILINE)
+    guidelines = "https://docs.yoctoproject.org/contributor-guide/recipe-style-guide.html#patch-upstream-status"
 
     with open(fullpath, encoding='utf-8', errors='ignore') as f:
         file_content = f.read()
diff --git a/poky/meta/lib/oe/sbom.py b/poky/meta/lib/oe/sbom.py
index 1130fa6..fd4b689 100644
--- a/poky/meta/lib/oe/sbom.py
+++ b/poky/meta/lib/oe/sbom.py
@@ -38,16 +38,34 @@
     return "SPDXRef-SDK-%s" % sdk
 
 
-def doc_path_by_namespace(spdx_deploy, doc_namespace):
-    return spdx_deploy / "by-namespace" / doc_namespace.replace("/", "_")
+def _doc_path_by_namespace(spdx_deploy, arch, doc_namespace):
+    return spdx_deploy / "by-namespace" / arch / doc_namespace.replace("/", "_")
 
 
-def doc_path_by_hashfn(spdx_deploy, doc_name, hashfn):
-    return spdx_deploy / "by-hash" / hashfn.split()[1] / (doc_name + ".spdx.json")
+def doc_find_by_namespace(spdx_deploy, search_arches, doc_namespace):
+    for pkgarch in search_arches:
+        p = _doc_path_by_namespace(spdx_deploy, pkgarch, doc_namespace)
+        if os.path.exists(p):
+            return p
+    return None
+
+
+def _doc_path_by_hashfn(spdx_deploy, arch, doc_name, hashfn):
+    return (
+        spdx_deploy / "by-hash" / arch / hashfn.split()[1] / (doc_name + ".spdx.json")
+    )
+
+
+def doc_find_by_hashfn(spdx_deploy, search_arches, doc_name, hashfn):
+    for pkgarch in search_arches:
+        p = _doc_path_by_hashfn(spdx_deploy, pkgarch, doc_name, hashfn)
+        if os.path.exists(p):
+            return p
+    return None
 
 
 def doc_path(spdx_deploy, doc_name, arch, subdir):
-    return spdx_deploy / arch/ subdir / (doc_name + ".spdx.json")
+    return spdx_deploy / arch / subdir / (doc_name + ".spdx.json")
 
 
 def write_doc(d, spdx_doc, arch, subdir, spdx_deploy=None, indent=None):
@@ -61,11 +79,13 @@
     with dest.open("wb") as f:
         doc_sha1 = spdx_doc.to_json(f, sort_keys=True, indent=indent)
 
-    l = doc_path_by_namespace(spdx_deploy, spdx_doc.documentNamespace)
+    l = _doc_path_by_namespace(spdx_deploy, arch, spdx_doc.documentNamespace)
     l.parent.mkdir(exist_ok=True, parents=True)
     l.symlink_to(os.path.relpath(dest, l.parent))
 
-    l = doc_path_by_hashfn(spdx_deploy, spdx_doc.name, d.getVar("BB_HASHFILENAME"))
+    l = _doc_path_by_hashfn(
+        spdx_deploy, arch, spdx_doc.name, d.getVar("BB_HASHFILENAME")
+    )
     l.parent.mkdir(exist_ok=True, parents=True)
     l.symlink_to(os.path.relpath(dest, l.parent))
 
diff --git a/poky/meta/lib/oe/utils.py b/poky/meta/lib/oe/utils.py
index 1658f35..a3b1bb1 100644
--- a/poky/meta/lib/oe/utils.py
+++ b/poky/meta/lib/oe/utils.py
@@ -264,10 +264,17 @@
         bb.note("Executing %s ..." % cmd)
         bb.build.exec_func(cmd, d)
 
-# For each item in items, call the function 'target' with item as the first 
+def get_bb_number_threads(d):
+    return int(d.getVar("BB_NUMBER_THREADS") or os.cpu_count() or 1)
+
+def multiprocess_launch(target, items, d, extraargs=None):
+    max_process = get_bb_number_threads(d)
+    return multiprocess_launch_mp(target, items, max_process, extraargs)
+
+# For each item in items, call the function 'target' with item as the first
 # argument, extraargs as the other arguments and handle any exceptions in the
 # parent thread
-def multiprocess_launch(target, items, d, extraargs=None):
+def multiprocess_launch_mp(target, items, max_process, extraargs=None):
 
     class ProcessLaunch(multiprocessing.Process):
         def __init__(self, *args, **kwargs):
@@ -302,7 +309,6 @@
             self.update()
             return self._result
 
-    max_process = int(d.getVar("BB_NUMBER_THREADS") or os.cpu_count() or 1)
     launched = []
     errors = []
     results = []
diff --git a/poky/meta/lib/oeqa/core/runner.py b/poky/meta/lib/oeqa/core/runner.py
index 5077eb8..a86a706 100644
--- a/poky/meta/lib/oeqa/core/runner.py
+++ b/poky/meta/lib/oeqa/core/runner.py
@@ -44,6 +44,7 @@
         self.endtime = {}
         self.progressinfo = {}
         self.extraresults = {}
+        self.shownmsg = []
 
         # Inject into tc so that TestDepends decorator can see results
         tc.results = self
@@ -74,6 +75,7 @@
             for (scase, msg) in getattr(self, t):
                 if test.id() == scase.id():
                     self.tc.logger.info(str(msg))
+                    self.shownmsg.append(test.id())
                     break
 
     def logSummary(self, component, context_msg=''):
@@ -169,7 +171,6 @@
 
     def logDetails(self, json_file_dir=None, configuration=None, result_id=None,
             dump_streams=False):
-        self.tc.logger.info("RESULTS:")
 
         result = self.extraresults
         logs = {}
@@ -193,6 +194,10 @@
             report = {'status': status}
             if log:
                 report['log'] = log
+                # Class setup failures wouldn't enter stopTest so would never display
+                if case.id() not in self.shownmsg:
+                    self.tc.logger.info("Failure (%s) for %s:\n" % (status, case.id()) + log)
+
             if duration:
                 report['duration'] = duration
 
@@ -215,6 +220,7 @@
                 report['stderr'] = stderr
             result[case.id()] = report
 
+        self.tc.logger.info("RESULTS:")
         for i in ['PASSED', 'SKIPPED', 'EXPECTEDFAIL', 'ERROR', 'FAILED', 'UNKNOWN']:
             if i not in logs:
                 continue
diff --git a/poky/meta/lib/oeqa/core/utils/concurrencytest.py b/poky/meta/lib/oeqa/core/utils/concurrencytest.py
index 4f77589..5e20b0e 100644
--- a/poky/meta/lib/oeqa/core/utils/concurrencytest.py
+++ b/poky/meta/lib/oeqa/core/utils/concurrencytest.py
@@ -193,11 +193,12 @@
 #
 class ConcurrentTestSuite(unittest.TestSuite):
 
-    def __init__(self, suite, processes, setupfunc, removefunc):
+    def __init__(self, suite, processes, setupfunc, removefunc, bb_vars):
         super(ConcurrentTestSuite, self).__init__([suite])
         self.processes = processes
         self.setupfunc = setupfunc
         self.removefunc = removefunc
+        self.bb_vars = bb_vars
 
     def run(self, result):
         testservers, totaltests = fork_for_tests(self.processes, self)
@@ -243,7 +244,7 @@
 def fork_for_tests(concurrency_num, suite):
     testservers = []
     if 'BUILDDIR' in os.environ:
-        selftestdir = get_test_layer()
+        selftestdir = get_test_layer(suite.bb_vars['BBLAYERS'])
 
     test_blocks = partition_tests(suite, concurrency_num)
     # Clear the tests from the original suite so it doesn't keep them alive
diff --git a/poky/meta/lib/oeqa/runtime/cases/buildcpio.py b/poky/meta/lib/oeqa/runtime/cases/buildcpio.py
index 3728855..ce122eb 100644
--- a/poky/meta/lib/oeqa/runtime/cases/buildcpio.py
+++ b/poky/meta/lib/oeqa/runtime/cases/buildcpio.py
@@ -14,7 +14,7 @@
 
     @classmethod
     def setUpClass(cls):
-        uri = 'https://downloads.yoctoproject.org/mirror/sources/cpio-2.13.tar.gz'
+        uri = 'https://downloads.yoctoproject.org/mirror/sources/cpio-2.14.tar.gz'
         cls.project = TargetBuildProject(cls.tc.target,
                                          uri,
                                          dl_dir = cls.tc.td['DL_DIR'])
diff --git a/poky/meta/lib/oeqa/runtime/cases/go.py b/poky/meta/lib/oeqa/runtime/cases/go.py
index 7514d10..39a80f4 100644
--- a/poky/meta/lib/oeqa/runtime/cases/go.py
+++ b/poky/meta/lib/oeqa/runtime/cases/go.py
@@ -18,4 +18,4 @@
         self.assertEqual(status, 0, msg=msg)
 
         msg = 'Incorrect output: %s' % output
-        self.assertEqual(output, "Hello, Go examples!", msg=msg)
+        self.assertEqual(output, "Hello, world!", msg=msg)
diff --git a/poky/meta/lib/oeqa/runtime/cases/parselogs.py b/poky/meta/lib/oeqa/runtime/cases/parselogs.py
index e67d375..a805edd 100644
--- a/poky/meta/lib/oeqa/runtime/cases/parselogs.py
+++ b/poky/meta/lib/oeqa/runtime/cases/parselogs.py
@@ -4,17 +4,12 @@
 # SPDX-License-Identifier: MIT
 #
 
+import collections
 import os
 
-from subprocess import check_output
 from shutil import rmtree
 from oeqa.runtime.case import OERuntimeTestCase
 from oeqa.core.decorator.depends import OETestDepends
-from oeqa.core.decorator.data import skipIfDataVar
-from oeqa.runtime.decorator.package import OEHasPackage
-
-#in the future these lists could be moved outside of module
-errors = ["error", "cannot", "can\'t", "failed"]
 
 common_errors = [
     "(WW) warning, (EE) error, (NI) not implemented, (??) unknown.",
@@ -69,11 +64,9 @@
     "xf86OpenConsole: Switching VT failed",
     "Failed to read LoaderConfigTimeoutOneShot variable, ignoring: Operation not supported",
     "Failed to read LoaderEntryOneShot variable, ignoring: Operation not supported",
+    "invalid BAR (can't size)",
     ]
 
-video_related = [
-]
-
 x86_common = [
     '[drm:psb_do_init] *ERROR* Debug is',
     'wrong ELF class',
@@ -105,16 +98,13 @@
     'default' : common_errors,
     'qemux86' : [
         'Failed to access perfctr msr (MSR',
-        'pci 0000:00:00.0: [Firmware Bug]: reg 0x..: invalid BAR (can\'t size)',
         ] + qemux86_common,
     'qemux86-64' : qemux86_common,
     'qemumips' : [
         'Failed to load module "glx"',
-        'pci 0000:00:00.0: [Firmware Bug]: reg 0x..: invalid BAR (can\'t size)',
         'cacheinfo: Failed to find cpu0 device node',
         ] + common_errors,
     'qemumips64' : [
-        'pci 0000:00:00.0: [Firmware Bug]: reg 0x..: invalid BAR (can\'t size)',
         'cacheinfo: Failed to find cpu0 device node',
          ] + common_errors,
     'qemuppc' : [
@@ -206,17 +196,19 @@
         ] + common_errors,
 }
 
-log_locations = ["/var/log/","/var/log/dmesg", "/tmp/dmesg_output.log"]
-
 class ParseLogsTest(OERuntimeTestCase):
 
+    # Which log files should be collected
+    log_locations = ["/var/log/", "/var/log/dmesg", "/tmp/dmesg_output.log"]
+
+    # The keywords that identify error messages in the log files
+    errors = ["error", "cannot", "can't", "failed"]
+
     @classmethod
     def setUpClass(cls):
-        cls.errors = errors
-
         # When systemd is enabled we need to notice errors on
         # circular dependencies in units.
-        if 'systemd' in cls.td.get('DISTRO_FEATURES', ''):
+        if 'systemd' in cls.td.get('DISTRO_FEATURES'):
             cls.errors.extend([
                 'Found ordering cycle on',
                 'Breaking ordering cycle by deleting job',
@@ -224,48 +216,13 @@
                 'Ordering cycle found, skipping',
                 ])
 
-        cls.ignore_errors = ignore_errors
-        cls.log_locations = log_locations
-        cls.msg = ''
-        is_lsb, _ = cls.tc.target.run("which LSB_Test.sh")
-        if is_lsb == 0:
-            for machine in cls.ignore_errors:
-                cls.ignore_errors[machine] = cls.ignore_errors[machine] \
-                                             + video_related
+        cls.errors = [s.casefold() for s in cls.errors]
 
-    def getMachine(self):
-        return self.td.get('MACHINE', '')
-
-    def getWorkdir(self):
-        return self.td.get('WORKDIR', '')
-
-    # Get some information on the CPU of the machine to display at the
-    # beginning of the output. This info might be useful in some cases.
-    def getHardwareInfo(self):
-        hwi = ""
-        cmd = ('cat /proc/cpuinfo | grep "model name" | head -n1 | '
-               " awk 'BEGIN{FS=\":\"}{print $2}'")
-        _, cpu_name = self.target.run(cmd)
-
-        cmd = ('cat /proc/cpuinfo | grep "cpu cores" | head -n1 | '
-               "awk {'print $4'}")
-        _, cpu_physical_cores = self.target.run(cmd)
-
-        cmd = 'cat /proc/cpuinfo | grep "processor" | wc -l'
-        _, cpu_logical_cores = self.target.run(cmd)
-
-        _, cpu_arch = self.target.run('uname -m')
-
-        hwi += 'Machine information: \n'
-        hwi += '*******************************\n'
-        hwi += 'Machine name: ' + self.getMachine() + '\n'
-        hwi += 'CPU: ' + str(cpu_name) + '\n'
-        hwi += 'Arch: ' + str(cpu_arch)+ '\n'
-        hwi += 'Physical cores: ' + str(cpu_physical_cores) + '\n'
-        hwi += 'Logical cores: ' + str(cpu_logical_cores) + '\n'
-        hwi += '*******************************\n'
-
-        return hwi
+        try:
+            cls.ignore_errors = [s.casefold() for s in ignore_errors[cls.td.get('MACHINE')]]
+        except KeyError:
+            cls.logger.info('No ignore list found for this machine, using default')
+            cls.ignore_errors = [s.casefold() for s in ignore_errors['default']]
 
     # Go through the log locations provided and if it's a folder
     # create a list with all the .log files in it, if it's a file
@@ -273,23 +230,23 @@
     def getLogList(self, log_locations):
         logs = []
         for location in log_locations:
-            status, _ = self.target.run('test -f ' + str(location))
+            status, _ = self.target.run('test -f %s' % location)
             if status == 0:
-                logs.append(str(location))
+                logs.append(location)
             else:
-                status, _ = self.target.run('test -d ' + str(location))
+                status, _ = self.target.run('test -d %s' % location)
                 if status == 0:
-                    cmd = 'find ' + str(location) + '/*.log -maxdepth 1 -type f'
+                    cmd = 'find %s -name \\*.log -maxdepth 1 -type f' % location
                     status, output = self.target.run(cmd)
                     if status == 0:
                         output = output.splitlines()
                         for logfile in output:
-                            logs.append(os.path.join(location, str(logfile)))
+                            logs.append(os.path.join(location, logfile))
         return logs
 
     # Copy the log files to be parsed locally
     def transfer_logs(self, log_list):
-        workdir = self.getWorkdir()
+        workdir = self.td.get('WORKDIR')
         self.target_logs = workdir + '/' + 'target_logs'
         target_logs = self.target_logs
         if os.path.exists(target_logs):
@@ -306,65 +263,55 @@
         logs = [f for f in dir_files if os.path.isfile(f)]
         return logs
 
-    # Build the grep command to be used with filters and exclusions
-    def build_grepcmd(self, errors, ignore_errors, log):
-        grepcmd = 'grep '
-        grepcmd += '-Ei "'
-        for error in errors:
-            grepcmd += r'\<' + error + r'\>' + '|'
-        grepcmd = grepcmd[:-1]
-        grepcmd += '" ' + str(log) + " | grep -Eiv \'"
+    def get_context(self, lines, index, before=6, after=3):
+        """
+        Given a set of lines and the index of the line that is important, return
+        a number of lines surrounding that line.
+        """
+        last = len(lines)
 
-        try:
-            errorlist = ignore_errors[self.getMachine()]
-        except KeyError:
-            self.msg += 'No ignore list found for this machine, using default\n'
-            errorlist = ignore_errors['default']
+        start = index - before
+        end = index + after + 1
 
-        for ignore_error in errorlist:
-            ignore_error = ignore_error.replace('(', r'\(')
-            ignore_error = ignore_error.replace(')', r'\)')
-            ignore_error = ignore_error.replace("'", '.')
-            ignore_error = ignore_error.replace('?', r'\?')
-            ignore_error = ignore_error.replace('[', r'\[')
-            ignore_error = ignore_error.replace(']', r'\]')
-            ignore_error = ignore_error.replace('*', r'\*')
-            ignore_error = ignore_error.replace('0-9', '[0-9]')
-            grepcmd += ignore_error + '|'
-        grepcmd = grepcmd[:-1]
-        grepcmd += "\'"
+        if start < 0:
+            end -= start
+            start = 0
+        if end > last:
+            start -= end - last
+            end = last
 
-        return grepcmd
+        return lines[start:end]
 
-    # Grep only the errors so that their context could be collected.
-    # Default context is 10 lines before and after the error itself
-    def parse_logs(self, errors, ignore_errors, logs,
-                   lines_before = 10, lines_after = 10):
-        results = {}
-        rez = []
-        grep_output = ''
+    def test_get_context(self):
+        """
+        A test case for the test case.
+        """
+        lines = list(range(0,10))
+        self.assertEqual(self.get_context(lines, 0, 2, 1), [0, 1, 2, 3])
+        self.assertEqual(self.get_context(lines, 5, 2, 1), [3, 4, 5, 6])
+        self.assertEqual(self.get_context(lines, 9, 2, 1), [6, 7, 8, 9])
+
+    def parse_logs(self, logs, lines_before=10, lines_after=10):
+        """
+        Search the log files @logs looking for error lines (marked by
+        @self.errors), ignoring anything listed in @self.ignore_errors.
+
+        Returns a dictionary of log filenames to a dictionary of error lines to
+        the error context (controlled by @lines_before and @lines_after).
+        """
+        results = collections.defaultdict(dict)
 
         for log in logs:
-            result = None
-            thegrep = self.build_grepcmd(errors, ignore_errors, log)
+            with open(log) as f:
+                lines = f.readlines()
 
-            try:
-                result = check_output(thegrep, shell=True).decode('utf-8')
-            except:
-                pass
+            for i, line in enumerate(lines):
+                line = line.strip()
+                line_lower = line.casefold()
 
-            if result is not None:
-                results[log] = {}
-                rez = result.splitlines()
-
-                for xrez in rez:
-                    try:
-                        cmd = ['grep', '-F', xrez, '-B', str(lines_before)]
-                        cmd += ['-A', str(lines_after), log]
-                        grep_output = check_output(cmd).decode('utf-8')
-                    except:
-                        pass
-                    results[log][xrez]=grep_output
+                if any(keyword in line_lower for keyword in self.errors):
+                    if not any(ignore in line_lower for ignore in self.ignore_errors):
+                        results[log][line] = "".join(self.get_context(lines, i, lines_before, lines_after))
 
         return results
 
@@ -377,17 +324,18 @@
     def test_parselogs(self):
         self.write_dmesg()
         log_list = self.get_local_log_list(self.log_locations)
-        result = self.parse_logs(self.errors, self.ignore_errors, log_list)
-        print(self.getHardwareInfo())
+        result = self.parse_logs(log_list)
+
         errcount = 0
+        self.msg = ""
         for log in result:
             self.msg += 'Log: ' + log + '\n'
             self.msg += '-----------------------\n'
             for error in result[log]:
                 errcount += 1
-                self.msg += 'Central error: ' + str(error) + '\n'
+                self.msg += 'Central error: ' + error + '\n'
                 self.msg +=  '***********************\n'
-                self.msg +=  result[str(log)][str(error)] + '\n'
+                self.msg +=  result[log][error] + '\n'
                 self.msg +=  '***********************\n'
         self.msg += '%s errors found in logs.' % errcount
         self.assertEqual(errcount, 0, msg=self.msg)
diff --git a/poky/meta/lib/oeqa/runtime/cases/ptest.py b/poky/meta/lib/oeqa/runtime/cases/ptest.py
index 23a71ea..fbaeb84 100644
--- a/poky/meta/lib/oeqa/runtime/cases/ptest.py
+++ b/poky/meta/lib/oeqa/runtime/cases/ptest.py
@@ -96,7 +96,7 @@
         failed_tests = {}
 
         for section in sections:
-            if 'exitcode' in sections[section].keys():
+            if 'exitcode' in sections[section].keys() or 'timeout' in sections[section].keys():
                 failed_tests[section] = sections[section]["log"]
 
         for section in results:
diff --git a/poky/meta/lib/oeqa/sdk/cases/buildcpio.py b/poky/meta/lib/oeqa/sdk/cases/buildcpio.py
index c42c670..33b946f 100644
--- a/poky/meta/lib/oeqa/sdk/cases/buildcpio.py
+++ b/poky/meta/lib/oeqa/sdk/cases/buildcpio.py
@@ -19,10 +19,10 @@
     """
     def test_cpio(self):
         with tempfile.TemporaryDirectory(prefix="cpio-", dir=self.tc.sdk_dir) as testdir:
-            tarball = self.fetch(testdir, self.td["DL_DIR"], "https://ftp.gnu.org/gnu/cpio/cpio-2.13.tar.gz")
+            tarball = self.fetch(testdir, self.td["DL_DIR"], "https://ftp.gnu.org/gnu/cpio/cpio-2.14.tar.gz")
 
             dirs = {}
-            dirs["source"] = os.path.join(testdir, "cpio-2.13")
+            dirs["source"] = os.path.join(testdir, "cpio-2.14")
             dirs["build"] = os.path.join(testdir, "build")
             dirs["install"] = os.path.join(testdir, "install")
 
diff --git a/poky/meta/lib/oeqa/selftest/cases/bbtests.py b/poky/meta/lib/oeqa/selftest/cases/bbtests.py
index 31aa568..d242352 100644
--- a/poky/meta/lib/oeqa/selftest/cases/bbtests.py
+++ b/poky/meta/lib/oeqa/selftest/cases/bbtests.py
@@ -236,8 +236,11 @@
         result = bitbake('selftest-ed', ignore_status=True)
         self.assertEqual(result.status, 0, "Bitbake failed, exit code %s, output %s" % (result.status, result.output))
         lic_dir = get_bb_var('LICENSE_DIRECTORY')
-        self.assertFalse(os.path.isfile(os.path.join(lic_dir, 'selftest-ed/generic_GPL-3.0-or-later')))
-        self.assertTrue(os.path.isfile(os.path.join(lic_dir, 'selftest-ed/generic_GPL-2.0-or-later')))
+        arch = get_bb_var('SSTATE_PKGARCH')
+        filename = os.path.join(lic_dir, arch, 'selftest-ed', 'generic_GPL-3.0-or-later')
+        self.assertFalse(os.path.isfile(filename), msg="License file %s exists and shouldn't" % filename)
+        filename = os.path.join(lic_dir, arch, 'selftest-ed', 'generic_GPL-2.0-or-later')
+        self.assertTrue(os.path.isfile(filename), msg="License file %s doesn't exist" % filename)
 
     def test_setscene_only(self):
         """ Bitbake option to restore from sstate only within a build (i.e. execute no real tasks, only setscene)"""
diff --git a/poky/meta/lib/oeqa/selftest/cases/devtool.py b/poky/meta/lib/oeqa/selftest/cases/devtool.py
index a2b77e5..b577f6d 100644
--- a/poky/meta/lib/oeqa/selftest/cases/devtool.py
+++ b/poky/meta/lib/oeqa/selftest/cases/devtool.py
@@ -256,6 +256,31 @@
         if remaining_removelines:
             self.fail('Expected removed lines not found: %s' % remaining_removelines)
 
+    def _check_runqemu_prerequisites(self):
+        """Check runqemu is available
+
+        Whilst some tests would seemingly be better placed as a runtime test,
+        unfortunately the runtime tests run under bitbake and you can't run
+        devtool within bitbake (since devtool needs to run bitbake itself).
+        Additionally we are testing build-time functionality as well, so
+        really this has to be done as an oe-selftest test.
+        """
+        machine = get_bb_var('MACHINE')
+        if not machine.startswith('qemu'):
+            self.skipTest('This test only works with qemu machines')
+        if not os.path.exists('/etc/runqemu-nosudo'):
+            self.skipTest('You must set up tap devices with scripts/runqemu-gen-tapdevs before running this test')
+        result = runCmd('PATH="$PATH:/sbin:/usr/sbin" ip tuntap show', ignore_status=True)
+        if result.status != 0:
+            result = runCmd('PATH="$PATH:/sbin:/usr/sbin" ifconfig -a', ignore_status=True)
+            if result.status != 0:
+                self.skipTest('Failed to determine if tap devices exist with ifconfig or ip: %s' % result.output)
+        for line in result.output.splitlines():
+            if line.startswith('tap'):
+                break
+        else:
+            self.skipTest('No tap devices found - you must set up tap devices with scripts/runqemu-gen-tapdevs before running this test')
+
     def _test_devtool_add_git_url(self, git_url, version, pn, resulting_src_uri):
         self.track_for_cleanup(self.workspacedir)
         self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
@@ -1616,28 +1641,7 @@
 
     @OETestTag("runqemu")
     def test_devtool_deploy_target(self):
-        # NOTE: Whilst this test would seemingly be better placed as a runtime test,
-        # unfortunately the runtime tests run under bitbake and you can't run
-        # devtool within bitbake (since devtool needs to run bitbake itself).
-        # Additionally we are testing build-time functionality as well, so
-        # really this has to be done as an oe-selftest test.
-        #
-        # Check preconditions
-        machine = get_bb_var('MACHINE')
-        if not machine.startswith('qemu'):
-            self.skipTest('This test only works with qemu machines')
-        if not os.path.exists('/etc/runqemu-nosudo'):
-            self.skipTest('You must set up tap devices with scripts/runqemu-gen-tapdevs before running this test')
-        result = runCmd('PATH="$PATH:/sbin:/usr/sbin" ip tuntap show', ignore_status=True)
-        if result.status != 0:
-            result = runCmd('PATH="$PATH:/sbin:/usr/sbin" ifconfig -a', ignore_status=True)
-            if result.status != 0:
-                self.skipTest('Failed to determine if tap devices exist with ifconfig or ip: %s' % result.output)
-        for line in result.output.splitlines():
-            if line.startswith('tap'):
-                break
-        else:
-            self.skipTest('No tap devices found - you must set up tap devices with scripts/runqemu-gen-tapdevs before running this test')
+        self._check_runqemu_prerequisites()
         self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
         # Definitions
         testrecipe = 'mdadm'
diff --git a/poky/meta/lib/oeqa/selftest/cases/meta_ide.py b/poky/meta/lib/oeqa/selftest/cases/meta_ide.py
index 59270fb..e446d93 100644
--- a/poky/meta/lib/oeqa/selftest/cases/meta_ide.py
+++ b/poky/meta/lib/oeqa/selftest/cases/meta_ide.py
@@ -44,7 +44,7 @@
     def test_meta_ide_can_build_cpio_project(self):
         dl_dir = self.td.get('DL_DIR', None)
         self.project = SDKBuildProject(self.tmpdir_metaideQA + "/cpio/", self.environment_script_path,
-                        "https://ftp.gnu.org/gnu/cpio/cpio-2.13.tar.gz",
+                        "https://ftp.gnu.org/gnu/cpio/cpio-2.14.tar.gz",
                         self.tmpdir_metaideQA, self.td['DATETIME'], dl_dir=dl_dir)
         self.project.download_archive()
         self.assertEqual(self.project.run_configure('$CONFIGURE_FLAGS --disable-maintainer-mode','sed -i -e "/char \*program_name/d" src/global.c;'), 0,
diff --git a/poky/meta/lib/oeqa/selftest/cases/oescripts.py b/poky/meta/lib/oeqa/selftest/cases/oescripts.py
index 7d3a00e..f69efcc 100644
--- a/poky/meta/lib/oeqa/selftest/cases/oescripts.py
+++ b/poky/meta/lib/oeqa/selftest/cases/oescripts.py
@@ -36,18 +36,16 @@
         if expected_endlines:
             self.fail('Missing expected line endings:\n  %s' % '\n  '.join(expected_endlines))
 
-class OEScriptTests(OESelftestTestCase):
-    scripts_dir = os.path.join(get_bb_var('COREBASE'), 'scripts')
-
 @unittest.skipUnless(importlib.util.find_spec("cairo"), "Python cairo module is not present")
-class OEPybootchartguyTests(OEScriptTests):
+class OEPybootchartguyTests(OESelftestTestCase):
 
     @classmethod
     def setUpClass(cls):
-        super(OEScriptTests, cls).setUpClass()
+        super().setUpClass()
         bitbake("core-image-minimal -c rootfs -f")
         cls.tmpdir = get_bb_var('TMPDIR')
         cls.buildstats = cls.tmpdir + "/buildstats/" + sorted(os.listdir(cls.tmpdir + "/buildstats"))[-1]
+        cls.scripts_dir = os.path.join(get_bb_var('COREBASE'), 'scripts')
 
     def test_pybootchartguy_help(self):
         runCmd('%s/pybootchartgui/pybootchartgui.py  --help' % self.scripts_dir)
@@ -65,7 +63,12 @@
         self.assertTrue(os.path.exists(self.tmpdir + "/charts.pdf"))
 
 
-class OEGitproxyTests(OEScriptTests):
+class OEGitproxyTests(OESelftestTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        super().setUpClass()
+        cls.scripts_dir = os.path.join(get_bb_var('COREBASE'), 'scripts')
 
     def test_oegitproxy_help(self):
         try:
@@ -126,7 +129,13 @@
         result = runCmd("oe-run-native qemu-helper-native qemu-oe-bridge-helper --help")
         self.assertIn("Helper function to find and exec qemu-bridge-helper", result.output)
 
-class OEListPackageconfigTests(OEScriptTests):
+class OEListPackageconfigTests(OESelftestTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        super().setUpClass()
+        cls.scripts_dir = os.path.join(get_bb_var('COREBASE'), 'scripts')
+
     #oe-core.scripts.List_all_the_PACKAGECONFIG's_flags
     def check_endlines(self, results,  expected_endlines): 
         for line in results.output.splitlines():
diff --git a/poky/meta/lib/oeqa/selftest/cases/reproducible.py b/poky/meta/lib/oeqa/selftest/cases/reproducible.py
index 4c6ed4e..84c6c3a 100644
--- a/poky/meta/lib/oeqa/selftest/cases/reproducible.py
+++ b/poky/meta/lib/oeqa/selftest/cases/reproducible.py
@@ -128,23 +128,17 @@
 class ReproducibleTests(OESelftestTestCase):
     # Test the reproducibility of whatever is built between sstate_targets and targets
 
-    package_classes = get_bb_var("OEQA_REPRODUCIBLE_TEST_PACKAGE")
-    if package_classes:
-        package_classes = package_classes.split()
-    else:
-        package_classes = ['deb', 'ipk', 'rpm']
+    package_classes = ['deb', 'ipk', 'rpm']
 
     # Maximum report size, in bytes
     max_report_size = 250 * 1024 * 1024
 
     # targets are the things we want to test the reproducibility of
-    targets = get_bb_var("OEQA_REPRODUCIBLE_TEST_TARGET")
-    if targets:
-        targets = targets.split()
-    else:
-        targets = ['core-image-minimal', 'core-image-sato', 'core-image-full-cmdline', 'core-image-weston', 'world']
+    targets = ['core-image-minimal', 'core-image-sato', 'core-image-full-cmdline', 'core-image-weston', 'world']
+
     # sstate targets are things to pull from sstate to potentially cut build/debugging time
-    sstate_targets = (get_bb_var("OEQA_REPRODUCIBLE_TEST_SSTATE_TARGETS") or "").split()
+    sstate_targets = []
+
     save_results = False
     if 'OEQA_DEBUGGING_SAVED_OUTPUT' in os.environ:
         save_results = os.environ['OEQA_DEBUGGING_SAVED_OUTPUT']
@@ -159,11 +153,20 @@
 
     def setUpLocal(self):
         super().setUpLocal()
-        needed_vars = ['TOPDIR', 'TARGET_PREFIX', 'BB_NUMBER_THREADS', 'BB_HASHSERVE']
+        needed_vars = ['TOPDIR', 'TARGET_PREFIX', 'BB_NUMBER_THREADS', 'BB_HASHSERVE', 'OEQA_REPRODUCIBLE_TEST_PACKAGE', 'OEQA_REPRODUCIBLE_TEST_TARGET', 'OEQA_REPRODUCIBLE_TEST_SSTATE_TARGETS']
         bb_vars = get_bb_vars(needed_vars)
         for v in needed_vars:
             setattr(self, v.lower(), bb_vars[v])
 
+        if bb_vars['OEQA_REPRODUCIBLE_TEST_PACKAGE']:
+            self.package_classes = bb_vars['OEQA_REPRODUCIBLE_TEST_PACKAGE'].split()
+
+        if bb_vars['OEQA_REPRODUCIBLE_TEST_TARGET']:
+            self.targets = bb_vars['OEQA_REPRODUCIBLE_TEST_TARGET'].split()
+
+        if bb_vars['OEQA_REPRODUCIBLE_TEST_SSTATE_TARGETS']:
+            self.sstate_targets = bb_vars['OEQA_REPRODUCIBLE_TEST_SSTATE_TARGETS'].split()
+
         self.extraresults = {}
         self.extraresults.setdefault('reproducible.rawlogs', {})['log'] = ''
         self.extraresults.setdefault('reproducible', {}).setdefault('files', {})
diff --git a/poky/meta/lib/oeqa/selftest/cases/runtime_test.py b/poky/meta/lib/oeqa/selftest/cases/runtime_test.py
index 463679d..12000aa 100644
--- a/poky/meta/lib/oeqa/selftest/cases/runtime_test.py
+++ b/poky/meta/lib/oeqa/selftest/cases/runtime_test.py
@@ -129,6 +129,22 @@
         bitbake('core-image-full-cmdline socat')
         bitbake('-c testimage core-image-full-cmdline')
 
+    def test_testimage_slirp(self):
+        """
+        Summary: Check basic testimage functionality with qemu and slirp networking.
+        """
+
+        features = '''
+IMAGE_CLASSES:append = " testimage"
+IMAGE_FEATURES:append = " ssh-server-dropbear"
+IMAGE_ROOTFS_EXTRA_SPACE:append = "${@bb.utils.contains("IMAGE_CLASSES", "testimage", " + 5120", "", d)}"
+TEST_RUNQEMUPARAMS += " slirp"
+'''
+        self.write_config(features)
+
+        bitbake('core-image-minimal')
+        bitbake('-c testimage core-image-minimal')
+
     def test_testimage_dnf(self):
         """
         Summary: Check package feeds functionality for dnf
@@ -236,11 +252,11 @@
         features += 'TEST_SUITES = "ping ssh virgl"\n'
         features += 'IMAGE_FEATURES:append = " ssh-server-dropbear"\n'
         features += 'IMAGE_INSTALL:append = " kmscube"\n'
-        features_gtk = features + 'TEST_RUNQEMUPARAMS = "gtk gl"\n'
+        features_gtk = features + 'TEST_RUNQEMUPARAMS += " gtk gl"\n'
         self.write_config(features_gtk)
         bitbake('core-image-minimal')
         bitbake('-c testimage core-image-minimal')
-        features_sdl = features + 'TEST_RUNQEMUPARAMS = "sdl gl"\n'
+        features_sdl = features + 'TEST_RUNQEMUPARAMS += " sdl gl"\n'
         self.write_config(features_sdl)
         bitbake('core-image-minimal')
         bitbake('-c testimage core-image-minimal')
@@ -268,7 +284,7 @@
         features += 'TEST_SUITES = "ping ssh virgl"\n'
         features += 'IMAGE_FEATURES:append = " ssh-server-dropbear"\n'
         features += 'IMAGE_INSTALL:append = " kmscube"\n'
-        features += 'TEST_RUNQEMUPARAMS = "egl-headless"\n'
+        features += 'TEST_RUNQEMUPARAMS += " egl-headless"\n'
         self.write_config(features)
         bitbake('core-image-minimal')
         bitbake('-c testimage core-image-minimal')
diff --git a/poky/meta/lib/oeqa/selftest/cases/spdx.py b/poky/meta/lib/oeqa/selftest/cases/spdx.py
new file mode 100644
index 0000000..05fc4e3
--- /dev/null
+++ b/poky/meta/lib/oeqa/selftest/cases/spdx.py
@@ -0,0 +1,54 @@
+#
+# Copyright OpenEmbedded Contributors
+#
+# SPDX-License-Identifier: MIT
+#
+
+import json
+import os
+from oeqa.selftest.case import OESelftestTestCase
+from oeqa.utils.commands import bitbake, get_bb_var, runCmd
+
+class SPDXCheck(OESelftestTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        super(SPDXCheck, cls).setUpClass()
+        bitbake("python3-spdx-tools-native")
+        bitbake("-c addto_recipe_sysroot python3-spdx-tools-native")
+
+    def check_recipe_spdx(self, high_level_dir, spdx_file, target_name):
+        config = """
+INHERIT += "create-spdx"
+"""
+        self.write_config(config)
+
+        deploy_dir = get_bb_var("DEPLOY_DIR")
+        machine_var = get_bb_var("MACHINE")
+        # qemux86-64 creates the directory qemux86_64
+        machine_dir = machine_var.replace("-", "_")
+
+        full_file_path = os.path.join(deploy_dir, "spdx", machine_dir, high_level_dir, spdx_file)
+
+        try:
+            os.remove(full_file_path)
+        except FileNotFoundError:
+            pass
+
+        bitbake("%s -c create_spdx" % target_name)
+
+        def check_spdx_json(filename):
+            with open(filename) as f:
+                report = json.load(f)
+                self.assertNotEqual(report, None)
+                self.assertNotEqual(report["SPDXID"], None)
+
+            python = os.path.join(get_bb_var('STAGING_BINDIR', 'python3-spdx-tools-native'), 'nativepython3')
+            validator = os.path.join(get_bb_var('STAGING_BINDIR', 'python3-spdx-tools-native'), 'pyspdxtools')
+            result = runCmd("{} {} -i {}".format(python, validator, filename))
+
+        self.assertExists(full_file_path)
+        result = check_spdx_json(full_file_path)
+
+    def test_spdx_base_files(self):
+        self.check_recipe_spdx("packages", "base-files.spdx.json", "base-files")
diff --git a/poky/meta/lib/oeqa/selftest/cases/wic.py b/poky/meta/lib/oeqa/selftest/cases/wic.py
index aa61349..b4866bc 100644
--- a/poky/meta/lib/oeqa/selftest/cases/wic.py
+++ b/poky/meta/lib/oeqa/selftest/cases/wic.py
@@ -729,7 +729,7 @@
         wicout = glob(os.path.join(self.resultdir, "wictestdisk-*.direct"))
         self.assertEqual(1, len(wicout))
         size = os.path.getsize(wicout[0])
-        self.assertTrue(size > extraspace)
+        self.assertTrue(size > extraspace, msg="Extra space not present (%s vs %s)" % (size, extraspace))
 
     def test_no_table(self):
         """Test --no-table wks option."""
@@ -773,7 +773,7 @@
         basename = bb_vars['IMAGE_BASENAME']
         self.assertEqual(basename, image)
         path = os.path.join(imgdatadir, basename) + '.env'
-        self.assertTrue(os.path.isfile(path))
+        self.assertTrue(os.path.isfile(path), msg="File %s wasn't generated as expected" % path)
 
         wicvars = set(bb_vars['WICVARS'].split())
         # filter out optional variables
@@ -786,7 +786,7 @@
             # test if variables used by wic present in the .env file
             for var in wicvars:
                 self.assertTrue(var in content, "%s is not in .env file" % var)
-                self.assertTrue(content[var])
+                self.assertTrue(content[var], "%s doesn't have a value (%s)" % (var, content[var]))
 
     def test_image_vars_dir_short(self):
         """Test image vars directory selection -v option"""
@@ -833,8 +833,8 @@
         # pointing to existing files
         for suffix in ('wic', 'manifest'):
             path = prefix + suffix
-            self.assertTrue(os.path.islink(path))
-            self.assertTrue(os.path.isfile(os.path.realpath(path)))
+            self.assertTrue(os.path.islink(path), msg="Link %s wasn't generated as expected" % path)
+            self.assertTrue(os.path.isfile(os.path.realpath(path)), msg="File linked to by %s wasn't generated as expected" % path)
 
     # TODO this should work on aarch64
     @skipIfNotArch(['i586', 'i686', 'x86_64'])
@@ -1104,7 +1104,7 @@
         self.remove_config(config)
         bb_vars = get_bb_vars(['DEPLOY_DIR_IMAGE', 'IMAGE_LINK_NAME'], image)
         image_path = os.path.join(bb_vars['DEPLOY_DIR_IMAGE'], '%s.wic' % bb_vars['IMAGE_LINK_NAME'])
-        self.assertTrue(os.path.exists(image_path))
+        self.assertTrue(os.path.exists(image_path), msg="Image file %s wasn't generated as expected" % image_path)
 
         sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools')
 
@@ -1345,11 +1345,11 @@
             orig_sizes = [int(line.split()[3]) for line in orig.output.split('\n')[1:]]
             exp_sizes = [int(line.split()[3]) for line in exp.output.split('\n')[1:]]
             self.assertEqual(orig_sizes[0], exp_sizes[0]) # first partition is not resized
-            self.assertTrue(orig_sizes[1] < exp_sizes[1])
+            self.assertTrue(orig_sizes[1] < exp_sizes[1], msg="Parition size wasn't enlarged (%s vs %s)" % (orig_sizes[1], exp_sizes[1]))
 
             # Check if all free space is partitioned
             result = runCmd("%s/usr/sbin/sfdisk -F %s" % (sysroot, new_image_path))
-            self.assertTrue("0 B, 0 bytes, 0 sectors" in result.output)
+            self.assertIn("0 B, 0 bytes, 0 sectors", result.output)
 
             os.rename(image_path, image_path + '.bak')
             os.rename(new_image_path, image_path)
@@ -1433,7 +1433,7 @@
             # check if file is there
             result = runCmd("wic ls %s:1/ -n %s" % (images[0], sysroot))
             self.assertEqual(7, len(result.output.split('\n')))
-            self.assertTrue(os.path.basename(testfile.name) in result.output)
+            self.assertIn(os.path.basename(testfile.name), result.output)
 
             # prepare directory
             testdir = os.path.join(self.resultdir, 'wic-test-cp-dir')
@@ -1447,13 +1447,13 @@
             # check if directory is there
             result = runCmd("wic ls %s:1/ -n %s" % (images[0], sysroot))
             self.assertEqual(8, len(result.output.split('\n')))
-            self.assertTrue(os.path.basename(testdir) in result.output)
+            self.assertIn(os.path.basename(testdir), result.output)
 
             # copy the file from the partition and check if it success
             dest = '%s-cp' % testfile.name
             runCmd("wic cp %s:1/%s %s -n %s" % (images[0],
                     os.path.basename(testfile.name), dest, sysroot))
-            self.assertTrue(os.path.exists(dest))
+            self.assertTrue(os.path.exists(dest), msg="File %s wasn't generated as expected" % dest)
 
 
     def test_wic_rm(self):
@@ -1497,7 +1497,7 @@
         # list directory content of the second ext4 partition
         result = runCmd("wic ls %s:2/ -n %s" % (images[0], sysroot))
         self.assertTrue(set(['bin', 'home', 'proc', 'usr', 'var', 'dev', 'lib', 'sbin']).issubset(
-                            set(line.split()[-1] for line in result.output.split('\n') if line)))
+                            set(line.split()[-1] for line in result.output.split('\n') if line)), msg="Expected directories not present %s" % result.output)
 
     def test_wic_cp_ext(self):
         """Test copy files and directories to the ext partition."""
@@ -1512,7 +1512,7 @@
         # list directory content of the ext4 partition
         result = runCmd("wic ls %s:2/ -n %s" % (images[0], sysroot))
         dirs = set(line.split()[-1] for line in result.output.split('\n') if line)
-        self.assertTrue(set(['bin', 'home', 'proc', 'usr', 'var', 'dev', 'lib', 'sbin']).issubset(dirs))
+        self.assertTrue(set(['bin', 'home', 'proc', 'usr', 'var', 'dev', 'lib', 'sbin']).issubset(dirs), msg="Expected directories not present %s" % dirs)
 
         with NamedTemporaryFile("w", suffix=".wic-cp") as testfile:
             testfile.write("test")
@@ -1527,12 +1527,12 @@
 
             # check if the file to copy is in the partition
             result = runCmd("wic ls %s:2/etc/ -n %s" % (images[0], sysroot))
-            self.assertTrue('fstab' in [line.split()[-1] for line in result.output.split('\n') if line])
+            self.assertIn('fstab', [line.split()[-1] for line in result.output.split('\n') if line])
 
             # copy file from the partition, replace the temporary file content with it and
             # check for the file size to validate the copy
             runCmd("wic cp %s:2/etc/fstab %s -n %s" % (images[0], testfile.name, sysroot))
-            self.assertTrue(os.stat(testfile.name).st_size > 0)
+            self.assertTrue(os.stat(testfile.name).st_size > 0, msg="Filesize not as expected %s" % os.stat(testfile.name).st_size)
 
 
     def test_wic_rm_ext(self):
@@ -1547,18 +1547,18 @@
 
         # list directory content of the /etc directory on ext4 partition
         result = runCmd("wic ls %s:2/etc/ -n %s" % (images[0], sysroot))
-        self.assertTrue('fstab' in [line.split()[-1] for line in result.output.split('\n') if line])
+        self.assertIn('fstab', [line.split()[-1] for line in result.output.split('\n') if line])
 
         # remove file
         runCmd("wic rm %s:2/etc/fstab -n %s" % (images[0], sysroot))
 
         # check if it's removed
         result = runCmd("wic ls %s:2/etc/ -n %s" % (images[0], sysroot))
-        self.assertTrue('fstab' not in [line.split()[-1] for line in result.output.split('\n') if line])
+        self.assertNotIn('fstab', [line.split()[-1] for line in result.output.split('\n') if line])
 
         # remove non-empty directory
         runCmd("wic rm -r %s:2/etc/ -n %s" % (images[0], sysroot))
 
         # check if it's removed
         result = runCmd("wic ls %s:2/ -n %s" % (images[0], sysroot))
-        self.assertTrue('etc' not in [line.split()[-1] for line in result.output.split('\n') if line])
+        self.assertNotIn('etc', [line.split()[-1] for line in result.output.split('\n') if line])
diff --git a/poky/meta/lib/oeqa/selftest/context.py b/poky/meta/lib/oeqa/selftest/context.py
index bd03e76..5a09aee 100644
--- a/poky/meta/lib/oeqa/selftest/context.py
+++ b/poky/meta/lib/oeqa/selftest/context.py
@@ -35,12 +35,13 @@
     return result
 
 class NonConcurrentTestSuite(unittest.TestSuite):
-    def __init__(self, suite, processes, setupfunc, removefunc):
+    def __init__(self, suite, processes, setupfunc, removefunc, bb_vars):
         super().__init__([suite])
         self.processes = processes
         self.suite = suite
         self.setupfunc = setupfunc
         self.removefunc = removefunc
+        self.bb_vars = bb_vars
 
     def run(self, result):
         (builddir, newbuilddir) = self.setupfunc("-st", None, self.suite)
@@ -79,16 +80,15 @@
         else:
             self.removebuilddir = removebuilddir
 
+    def set_variables(self, vars):
+        self.bb_vars = vars
+
     def setup_builddir(self, suffix, selftestdir, suite):
-        # Get SSTATE_DIR from the parent build dir
-        with bb.tinfoil.Tinfoil(tracking=True) as tinfoil:
-            tinfoil.prepare(quiet=2, config_only=True)
-            d = tinfoil.config_data
-            sstatedir = str(d.getVar('SSTATE_DIR'))
+        sstatedir = self.bb_vars['SSTATE_DIR']
 
         builddir = os.environ['BUILDDIR']
         if not selftestdir:
-            selftestdir = get_test_layer()
+            selftestdir = get_test_layer(self.bb_vars['BBLAYERS'])
         if self.newbuilddir:
             newbuilddir = os.path.join(self.newbuilddir, 'build' + suffix)
         else:
@@ -104,7 +104,7 @@
         oe.path.copytree(builddir + "/cache", newbuilddir + "/cache")
         oe.path.copytree(selftestdir, newselftestdir)
 
-        subprocess.check_output("git init; git add *; git commit -a -m 'initial'", cwd=newselftestdir, shell=True)
+        subprocess.check_output("git init && git add * && git commit -a -m 'initial'", cwd=newselftestdir, shell=True)
 
         # Tried to used bitbake-layers add/remove but it requires recipe parsing and hence is too slow
         subprocess.check_output("sed %s/conf/bblayers.conf -i -e 's#%s#%s#g'" % (newbuilddir, selftestdir, newselftestdir), cwd=newbuilddir, shell=True)
@@ -155,9 +155,9 @@
         if processes:
             from oeqa.core.utils.concurrencytest import ConcurrentTestSuite
 
-            return ConcurrentTestSuite(suites, processes, self.setup_builddir, self.removebuilddir)
+            return ConcurrentTestSuite(suites, processes, self.setup_builddir, self.removebuilddir, self.bb_vars)
         else:
-            return NonConcurrentTestSuite(suites, processes, self.setup_builddir, self.removebuilddir)
+            return NonConcurrentTestSuite(suites, processes, self.setup_builddir, self.removebuilddir, self.bb_vars)
 
     def runTests(self, processes=None, machine=None, skips=[]):
         if machine:
@@ -270,7 +270,7 @@
 
         builddir = os.environ.get("BUILDDIR")
         self.tc_kwargs['init']['config_paths'] = {}
-        self.tc_kwargs['init']['config_paths']['testlayer_path'] = get_test_layer()
+        self.tc_kwargs['init']['config_paths']['testlayer_path'] = get_test_layer(bbvars["BBLAYERS"])
         self.tc_kwargs['init']['config_paths']['builddir'] = builddir
         self.tc_kwargs['init']['config_paths']['localconf'] = os.path.join(builddir, "conf/local.conf")
         self.tc_kwargs['init']['config_paths']['bblayers'] = os.path.join(builddir, "conf/bblayers.conf")
@@ -310,10 +310,10 @@
                 meta_selftestdir = os.path.join(
                     self.tc.td["BBLAYERS_FETCH_DIR"], 'meta-selftest')
                 if os.path.isdir(meta_selftestdir):
-                    runCmd("bitbake-layers add-layer %s" %meta_selftestdir)
+                    runCmd("bitbake-layers add-layer %s" % meta_selftestdir)
                     # reload data is needed because a meta-selftest layer was add
                     self.tc.td = get_bb_vars()
-                    self.tc.config_paths['testlayer_path'] = get_test_layer()
+                    self.tc.config_paths['testlayer_path'] = get_test_layer(self.tc.td["BBLAYERS"])
                 else:
                     self.tc.logger.error("could not locate meta-selftest in:\n%s" % meta_selftestdir)
                     raise OEQAPreRun
@@ -351,8 +351,15 @@
 
         _add_layer_libs()
 
-        self.tc.logger.info("Running bitbake -e to test the configuration is valid/parsable")
-        runCmd("bitbake -e")
+        self.tc.logger.info("Checking base configuration is valid/parsable")
+
+        with bb.tinfoil.Tinfoil(tracking=True) as tinfoil:
+            tinfoil.prepare(quiet=2, config_only=True)
+            d = tinfoil.config_data
+            vars = {}
+            vars['SSTATE_DIR'] = str(d.getVar('SSTATE_DIR'))
+            vars['BBLAYERS'] = str(d.getVar('BBLAYERS'))
+        self.tc.set_variables(vars)
 
     def get_json_result_dir(self, args):
         json_result_dir = os.path.join(self.tc.td["LOG_DIR"], 'oeqa')
@@ -437,7 +444,7 @@
             output_link = os.path.join(os.path.dirname(args.output_log),
                     "%s-results.log" % self.name)
             if os.path.lexists(output_link):
-                os.remove(output_link)
+                os.unlink(output_link)
             os.symlink(args.output_log, output_link)
 
         return rc
diff --git a/poky/meta/lib/oeqa/utils/commands.py b/poky/meta/lib/oeqa/utils/commands.py
index c1f5338..575e380 100644
--- a/poky/meta/lib/oeqa/utils/commands.py
+++ b/poky/meta/lib/oeqa/utils/commands.py
@@ -285,8 +285,10 @@
 def get_bb_var(var, target=None, postconfig=None):
     return get_bb_vars([var], target, postconfig)[var]
 
-def get_test_layer():
-    layers = get_bb_var("BBLAYERS").split()
+def get_test_layer(bblayers=None):
+    if bblayers is None:
+        bblayers = get_bb_var("BBLAYERS")
+    layers = bblayers.split()
     testlayer = None
     for l in layers:
         if '~' in l:
diff --git a/poky/meta/lib/oeqa/utils/gitarchive.py b/poky/meta/lib/oeqa/utils/gitarchive.py
index 64448f4..f9c1526 100644
--- a/poky/meta/lib/oeqa/utils/gitarchive.py
+++ b/poky/meta/lib/oeqa/utils/gitarchive.py
@@ -255,7 +255,15 @@
         if not commit in revs:
             revs[commit] = TestedRev(commit, commit_num, [tag])
         else:
-            assert commit_num == revs[commit].commit_number, "Commit numbers do not match"
+            if commit_num != revs[commit].commit_number:
+                # Historically we have incorrect commit counts of '1' in the repo so fix these up
+                if int(revs[commit].commit_number) < 5:
+                    tags = revs[commit].tags
+                    revs[commit] = TestedRev(commit, commit_num, [tags])
+                elif int(commit_num) < 5:
+                    pass
+                else:
+                    sys.exit("Commit numbers for commit %s don't match (%s vs %s)" % (commit, commit_num, revs[commit].commit_number))
             revs[commit].tags.append(tag)
 
     # Return in sorted table
diff --git a/poky/meta/lib/patchtest/README.md b/poky/meta/lib/patchtest/README.md
new file mode 100644
index 0000000..f66613c
--- /dev/null
+++ b/poky/meta/lib/patchtest/README.md
@@ -0,0 +1,20 @@
+# patchtest selftests for openembedded-core
+
+This directory provides a test suite and selftest script for use with the
+patchtest repository: https://git.yoctoproject.org/patchtest/
+
+To setup for use:
+
+1. Clone https://git.openembedded.org/openembedded-core (this repo) and https://git.openembedded.org/bitbake/
+2. Clone https://git.yoctoproject.org/patchtest
+3. Install the necessary Python modules: in meta/lib/patchtest or the patchtest
+   repo, do `pip install -r requirements.txt`
+4. Add patchtest to PATH: `export PATH=/path/to/patchtest/repo:$PATH`
+5. Initialize the environment: `source oe-init-build-env`
+6. Add meta-selftest to bblayers.conf: `bitbake-layers add-layer
+   /path/to/meta-selftest/` (the selftests use this layer's recipes as test
+   targets)
+7. Finally, run the selftest script: `./meta/lib/patchtest/selftest/selftest`
+
+For more information on using patchtest, see the patchtest repo at
+https://git.yoctoproject.org/patchtest/.
diff --git a/poky/meta/lib/patchtest/requirements.txt b/poky/meta/lib/patchtest/requirements.txt
new file mode 100644
index 0000000..785aa46
--- /dev/null
+++ b/poky/meta/lib/patchtest/requirements.txt
@@ -0,0 +1,4 @@
+jinja2
+pylint
+pyparsing>=3.0.9
+unidiff
diff --git a/poky/meta/lib/patchtest/selftest/files/Author.test_author_valid.1.fail b/poky/meta/lib/patchtest/selftest/files/Author.test_author_valid.1.fail
new file mode 100644
index 0000000..0c40cdc
--- /dev/null
+++ b/poky/meta/lib/patchtest/selftest/files/Author.test_author_valid.1.fail
@@ -0,0 +1,32 @@
+From 1fbb446d1849b1208012cbdae5d85d228cdbe4a6 Mon Sep 17 00:00:00 2001
+From: First Last <first.last@example.com>
+Date: Tue, 29 Aug 2023 13:32:24 -0400
+Subject: [PATCH] selftest-hello: add a summary
+
+This patch should fail the selftests because the author address is from the
+invalid "example.com".
+
+Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
+---
+ .../recipes-test/selftest-hello/selftest-hello_1.0.bb          | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
+index 547587bef4..491f0a3df7 100644
+--- a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
++++ b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
+@@ -1,3 +1,4 @@
++SUMMARY = "A cool sample"
+ DESCRIPTION = "Simple helloworld application -- selftest variant"
+ SECTION = "examples"
+ LICENSE = "MIT"
+@@ -16,4 +17,4 @@ do_install() {
+ 	install -m 0755 helloworld ${D}${bindir}
+ }
+ 
+-BBCLASSEXTEND = "native nativesdk"
+\ No newline at end of file
++BBCLASSEXTEND = "native nativesdk"
+-- 
+2.41.0
+
diff --git a/poky/meta/lib/patchtest/selftest/files/Author.test_author_valid.1.pass b/poky/meta/lib/patchtest/selftest/files/Author.test_author_valid.1.pass
new file mode 100644
index 0000000..cbb8ef2
--- /dev/null
+++ b/poky/meta/lib/patchtest/selftest/files/Author.test_author_valid.1.pass
@@ -0,0 +1,31 @@
+From 1fbb446d1849b1208012cbdae5d85d228cdbe4a6 Mon Sep 17 00:00:00 2001
+From: First Last <first.last@address.com>
+Date: Tue, 29 Aug 2023 13:32:24 -0400
+Subject: [PATCH] selftest-hello: add a summary
+
+This patch should pass the selftests because the author address is in a valid format.
+
+Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
+---
+ .../recipes-test/selftest-hello/selftest-hello_1.0.bb          | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
+index 547587bef4..491f0a3df7 100644
+--- a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
++++ b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
+@@ -1,3 +1,4 @@
++SUMMARY = "A cool sample"
+ DESCRIPTION = "Simple helloworld application -- selftest variant"
+ SECTION = "examples"
+ LICENSE = "MIT"
+@@ -16,4 +17,4 @@ do_install() {
+ 	install -m 0755 helloworld ${D}${bindir}
+ }
+ 
+-BBCLASSEXTEND = "native nativesdk"
+\ No newline at end of file
++BBCLASSEXTEND = "native nativesdk"
+-- 
+2.41.0
+
diff --git a/poky/meta/lib/patchtest/selftest/files/Author.test_author_valid.2.fail b/poky/meta/lib/patchtest/selftest/files/Author.test_author_valid.2.fail
new file mode 100644
index 0000000..3e2b81b
--- /dev/null
+++ b/poky/meta/lib/patchtest/selftest/files/Author.test_author_valid.2.fail
@@ -0,0 +1,31 @@
+From 1fbb446d1849b1208012cbdae5d85d228cdbe4a6 Mon Sep 17 00:00:00 2001
+From: Upgrade Helper <auh@auh.yoctoproject.org>
+Date: Tue, 29 Aug 2023 13:32:24 -0400
+Subject: [PATCH] selftest-hello: add a summary
+
+This patch should fail the selftests because AUH is an invalid sender.
+
+Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
+---
+ .../recipes-test/selftest-hello/selftest-hello_1.0.bb          | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
+index 547587bef4..491f0a3df7 100644
+--- a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
++++ b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
+@@ -1,3 +1,4 @@
++SUMMARY = "A cool sample"
+ DESCRIPTION = "Simple helloworld application -- selftest variant"
+ SECTION = "examples"
+ LICENSE = "MIT"
+@@ -16,4 +17,4 @@ do_install() {
+ 	install -m 0755 helloworld ${D}${bindir}
+ }
+ 
+-BBCLASSEXTEND = "native nativesdk"
+\ No newline at end of file
++BBCLASSEXTEND = "native nativesdk"
+-- 
+2.41.0
+
diff --git a/poky/meta/lib/patchtest/selftest/files/Author.test_author_valid.2.pass b/poky/meta/lib/patchtest/selftest/files/Author.test_author_valid.2.pass
new file mode 100644
index 0000000..f84e126
--- /dev/null
+++ b/poky/meta/lib/patchtest/selftest/files/Author.test_author_valid.2.pass
@@ -0,0 +1,31 @@
+From 1fbb446d1849b1208012cbdae5d85d228cdbe4a6 Mon Sep 17 00:00:00 2001
+From: First Last <averylongemailaddressthatishardtoread.from@address.com>
+Date: Tue, 29 Aug 2023 13:32:24 -0400
+Subject: [PATCH] selftest-hello: add a summary
+
+This patch should pass the selftests because the author address is in a valid format.
+
+Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
+---
+ .../recipes-test/selftest-hello/selftest-hello_1.0.bb          | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
+index 547587bef4..491f0a3df7 100644
+--- a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
++++ b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
+@@ -1,3 +1,4 @@
++SUMMARY = "A cool sample"
+ DESCRIPTION = "Simple helloworld application -- selftest variant"
+ SECTION = "examples"
+ LICENSE = "MIT"
+@@ -16,4 +17,4 @@ do_install() {
+ 	install -m 0755 helloworld ${D}${bindir}
+ }
+ 
+-BBCLASSEXTEND = "native nativesdk"
+\ No newline at end of file
++BBCLASSEXTEND = "native nativesdk"
+-- 
+2.41.0
+
diff --git a/poky/meta/lib/patchtest/selftest/files/Bugzilla.test_bugzilla_entry_format.fail b/poky/meta/lib/patchtest/selftest/files/Bugzilla.test_bugzilla_entry_format.fail
new file mode 100644
index 0000000..80f409e
--- /dev/null
+++ b/poky/meta/lib/patchtest/selftest/files/Bugzilla.test_bugzilla_entry_format.fail
@@ -0,0 +1,25 @@
+From fdfd605e565d874502522c4b70b786c8c5aa0bad Mon Sep 17 00:00:00 2001
+From: name@somedomain.com <email@address.com>
+Date: Fri, 17 Feb 2017 16:29:21 -0600
+Subject: [PATCH] README: adds 'foo' to the header
+
+This test patch adds 'foo' to the header
+
+[YOCTO 1234]
+
+Signed-off-by: Daniela Plascencia <daniela.plascencia@linux.intel.com>
+---
+ README | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/README b/README
+index 521916cd4f..cdf29dcea3 100644
+--- a/README
++++ b/README
+@@ -1,3 +1,4 @@
++**** FOO ****
+ OpenEmbedded-Core
+ =================
+
+--
+2.11.0
diff --git a/poky/meta/lib/patchtest/selftest/files/Bugzilla.test_bugzilla_entry_format.pass b/poky/meta/lib/patchtest/selftest/files/Bugzilla.test_bugzilla_entry_format.pass
new file mode 100644
index 0000000..2648b03
--- /dev/null
+++ b/poky/meta/lib/patchtest/selftest/files/Bugzilla.test_bugzilla_entry_format.pass
@@ -0,0 +1,25 @@
+From fdfd605e565d874502522c4b70b786c8c5aa0bad Mon Sep 17 00:00:00 2001
+From: name@somedomain.com <email@address.com>
+Date: Fri, 17 Feb 2017 16:29:21 -0600
+Subject: [PATCH] README: adds 'foo' to the header
+
+This test patch adds 'foo' to the header
+
+[YOCTO #1234]
+
+Signed-off-by: Daniela Plascencia <daniela.plascencia@linux.intel.com>
+---
+ README | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/README b/README
+index 521916cd4f..cdf29dcea3 100644
+--- a/README
++++ b/README
+@@ -1,3 +1,4 @@
++**** FOO ****
+ OpenEmbedded-Core
+ =================
+
+--
+2.11.0
diff --git a/poky/meta/lib/patchtest/selftest/files/CVE.test_cve_presence_in_commit_message.fail b/poky/meta/lib/patchtest/selftest/files/CVE.test_cve_presence_in_commit_message.fail
new file mode 100644
index 0000000..d40b8a9
--- /dev/null
+++ b/poky/meta/lib/patchtest/selftest/files/CVE.test_cve_presence_in_commit_message.fail
@@ -0,0 +1,72 @@
+From 14d72f6973270f78455a8628143f2cff90e8f41e Mon Sep 17 00:00:00 2001
+From: Trevor Gamblin <tgamblin@baylibre.com>
+Date: Tue, 29 Aug 2023 14:12:27 -0400
+Subject: [PATCH] selftest-hello: fix CVE-1234-56789
+
+This patch should fail the test for CVE presence in the mbox commit message.
+
+Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
+---
+ .../selftest-hello/files/CVE-1234-56789.patch | 27 +++++++++++++++++++
+ .../selftest-hello/selftest-hello_1.0.bb      |  6 +++--
+ 2 files changed, 31 insertions(+), 2 deletions(-)
+ create mode 100644 meta-selftest/recipes-test/selftest-hello/files/CVE-1234-56789.patch
+
+diff --git a/meta-selftest/recipes-test/selftest-hello/files/CVE-1234-56789.patch b/meta-selftest/recipes-test/selftest-hello/files/CVE-1234-56789.patch
+new file mode 100644
+index 0000000000..869cfb6fe5
+--- /dev/null
++++ b/meta-selftest/recipes-test/selftest-hello/files/CVE-1234-56789.patch
+@@ -0,0 +1,27 @@
++From b26a31186e6ee2eb1f506d5f2f9394d327a0df2f Mon Sep 17 00:00:00 2001
++From: Trevor Gamblin <tgamblin@baylibre.com>
++Date: Tue, 29 Aug 2023 14:08:20 -0400
++Subject: [PATCH] Fix CVE-NOT-REAL
++
++CVE: CVE-1234-56789
++Upstream-Status: Backport(http://example.com/example)
++
++Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
++---
++ strlen.c | 1 +
++ 1 file changed, 1 insertion(+)
++
++diff --git a/strlen.c b/strlen.c
++index 1788f38..83d7918 100644
++--- a/strlen.c
+++++ b/strlen.c
++@@ -8,6 +8,7 @@ int main() {
++ 
++ 	printf("%d\n", str_len(string1));
++ 	printf("%d\n", str_len(string2));
+++	printf("CVE FIXED!!!\n");
++ 
++ 	return 0;
++ }
++-- 
++2.41.0
+diff --git a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
+index 547587bef4..76975a6729 100644
+--- a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
++++ b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
+@@ -3,7 +3,9 @@ SECTION = "examples"
+ LICENSE = "MIT"
+ LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
+ 
+-SRC_URI = "file://helloworld.c"
++SRC_URI = "file://helloworld.c \
++           file://CVE-1234-56789.patch \
++           "
+ 
+ S = "${WORKDIR}"
+ 
+@@ -16,4 +18,4 @@ do_install() {
+ 	install -m 0755 helloworld ${D}${bindir}
+ }
+ 
+-BBCLASSEXTEND = "native nativesdk"
+\ No newline at end of file
++BBCLASSEXTEND = "native nativesdk"
+-- 
+2.41.0
+
diff --git a/poky/meta/lib/patchtest/selftest/files/CVE.test_cve_presence_in_commit_message.pass b/poky/meta/lib/patchtest/selftest/files/CVE.test_cve_presence_in_commit_message.pass
new file mode 100644
index 0000000..433c7a4
--- /dev/null
+++ b/poky/meta/lib/patchtest/selftest/files/CVE.test_cve_presence_in_commit_message.pass
@@ -0,0 +1,74 @@
+From 14d72f6973270f78455a8628143f2cff90e8f41e Mon Sep 17 00:00:00 2001
+From: Trevor Gamblin <tgamblin@baylibre.com>
+Date: Tue, 29 Aug 2023 14:12:27 -0400
+Subject: [PATCH] selftest-hello: fix CVE-1234-56789
+
+This test should pass the mbox cve tag test.
+
+CVE: CVE-1234-56789
+
+Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
+---
+ .../selftest-hello/files/CVE-1234-56789.patch | 27 +++++++++++++++++++
+ .../selftest-hello/selftest-hello_1.0.bb      |  6 +++--
+ 2 files changed, 31 insertions(+), 2 deletions(-)
+ create mode 100644 meta-selftest/recipes-test/selftest-hello/files/CVE-1234-56789.patch
+
+diff --git a/meta-selftest/recipes-test/selftest-hello/files/CVE-1234-56789.patch b/meta-selftest/recipes-test/selftest-hello/files/CVE-1234-56789.patch
+new file mode 100644
+index 0000000000..869cfb6fe5
+--- /dev/null
++++ b/meta-selftest/recipes-test/selftest-hello/files/CVE-1234-56789.patch
+@@ -0,0 +1,27 @@
++From b26a31186e6ee2eb1f506d5f2f9394d327a0df2f Mon Sep 17 00:00:00 2001
++From: Trevor Gamblin <tgamblin@baylibre.com>
++Date: Tue, 29 Aug 2023 14:08:20 -0400
++Subject: [PATCH] Fix CVE-NOT-REAL
++
++CVE: CVE-1234-56789
++Upstream-Status: Backport(http://example.com/example)
++
++Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
++---
++ strlen.c | 1 +
++ 1 file changed, 1 insertion(+)
++
++diff --git a/strlen.c b/strlen.c
++index 1788f38..83d7918 100644
++--- a/strlen.c
+++++ b/strlen.c
++@@ -8,6 +8,7 @@ int main() {
++ 
++ 	printf("%d\n", str_len(string1));
++ 	printf("%d\n", str_len(string2));
+++	printf("CVE FIXED!!!\n");
++ 
++ 	return 0;
++ }
++-- 
++2.41.0
+diff --git a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
+index 547587bef4..76975a6729 100644
+--- a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
++++ b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
+@@ -3,7 +3,9 @@ SECTION = "examples"
+ LICENSE = "MIT"
+ LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
+ 
+-SRC_URI = "file://helloworld.c"
++SRC_URI = "file://helloworld.c \
++           file://CVE-1234-56789.patch \
++           "
+ 
+ S = "${WORKDIR}"
+ 
+@@ -16,4 +18,4 @@ do_install() {
+ 	install -m 0755 helloworld ${D}${bindir}
+ }
+ 
+-BBCLASSEXTEND = "native nativesdk"
+\ No newline at end of file
++BBCLASSEXTEND = "native nativesdk"
+-- 
+2.41.0
+
diff --git a/poky/meta/lib/patchtest/selftest/files/CVE.test_cve_tag_format.fail b/poky/meta/lib/patchtest/selftest/files/CVE.test_cve_tag_format.fail
new file mode 100644
index 0000000..c763a75
--- /dev/null
+++ b/poky/meta/lib/patchtest/selftest/files/CVE.test_cve_tag_format.fail
@@ -0,0 +1,73 @@
+From 35ccee3cee96fb29514475279248078d88907231 Mon Sep 17 00:00:00 2001
+From: Trevor Gamblin <tgamblin@baylibre.com>
+Date: Tue, 29 Aug 2023 14:12:27 -0400
+Subject: [PATCH] selftest-hello: fix CVE-1234-56789
+
+CVE: CVE-BAD-FORMAT
+
+Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
+---
+ .../files/0001-Fix-CVE-1234-56789.patch       | 27 +++++++++++++++++++
+ .../selftest-hello/selftest-hello_1.0.bb      |  6 +++--
+ 2 files changed, 31 insertions(+), 2 deletions(-)
+ create mode 100644 meta-selftest/recipes-test/selftest-hello/files/0001-Fix-CVE-1234-56789.patch
+
+diff --git a/meta-selftest/recipes-test/selftest-hello/files/0001-Fix-CVE-1234-56789.patch b/meta-selftest/recipes-test/selftest-hello/files/0001-Fix-CVE-1234-56789.patch
+new file mode 100644
+index 0000000000..9219b8db62
+--- /dev/null
++++ b/meta-selftest/recipes-test/selftest-hello/files/0001-Fix-CVE-1234-56789.patch
+@@ -0,0 +1,27 @@
++From b26a31186e6ee2eb1f506d5f2f9394d327a0df2f Mon Sep 17 00:00:00 2001
++From: Trevor Gamblin <tgamblin@baylibre.com>
++Date: Tue, 29 Aug 2023 14:08:20 -0400
++Subject: [PATCH] Fix CVE-NOT-REAL
++
++CVE: CVE-BAD-FORMAT
++Upstream-Status: Backport(http://example.com/example)
++
++Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
++---
++ strlen.c | 1 +
++ 1 file changed, 1 insertion(+)
++
++diff --git a/strlen.c b/strlen.c
++index 1788f38..83d7918 100644
++--- a/strlen.c
+++++ b/strlen.c
++@@ -8,6 +8,7 @@ int main() {
++ 
++ 	printf("%d\n", str_len(string1));
++ 	printf("%d\n", str_len(string2));
+++	printf("CVE FIXED!!!\n");
++ 
++ 	return 0;
++ }
++-- 
++2.41.0
++
+diff --git a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
+index 547587bef4..76975a6729 100644
+--- a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
++++ b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
+@@ -3,7 +3,9 @@ SECTION = "examples"
+ LICENSE = "MIT"
+ LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
+ 
+-SRC_URI = "file://helloworld.c"
++SRC_URI = "file://helloworld.c \
++           file://CVE-1234-56789.patch \
++           "
+ 
+ S = "${WORKDIR}"
+ 
+@@ -16,4 +18,4 @@ do_install() {
+ 	install -m 0755 helloworld ${D}${bindir}
+ }
+ 
+-BBCLASSEXTEND = "native nativesdk"
+\ No newline at end of file
++BBCLASSEXTEND = "native nativesdk"
+-- 
+2.41.0
+
diff --git a/poky/meta/lib/patchtest/selftest/files/CVE.test_cve_tag_format.pass b/poky/meta/lib/patchtest/selftest/files/CVE.test_cve_tag_format.pass
new file mode 100644
index 0000000..ef60170
--- /dev/null
+++ b/poky/meta/lib/patchtest/selftest/files/CVE.test_cve_tag_format.pass
@@ -0,0 +1,73 @@
+From 35ccee3cee96fb29514475279248078d88907231 Mon Sep 17 00:00:00 2001
+From: Trevor Gamblin <tgamblin@baylibre.com>
+Date: Tue, 29 Aug 2023 14:12:27 -0400
+Subject: [PATCH] selftest-hello: fix CVE-1234-56789
+
+CVE: CVE-1234-56789
+
+Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
+---
+ .../files/0001-Fix-CVE-1234-56789.patch       | 27 +++++++++++++++++++
+ .../selftest-hello/selftest-hello_1.0.bb      |  6 +++--
+ 2 files changed, 31 insertions(+), 2 deletions(-)
+ create mode 100644 meta-selftest/recipes-test/selftest-hello/files/0001-Fix-CVE-1234-56789.patch
+
+diff --git a/meta-selftest/recipes-test/selftest-hello/files/0001-Fix-CVE-1234-56789.patch b/meta-selftest/recipes-test/selftest-hello/files/0001-Fix-CVE-1234-56789.patch
+new file mode 100644
+index 0000000000..9219b8db62
+--- /dev/null
++++ b/meta-selftest/recipes-test/selftest-hello/files/0001-Fix-CVE-1234-56789.patch
+@@ -0,0 +1,27 @@
++From b26a31186e6ee2eb1f506d5f2f9394d327a0df2f Mon Sep 17 00:00:00 2001
++From: Trevor Gamblin <tgamblin@baylibre.com>
++Date: Tue, 29 Aug 2023 14:08:20 -0400
++Subject: [PATCH] Fix CVE-NOT-REAL
++
++CVE: CVE-1234-56789
++Upstream-Status: Backport(http://example.com/example)
++
++Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
++---
++ strlen.c | 1 +
++ 1 file changed, 1 insertion(+)
++
++diff --git a/strlen.c b/strlen.c
++index 1788f38..83d7918 100644
++--- a/strlen.c
+++++ b/strlen.c
++@@ -8,6 +8,7 @@ int main() {
++ 
++ 	printf("%d\n", str_len(string1));
++ 	printf("%d\n", str_len(string2));
+++	printf("CVE FIXED!!!\n");
++ 
++ 	return 0;
++ }
++-- 
++2.41.0
++
+diff --git a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
+index 547587bef4..76975a6729 100644
+--- a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
++++ b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
+@@ -3,7 +3,9 @@ SECTION = "examples"
+ LICENSE = "MIT"
+ LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
+ 
+-SRC_URI = "file://helloworld.c"
++SRC_URI = "file://helloworld.c \
++           file://CVE-1234-56789.patch \
++           "
+ 
+ S = "${WORKDIR}"
+ 
+@@ -16,4 +18,4 @@ do_install() {
+ 	install -m 0755 helloworld ${D}${bindir}
+ }
+ 
+-BBCLASSEXTEND = "native nativesdk"
+\ No newline at end of file
++BBCLASSEXTEND = "native nativesdk"
+-- 
+2.41.0
+
diff --git a/poky/meta/lib/patchtest/selftest/files/CommitMessage.test_commit_message_presence.fail b/poky/meta/lib/patchtest/selftest/files/CommitMessage.test_commit_message_presence.fail
new file mode 100644
index 0000000..93ca0f9
--- /dev/null
+++ b/poky/meta/lib/patchtest/selftest/files/CommitMessage.test_commit_message_presence.fail
@@ -0,0 +1,22 @@
+From 0a52a62c9430c05d22cb7f46380488f2280b69bb Mon Sep 17 00:00:00 2001
+From: Trevor Gamblin <tgamblin@baylibre.com>
+Date: Fri, 1 Sep 2023 08:56:14 -0400
+Subject: [PATCH] README.OE-Core.md: add foo
+
+Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
+---
+ README.OE-Core.md | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/README.OE-Core.md b/README.OE-Core.md
+index 2f2127fb03..48464252c8 100644
+--- a/README.OE-Core.md
++++ b/README.OE-Core.md
+@@ -1,3 +1,4 @@
++** FOO **
+ OpenEmbedded-Core
+ =================
+ 
+-- 
+2.41.0
+
diff --git a/poky/meta/lib/patchtest/selftest/files/CommitMessage.test_commit_message_presence.pass b/poky/meta/lib/patchtest/selftest/files/CommitMessage.test_commit_message_presence.pass
new file mode 100644
index 0000000..5e3dcbd
--- /dev/null
+++ b/poky/meta/lib/patchtest/selftest/files/CommitMessage.test_commit_message_presence.pass
@@ -0,0 +1,24 @@
+From 0a52a62c9430c05d22cb7f46380488f2280b69bb Mon Sep 17 00:00:00 2001
+From: Trevor Gamblin <tgamblin@baylibre.com>
+Date: Fri, 1 Sep 2023 08:56:14 -0400
+Subject: [PATCH] README.OE-Core.md: add foo
+
+This is a commit message
+
+Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
+---
+ README.OE-Core.md | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/README.OE-Core.md b/README.OE-Core.md
+index 2f2127fb03..48464252c8 100644
+--- a/README.OE-Core.md
++++ b/README.OE-Core.md
+@@ -1,3 +1,4 @@
++** FOO **
+ OpenEmbedded-Core
+ =================
+ 
+-- 
+2.41.0
+
diff --git a/poky/meta/lib/patchtest/selftest/files/LicFilesChkSum.test_lic_files_chksum_modified_not_mentioned.fail b/poky/meta/lib/patchtest/selftest/files/LicFilesChkSum.test_lic_files_chksum_modified_not_mentioned.fail
new file mode 100644
index 0000000..ab6c52c
--- /dev/null
+++ b/poky/meta/lib/patchtest/selftest/files/LicFilesChkSum.test_lic_files_chksum_modified_not_mentioned.fail
@@ -0,0 +1,37 @@
+From f89919ea86d38404dd621521680a0162367bb965 Mon Sep 17 00:00:00 2001
+From: Trevor Gamblin <tgamblin@baylibre.com>
+Date: Wed, 6 Sep 2023 09:09:27 -0400
+Subject: [PATCH] selftest-hello: update LIC_FILES_CHKSUM
+
+This test should fail the
+test_metadata_lic_files_chksum.LicFilesChkSum.test_lic_files_chksum_modified_not_mentioned
+test.
+
+Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
+---
+ .../recipes-test/selftest-hello/selftest-hello_1.0.bb         | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
+index 547587bef4..65dda40aba 100644
+--- a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
++++ b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
+@@ -1,7 +1,7 @@
+ DESCRIPTION = "Simple helloworld application -- selftest variant"
+ SECTION = "examples"
+ LICENSE = "MIT"
+-LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
++LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f303"
+ 
+ SRC_URI = "file://helloworld.c"
+ 
+@@ -16,4 +16,4 @@ do_install() {
+ 	install -m 0755 helloworld ${D}${bindir}
+ }
+ 
+-BBCLASSEXTEND = "native nativesdk"
+\ No newline at end of file
++BBCLASSEXTEND = "native nativesdk"
+-- 
+2.41.0
+
diff --git a/poky/meta/lib/patchtest/selftest/files/LicFilesChkSum.test_lic_files_chksum_modified_not_mentioned.pass b/poky/meta/lib/patchtest/selftest/files/LicFilesChkSum.test_lic_files_chksum_modified_not_mentioned.pass
new file mode 100644
index 0000000..99d9f14
--- /dev/null
+++ b/poky/meta/lib/patchtest/selftest/files/LicFilesChkSum.test_lic_files_chksum_modified_not_mentioned.pass
@@ -0,0 +1,39 @@
+From f89919ea86d38404dd621521680a0162367bb965 Mon Sep 17 00:00:00 2001
+From: Trevor Gamblin <tgamblin@baylibre.com>
+Date: Wed, 6 Sep 2023 09:09:27 -0400
+Subject: [PATCH] selftest-hello: update LIC_FILES_CHKSUM
+
+License-Update: Fix checksum
+
+This test should pass the
+test_metadata_lic_files_chksum.LicFilesChkSum.test_lic_files_chksum_modified_not_mentioned
+test.
+
+Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
+---
+ .../recipes-test/selftest-hello/selftest-hello_1.0.bb         | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
+index 547587bef4..65dda40aba 100644
+--- a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
++++ b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
+@@ -1,7 +1,7 @@
+ DESCRIPTION = "Simple helloworld application -- selftest variant"
+ SECTION = "examples"
+ LICENSE = "MIT"
+-LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
++LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f303"
+ 
+ SRC_URI = "file://helloworld.c"
+ 
+@@ -16,4 +16,4 @@ do_install() {
+ 	install -m 0755 helloworld ${D}${bindir}
+ }
+ 
+-BBCLASSEXTEND = "native nativesdk"
+\ No newline at end of file
++BBCLASSEXTEND = "native nativesdk"
+-- 
+2.41.0
+
diff --git a/poky/meta/lib/patchtest/selftest/files/LicFilesChkSum.test_lic_files_chksum_presence.fail b/poky/meta/lib/patchtest/selftest/files/LicFilesChkSum.test_lic_files_chksum_presence.fail
new file mode 100644
index 0000000..e14d644
--- /dev/null
+++ b/poky/meta/lib/patchtest/selftest/files/LicFilesChkSum.test_lic_files_chksum_presence.fail
@@ -0,0 +1,53 @@
+From 66430e7c6fbd5187b66560909a510e136fed91c0 Mon Sep 17 00:00:00 2001
+From: Daniela Plascencia <daniela.plascencia@linux.intel.com>
+Date: Thu, 23 Feb 2017 10:34:27 -0600
+Subject: [PATCH] meta: adding hello-yocto recipe
+
+This is a sample recipe
+
+Signed-off-by: Daniela Plascencia <daniela.plascencia@linux.intel.com>
+---
+ .../hello-world/hello-world/hello_world.c      |  5 +++++
+ .../hello-world/hello-world_1.0.bb             | 18 ++++++++++++++++++
+ 2 files changed, 23 insertions(+)
+ create mode 100644 meta/recipes-devtools/hello-world/hello-world/hello_world.c
+ create mode 100644 meta/recipes-devtools/hello-world/hello-world_1.0.bb
+
+diff --git a/meta/recipes-devtools/hello-world/hello-world/hello_world.c b/meta/recipes-devtools/hello-world/hello-world/hello_world.c
+new file mode 100644
+index 0000000000..0d59f57d4c
+--- /dev/null
++++ b/meta/recipes-devtools/hello-world/hello-world/hello_world.c
+@@ -0,0 +1,5 @@
++#include <stdio.h>
++
++int main(){
++    printf("Hello World\n");
++}
+diff --git a/meta/recipes-devtools/hello-world/hello-world_1.0.bb b/meta/recipes-devtools/hello-world/hello-world_1.0.bb
+new file mode 100644
+index 0000000000..3c990c108a
+--- /dev/null
++++ b/meta/recipes-devtools/hello-world/hello-world_1.0.bb
+@@ -0,0 +1,18 @@
++SUMMARY = "This is a sample summary"
++DESCRIPTION = "This is a sample description"
++HOMEPAGE = "https://sample.com/this-is-a-sample"
++LICENSE = "MIT"
++
++SRC_URI += "file://hello_world.c"
++
++SRC_URI[md5sum] = "4ee21e9dcc9b5b6012c23038734e1632"
++SRC_URI[sha256sum] = "edef2bbde0fbf0d88232782a0eded323f483a0519d6fde9a3b1809056fd35f3e"
++
++do_compile(){
++    ${CC} -o hello_world ../hello_world.c
++}
++
++do_install(){
++    install -d ${D}${bindir}
++    install -m +x hello_world ${D}${bindir}/hello_world
++}
+-- 
+2.41.0
+
diff --git a/poky/meta/lib/patchtest/selftest/files/LicFilesChkSum.test_lic_files_chksum_presence.pass b/poky/meta/lib/patchtest/selftest/files/LicFilesChkSum.test_lic_files_chksum_presence.pass
new file mode 100644
index 0000000..b8da16d
--- /dev/null
+++ b/poky/meta/lib/patchtest/selftest/files/LicFilesChkSum.test_lic_files_chksum_presence.pass
@@ -0,0 +1,54 @@
+From 5144d2ba1aa763312c047dd5f8901368cff79da6 Mon Sep 17 00:00:00 2001
+From: Daniela Plascencia <daniela.plascencia@linux.intel.com>
+Date: Thu, 23 Feb 2017 10:34:27 -0600
+Subject: [PATCH] meta: adding hello-yocto recipe
+
+This is a sample recipe
+
+Signed-off-by: Daniela Plascencia <daniela.plascencia@linux.intel.com>
+---
+ .../hello-world/hello-world/hello_world.c     |  5 +++++
+ .../hello-world/hello-world_1.0.bb            | 19 +++++++++++++++++++
+ 2 files changed, 24 insertions(+)
+ create mode 100644 meta/recipes-devtools/hello-world/hello-world/hello_world.c
+ create mode 100644 meta/recipes-devtools/hello-world/hello-world_1.0.bb
+
+diff --git a/meta/recipes-devtools/hello-world/hello-world/hello_world.c b/meta/recipes-devtools/hello-world/hello-world/hello_world.c
+new file mode 100644
+index 0000000000..0d59f57d4c
+--- /dev/null
++++ b/meta/recipes-devtools/hello-world/hello-world/hello_world.c
+@@ -0,0 +1,5 @@
++#include <stdio.h>
++
++int main(){
++    printf("Hello World\n");
++}
+diff --git a/meta/recipes-devtools/hello-world/hello-world_1.0.bb b/meta/recipes-devtools/hello-world/hello-world_1.0.bb
+new file mode 100644
+index 0000000000..44d888c82a
+--- /dev/null
++++ b/meta/recipes-devtools/hello-world/hello-world_1.0.bb
+@@ -0,0 +1,19 @@
++SUMMARY = "This is a sample summary"
++DESCRIPTION = "This is a sample description"
++HOMEPAGE = "https://sample.com/this-is-a-sample"
++LICENSE = "MIT"
++LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
++
++SRC_URI += "file://hello_world.c"
++
++SRC_URI[md5sum] = "4ee21e9dcc9b5b6012c23038734e1632"
++SRC_URI[sha256sum] = "edef2bbde0fbf0d88232782a0eded323f483a0519d6fde9a3b1809056fd35f3e"
++
++do_compile(){
++    ${CC} -o hello_world ../hello_world.c
++}
++
++do_install(){
++    install -d ${D}${bindir}
++    install -m +x hello_world ${D}${bindir}/hello_world
++}
+-- 
+2.41.0
+
diff --git a/poky/meta/lib/patchtest/selftest/files/MboxFormat.test_mbox_format.1.fail b/poky/meta/lib/patchtest/selftest/files/MboxFormat.test_mbox_format.1.fail
new file mode 100644
index 0000000..9cc4aab
--- /dev/null
+++ b/poky/meta/lib/patchtest/selftest/files/MboxFormat.test_mbox_format.1.fail
@@ -0,0 +1,36 @@
+From d12db4cfa913b0e7a4b5bd858d3019acc53ce426 Mon Sep 17 00:00:00 2001
+From: Trevor Gamblin <tgamblin@baylibre.com>
+Date: Wed, 30 Aug 2023 12:15:00 -0400
+Subject: [PATCH] selftest-hello: upgrade 1.0 -> 1.1
+
+This test should fail the mbox formatting test and the merge on head
+test.
+
+Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
+---
+ .../{selftest-hello_1.0.bb => selftest-hello_1.1.bb}           | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+ rename meta-selftest/recipes-test/selftest-hello/{selftest-hello_1.0.bb => selftest-hello_1.1.bb} (88%)
+
+diff --git a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.1.bb
+similarity index 88%
+rename from meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
+rename to meta-selftest/recipes-test/selftest-hello/selftest-hello_1.1.bb
+index 547587bef4..acc388ec2c 100644
+--- a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
++++ b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.1.bb
+@@ -1,3 +1,4 @@
+%+SUMMARY = "Hello!"
+ DESCRIPTION = "Simple helloworld application -- selftest variant"
+ SECTION = "examples"
+ LICENSE = "MIT"
+@@ -16,4 +17,4 @@ do_install() {
+ 	install -m 0755 helloworld ${D}${bindir}
+ }
+ 
+-BBCLASSEXTEND = "native nativesdk"
+\ No newline at end of file
++BBCLASSEXTEND = "native nativesdk"
+-- 
+2.41.0
+
diff --git a/poky/meta/lib/patchtest/selftest/files/MboxFormat.test_mbox_format.2.fail b/poky/meta/lib/patchtest/selftest/files/MboxFormat.test_mbox_format.2.fail
new file mode 100644
index 0000000..eca1c60
--- /dev/null
+++ b/poky/meta/lib/patchtest/selftest/files/MboxFormat.test_mbox_format.2.fail
@@ -0,0 +1,35 @@
+From d12db4cfa913b0e7a4b5bd858d3019acc53ce426 Mon Sep 17 00:00:00 2001
+From: Trevor Gamblin <tgamblin@baylibre.com>
+Date: Wed, 30 Aug 2023 12:15:00 -0400
+Subject: [PATCH] selftest-hello: upgrade 1.0 -> 1.1
+
+This test should fail the merge-on-head and mbox formatting tests.
+
+Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
+---
+ .../{selftest-hello_1.0.bb => selftest-hello_1.1.bb}           | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+ rename meta-selftest/recipes-test/selftest-hello/{selftest-hello_1.0.bb => selftest-hello_1.1.bb} (88%)
+
+diff --git a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.1.bb
+similarity index 88%
+rename from meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
+rename to meta-selftest/recipes-test/selftest-hello/selftest-hello_1.1.bb
+index 547587bef4..acc388ec2c 100644
+--- a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
++++ b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.1.bb
+@@ -1,3 +1,4 @@
+%+SUMMARY = "Hello!"
+ DESCRIPTION = "Simple helloworld application -- selftest variant"
+ SECTION = "examples"
+ LICENSE = "MIT"
+@@ -16,4 +17,4 @@ do_install() {
+ 	install -m 0755 helloworld ${D}${bindir}
+ }
+ 
+-BBCLASSEXTEND = "native nativesdk"
+\ No newline at end of file
++BBCLASSEXTEND = "native nativesdk"
+-- 
+2.41.0
+
diff --git a/poky/meta/lib/patchtest/selftest/files/MboxFormat.test_mbox_format.pass b/poky/meta/lib/patchtest/selftest/files/MboxFormat.test_mbox_format.pass
new file mode 100644
index 0000000..33940ad
--- /dev/null
+++ b/poky/meta/lib/patchtest/selftest/files/MboxFormat.test_mbox_format.pass
@@ -0,0 +1,33 @@
+From d12db4cfa913b0e7a4b5bd858d3019acc53ce426 Mon Sep 17 00:00:00 2001
+From: Trevor Gamblin <tgamblin@baylibre.com>
+Date: Wed, 30 Aug 2023 12:15:00 -0400
+Subject: [PATCH] selftest-hello: upgrade 1.0 -> 1.1
+
+Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
+---
+ .../{selftest-hello_1.0.bb => selftest-hello_1.1.bb}           | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+ rename meta-selftest/recipes-test/selftest-hello/{selftest-hello_1.0.bb => selftest-hello_1.1.bb} (88%)
+
+diff --git a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.1.bb
+similarity index 88%
+rename from meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
+rename to meta-selftest/recipes-test/selftest-hello/selftest-hello_1.1.bb
+index 547587bef4..acc388ec2c 100644
+--- a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
++++ b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.1.bb
+@@ -1,3 +1,4 @@
++SUMMARY = "Hello!"
+ DESCRIPTION = "Simple helloworld application -- selftest variant"
+ SECTION = "examples"
+ LICENSE = "MIT"
+@@ -16,4 +17,4 @@ do_install() {
+ 	install -m 0755 helloworld ${D}${bindir}
+ }
+ 
+-BBCLASSEXTEND = "native nativesdk"
+\ No newline at end of file
++BBCLASSEXTEND = "native nativesdk"
+-- 
+2.41.0
+
diff --git a/poky/meta/lib/patchtest/selftest/files/Merge.test_series_merge_on_head.fail b/poky/meta/lib/patchtest/selftest/files/Merge.test_series_merge_on_head.fail
new file mode 100644
index 0000000..49bd1f8
--- /dev/null
+++ b/poky/meta/lib/patchtest/selftest/files/Merge.test_series_merge_on_head.fail
@@ -0,0 +1,41 @@
+From 55208224f492af0ad929555ffc9b95ff1d301c5f Mon Sep 17 00:00:00 2001
+From: Trevor Gamblin <tgamblin@baylibre.com>
+Date: Thu, 17 Aug 2023 15:02:38 -0400
+Subject: [PATCH] python3-dtc: upgrade 1.6.1 -> 1.7.0
+
+Changelog: https://kernel.googlesource.com/pub/scm/utils/dtc/dtc/+log/039a99414e778332d8f9c04cbd3072e1dcc62798
+
+Remove custom PV from the recipe since the relevant functionality is in
+1.7.0:
+
+[tgamblin@megalith dtc]$ git tag --contains c001fc01a43e7a06447c06ea3d50bd60641322b8
+v1.7.0
+
+Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
+Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
+---
+ .../python/{python3-dtc_1.6.1.bb => python3-dtc_1.7.0.bb}      | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+ rename meta/recipes-devtools/python/{python3-dtc_1.6.1.bb => python3-dtc_1.7.0.bb} (92%)
+
+diff --git a/meta/recipes-devtools/python/python3-dtc_1.6.1.bb b/meta/recipes-devtools/python/python3-dtc_1.7.0.bb
+similarity index 92%
+rename from meta/recipes-devtools/python/python3-dtc_1.6.1.bb
+rename to meta/recipes-devtools/python/python3-dtc_1.7.0.bb
+index 95ab0be474..85e48d4694 100644
+--- a/meta/recipes-devtools/python/python3-dtc_1.6.1.bb
++++ b/meta/recipes-devtools/python/python3-dtc_1.7.0.bb
+@@ -14,9 +14,8 @@ UPSTREAM_CHECK_GITTAGREGEX = "v(?P<pver>\d+(\.\d+)+)"
+ 
+ LIC_FILES_CHKSUM = "file://pylibfdt/libfdt.i;beginline=1;endline=6;md5=afda088c974174a29108c8d80b5dce90"
+ 
+-SRCREV = "c001fc01a43e7a06447c06ea3d50bd60641322b8"
++SRCREV = "039a99414e778332d8f9c04cbd3072e1dcc62798"
+ 
+-PV = "1.6.1+git"
+ S = "${WORKDIR}/git"
+ 
+ PYPA_WHEEL = "${S}/dist/libfdt-1.6.2*.whl"
+-- 
+2.41.0
+
diff --git a/poky/meta/lib/patchtest/selftest/files/Merge.test_series_merge_on_head.pass b/poky/meta/lib/patchtest/selftest/files/Merge.test_series_merge_on_head.pass
new file mode 100644
index 0000000..2a72457
--- /dev/null
+++ b/poky/meta/lib/patchtest/selftest/files/Merge.test_series_merge_on_head.pass
@@ -0,0 +1,35 @@
+From d12db4cfa913b0e7a4b5bd858d3019acc53ce426 Mon Sep 17 00:00:00 2001
+From: Trevor Gamblin <tgamblin@baylibre.com>
+Date: Wed, 30 Aug 2023 12:15:00 -0400
+Subject: [PATCH] selftest-hello: upgrade 1.0 -> 1.1
+
+This file should pass the test_series_merge_on_head test.
+
+Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
+---
+ .../{selftest-hello_1.0.bb => selftest-hello_1.1.bb}           | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+ rename meta-selftest/recipes-test/selftest-hello/{selftest-hello_1.0.bb => selftest-hello_1.1.bb} (88%)
+
+diff --git a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.1.bb
+similarity index 88%
+rename from meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
+rename to meta-selftest/recipes-test/selftest-hello/selftest-hello_1.1.bb
+index 547587bef4..acc388ec2c 100644
+--- a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
++++ b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.1.bb
+@@ -1,3 +1,4 @@
++SUMMARY = "Hello!"
+ DESCRIPTION = "Simple helloworld application -- selftest variant"
+ SECTION = "examples"
+ LICENSE = "MIT"
+@@ -16,4 +17,4 @@ do_install() {
+ 	install -m 0755 helloworld ${D}${bindir}
+ }
+ 
+-BBCLASSEXTEND = "native nativesdk"
+\ No newline at end of file
++BBCLASSEXTEND = "native nativesdk"
+-- 
+2.41.0
+
diff --git a/poky/meta/lib/patchtest/selftest/files/PatchSignedOffBy.test_signed_off_by_presence.fail b/poky/meta/lib/patchtest/selftest/files/PatchSignedOffBy.test_signed_off_by_presence.fail
new file mode 100644
index 0000000..ce8bf7b
--- /dev/null
+++ b/poky/meta/lib/patchtest/selftest/files/PatchSignedOffBy.test_signed_off_by_presence.fail
@@ -0,0 +1,71 @@
+From 5a2d0ac780a0f4c046fb1a3c3463d3e726f191cb Mon Sep 17 00:00:00 2001
+From: Trevor Gamblin <tgamblin@baylibre.com>
+Date: Tue, 29 Aug 2023 14:12:27 -0400
+Subject: [PATCH] selftest-hello: fix CVE-1234-56789
+
+CVE: CVE-1234-56789
+
+Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
+---
+ .../selftest-hello/files/CVE-1234-56789.patch | 26 +++++++++++++++++++
+ .../selftest-hello/selftest-hello_1.0.bb      |  6 +++--
+ 2 files changed, 30 insertions(+), 2 deletions(-)
+ create mode 100644 meta-selftest/recipes-test/selftest-hello/files/CVE-1234-56789.patch
+
+diff --git a/meta-selftest/recipes-test/selftest-hello/files/CVE-1234-56789.patch b/meta-selftest/recipes-test/selftest-hello/files/CVE-1234-56789.patch
+new file mode 100644
+index 0000000000..92a5b65a53
+--- /dev/null
++++ b/meta-selftest/recipes-test/selftest-hello/files/CVE-1234-56789.patch
+@@ -0,0 +1,26 @@
++From b26a31186e6ee2eb1f506d5f2f9394d327a0df2f Mon Sep 17 00:00:00 2001
++From: Trevor Gamblin <tgamblin@baylibre.com>
++Date: Tue, 29 Aug 2023 14:08:20 -0400
++Subject: [PATCH] Fix CVE-NOT-REAL
++
++CVE: CVE-1234-56789
++Upstream-Status: Backport(http://example.com/example)
++
++---
++ strlen.c | 1 +
++ 1 file changed, 1 insertion(+)
++
++diff --git a/strlen.c b/strlen.c
++index 1788f38..83d7918 100644
++--- a/strlen.c
+++++ b/strlen.c
++@@ -8,6 +8,7 @@ int main() {
++ 
++ 	printf("%d\n", str_len(string1));
++ 	printf("%d\n", str_len(string2));
+++	printf("CVE FIXED!!!\n");
++ 
++ 	return 0;
++ }
++-- 
++2.41.0
+diff --git a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
+index 547587bef4..76975a6729 100644
+--- a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
++++ b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
+@@ -3,7 +3,9 @@ SECTION = "examples"
+ LICENSE = "MIT"
+ LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
+ 
+-SRC_URI = "file://helloworld.c"
++SRC_URI = "file://helloworld.c \
++           file://CVE-1234-56789.patch \
++           "
+ 
+ S = "${WORKDIR}"
+ 
+@@ -16,4 +18,4 @@ do_install() {
+ 	install -m 0755 helloworld ${D}${bindir}
+ }
+ 
+-BBCLASSEXTEND = "native nativesdk"
+\ No newline at end of file
++BBCLASSEXTEND = "native nativesdk"
+-- 
+2.41.0
+
diff --git a/poky/meta/lib/patchtest/selftest/files/PatchSignedOffBy.test_signed_off_by_presence.pass b/poky/meta/lib/patchtest/selftest/files/PatchSignedOffBy.test_signed_off_by_presence.pass
new file mode 100644
index 0000000..ea34c76
--- /dev/null
+++ b/poky/meta/lib/patchtest/selftest/files/PatchSignedOffBy.test_signed_off_by_presence.pass
@@ -0,0 +1,72 @@
+From 14d72f6973270f78455a8628143f2cff90e8f41e Mon Sep 17 00:00:00 2001
+From: Trevor Gamblin <tgamblin@baylibre.com>
+Date: Tue, 29 Aug 2023 14:12:27 -0400
+Subject: [PATCH] selftest-hello: fix CVE-1234-56789
+
+CVE: CVE-1234-56789
+
+Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
+---
+ .../selftest-hello/files/CVE-1234-56789.patch | 27 +++++++++++++++++++
+ .../selftest-hello/selftest-hello_1.0.bb      |  6 +++--
+ 2 files changed, 31 insertions(+), 2 deletions(-)
+ create mode 100644 meta-selftest/recipes-test/selftest-hello/files/CVE-1234-56789.patch
+
+diff --git a/meta-selftest/recipes-test/selftest-hello/files/CVE-1234-56789.patch b/meta-selftest/recipes-test/selftest-hello/files/CVE-1234-56789.patch
+new file mode 100644
+index 0000000000..869cfb6fe5
+--- /dev/null
++++ b/meta-selftest/recipes-test/selftest-hello/files/CVE-1234-56789.patch
+@@ -0,0 +1,27 @@
++From b26a31186e6ee2eb1f506d5f2f9394d327a0df2f Mon Sep 17 00:00:00 2001
++From: Trevor Gamblin <tgamblin@baylibre.com>
++Date: Tue, 29 Aug 2023 14:08:20 -0400
++Subject: [PATCH] Fix CVE-NOT-REAL
++
++CVE: CVE-1234-56789
++Upstream-Status: Backport(http://example.com/example)
++
++Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
++---
++ strlen.c | 1 +
++ 1 file changed, 1 insertion(+)
++
++diff --git a/strlen.c b/strlen.c
++index 1788f38..83d7918 100644
++--- a/strlen.c
+++++ b/strlen.c
++@@ -8,6 +8,7 @@ int main() {
++ 
++ 	printf("%d\n", str_len(string1));
++ 	printf("%d\n", str_len(string2));
+++	printf("CVE FIXED!!!\n");
++ 
++ 	return 0;
++ }
++-- 
++2.41.0
+diff --git a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
+index 547587bef4..76975a6729 100644
+--- a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
++++ b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
+@@ -3,7 +3,9 @@ SECTION = "examples"
+ LICENSE = "MIT"
+ LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
+ 
+-SRC_URI = "file://helloworld.c"
++SRC_URI = "file://helloworld.c \
++           file://CVE-1234-56789.patch \
++           "
+ 
+ S = "${WORKDIR}"
+ 
+@@ -16,4 +18,4 @@ do_install() {
+ 	install -m 0755 helloworld ${D}${bindir}
+ }
+ 
+-BBCLASSEXTEND = "native nativesdk"
+\ No newline at end of file
++BBCLASSEXTEND = "native nativesdk"
+-- 
+2.41.0
+
diff --git a/poky/meta/lib/patchtest/selftest/files/Shortlog.test_shortlog_format.fail b/poky/meta/lib/patchtest/selftest/files/Shortlog.test_shortlog_format.fail
new file mode 100644
index 0000000..cdbbc61
--- /dev/null
+++ b/poky/meta/lib/patchtest/selftest/files/Shortlog.test_shortlog_format.fail
@@ -0,0 +1,73 @@
+From 35ccee3cee96fb29514475279248078d88907231 Mon Sep 17 00:00:00 2001
+From: Trevor Gamblin <tgamblin@baylibre.com>
+Date: Tue, 29 Aug 2023 14:12:27 -0400
+Subject: [PATCH] selftest-hello% fix CVE-1234-56789
+
+CVE: CVE-1234-56789
+
+Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
+---
+ .../files/0001-Fix-CVE-1234-56789.patch       | 27 +++++++++++++++++++
+ .../selftest-hello/selftest-hello_1.0.bb      |  6 +++--
+ 2 files changed, 31 insertions(+), 2 deletions(-)
+ create mode 100644 meta-selftest/recipes-test/selftest-hello/files/0001-Fix-CVE-1234-56789.patch
+
+diff --git a/meta-selftest/recipes-test/selftest-hello/files/0001-Fix-CVE-1234-56789.patch b/meta-selftest/recipes-test/selftest-hello/files/0001-Fix-CVE-1234-56789.patch
+new file mode 100644
+index 0000000000..9219b8db62
+--- /dev/null
++++ b/meta-selftest/recipes-test/selftest-hello/files/0001-Fix-CVE-1234-56789.patch
+@@ -0,0 +1,27 @@
++From b26a31186e6ee2eb1f506d5f2f9394d327a0df2f Mon Sep 17 00:00:00 2001
++From: Trevor Gamblin <tgamblin@baylibre.com>
++Date: Tue, 29 Aug 2023 14:08:20 -0400
++Subject: [PATCH] Fix CVE-NOT-REAL
++
++CVE: CVE-1234-56789
++Upstream-Status: Backport(http://example.com/example)
++
++Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
++---
++ strlen.c | 1 +
++ 1 file changed, 1 insertion(+)
++
++diff --git a/strlen.c b/strlen.c
++index 1788f38..83d7918 100644
++--- a/strlen.c
+++++ b/strlen.c
++@@ -8,6 +8,7 @@ int main() {
++ 
++ 	printf("%d\n", str_len(string1));
++ 	printf("%d\n", str_len(string2));
+++	printf("CVE FIXED!!!\n");
++ 
++ 	return 0;
++ }
++-- 
++2.41.0
++
+diff --git a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
+index 547587bef4..76975a6729 100644
+--- a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
++++ b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
+@@ -3,7 +3,9 @@ SECTION = "examples"
+ LICENSE = "MIT"
+ LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
+ 
+-SRC_URI = "file://helloworld.c"
++SRC_URI = "file://helloworld.c \
++           file://CVE-1234-56789.patch \
++           "
+ 
+ S = "${WORKDIR}"
+ 
+@@ -16,4 +18,4 @@ do_install() {
+ 	install -m 0755 helloworld ${D}${bindir}
+ }
+ 
+-BBCLASSEXTEND = "native nativesdk"
+\ No newline at end of file
++BBCLASSEXTEND = "native nativesdk"
+-- 
+2.41.0
+
diff --git a/poky/meta/lib/patchtest/selftest/files/Shortlog.test_shortlog_format.pass b/poky/meta/lib/patchtest/selftest/files/Shortlog.test_shortlog_format.pass
new file mode 100644
index 0000000..ef60170
--- /dev/null
+++ b/poky/meta/lib/patchtest/selftest/files/Shortlog.test_shortlog_format.pass
@@ -0,0 +1,73 @@
+From 35ccee3cee96fb29514475279248078d88907231 Mon Sep 17 00:00:00 2001
+From: Trevor Gamblin <tgamblin@baylibre.com>
+Date: Tue, 29 Aug 2023 14:12:27 -0400
+Subject: [PATCH] selftest-hello: fix CVE-1234-56789
+
+CVE: CVE-1234-56789
+
+Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
+---
+ .../files/0001-Fix-CVE-1234-56789.patch       | 27 +++++++++++++++++++
+ .../selftest-hello/selftest-hello_1.0.bb      |  6 +++--
+ 2 files changed, 31 insertions(+), 2 deletions(-)
+ create mode 100644 meta-selftest/recipes-test/selftest-hello/files/0001-Fix-CVE-1234-56789.patch
+
+diff --git a/meta-selftest/recipes-test/selftest-hello/files/0001-Fix-CVE-1234-56789.patch b/meta-selftest/recipes-test/selftest-hello/files/0001-Fix-CVE-1234-56789.patch
+new file mode 100644
+index 0000000000..9219b8db62
+--- /dev/null
++++ b/meta-selftest/recipes-test/selftest-hello/files/0001-Fix-CVE-1234-56789.patch
+@@ -0,0 +1,27 @@
++From b26a31186e6ee2eb1f506d5f2f9394d327a0df2f Mon Sep 17 00:00:00 2001
++From: Trevor Gamblin <tgamblin@baylibre.com>
++Date: Tue, 29 Aug 2023 14:08:20 -0400
++Subject: [PATCH] Fix CVE-NOT-REAL
++
++CVE: CVE-1234-56789
++Upstream-Status: Backport(http://example.com/example)
++
++Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
++---
++ strlen.c | 1 +
++ 1 file changed, 1 insertion(+)
++
++diff --git a/strlen.c b/strlen.c
++index 1788f38..83d7918 100644
++--- a/strlen.c
+++++ b/strlen.c
++@@ -8,6 +8,7 @@ int main() {
++ 
++ 	printf("%d\n", str_len(string1));
++ 	printf("%d\n", str_len(string2));
+++	printf("CVE FIXED!!!\n");
++ 
++ 	return 0;
++ }
++-- 
++2.41.0
++
+diff --git a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
+index 547587bef4..76975a6729 100644
+--- a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
++++ b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
+@@ -3,7 +3,9 @@ SECTION = "examples"
+ LICENSE = "MIT"
+ LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
+ 
+-SRC_URI = "file://helloworld.c"
++SRC_URI = "file://helloworld.c \
++           file://CVE-1234-56789.patch \
++           "
+ 
+ S = "${WORKDIR}"
+ 
+@@ -16,4 +18,4 @@ do_install() {
+ 	install -m 0755 helloworld ${D}${bindir}
+ }
+ 
+-BBCLASSEXTEND = "native nativesdk"
+\ No newline at end of file
++BBCLASSEXTEND = "native nativesdk"
+-- 
+2.41.0
+
diff --git a/poky/meta/lib/patchtest/selftest/files/Shortlog.test_shortlog_length.fail b/poky/meta/lib/patchtest/selftest/files/Shortlog.test_shortlog_length.fail
new file mode 100644
index 0000000..247b2a8
--- /dev/null
+++ b/poky/meta/lib/patchtest/selftest/files/Shortlog.test_shortlog_length.fail
@@ -0,0 +1,73 @@
+From 35ccee3cee96fb29514475279248078d88907231 Mon Sep 17 00:00:00 2001
+From: Trevor Gamblin <tgamblin@baylibre.com>
+Date: Tue, 29 Aug 2023 14:12:27 -0400
+Subject: [PATCH] selftest-hello: this is a very long commit shortlog with way too many words included in it to pass the test
+
+CVE: CVE-1234-56789
+
+Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
+---
+ .../files/0001-Fix-CVE-1234-56789.patch       | 27 +++++++++++++++++++
+ .../selftest-hello/selftest-hello_1.0.bb      |  6 +++--
+ 2 files changed, 31 insertions(+), 2 deletions(-)
+ create mode 100644 meta-selftest/recipes-test/selftest-hello/files/0001-Fix-CVE-1234-56789.patch
+
+diff --git a/meta-selftest/recipes-test/selftest-hello/files/0001-Fix-CVE-1234-56789.patch b/meta-selftest/recipes-test/selftest-hello/files/0001-Fix-CVE-1234-56789.patch
+new file mode 100644
+index 0000000000..9219b8db62
+--- /dev/null
++++ b/meta-selftest/recipes-test/selftest-hello/files/0001-Fix-CVE-1234-56789.patch
+@@ -0,0 +1,27 @@
++From b26a31186e6ee2eb1f506d5f2f9394d327a0df2f Mon Sep 17 00:00:00 2001
++From: Trevor Gamblin <tgamblin@baylibre.com>
++Date: Tue, 29 Aug 2023 14:08:20 -0400
++Subject: [PATCH] Fix CVE-NOT-REAL
++
++CVE: CVE-1234-56789
++Upstream-Status: Backport(http://example.com/example)
++
++Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
++---
++ strlen.c | 1 +
++ 1 file changed, 1 insertion(+)
++
++diff --git a/strlen.c b/strlen.c
++index 1788f38..83d7918 100644
++--- a/strlen.c
+++++ b/strlen.c
++@@ -8,6 +8,7 @@ int main() {
++ 
++ 	printf("%d\n", str_len(string1));
++ 	printf("%d\n", str_len(string2));
+++	printf("CVE FIXED!!!\n");
++ 
++ 	return 0;
++ }
++-- 
++2.41.0
++
+diff --git a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
+index 547587bef4..76975a6729 100644
+--- a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
++++ b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
+@@ -3,7 +3,9 @@ SECTION = "examples"
+ LICENSE = "MIT"
+ LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
+ 
+-SRC_URI = "file://helloworld.c"
++SRC_URI = "file://helloworld.c \
++           file://CVE-1234-56789.patch \
++           "
+ 
+ S = "${WORKDIR}"
+ 
+@@ -16,4 +18,4 @@ do_install() {
+ 	install -m 0755 helloworld ${D}${bindir}
+ }
+ 
+-BBCLASSEXTEND = "native nativesdk"
+\ No newline at end of file
++BBCLASSEXTEND = "native nativesdk"
+-- 
+2.41.0
+
diff --git a/poky/meta/lib/patchtest/selftest/files/Shortlog.test_shortlog_length.pass b/poky/meta/lib/patchtest/selftest/files/Shortlog.test_shortlog_length.pass
new file mode 100644
index 0000000..ef60170
--- /dev/null
+++ b/poky/meta/lib/patchtest/selftest/files/Shortlog.test_shortlog_length.pass
@@ -0,0 +1,73 @@
+From 35ccee3cee96fb29514475279248078d88907231 Mon Sep 17 00:00:00 2001
+From: Trevor Gamblin <tgamblin@baylibre.com>
+Date: Tue, 29 Aug 2023 14:12:27 -0400
+Subject: [PATCH] selftest-hello: fix CVE-1234-56789
+
+CVE: CVE-1234-56789
+
+Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
+---
+ .../files/0001-Fix-CVE-1234-56789.patch       | 27 +++++++++++++++++++
+ .../selftest-hello/selftest-hello_1.0.bb      |  6 +++--
+ 2 files changed, 31 insertions(+), 2 deletions(-)
+ create mode 100644 meta-selftest/recipes-test/selftest-hello/files/0001-Fix-CVE-1234-56789.patch
+
+diff --git a/meta-selftest/recipes-test/selftest-hello/files/0001-Fix-CVE-1234-56789.patch b/meta-selftest/recipes-test/selftest-hello/files/0001-Fix-CVE-1234-56789.patch
+new file mode 100644
+index 0000000000..9219b8db62
+--- /dev/null
++++ b/meta-selftest/recipes-test/selftest-hello/files/0001-Fix-CVE-1234-56789.patch
+@@ -0,0 +1,27 @@
++From b26a31186e6ee2eb1f506d5f2f9394d327a0df2f Mon Sep 17 00:00:00 2001
++From: Trevor Gamblin <tgamblin@baylibre.com>
++Date: Tue, 29 Aug 2023 14:08:20 -0400
++Subject: [PATCH] Fix CVE-NOT-REAL
++
++CVE: CVE-1234-56789
++Upstream-Status: Backport(http://example.com/example)
++
++Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
++---
++ strlen.c | 1 +
++ 1 file changed, 1 insertion(+)
++
++diff --git a/strlen.c b/strlen.c
++index 1788f38..83d7918 100644
++--- a/strlen.c
+++++ b/strlen.c
++@@ -8,6 +8,7 @@ int main() {
++ 
++ 	printf("%d\n", str_len(string1));
++ 	printf("%d\n", str_len(string2));
+++	printf("CVE FIXED!!!\n");
++ 
++ 	return 0;
++ }
++-- 
++2.41.0
++
+diff --git a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
+index 547587bef4..76975a6729 100644
+--- a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
++++ b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
+@@ -3,7 +3,9 @@ SECTION = "examples"
+ LICENSE = "MIT"
+ LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
+ 
+-SRC_URI = "file://helloworld.c"
++SRC_URI = "file://helloworld.c \
++           file://CVE-1234-56789.patch \
++           "
+ 
+ S = "${WORKDIR}"
+ 
+@@ -16,4 +18,4 @@ do_install() {
+ 	install -m 0755 helloworld ${D}${bindir}
+ }
+ 
+-BBCLASSEXTEND = "native nativesdk"
+\ No newline at end of file
++BBCLASSEXTEND = "native nativesdk"
+-- 
+2.41.0
+
diff --git a/poky/meta/lib/patchtest/selftest/files/SignedOffBy.test_signed_off_by_presence.1.fail b/poky/meta/lib/patchtest/selftest/files/SignedOffBy.test_signed_off_by_presence.1.fail
new file mode 100644
index 0000000..35d92ae
--- /dev/null
+++ b/poky/meta/lib/patchtest/selftest/files/SignedOffBy.test_signed_off_by_presence.1.fail
@@ -0,0 +1,71 @@
+From 14d72f6973270f78455a8628143f2cff90e8f41e Mon Sep 17 00:00:00 2001
+From: Trevor Gamblin <tgamblin@baylibre.com>
+Date: Tue, 29 Aug 2023 14:12:27 -0400
+Subject: [PATCH] selftest-hello: fix CVE-1234-56789
+
+CVE: CVE-1234-56789
+
+---
+ .../selftest-hello/files/CVE-1234-56789.patch | 27 +++++++++++++++++++
+ .../selftest-hello/selftest-hello_1.0.bb      |  6 +++--
+ 2 files changed, 31 insertions(+), 2 deletions(-)
+ create mode 100644 meta-selftest/recipes-test/selftest-hello/files/CVE-1234-56789.patch
+
+diff --git a/meta-selftest/recipes-test/selftest-hello/files/CVE-1234-56789.patch b/meta-selftest/recipes-test/selftest-hello/files/CVE-1234-56789.patch
+new file mode 100644
+index 0000000000..869cfb6fe5
+--- /dev/null
++++ b/meta-selftest/recipes-test/selftest-hello/files/CVE-1234-56789.patch
+@@ -0,0 +1,27 @@
++From b26a31186e6ee2eb1f506d5f2f9394d327a0df2f Mon Sep 17 00:00:00 2001
++From: Trevor Gamblin <tgamblin@baylibre.com>
++Date: Tue, 29 Aug 2023 14:08:20 -0400
++Subject: [PATCH] Fix CVE-NOT-REAL
++
++CVE: CVE-1234-56789
++Upstream-Status: Backport(http://example.com/example)
++
++Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
++---
++ strlen.c | 1 +
++ 1 file changed, 1 insertion(+)
++
++diff --git a/strlen.c b/strlen.c
++index 1788f38..83d7918 100644
++--- a/strlen.c
+++++ b/strlen.c
++@@ -8,6 +8,7 @@ int main() {
++ 
++ 	printf("%d\n", str_len(string1));
++ 	printf("%d\n", str_len(string2));
+++	printf("CVE FIXED!!!\n");
++ 
++ 	return 0;
++ }
++-- 
++2.41.0
+diff --git a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
+index 547587bef4..76975a6729 100644
+--- a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
++++ b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
+@@ -3,7 +3,9 @@ SECTION = "examples"
+ LICENSE = "MIT"
+ LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
+ 
+-SRC_URI = "file://helloworld.c"
++SRC_URI = "file://helloworld.c \
++           file://CVE-1234-56789.patch \
++           "
+ 
+ S = "${WORKDIR}"
+ 
+@@ -16,4 +18,4 @@ do_install() {
+ 	install -m 0755 helloworld ${D}${bindir}
+ }
+ 
+-BBCLASSEXTEND = "native nativesdk"
+\ No newline at end of file
++BBCLASSEXTEND = "native nativesdk"
+-- 
+2.41.0
+
diff --git a/poky/meta/lib/patchtest/selftest/files/SignedOffBy.test_signed_off_by_presence.2.fail b/poky/meta/lib/patchtest/selftest/files/SignedOffBy.test_signed_off_by_presence.2.fail
new file mode 100644
index 0000000..68f38de
--- /dev/null
+++ b/poky/meta/lib/patchtest/selftest/files/SignedOffBy.test_signed_off_by_presence.2.fail
@@ -0,0 +1,72 @@
+From 14d72f6973270f78455a8628143f2cff90e8f41e Mon Sep 17 00:00:00 2001
+From: Trevor Gamblin <tgamblin@baylibre.com>
+Date: Tue, 29 Aug 2023 14:12:27 -0400
+Subject: [PATCH] selftest-hello: fix CVE-1234-56789
+
+CVE: CVE-1234-56789
+
+Approved: Trevor Gamblin <tgamblin@baylibre.com>
+---
+ .../selftest-hello/files/CVE-1234-56789.patch | 27 +++++++++++++++++++
+ .../selftest-hello/selftest-hello_1.0.bb      |  6 +++--
+ 2 files changed, 31 insertions(+), 2 deletions(-)
+ create mode 100644 meta-selftest/recipes-test/selftest-hello/files/CVE-1234-56789.patch
+
+diff --git a/meta-selftest/recipes-test/selftest-hello/files/CVE-1234-56789.patch b/meta-selftest/recipes-test/selftest-hello/files/CVE-1234-56789.patch
+new file mode 100644
+index 0000000000..869cfb6fe5
+--- /dev/null
++++ b/meta-selftest/recipes-test/selftest-hello/files/CVE-1234-56789.patch
+@@ -0,0 +1,27 @@
++From b26a31186e6ee2eb1f506d5f2f9394d327a0df2f Mon Sep 17 00:00:00 2001
++From: Trevor Gamblin <tgamblin@baylibre.com>
++Date: Tue, 29 Aug 2023 14:08:20 -0400
++Subject: [PATCH] Fix CVE-NOT-REAL
++
++CVE: CVE-1234-56789
++Upstream-Status: Backport(http://example.com/example)
++
++Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
++---
++ strlen.c | 1 +
++ 1 file changed, 1 insertion(+)
++
++diff --git a/strlen.c b/strlen.c
++index 1788f38..83d7918 100644
++--- a/strlen.c
+++++ b/strlen.c
++@@ -8,6 +8,7 @@ int main() {
++ 
++ 	printf("%d\n", str_len(string1));
++ 	printf("%d\n", str_len(string2));
+++	printf("CVE FIXED!!!\n");
++ 
++ 	return 0;
++ }
++-- 
++2.41.0
+diff --git a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
+index 547587bef4..76975a6729 100644
+--- a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
++++ b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
+@@ -3,7 +3,9 @@ SECTION = "examples"
+ LICENSE = "MIT"
+ LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
+ 
+-SRC_URI = "file://helloworld.c"
++SRC_URI = "file://helloworld.c \
++           file://CVE-1234-56789.patch \
++           "
+ 
+ S = "${WORKDIR}"
+ 
+@@ -16,4 +18,4 @@ do_install() {
+ 	install -m 0755 helloworld ${D}${bindir}
+ }
+ 
+-BBCLASSEXTEND = "native nativesdk"
+\ No newline at end of file
++BBCLASSEXTEND = "native nativesdk"
+-- 
+2.41.0
+
diff --git a/poky/meta/lib/patchtest/selftest/files/SignedOffBy.test_signed_off_by_presence.pass b/poky/meta/lib/patchtest/selftest/files/SignedOffBy.test_signed_off_by_presence.pass
new file mode 100644
index 0000000..ea34c76
--- /dev/null
+++ b/poky/meta/lib/patchtest/selftest/files/SignedOffBy.test_signed_off_by_presence.pass
@@ -0,0 +1,72 @@
+From 14d72f6973270f78455a8628143f2cff90e8f41e Mon Sep 17 00:00:00 2001
+From: Trevor Gamblin <tgamblin@baylibre.com>
+Date: Tue, 29 Aug 2023 14:12:27 -0400
+Subject: [PATCH] selftest-hello: fix CVE-1234-56789
+
+CVE: CVE-1234-56789
+
+Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
+---
+ .../selftest-hello/files/CVE-1234-56789.patch | 27 +++++++++++++++++++
+ .../selftest-hello/selftest-hello_1.0.bb      |  6 +++--
+ 2 files changed, 31 insertions(+), 2 deletions(-)
+ create mode 100644 meta-selftest/recipes-test/selftest-hello/files/CVE-1234-56789.patch
+
+diff --git a/meta-selftest/recipes-test/selftest-hello/files/CVE-1234-56789.patch b/meta-selftest/recipes-test/selftest-hello/files/CVE-1234-56789.patch
+new file mode 100644
+index 0000000000..869cfb6fe5
+--- /dev/null
++++ b/meta-selftest/recipes-test/selftest-hello/files/CVE-1234-56789.patch
+@@ -0,0 +1,27 @@
++From b26a31186e6ee2eb1f506d5f2f9394d327a0df2f Mon Sep 17 00:00:00 2001
++From: Trevor Gamblin <tgamblin@baylibre.com>
++Date: Tue, 29 Aug 2023 14:08:20 -0400
++Subject: [PATCH] Fix CVE-NOT-REAL
++
++CVE: CVE-1234-56789
++Upstream-Status: Backport(http://example.com/example)
++
++Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
++---
++ strlen.c | 1 +
++ 1 file changed, 1 insertion(+)
++
++diff --git a/strlen.c b/strlen.c
++index 1788f38..83d7918 100644
++--- a/strlen.c
+++++ b/strlen.c
++@@ -8,6 +8,7 @@ int main() {
++ 
++ 	printf("%d\n", str_len(string1));
++ 	printf("%d\n", str_len(string2));
+++	printf("CVE FIXED!!!\n");
++ 
++ 	return 0;
++ }
++-- 
++2.41.0
+diff --git a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
+index 547587bef4..76975a6729 100644
+--- a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
++++ b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
+@@ -3,7 +3,9 @@ SECTION = "examples"
+ LICENSE = "MIT"
+ LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
+ 
+-SRC_URI = "file://helloworld.c"
++SRC_URI = "file://helloworld.c \
++           file://CVE-1234-56789.patch \
++           "
+ 
+ S = "${WORKDIR}"
+ 
+@@ -16,4 +18,4 @@ do_install() {
+ 	install -m 0755 helloworld ${D}${bindir}
+ }
+ 
+-BBCLASSEXTEND = "native nativesdk"
+\ No newline at end of file
++BBCLASSEXTEND = "native nativesdk"
+-- 
+2.41.0
+
diff --git a/poky/meta/lib/patchtest/selftest/files/SrcUri.test_src_uri_left_files.fail b/poky/meta/lib/patchtest/selftest/files/SrcUri.test_src_uri_left_files.fail
new file mode 100644
index 0000000..983b6e0
--- /dev/null
+++ b/poky/meta/lib/patchtest/selftest/files/SrcUri.test_src_uri_left_files.fail
@@ -0,0 +1,35 @@
+From 4ab06b5f81455249cd5e89d2cce9863803b5ecb5 Mon Sep 17 00:00:00 2001
+From: Trevor Gamblin <tgamblin@baylibre.com>
+Date: Fri, 8 Sep 2023 14:41:00 -0400
+Subject: [PATCH] selftest-hello: remove helloworld.c
+
+This should fail the test_src_uri_left_files selftest.
+
+Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
+---
+ .../recipes-test/selftest-hello/selftest-hello_1.0.bb         | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+diff --git a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
+index 547587bef4..f6817f05bc 100644
+--- a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
++++ b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
+@@ -3,8 +3,6 @@ SECTION = "examples"
+ LICENSE = "MIT"
+ LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
+ 
+-SRC_URI = "file://helloworld.c"
+-
+ S = "${WORKDIR}"
+ 
+ do_compile() {
+@@ -16,4 +14,4 @@ do_install() {
+ 	install -m 0755 helloworld ${D}${bindir}
+ }
+ 
+-BBCLASSEXTEND = "native nativesdk"
+\ No newline at end of file
++BBCLASSEXTEND = "native nativesdk"
+-- 
+2.41.0
+
diff --git a/poky/meta/lib/patchtest/selftest/files/SrcUri.test_src_uri_left_files.pass b/poky/meta/lib/patchtest/selftest/files/SrcUri.test_src_uri_left_files.pass
new file mode 100644
index 0000000..1f1a77e
--- /dev/null
+++ b/poky/meta/lib/patchtest/selftest/files/SrcUri.test_src_uri_left_files.pass
@@ -0,0 +1,51 @@
+From 6c7ac367a873bf827c19b81085c943eace917a99 Mon Sep 17 00:00:00 2001
+From: Trevor Gamblin <tgamblin@baylibre.com>
+Date: Fri, 8 Sep 2023 14:41:00 -0400
+Subject: [PATCH] selftest-hello: remove helloworld.c
+
+This should pass the test_src_uri_left_files selftest.
+
+Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
+---
+ .../recipes-test/selftest-hello/files/helloworld.c        | 8 --------
+ .../recipes-test/selftest-hello/selftest-hello_1.0.bb     | 4 +---
+ 2 files changed, 1 insertion(+), 11 deletions(-)
+ delete mode 100644 meta-selftest/recipes-test/selftest-hello/files/helloworld.c
+
+diff --git a/meta-selftest/recipes-test/selftest-hello/files/helloworld.c b/meta-selftest/recipes-test/selftest-hello/files/helloworld.c
+deleted file mode 100644
+index fc7169b7b8..0000000000
+--- a/meta-selftest/recipes-test/selftest-hello/files/helloworld.c
++++ /dev/null
+@@ -1,8 +0,0 @@
+-#include <stdio.h>
+-
+-int main(void)
+-{
+-	printf("Hello world!\n");
+-
+-	return 0;
+-}
+diff --git a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
+index 547587bef4..f6817f05bc 100644
+--- a/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
++++ b/meta-selftest/recipes-test/selftest-hello/selftest-hello_1.0.bb
+@@ -3,8 +3,6 @@ SECTION = "examples"
+ LICENSE = "MIT"
+ LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
+ 
+-SRC_URI = "file://helloworld.c"
+-
+ S = "${WORKDIR}"
+ 
+ do_compile() {
+@@ -16,4 +14,4 @@ do_install() {
+ 	install -m 0755 helloworld ${D}${bindir}
+ }
+ 
+-BBCLASSEXTEND = "native nativesdk"
+\ No newline at end of file
++BBCLASSEXTEND = "native nativesdk"
+-- 
+2.41.0
+
diff --git a/poky/meta/lib/patchtest/selftest/files/Summary.test_summary_presence.fail b/poky/meta/lib/patchtest/selftest/files/Summary.test_summary_presence.fail
new file mode 100644
index 0000000..2d2b4e6
--- /dev/null
+++ b/poky/meta/lib/patchtest/selftest/files/Summary.test_summary_presence.fail
@@ -0,0 +1,46 @@
+From e29da5faa74409be394caa09d9f3b7b60f8592b9 Mon Sep 17 00:00:00 2001
+From: Daniela Plascencia <daniela.plascencia@linux.intel.com>
+Date: Thu, 23 Feb 2017 10:34:27 -0600
+Subject: [PATCH] meta: adding hello-yocto recipe
+
+This is a sample recipe
+
+Signed-off-by: Daniela Plascencia <daniela.plascencia@linux.intel.com>
+---
+ meta/recipes-devtools/hello-world/hello-world/hello_world.c |  5 +++++
+ meta/recipes-devtools/hello-world/hello-world_1.0.bb        | 12 ++++++++++++
+ 2 files changed, 17 insertions(+)
+ create mode 100644 meta/recipes-devtools/hello-world/hello-world/hello_world.c
+ create mode 100644 meta/recipes-devtools/hello-world/hello-world_1.0.bb
+
+diff --git a/meta/recipes-devtools/hello-world/hello-world/hello_world.c b/meta/recipes-devtools/hello-world/hello-world/hello_world.c
+new file mode 100644
+index 0000000000..0d59f57d4c
+--- /dev/null
++++ b/meta/recipes-devtools/hello-world/hello-world/hello_world.c
+@@ -0,0 +1,5 @@
++#include <stdio.h>
++
++int main(){
++    printf("Hello World\n");
++}
+diff --git a/meta/recipes-devtools/hello-world/hello-world_1.0.bb b/meta/recipes-devtools/hello-world/hello-world_1.0.bb
+new file mode 100644
+index 0000000000..c4e1359217
+--- /dev/null
++++ b/meta/recipes-devtools/hello-world/hello-world_1.0.bb
+@@ -0,0 +1,12 @@
++LICENSE = "CLOSED"
++
++SRC_URI += "file://hello_world.c"
++
++do_compile(){
++    ${CC} -o hello_world ../hello_world.c
++}
++
++do_install(){
++    install -d ${D}${bindir}
++    install -m +x hello_world ${D}${bindir}/hello_world
++}
+--
+2.11.0
diff --git a/poky/meta/lib/patchtest/selftest/files/Summary.test_summary_presence.pass b/poky/meta/lib/patchtest/selftest/files/Summary.test_summary_presence.pass
new file mode 100644
index 0000000..55f0309
--- /dev/null
+++ b/poky/meta/lib/patchtest/selftest/files/Summary.test_summary_presence.pass
@@ -0,0 +1,49 @@
+From 0cd2fed12ce4b7b071edde12aec4481ad7a6f107 Mon Sep 17 00:00:00 2001
+From: Daniela Plascencia <daniela.plascencia@linux.intel.com>
+Date: Thu, 23 Feb 2017 10:34:27 -0600
+Subject: [PATCH] meta: adding hello-yocto recipe
+
+This is a sample recipe
+
+Signed-off-by: Daniela Plascencia <daniela.plascencia@linux.intel.com>
+---
+ .../hello-world/hello-world/hello_world.c                 |  5 +++++
+ meta/recipes-devtools/hello-world/hello-world_1.0.bb      | 15 +++++++++++++++
+ 2 files changed, 20 insertions(+)
+ create mode 100644 meta/recipes-devtools/hello-world/hello-world/hello_world.c
+ create mode 100644 meta/recipes-devtools/hello-world/hello-world_1.0.bb
+
+diff --git a/meta/recipes-devtools/hello-world/hello-world/hello_world.c b/meta/recipes-devtools/hello-world/hello-world/hello_world.c
+new file mode 100644
+index 0000000000..0d59f57d4c
+--- /dev/null
++++ b/meta/recipes-devtools/hello-world/hello-world/hello_world.c
+@@ -0,0 +1,5 @@
++#include <stdio.h>
++
++int main(){
++    printf("Hello World\n");
++}
+diff --git a/meta/recipes-devtools/hello-world/hello-world_1.0.bb b/meta/recipes-devtools/hello-world/hello-world_1.0.bb
+new file mode 100644
+index 0000000000..c54283eece
+--- /dev/null
++++ b/meta/recipes-devtools/hello-world/hello-world_1.0.bb
+@@ -0,0 +1,15 @@
++SUMMARY = "This is a sample summary"
++DESCRIPTION = "This is a sample description"
++HOMEPAGE = "https://sample.com/this-is-a-sample"
++LICENSE = "CLOSED"
++
++SRC_URI += "file://hello_world.c"
++
++do_compile(){
++    ${CC} -o hello_world ../hello_world.c
++}
++
++do_install(){
++    install -d ${D}${bindir}
++    install -m +x hello_world ${D}${bindir}/hello_world
++}
+--
+2.11.0
diff --git a/poky/meta/lib/patchtest/selftest/selftest b/poky/meta/lib/patchtest/selftest/selftest
new file mode 100755
index 0000000..d2b61e9
--- /dev/null
+++ b/poky/meta/lib/patchtest/selftest/selftest
@@ -0,0 +1,89 @@
+#!/usr/bin/env python3
+
+# Test every patch from files folder and output error on failure
+#
+# Copyright (C) 2016 Intel Corporation
+#
+# SPDX-License-Identifier: GPL-2.0
+
+import os
+import subprocess
+import sys
+
+currentdir = os.path.dirname(os.path.abspath(__file__))
+patchesdir = os.path.join(currentdir, 'files')
+topdir     = os.path.dirname(currentdir)
+parentdir  = os.path.dirname(topdir)
+
+# path to the repo root
+repodir = os.path.dirname(os.path.dirname(parentdir))
+
+def print_results(passcount, skipcount, failcount, xpasscount, xfailcount, errorcount):
+    total = passcount + skipcount + failcount + xpasscount + xfailcount + errorcount
+    print("============================================================================")
+    print("Testsuite summary for %s" % os.path.basename(topdir))
+    print("============================================================================")
+    print("# TOTAL: %s" % str(total))
+    print("# XPASS: %s" % str(xpasscount))
+    print("# XFAIL: %s" % str(xfailcount))
+    print("# PASS: %s" % str(passcount))
+    print("# FAIL: %s" % str(failcount))
+    print("# SKIP: %s" % str(skipcount))
+    print("# ERROR: %s" % str(errorcount))
+    print("============================================================================")
+
+# Once the tests are in oe-core, we can remove the testdir param and use os.path.dirname to get relative paths
+def test(root, patch):
+    res = True
+    patchpath = os.path.abspath(os.path.join(root, patch))
+    
+    cmd     = 'patchtest %s %s/tests --patch %s' % (repodir, topdir, patchpath)
+    results = subprocess.check_output(cmd, stderr=subprocess.STDOUT, universal_newlines=True, shell=True)
+
+    return results
+
+if __name__ == '__main__':
+    passcount = 0
+    failcount = 0
+    skipcount = 0
+    xpasscount = 0
+    xfailcount = 0
+    errorcount = 0
+
+    results = None
+        
+    for root, dirs, patches in os.walk(patchesdir):
+        for patch in patches:
+            results = test(root, patch)
+
+            a = patch.split('.')
+            klass, testname = a[0], a[1]
+            expected_result = a[-1]
+            testid          = ".%s.%s" % (klass,testname)
+
+            for resultline in results.splitlines():
+                if testid in resultline:
+                    result, _ = resultline.split(' ', 1)
+
+                    if expected_result.upper() == "FAIL" and result.upper() == "FAIL":
+                        xfailcount = xfailcount + 1
+                        print("XFAIL: %s (file: %s)" % (testid.strip("."), os.path.basename(patch)))
+                    elif expected_result.upper() == "PASS" and result.upper() == "PASS":
+                        xpasscount = xpasscount + 1
+                        print("XPASS: %s (file: %s)" % (testid.strip("."), os.path.basename(patch)))
+                    else:
+                        print("%s: %s (%s)" % (result.upper(), testid.strip("."), os.path.basename(patch)))
+                        if result.upper() == "PASS":
+                            passcount = passcount + 1
+                        elif result.upper() == "FAIL":
+                            failcount = failcount + 1
+                        elif result.upper() == "SKIP":
+                            skipcount = skipcount + 1
+                        else:
+                            print("Bad result on test %s against %s" % (testid.strip("."), os.path.basename(patch)))
+                            errorcount = errorcount + 1
+                    break
+            else:
+                print ("No test for=%s" % patch)
+
+    print_results(passcount, skipcount, failcount, xpasscount, xfailcount, errorcount)
diff --git a/poky/meta/lib/patchtest/tests/__init__.py b/poky/meta/lib/patchtest/tests/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/poky/meta/lib/patchtest/tests/__init__.py
diff --git a/poky/meta/lib/patchtest/tests/base.py b/poky/meta/lib/patchtest/tests/base.py
new file mode 100644
index 0000000..27db380
--- /dev/null
+++ b/poky/meta/lib/patchtest/tests/base.py
@@ -0,0 +1,239 @@
+# Base class to be used by all test cases defined in the suite
+#
+# Copyright (C) 2016 Intel Corporation
+#
+# SPDX-License-Identifier: GPL-2.0
+
+import unittest
+import logging
+import json
+import unidiff
+from data import PatchTestInput
+import mailbox
+import collections
+import sys
+import os
+import re
+
+sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'pyparsing'))
+
+logger = logging.getLogger('patchtest')
+debug=logger.debug
+info=logger.info
+warn=logger.warn
+error=logger.error
+
+Commit = collections.namedtuple('Commit', ['author', 'subject', 'commit_message', 'shortlog', 'payload'])
+
+class PatchtestOEError(Exception):
+    """Exception for handling patchtest-oe errors"""
+    def __init__(self, message, exitcode=1):
+        super().__init__(message)
+        self.exitcode = exitcode
+
+class Base(unittest.TestCase):
+    # if unit test fails, fail message will throw at least the following JSON: {"id": <testid>}
+
+    endcommit_messages_regex = re.compile('\(From \w+-\w+ rev:|(?<!\S)Signed-off-by|(?<!\S)---\n')
+    patchmetadata_regex   = re.compile('-{3} \S+|\+{3} \S+|@{2} -\d+,\d+ \+\d+,\d+ @{2} \S+')
+
+
+    @staticmethod
+    def msg_to_commit(msg):
+        payload = msg.get_payload()
+        return Commit(subject=msg['subject'].replace('\n', ' ').replace('  ', ' '),
+                      author=msg.get('From'),
+                      shortlog=Base.shortlog(msg['subject']),
+                      commit_message=Base.commit_message(payload),
+                      payload=payload)
+
+    @staticmethod
+    def commit_message(payload):
+        commit_message = payload.__str__()
+        match = Base.endcommit_messages_regex.search(payload)
+        if match:
+            commit_message = payload[:match.start()]
+        return commit_message
+
+    @staticmethod
+    def shortlog(shlog):
+        # remove possible prefix (between brackets) before colon
+        start = shlog.find(']', 0, shlog.find(':'))
+        # remove also newlines and spaces at both sides
+        return shlog[start + 1:].replace('\n', '').strip()
+
+    @classmethod
+    def setUpClass(cls):
+
+        # General objects: mailbox.mbox and patchset
+        cls.mbox = mailbox.mbox(PatchTestInput.repo.patch)
+
+        # Patch may be malformed, so try parsing it
+        cls.unidiff_parse_error = ''
+        cls.patchset = None
+        try:
+            cls.patchset = unidiff.PatchSet.from_filename(PatchTestInput.repo.patch, encoding=u'UTF-8')
+        except unidiff.UnidiffParseError as upe:
+            cls.patchset = []
+            cls.unidiff_parse_error = str(upe)
+
+        # Easy to iterate list of commits
+        cls.commits = []
+        for msg in cls.mbox:
+            if msg['subject'] and msg.get_payload():
+                cls.commits.append(Base.msg_to_commit(msg))
+
+        cls.setUpClassLocal()
+
+    @classmethod
+    def tearDownClass(cls):
+        cls.tearDownClassLocal()
+
+    @classmethod
+    def setUpClassLocal(cls):
+        pass
+
+    @classmethod
+    def tearDownClassLocal(cls):
+        pass
+
+    def fail(self, issue, fix=None, commit=None, data=None):
+        """ Convert to a JSON string failure data"""
+        value = {'id': self.id(),
+                 'issue': issue}
+
+        if fix:
+            value['fix'] = fix
+        if commit:
+            value['commit'] = {'subject': commit.subject,
+                               'shortlog': commit.shortlog}
+
+        # extend return value with other useful info
+        if data:
+            value['data'] = data
+
+        return super(Base, self).fail(json.dumps(value))
+
+    def skip(self, issue, data=None):
+        """ Convert the skip string to JSON"""
+        value = {'id': self.id(),
+                 'issue': issue}
+
+        # extend return value with other useful info
+        if data:
+            value['data'] = data
+
+        return super(Base, self).skipTest(json.dumps(value))
+
+    def shortid(self):
+        return self.id().split('.')[-1]
+
+    def __str__(self):
+        return json.dumps({'id': self.id()})
+
+class Metadata(Base):
+    @classmethod
+    def setUpClassLocal(cls):
+        cls.tinfoil = cls.setup_tinfoil()
+
+        # get info about added/modified/remove recipes
+        cls.added, cls.modified, cls.removed = cls.get_metadata_stats(cls.patchset)
+
+    @classmethod
+    def tearDownClassLocal(cls):
+        cls.tinfoil.shutdown()
+
+    @classmethod
+    def setup_tinfoil(cls, config_only=False):
+        """Initialize tinfoil api from bitbake"""
+
+        # import relevant libraries
+        try:
+            scripts_path = os.path.join(PatchTestInput.repodir, 'scripts', 'lib')
+            if scripts_path not in sys.path:
+                sys.path.insert(0, scripts_path)
+            import scriptpath
+            scriptpath.add_bitbake_lib_path()
+            import bb.tinfoil
+        except ImportError:
+            raise PatchtestOEError('Could not import tinfoil module')
+
+        orig_cwd = os.path.abspath(os.curdir)
+
+        # Load tinfoil
+        tinfoil = None
+        try:
+            builddir = os.environ.get('BUILDDIR')
+            if not builddir:
+                logger.warn('Bitbake environment not loaded?')
+                return tinfoil
+            os.chdir(builddir)
+            tinfoil = bb.tinfoil.Tinfoil()
+            tinfoil.prepare(config_only=config_only)
+        except bb.tinfoil.TinfoilUIException as te:
+            if tinfoil:
+                tinfoil.shutdown()
+            raise PatchtestOEError('Could not prepare properly tinfoil (TinfoilUIException)')
+        except Exception as e:
+            if tinfoil:
+                tinfoil.shutdown()
+            raise e
+        finally:
+            os.chdir(orig_cwd)
+
+        return tinfoil
+
+    @classmethod
+    def get_metadata_stats(cls, patchset):
+        """Get lists of added, modified and removed metadata files"""
+
+        def find_pn(data, path):
+            """Find the PN from data"""
+            pn = None
+            pn_native = None
+            for _path, _pn in data:
+                if path in _path:
+                    if 'native' in _pn:
+                        # store the native PN but look for the non-native one first
+                        pn_native = _pn
+                    else:
+                        pn = _pn
+                        break
+            else:
+                # sent the native PN if found previously
+                if pn_native:
+                    return pn_native
+
+                # on renames (usually upgrades), we need to check (FILE) base names
+                # because the unidiff library does not provided the new filename, just the modified one
+                # and tinfoil datastore, once the patch is merged, will contain the new filename
+                path_basename = path.split('_')[0]
+                for _path, _pn in data:
+                    _path_basename = _path.split('_')[0]
+                    if path_basename == _path_basename:
+                        pn = _pn
+            return pn
+
+        if not cls.tinfoil:
+            cls.tinfoil = cls.setup_tinfoil()
+
+        added_paths, modified_paths, removed_paths = [], [], []
+        added, modified, removed = [], [], []
+
+        # get metadata filename additions, modification and removals
+        for patch in patchset:
+            if patch.path.endswith('.bb') or patch.path.endswith('.bbappend') or patch.path.endswith('.inc'):
+                if patch.is_added_file:
+                    added_paths.append(os.path.join(os.path.abspath(PatchTestInput.repodir), patch.path))
+                elif patch.is_modified_file:
+                    modified_paths.append(os.path.join(os.path.abspath(PatchTestInput.repodir), patch.path))
+                elif patch.is_removed_file:
+                    removed_paths.append(os.path.join(os.path.abspath(PatchTestInput.repodir), patch.path))
+
+        data = cls.tinfoil.cooker.recipecaches[''].pkg_fn.items()
+
+        added = [find_pn(data,path) for path in added_paths]
+        modified = [find_pn(data,path) for path in modified_paths]
+        removed = [find_pn(data,path) for path in removed_paths]
+
+        return [a for a in added if a], [m for m in modified if m], [r for r in removed if r]
diff --git a/poky/meta/lib/patchtest/tests/pyparsing/common.py b/poky/meta/lib/patchtest/tests/pyparsing/common.py
new file mode 100644
index 0000000..9d37b04
--- /dev/null
+++ b/poky/meta/lib/patchtest/tests/pyparsing/common.py
@@ -0,0 +1,26 @@
+# common pyparsing variables
+#
+# Copyright (C) 2016 Intel Corporation
+#
+# SPDX-License-Identifier: GPL-2.0
+
+import pyparsing
+
+# general
+colon = pyparsing.Literal(":")
+start = pyparsing.LineStart()
+end   = pyparsing.LineEnd()
+at = pyparsing.Literal("@")
+lessthan = pyparsing.Literal("<")
+greaterthan = pyparsing.Literal(">")
+opensquare = pyparsing.Literal("[")
+closesquare = pyparsing.Literal("]")
+inappropriate = pyparsing.CaselessLiteral("Inappropriate")
+submitted = pyparsing.CaselessLiteral("Submitted")
+
+# word related
+nestexpr = pyparsing.nestedExpr(opener='[', closer=']')
+inappropriateinfo = pyparsing.Literal("Inappropriate") + nestexpr
+submittedinfo = pyparsing.Literal("Submitted") + nestexpr
+word = pyparsing.Word(pyparsing.alphas)
+worddot = pyparsing.Word(pyparsing.alphas+".")
diff --git a/poky/meta/lib/patchtest/tests/pyparsing/parse_cve_tags.py b/poky/meta/lib/patchtest/tests/pyparsing/parse_cve_tags.py
new file mode 100644
index 0000000..dd7131a
--- /dev/null
+++ b/poky/meta/lib/patchtest/tests/pyparsing/parse_cve_tags.py
@@ -0,0 +1,18 @@
+# signed-off-by pyparsing definition
+#
+# Copyright (C) 2016 Intel Corporation
+#
+# SPDX-License-Identifier: GPL-2.0
+
+
+import pyparsing
+import common
+
+name = pyparsing.Regex('\S+.*(?= <)')
+username = pyparsing.OneOrMore(common.worddot)
+domain = pyparsing.OneOrMore(common.worddot)
+cve = pyparsing.Regex('CVE\-\d{4}\-\d+')
+cve_mark = pyparsing.Literal("CVE:")
+
+cve_tag = pyparsing.AtLineStart(cve_mark + cve)
+patch_cve_tag = pyparsing.AtLineStart("+" + cve_mark + cve)
diff --git a/poky/meta/lib/patchtest/tests/pyparsing/parse_shortlog.py b/poky/meta/lib/patchtest/tests/pyparsing/parse_shortlog.py
new file mode 100644
index 0000000..26e9612
--- /dev/null
+++ b/poky/meta/lib/patchtest/tests/pyparsing/parse_shortlog.py
@@ -0,0 +1,14 @@
+# subject pyparsing definition
+#
+# Copyright (C) 2016 Intel Corporation
+#
+# SPDX-License-Identifier: GPL-2.0
+
+# NOTE:This is an oversimplified syntax of the mbox's summary
+
+import pyparsing
+import common
+
+target        = pyparsing.OneOrMore(pyparsing.Word(pyparsing.printables.replace(':','')))
+summary       = pyparsing.OneOrMore(pyparsing.Word(pyparsing.printables))
+shortlog       = common.start + target + common.colon + summary + common.end
diff --git a/poky/meta/lib/patchtest/tests/pyparsing/parse_signed_off_by.py b/poky/meta/lib/patchtest/tests/pyparsing/parse_signed_off_by.py
new file mode 100644
index 0000000..c8a4351
--- /dev/null
+++ b/poky/meta/lib/patchtest/tests/pyparsing/parse_signed_off_by.py
@@ -0,0 +1,22 @@
+# signed-off-by pyparsing definition
+#
+# Copyright (C) 2016 Intel Corporation
+#
+# SPDX-License-Identifier: GPL-2.0
+
+
+import pyparsing
+import common
+
+name = pyparsing.Regex('\S+.*(?= <)')
+username = pyparsing.OneOrMore(common.worddot)
+domain = pyparsing.OneOrMore(common.worddot)
+
+# taken from https://pyparsing-public.wikispaces.com/Helpful+Expressions
+email = pyparsing.Regex(r"(?P<user>[A-Za-z0-9._%+-]+)@(?P<hostname>[A-Za-z0-9.-]+)\.(?P<domain>[A-Za-z]{2,})")
+
+email_enclosed = common.lessthan + email + common.greaterthan
+
+signed_off_by_mark = pyparsing.Literal("Signed-off-by:")
+signed_off_by = pyparsing.AtLineStart(signed_off_by_mark + name + email_enclosed)
+patch_signed_off_by = pyparsing.AtLineStart("+" + signed_off_by_mark + name + email_enclosed)
diff --git a/poky/meta/lib/patchtest/tests/pyparsing/parse_upstream_status.py b/poky/meta/lib/patchtest/tests/pyparsing/parse_upstream_status.py
new file mode 100644
index 0000000..d63567e
--- /dev/null
+++ b/poky/meta/lib/patchtest/tests/pyparsing/parse_upstream_status.py
@@ -0,0 +1,24 @@
+# upstream-status pyparsing definition
+#
+# Copyright (C) 2016 Intel Corporation
+#
+# SPDX-License-Identifier: GPL-2.0
+
+
+import common
+import pyparsing
+
+upstream_status_literal_valid_status = ["Pending", "Backport", "Denied", "Inappropriate", "Submitted"]
+upstream_status_nonliteral_valid_status = ["Pending", "Backport", "Denied", "Inappropriate [reason]", "Submitted [where]"]
+
+upstream_status_valid_status = pyparsing.Or(
+    [pyparsing.Literal(status) for status in upstream_status_literal_valid_status]
+)
+
+upstream_status_mark         = pyparsing.Literal("Upstream-Status")
+inappropriate_status_mark    = common.inappropriate
+submitted_status_mark        = common.submitted
+
+upstream_status              = common.start + upstream_status_mark + common.colon + upstream_status_valid_status
+upstream_status_inappropriate_info = common.start + upstream_status_mark + common.colon + common.inappropriateinfo
+upstream_status_submitted_info = common.start + upstream_status_mark + common.colon + common.submittedinfo
diff --git a/poky/meta/lib/patchtest/tests/test_mbox_author.py b/poky/meta/lib/patchtest/tests/test_mbox_author.py
new file mode 100644
index 0000000..6c79f16
--- /dev/null
+++ b/poky/meta/lib/patchtest/tests/test_mbox_author.py
@@ -0,0 +1,29 @@
+# Checks related to the patch's author
+#
+# Copyright (C) 2016 Intel Corporation
+#
+# SPDX-License-Identifier: GPL-2.0
+
+import base
+import re
+
+class Author(base.Base):
+
+    auh_email = '<auh@auh.yoctoproject.org>'
+
+    invalids = [re.compile("^Upgrade Helper.+"),
+                re.compile(re.escape(auh_email)),
+                re.compile("uh@not\.set"),
+                re.compile("\S+@example\.com")]
+
+
+    def test_author_valid(self):
+        for commit in self.commits:
+            for invalid in self.invalids:
+                if invalid.search(commit.author):
+                    self.fail('Invalid author %s' % commit.author, 'Resend the series with a valid patch\'s author', commit)
+
+    def test_non_auh_upgrade(self):
+        for commit in self.commits:
+            if self.auh_email in commit.payload:
+                self.fail('Invalid author %s in commit message' % self.auh_email, 'Resend the series with a valid patch\'s author', commit)
diff --git a/poky/meta/lib/patchtest/tests/test_mbox_bugzilla.py b/poky/meta/lib/patchtest/tests/test_mbox_bugzilla.py
new file mode 100644
index 0000000..e8de48b
--- /dev/null
+++ b/poky/meta/lib/patchtest/tests/test_mbox_bugzilla.py
@@ -0,0 +1,22 @@
+# Checks related to the patch's bugzilla tag
+#
+# Copyright (C) 2016 Intel Corporation
+#
+# SPDX-License-Identifier: GPL-2.0
+
+import re
+import base
+
+class Bugzilla(base.Base):
+    rexp_detect     = re.compile("\[\s?YOCTO.*\]", re.IGNORECASE)
+    rexp_validation = re.compile("\[(\s?YOCTO\s?#\s?(\d+)\s?,?)+\]", re.IGNORECASE)
+
+    def test_bugzilla_entry_format(self):
+        for commit in Bugzilla.commits:
+            for line in commit.commit_message.splitlines():
+                if self.rexp_detect.match(line):
+                    if not self.rexp_validation.match(line):
+                        self.fail('Yocto Project bugzilla tag is not correctly formatted',
+                                  'Specify bugzilla ID in commit description with format: "[YOCTO #<bugzilla ID>]"',
+                                  commit)
+
diff --git a/poky/meta/lib/patchtest/tests/test_mbox_cve.py b/poky/meta/lib/patchtest/tests/test_mbox_cve.py
new file mode 100644
index 0000000..f99194c
--- /dev/null
+++ b/poky/meta/lib/patchtest/tests/test_mbox_cve.py
@@ -0,0 +1,49 @@
+# Checks related to the patch's CVE lines
+#
+# Copyright (C) 2016 Intel Corporation
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import base
+import os
+import parse_cve_tags
+import re
+
+class CVE(base.Base):
+
+    revert_shortlog_regex = re.compile('Revert\s+".*"')
+    prog = parse_cve_tags.cve_tag
+
+    def setUp(self):
+        if self.unidiff_parse_error:
+            self.skip('Parse error %s' % self.unidiff_parse_error)
+
+        # we are just interested in series that introduce CVE patches, thus discard other
+        # possibilities: modification to current CVEs, patch directly introduced into the
+        # recipe, upgrades already including the CVE, etc.
+        new_cves = [p for p in self.patchset if p.path.endswith('.patch') and p.is_added_file]
+        if not new_cves:
+            self.skip('No new CVE patches introduced')
+
+    def test_cve_presence_in_commit_message(self):
+        for commit in CVE.commits:
+            # skip those patches that revert older commits, these do not required the tag presence
+            if self.revert_shortlog_regex.match(commit.shortlog):
+                continue
+            if not self.prog.search_string(commit.payload):
+                self.fail('Missing or incorrectly formatted CVE tag in mbox',
+                          'Correct or include the CVE tag in the mbox with format: "CVE: CVE-YYYY-XXXX"',
+                          commit)
diff --git a/poky/meta/lib/patchtest/tests/test_mbox_description.py b/poky/meta/lib/patchtest/tests/test_mbox_description.py
new file mode 100644
index 0000000..7addc6b
--- /dev/null
+++ b/poky/meta/lib/patchtest/tests/test_mbox_description.py
@@ -0,0 +1,17 @@
+# Checks related to the patch's commit_message
+#
+# Copyright (C) 2016 Intel Corporation
+#
+# SPDX-License-Identifier: GPL-2.0
+
+import base
+
+class CommitMessage(base.Base):
+
+    def test_commit_message_presence(self):
+        for commit in CommitMessage.commits:
+            if not commit.commit_message.strip():
+                self.fail('Patch is missing a descriptive commit message',
+                          'Please include a commit message on your patch explaining the change (most importantly why the change is being made)',
+                          commit)
+
diff --git a/poky/meta/lib/patchtest/tests/test_mbox_format.py b/poky/meta/lib/patchtest/tests/test_mbox_format.py
new file mode 100644
index 0000000..85c452c
--- /dev/null
+++ b/poky/meta/lib/patchtest/tests/test_mbox_format.py
@@ -0,0 +1,16 @@
+# Checks correct parsing of mboxes
+#
+# Copyright (C) 2016 Intel Corporation
+#
+# SPDX-License-Identifier: GPL-2.0
+
+import base
+import re
+
+class MboxFormat(base.Base):
+
+    def test_mbox_format(self):
+        if self.unidiff_parse_error:
+            self.fail('Series cannot be parsed correctly due to malformed diff lines',
+                      'Create the series again using git-format-patch and ensure it can be applied using git am',
+                      data=[('Diff line', re.sub('^.+:\s(?<!$)','',self.unidiff_parse_error))])
diff --git a/poky/meta/lib/patchtest/tests/test_mbox_mailinglist.py b/poky/meta/lib/patchtest/tests/test_mbox_mailinglist.py
new file mode 100644
index 0000000..de38e20
--- /dev/null
+++ b/poky/meta/lib/patchtest/tests/test_mbox_mailinglist.py
@@ -0,0 +1,64 @@
+# Check if the series was intended for other project (not OE-Core)
+#
+# Copyright (C) 2017 Intel Corporation
+#
+# SPDX-License-Identifier: GPL-2.0
+
+import subprocess
+import collections
+import base
+import re
+from data import PatchTestInput
+
+class MailingList(base.Base):
+
+    # base paths of main yocto project sub-projects
+    paths = {
+        'oe-core': ['meta-selftest', 'meta-skeleton', 'meta', 'scripts'],
+        'bitbake': ['bitbake'],
+        'documentation': ['documentation'],
+        'poky': ['meta-poky','meta-yocto-bsp'],
+        'oe': ['meta-gpe', 'meta-gnome', 'meta-efl', 'meta-networking', 'meta-multimedia','meta-initramfs', 'meta-ruby', 'contrib', 'meta-xfce', 'meta-filesystems', 'meta-perl', 'meta-webserver', 'meta-systemd', 'meta-oe', 'meta-python']
+        }
+
+    # scripts folder is a mix of oe-core and poky, most is oe-core code except:
+    poky_scripts = ['scripts/yocto-bsp', 'scripts/yocto-kernel', 'scripts/yocto-layer', 'scripts/lib/bsp']
+
+    Project = collections.namedtuple('Project', ['name', 'listemail', 'gitrepo', 'paths'])
+
+    bitbake = Project(name='Bitbake', listemail='bitbake-devel@lists.openembedded.org', gitrepo='http://git.openembedded.org/bitbake/', paths=paths['bitbake'])
+    doc     = Project(name='Documentantion', listemail='yocto@yoctoproject.org', gitrepo='http://git.yoctoproject.org/cgit/cgit.cgi/yocto-docs/', paths=paths['documentation'])
+    poky    = Project(name='Poky', listemail='poky@yoctoproject.org', gitrepo='http://git.yoctoproject.org/cgit/cgit.cgi/poky/', paths=paths['poky'])
+    oe      = Project(name='oe', listemail='openembedded-devel@lists.openembedded.org', gitrepo='http://git.openembedded.org/meta-openembedded/', paths=paths['oe'])
+
+
+    def test_target_mailing_list(self):
+        """In case of merge failure, check for other targeted projects"""
+        if PatchTestInput.repo.ismerged:
+            self.skip('Series merged, no reason to check other mailing lists')
+
+        # a meta project may be indicted in the message subject, if this is the case, just fail
+        # TODO: there may be other project with no-meta prefix, we also need to detect these
+        project_regex = re.compile("\[(?P<project>meta-.+)\]")
+        for commit in MailingList.commits:
+            match = project_regex.match(commit.subject)
+            if match:
+                self.fail('Series sent to the wrong mailing list',
+                          'Check the project\'s README (%s) and send the patch to the indicated list' % match.group('project'),
+                          commit)
+
+        for patch in self.patchset:
+            folders = patch.path.split('/')
+            base_path = folders[0]
+            for project in [self.bitbake, self.doc, self.oe, self.poky]:
+                if base_path in  project.paths:
+                    self.fail('Series sent to the wrong mailing list or some patches from the series correspond to different mailing lists', 'Send the series again to the correct mailing list (ML)',
+                              data=[('Suggested ML', '%s [%s]' % (project.listemail, project.gitrepo)),
+                                    ('Patch\'s path:', patch.path)])
+
+            # check for poky's scripts code
+            if base_path.startswith('scripts'):
+                for poky_file in self.poky_scripts:
+                    if patch.path.startswith(poky_file):
+                        self.fail('Series sent to the wrong mailing list or some patches from the series correspond to different mailing lists', 'Send the series again to the correct mailing list (ML)',
+                                  data=[('Suggested ML', '%s [%s]' % (self.poky.listemail, self.poky.gitrepo)),('Patch\'s path:', patch.path)])
diff --git a/poky/meta/lib/patchtest/tests/test_mbox_merge.py b/poky/meta/lib/patchtest/tests/test_mbox_merge.py
new file mode 100644
index 0000000..c8b6718
--- /dev/null
+++ b/poky/meta/lib/patchtest/tests/test_mbox_merge.py
@@ -0,0 +1,25 @@
+# Check if mbox was merged by patchtest
+#
+# Copyright (C) 2016 Intel Corporation
+#
+# SPDX-License-Identifier: GPL-2.0
+
+import subprocess
+import base
+from data import PatchTestInput
+
+def headlog():
+    output = subprocess.check_output(
+        "cd %s; git log --pretty='%%h#%%aN#%%cD:#%%s' -1" % PatchTestInput.repodir,
+        universal_newlines=True,
+        shell=True
+        )
+    return output.split('#')
+
+class Merge(base.Base):
+    def test_series_merge_on_head(self):
+        if not PatchTestInput.repo.ismerged:
+            commithash, author, date, shortlog = headlog()
+            self.fail('Series does not apply on top of target branch',
+                      'Rebase your series on top of targeted branch',
+                      data=[('Targeted branch', '%s (currently at %s)' % (PatchTestInput.repo.branch, commithash))])
diff --git a/poky/meta/lib/patchtest/tests/test_mbox_shortlog.py b/poky/meta/lib/patchtest/tests/test_mbox_shortlog.py
new file mode 100644
index 0000000..b6c2a20
--- /dev/null
+++ b/poky/meta/lib/patchtest/tests/test_mbox_shortlog.py
@@ -0,0 +1,41 @@
+# Checks related to the patch's  summary
+#
+# Copyright (C) 2016 Intel Corporation
+#
+# SPDX-License-Identifier: GPL-2.0
+
+import base
+import parse_shortlog
+import pyparsing
+
+maxlength = 90
+
+class Shortlog(base.Base):
+
+    def test_shortlog_format(self):
+        for commit in Shortlog.commits:
+            shortlog = commit.shortlog
+            if not shortlog.strip():
+                self.skip('Empty shortlog, no reason to execute shortlog format test')
+            else:
+                # no reason to re-check on revert shortlogs
+                if shortlog.startswith('Revert "'):
+                    continue
+                try:
+                    parse_shortlog.shortlog.parseString(shortlog)
+                except pyparsing.ParseException as pe:
+                    self.fail('Shortlog does not follow expected format',
+                              'Commit shortlog (first line of commit message) should follow the format "<target>: <summary>"',
+                              commit)
+
+    def test_shortlog_length(self):
+        for commit in Shortlog.commits:
+            # no reason to re-check on revert shortlogs
+            shortlog = commit.shortlog
+            if shortlog.startswith('Revert "'):
+                continue
+            l = len(shortlog)
+            if l > maxlength:
+                self.fail('Commit shortlog is too long',
+                          'Edit shortlog so that it is %d characters or less (currently %d characters)' % (maxlength, l),
+                          commit)
diff --git a/poky/meta/lib/patchtest/tests/test_mbox_signed_off_by.py b/poky/meta/lib/patchtest/tests/test_mbox_signed_off_by.py
new file mode 100644
index 0000000..6458951
--- /dev/null
+++ b/poky/meta/lib/patchtest/tests/test_mbox_signed_off_by.py
@@ -0,0 +1,28 @@
+# Checks related to the patch's signed-off-by lines
+#
+# Copyright (C) 2016 Intel Corporation
+#
+# SPDX-License-Identifier: GPL-2.0
+
+import base
+import parse_signed_off_by
+import re
+
+class SignedOffBy(base.Base):
+
+    revert_shortlog_regex = re.compile('Revert\s+".*"')
+
+    @classmethod
+    def setUpClassLocal(cls):
+        # match self.mark with no '+' preceding it
+        cls.prog = parse_signed_off_by.signed_off_by
+
+    def test_signed_off_by_presence(self):
+        for commit in SignedOffBy.commits:
+            # skip those patches that revert older commits, these do not required the tag presence
+            if self.revert_shortlog_regex.match(commit.shortlog):
+                continue
+            if not SignedOffBy.prog.search_string(commit.payload):
+                self.fail('Patch is missing Signed-off-by',
+                          'Sign off the patch (either manually or with "git commit --amend -s")',
+                          commit)
diff --git a/poky/meta/lib/patchtest/tests/test_metadata_lic_files_chksum.py b/poky/meta/lib/patchtest/tests/test_metadata_lic_files_chksum.py
new file mode 100644
index 0000000..e9a5b6b
--- /dev/null
+++ b/poky/meta/lib/patchtest/tests/test_metadata_lic_files_chksum.py
@@ -0,0 +1,82 @@
+# Checks related to the patch's LIC_FILES_CHKSUM  metadata variable
+#
+# Copyright (C) 2016 Intel Corporation
+#
+# SPDX-License-Identifier: GPL-2.0
+
+import base
+import re
+from data import PatchTestInput, PatchTestDataStore
+
+class LicFilesChkSum(base.Metadata):
+    metadata = 'LIC_FILES_CHKSUM'
+    license  = 'LICENSE'
+    closed   = 'CLOSED'
+    lictag   = 'License-Update'
+    lictag_re  = re.compile("^%s:" % lictag, re.MULTILINE)
+
+    def setUp(self):
+        # these tests just make sense on patches that can be merged
+        if not PatchTestInput.repo.canbemerged:
+            self.skip('Patch cannot be merged')
+
+    def test_lic_files_chksum_presence(self):
+        if not self.added:
+            self.skip('No added recipes, skipping test')
+
+        for pn in self.added:
+            rd = self.tinfoil.parse_recipe(pn)
+            pathname = rd.getVar('FILE')
+            # we are not interested in images
+            if '/images/' in pathname:
+                continue
+            lic_files_chksum = rd.getVar(self.metadata)
+            if rd.getVar(self.license) == self.closed:
+                continue
+            if not lic_files_chksum:
+                self.fail('%s is missing in newly added recipe' % self.metadata,
+                          'Specify the variable %s in %s' % (self.metadata, pn))
+
+    def pretest_lic_files_chksum_modified_not_mentioned(self):
+        if not self.modified:
+            self.skip('No modified recipes, skipping pretest')
+        # get the proper metadata values
+        for pn in self.modified:
+            rd = self.tinfoil.parse_recipe(pn)
+            pathname = rd.getVar('FILE')
+            # we are not interested in images
+            if '/images/' in pathname:
+                continue
+            PatchTestDataStore['%s-%s-%s' % (self.shortid(),self.metadata,pn)] = rd.getVar(self.metadata)
+
+    def test_lic_files_chksum_modified_not_mentioned(self):
+        if not self.modified:
+            self.skip('No modified recipes, skipping test')
+
+        # get the proper metadata values
+        for pn in self.modified:
+            rd = self.tinfoil.parse_recipe(pn)
+            pathname = rd.getVar('FILE')
+            # we are not interested in images
+            if '/images/' in pathname:
+                continue
+            PatchTestDataStore['%s-%s-%s' % (self.shortid(),self.metadata,pn)] = rd.getVar(self.metadata)
+        # compare if there were changes between pre-merge and merge
+        for pn in self.modified:
+            pretest = PatchTestDataStore['pre%s-%s-%s' % (self.shortid(),self.metadata, pn)]
+            test    = PatchTestDataStore['%s-%s-%s' % (self.shortid(),self.metadata, pn)]
+
+            # TODO: this is workaround to avoid false-positives when pretest metadata is empty (not reason found yet)
+            # For more info, check bug 12284
+            if not pretest:
+                return
+
+            if pretest != test:
+                # if any patch on the series contain reference on the metadata, fail
+                for commit in self.commits:
+                    if self.lictag_re.search(commit.commit_message):
+                       break
+                else:
+                    self.fail('LIC_FILES_CHKSUM changed on target %s but there is no "%s" tag in commit message' % (pn, self.lictag),
+                              'Include "%s: <description>" into the commit message with a brief description' % self.lictag,
+                              data=[('Current checksum', pretest), ('New checksum', test)])
diff --git a/poky/meta/lib/patchtest/tests/test_metadata_license.py b/poky/meta/lib/patchtest/tests/test_metadata_license.py
new file mode 100644
index 0000000..16604db
--- /dev/null
+++ b/poky/meta/lib/patchtest/tests/test_metadata_license.py
@@ -0,0 +1,55 @@
+# Checks related to the patch's LIC_FILES_CHKSUM  metadata variable
+#
+# Copyright (C) 2016 Intel Corporation
+#
+# SPDX-License-Identifier: GPL-2.0
+
+import base
+import os
+from data import PatchTestInput
+
+class License(base.Metadata):
+    metadata = 'LICENSE'
+    invalid_license = 'PATCHTESTINVALID'
+
+    def setUp(self):
+        # these tests just make sense on patches that can be merged
+        if not PatchTestInput.repo.canbemerged:
+            self.skip('Patch cannot be merged')
+
+    def test_license_presence(self):
+        if not self.added:
+            self.skip('No added recipes, skipping test')
+
+        # TODO: this is a workaround so we can parse the recipe not
+        # containing the LICENSE var: add some default license instead
+        # of INVALID into auto.conf, then remove this line at the end
+        auto_conf = os.path.join(os.environ.get('BUILDDIR'), 'conf', 'auto.conf')
+        open_flag = 'w'
+        if os.path.exists(auto_conf):
+            open_flag = 'a'
+        with open(auto_conf, open_flag) as fd:
+            for pn in self.added:
+                fd.write('LICENSE ??= "%s"\n' % self.invalid_license)
+
+        no_license = False
+        for pn in self.added:
+            rd = self.tinfoil.parse_recipe(pn)
+            license = rd.getVar(self.metadata)
+            if license == self.invalid_license:
+                no_license = True
+                break
+
+        # remove auto.conf line or the file itself
+        if open_flag == 'w':
+            os.remove(auto_conf)
+        else:
+            fd = open(auto_conf, 'r')
+            lines = fd.readlines()
+            fd.close()
+            with open(auto_conf, 'w') as fd:
+                fd.write(''.join(lines[:-1]))
+
+        if no_license:
+            self.fail('Recipe does not have the LICENSE field set', 'Include a LICENSE into the new recipe')
+
diff --git a/poky/meta/lib/patchtest/tests/test_metadata_max_length.py b/poky/meta/lib/patchtest/tests/test_metadata_max_length.py
new file mode 100644
index 0000000..04a5e23
--- /dev/null
+++ b/poky/meta/lib/patchtest/tests/test_metadata_max_length.py
@@ -0,0 +1,26 @@
+# Checks related to patch line lengths
+#
+# Copyright (C) 2016 Intel Corporation
+#
+# SPDX-License-Identifier: GPL-2.0
+
+import base
+import re
+
+class MaxLength(base.Base):
+    add_mark = re.compile('\+ ')
+    max_length = 200
+
+    def test_max_line_length(self):
+        for patch in self.patchset:
+            # for the moment, we are just interested in metadata
+            if patch.path.endswith('.patch'):
+                continue
+            payload = str(patch)
+            for line in payload.splitlines():
+                if self.add_mark.match(line):
+                    current_line_length = len(line[1:])
+                    if current_line_length > self.max_length:
+                        self.fail('Patch line too long (current length %s)' % current_line_length,
+                                  'Shorten the corresponding patch line (max length supported %s)' % self.max_length,
+                                  data=[('Patch', patch.path), ('Line', '%s ...' % line[0:80])])
diff --git a/poky/meta/lib/patchtest/tests/test_metadata_src_uri.py b/poky/meta/lib/patchtest/tests/test_metadata_src_uri.py
new file mode 100644
index 0000000..718229d
--- /dev/null
+++ b/poky/meta/lib/patchtest/tests/test_metadata_src_uri.py
@@ -0,0 +1,75 @@
+# Checks related to the patch's SRC_URI metadata variable
+#
+# Copyright (C) 2016 Intel Corporation
+#
+# SPDX-License-Identifier: GPL-2.0
+
+import subprocess
+import base
+import re
+import os
+from data import PatchTestInput, PatchTestDataStore
+
+class SrcUri(base.Metadata):
+
+    metadata  = 'SRC_URI'
+    md5sum    = 'md5sum'
+    sha256sum = 'sha256sum'
+    git_regex = re.compile('^git\:\/\/.*')
+
+    def setUp(self):
+        # these tests just make sense on patches that can be merged
+        if not PatchTestInput.repo.canbemerged:
+            self.skip('Patch cannot be merged')
+
+    def pretest_src_uri_left_files(self):
+        if not self.modified:
+            self.skip('No modified recipes, skipping pretest')
+
+        # get the proper metadata values
+        for pn in self.modified:
+            # we are not interested in images
+            if 'core-image' in pn:
+                continue
+            rd = self.tinfoil.parse_recipe(pn)
+            PatchTestDataStore['%s-%s-%s' % (self.shortid(), self.metadata, pn)] = rd.getVar(self.metadata)
+
+    def test_src_uri_left_files(self):
+        if not self.modified:
+            self.skip('No modified recipes, skipping pretest')
+
+        # get the proper metadata values
+        for pn in self.modified:
+            # we are not interested in images
+            if 'core-image' in pn:
+                continue
+            rd = self.tinfoil.parse_recipe(pn)
+            PatchTestDataStore['%s-%s-%s' % (self.shortid(), self.metadata, pn)] = rd.getVar(self.metadata)
+
+        for pn in self.modified:
+            pretest_src_uri = PatchTestDataStore['pre%s-%s-%s' % (self.shortid(), self.metadata, pn)].split()
+            test_src_uri    = PatchTestDataStore['%s-%s-%s' % (self.shortid(), self.metadata, pn)].split()
+
+            pretest_files = set([os.path.basename(patch) for patch in pretest_src_uri if patch.startswith('file://')])
+            test_files    = set([os.path.basename(patch) for patch in test_src_uri    if patch.startswith('file://')])
+
+            # check if files were removed
+            if len(test_files) < len(pretest_files):
+
+                # get removals from patchset
+                filesremoved_from_patchset = set()
+                for patch in self.patchset:
+                    if patch.is_removed_file:
+                        filesremoved_from_patchset.add(os.path.basename(patch.path))
+
+                # get the deleted files from the SRC_URI
+                filesremoved_from_usr_uri = pretest_files - test_files
+
+                # finally, get those patches removed at SRC_URI and not removed from the patchset
+                # TODO: we are not taking into account  renames, so test may raise false positives
+                not_removed = filesremoved_from_usr_uri - filesremoved_from_patchset
+                if not_removed:
+                    self.fail('Patches not removed from tree',
+                              'Amend the patch containing the software patch file removal',
+                              data=[('Patch', f) for f in not_removed])
+
diff --git a/poky/meta/lib/patchtest/tests/test_metadata_summary.py b/poky/meta/lib/patchtest/tests/test_metadata_summary.py
new file mode 100644
index 0000000..931b267
--- /dev/null
+++ b/poky/meta/lib/patchtest/tests/test_metadata_summary.py
@@ -0,0 +1,32 @@
+# Checks related to the patch's summary metadata variable
+#
+# Copyright (C) 2016 Intel Corporation
+#
+# SPDX-License-Identifier: GPL-2.0
+
+import base
+from data import PatchTestInput
+
+class Summary(base.Metadata):
+    metadata = 'SUMMARY'
+
+    def setUp(self):
+        # these tests just make sense on patches that can be merged
+        if not PatchTestInput.repo.canbemerged:
+            self.skip('Patch cannot be merged')
+
+    def test_summary_presence(self):
+        if not self.added:
+            self.skip('No added recipes, skipping test')
+
+        for pn in self.added:
+            # we are not interested in images
+            if 'core-image' in pn:
+                continue
+            rd = self.tinfoil.parse_recipe(pn)
+            summary = rd.getVar(self.metadata)
+
+            # "${PN} version ${PN}-${PR}" is the default, so fail if default
+            if summary.startswith('%s version' % pn):
+                self.fail('%s is missing in newly added recipe' % self.metadata,
+                          'Specify the variable %s in %s' % (self.metadata, pn))
diff --git a/poky/meta/lib/patchtest/tests/test_patch_cve.py b/poky/meta/lib/patchtest/tests/test_patch_cve.py
new file mode 100644
index 0000000..46ed9ef
--- /dev/null
+++ b/poky/meta/lib/patchtest/tests/test_patch_cve.py
@@ -0,0 +1,51 @@
+# Checks related to the patch's CVE lines
+#
+# Copyright (C) 2016 Intel Corporation
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import base
+import os
+import re
+
+class CVE(base.Base):
+
+    re_cve_pattern = re.compile("CVE\-\d{4}\-\d+", re.IGNORECASE)
+    re_cve_payload_tag     = re.compile("\+CVE:(\s+CVE\-\d{4}\-\d+)+")
+
+    def setUp(self):
+        if self.unidiff_parse_error:
+            self.skip('Parse error %s' % self.unidiff_parse_error)
+
+        # we are just interested in series that introduce CVE patches, thus discard other
+        # possibilities: modification to current CVEs, patch directly introduced into the
+        # recipe, upgrades already including the CVE, etc.
+        new_cves = [p for p in self.patchset if p.path.endswith('.patch') and p.is_added_file]
+        if not new_cves:
+            self.skip('No new CVE patches introduced')
+
+    def test_cve_tag_format(self):
+        for commit in CVE.commits:
+            if self.re_cve_pattern.search(commit.shortlog) or self.re_cve_pattern.search(commit.commit_message):
+                tag_found = False
+                for line in commit.payload.splitlines():
+                    if self.re_cve_payload_tag.match(line):
+                        tag_found = True
+                        break
+                if not tag_found:
+                    self.fail('Missing or incorrectly formatted CVE tag in included patch file',
+                              'Correct or include the CVE tag on cve patch with format: "CVE: CVE-YYYY-XXXX"',
+                              commit)
diff --git a/poky/meta/lib/patchtest/tests/test_patch_signed_off_by.py b/poky/meta/lib/patchtest/tests/test_patch_signed_off_by.py
new file mode 100644
index 0000000..4855d6d
--- /dev/null
+++ b/poky/meta/lib/patchtest/tests/test_patch_signed_off_by.py
@@ -0,0 +1,43 @@
+# Checks related to the patch's signed-off-by lines
+#
+# Copyright (C) 2016 Intel Corporation
+#
+# SPDX-License-Identifier: GPL-2.0
+
+import base
+import parse_signed_off_by
+import re
+
+class PatchSignedOffBy(base.Base):
+
+    @classmethod
+    def setUpClassLocal(cls):
+        cls.newpatches = []
+        # get just those relevant patches: new software patches
+        for patch in cls.patchset:
+            if patch.path.endswith('.patch') and patch.is_added_file:
+                cls.newpatches.append(patch)
+
+        cls.mark = str(parse_signed_off_by.signed_off_by_mark).strip('"')
+
+        # match PatchSignedOffBy.mark with '+' preceding it
+        cls.prog = parse_signed_off_by.patch_signed_off_by
+
+    def setUp(self):
+        if self.unidiff_parse_error:
+            self.skip('Parse error %s' % self.unidiff_parse_error)
+
+    def test_signed_off_by_presence(self):
+        if not PatchSignedOffBy.newpatches:
+            self.skip("There are no new software patches, no reason to test %s presence" % PatchSignedOffBy.mark)
+
+        for newpatch in PatchSignedOffBy.newpatches:
+            payload = newpatch.__str__()
+            for line in payload.splitlines():
+                if self.patchmetadata_regex.match(line):
+                    continue
+                if PatchSignedOffBy.prog.search_string(payload):
+                    break
+            else:
+                self.fail('A patch file has been added, but does not have a Signed-off-by tag',
+                          'Sign off the added patch file (%s)' % newpatch.path)
diff --git a/poky/meta/lib/patchtest/tests/test_patch_upstream_status.py b/poky/meta/lib/patchtest/tests/test_patch_upstream_status.py
new file mode 100644
index 0000000..eda5353
--- /dev/null
+++ b/poky/meta/lib/patchtest/tests/test_patch_upstream_status.py
@@ -0,0 +1,64 @@
+# Checks related to the patch's upstream-status lines
+#
+# Copyright (C) 2016 Intel Corporation
+#
+# SPDX-License-Identifier: GPL-2.0
+
+import base
+import parse_upstream_status
+import pyparsing
+import os
+
+class PatchUpstreamStatus(base.Base):
+
+    upstream_status_regex = pyparsing.AtLineStart("+" + "Upstream-Status")
+
+    @classmethod
+    def setUpClassLocal(cls):
+        cls.newpatches = []
+        # get just those relevant patches: new software patches
+        for patch in cls.patchset:
+            if patch.path.endswith('.patch') and patch.is_added_file:
+                cls.newpatches.append(patch)
+
+    def setUp(self):
+        if self.unidiff_parse_error:
+            self.skip('Python-unidiff parse error')
+        self.valid_status    = ', '.join(parse_upstream_status.upstream_status_nonliteral_valid_status)
+        self.standard_format = 'Upstream-Status: <Valid status>'
+
+    def test_upstream_status_presence_format(self):
+        if not PatchUpstreamStatus.newpatches:
+            self.skip("There are no new software patches, no reason to test Upstream-Status presence/format")
+
+        for newpatch in PatchUpstreamStatus.newpatches:
+            payload = newpatch.__str__()
+            if not self.upstream_status_regex.search_string(payload):
+                self.fail('Added patch file is missing Upstream-Status in the header',
+                          'Add Upstream-Status: <Valid status> to the header of %s' % newpatch.path,
+                          data=[('Standard format', self.standard_format), ('Valid status', self.valid_status)])
+            for line in payload.splitlines():
+                if self.patchmetadata_regex.match(line):
+                    continue
+                if self.upstream_status_regex.search_string(line):
+                        if parse_upstream_status.inappropriate_status_mark.searchString(line):
+                            try:
+                                parse_upstream_status.upstream_status_inappropriate_info.parseString(line.lstrip('+'))
+                            except pyparsing.ParseException as pe:
+                                self.fail('Upstream-Status is Inappropriate, but no reason was provided',
+                                          'Include a brief reason why %s is inappropriate' % os.path.basename(newpatch.path),
+                                          data=[('Current', pe.pstr), ('Standard format', 'Upstream-Status: Inappropriate [reason]')])
+                        elif parse_upstream_status.submitted_status_mark.searchString(line):
+                            try:
+                                parse_upstream_status.upstream_status_submitted_info.parseString(line.lstrip('+'))
+                            except pyparsing.ParseException as pe:
+                                self.fail('Upstream-Status is Submitted, but it is not mentioned where',
+                                          'Include where %s was submitted' % os.path.basename(newpatch.path),
+                                          data=[('Current', pe.pstr), ('Standard format', 'Upstream-Status: Submitted [where]')])
+                        else:
+                            try:
+                                parse_upstream_status.upstream_status.parseString(line.lstrip('+'))
+                            except pyparsing.ParseException as pe:
+                                self.fail('Upstream-Status is in incorrect format',
+                                          'Fix Upstream-Status format in %s' % os.path.basename(newpatch.path),
+                                          data=[('Current', pe.pstr), ('Standard format', self.standard_format), ('Valid status', self.valid_status)])
diff --git a/poky/meta/lib/patchtest/tests/test_python_pylint.py b/poky/meta/lib/patchtest/tests/test_python_pylint.py
new file mode 100644
index 0000000..ea8efb7
--- /dev/null
+++ b/poky/meta/lib/patchtest/tests/test_python_pylint.py
@@ -0,0 +1,61 @@
+# Checks related to the python code done with pylint
+#
+# Copyright (C) 2016 Intel Corporation
+#
+# SPDX-License-Identifier: GPL-2.0
+
+import base
+from data import PatchTestInput
+import pylint.epylint as lint
+
+class PyLint(base.Base):
+    pythonpatches  = []
+    pylint_pretest = {}
+    pylint_test    = {}
+    pylint_options = " -E --disable='E0611, E1101, F0401, E0602' --msg-template='L:{line} F:{module} I:{msg}'"
+
+    @classmethod
+    def setUpClassLocal(cls):
+        # get just those patches touching python files
+        cls.pythonpatches = []
+        for patch in cls.patchset:
+            if patch.path.endswith('.py'):
+                if not patch.is_removed_file:
+                    cls.pythonpatches.append(patch)
+
+    def setUp(self):
+        if self.unidiff_parse_error:
+            self.skip('Python-unidiff parse error')
+        if not PatchTestInput.repo.canbemerged:
+            self.skip('Patch cannot be merged, no reason to execute the test method')
+        if not PyLint.pythonpatches:
+            self.skip('No python related patches, skipping test')
+
+    def pretest_pylint(self):
+        for pythonpatch in self.pythonpatches:
+            if pythonpatch.is_modified_file:
+                (pylint_stdout, pylint_stderr) = lint.py_run(command_options = pythonpatch.path + self.pylint_options, return_std=True)
+                for line in pylint_stdout.readlines():
+                    if not '*' in line:
+                        if line.strip():
+                            self.pylint_pretest[line.strip().split(' ',1)[0]] = line.strip().split(' ',1)[1]
+
+    def test_pylint(self):
+        for pythonpatch in self.pythonpatches:
+            # a condition checking whether a file is renamed or not
+            # unidiff doesn't support this yet
+            if pythonpatch.target_file is not pythonpatch.path:
+                path = pythonpatch.target_file[2:]
+            else:
+                path = pythonpatch.path
+            (pylint_stdout, pylint_stderr) = lint.py_run(command_options = path + self.pylint_options, return_std=True)
+            for line in pylint_stdout.readlines():
+                    if not '*' in line:
+                        if line.strip():
+                            self.pylint_test[line.strip().split(' ',1)[0]] = line.strip().split(' ',1)[1]
+
+        for issue in self.pylint_test:
+             if self.pylint_test[issue] not in self.pylint_pretest.values():
+                 self.fail('Errors in your Python code were encountered',
+                           'Correct the lines introduced by your patch',
+                           data=[('Output', 'Please, fix the listed issues:'), ('', issue + ' ' + self.pylint_test[issue])])