Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions .github/workflows/oelint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: OE Lint

on:
pull_request:
merge_group:
push:
branches:
- master

concurrency:
group: ${{ github.repository }}-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
oelint:
runs-on: ubuntu-latest
# Advisory (non-blocking) for now. Released oelint-adv still reports known
# false positives that our upstream fixes remove but which are not in a
# release yet:
# * oelint-adv #889 - gomod SRC_URI support; without it the generated
# telegraf-go-mods.inc trips ~536 srcuri* findings.
# * oelint-parser #383 - leftover-buffer drain; without it two event
# handlers trip oelint.task.docstrings.
# The findings stay visible in the job log. Once both land in nixpkgs'
# oelint-adv, drop continue-on-error to make this a blocking gate.
continue-on-error: true
steps:
- uses: ossystems/nix-actions@v1
with:
install-nix: true # hosted runner ships no Nix
flake-check: false # this layer is not a flake
build-hosts: false # nothing local to build
build-devshells: false
# The lint shell is a plain mkShell (oelint-adv on PATH), so unlike
# the default FHS bwrap shell it runs `--command` non-interactively.
devshell: github:OSSystems/yocto-env.nix#lint
run: ./contrib/oelint/run-oelint.sh
12 changes: 12 additions & 0 deletions .oelint.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# oelint-adv defaults for this layer. Auto-loaded when oelint-adv runs with this
# directory as the working directory (see contrib/oelint/run-oelint.sh).
#
# The only layer-wide suppression is oelint.var.bbclassextend: every recipe in
# this layer is target-only, so the "add BBCLASSEXTEND" suggestion never applies
# and would otherwise need a redundant inline comment on every single recipe.
# All other exceptions stay inline as '# nooelint: <rule.id>' comments next to
# the finding, so new recipes are always fully linted and each exception is
# documented in place.
[oelint]
release = wrynose
suppress = oelint.var.bbclassextend
7 changes: 5 additions & 2 deletions classes/cve-filter.bbclass
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# nooelint: oelint.bbclass.underscores oelint.file.inlinesuppress_na no EXPORT_FUNCTIONS here, so the dash is harmless
# Copyright (c) 2024 O.S. Systems Software LTDA.
# Usage Instructions for the Yocto CVE Filter Class

Expand All @@ -18,7 +19,7 @@

# The cve-filter class provides several configurable variables:

# CVE_FILTER_PREVIOUS_FILE: Specifies the previous version of
# CVE_FILTER_PREVIOUS_FILE: Specifies the previous version of
# the CVE JSON file. If no file is provided, only the current
# file will be considered.
# Default: empty
Expand All @@ -29,7 +30,7 @@
# Example: "1.0.0"
# Default: "0.0.0"

# CVE_FILTER_MARKDOWN_FILE_NAME: Specifies the name of the
# CVE_FILTER_MARKDOWN_FILE_NAME: Specifies the name of the
# output Markdown file containing the list of detected CVEs.
# Default: "${IMAGE_NAME}.md"

Expand Down Expand Up @@ -96,10 +97,12 @@ python do_cve_filter (){
bb.plain("DONE!!")
}

do_cve_filter[doc] = "Compare the image CVE report against a previous version and emit a filtered Markdown summary of the new CVEs."
addtask cve_filter after do_rootfs before do_image

ROOTFS_POSTPROCESS_COMMAND:prepend = "link_cvefilter_markdownfile; "

link_cvefilter_markdownfile[doc] = "Create a stable-named symlink to the CVE filter Markdown report in the deploy directory."
link_cvefilter_markdownfile () {
ln -sf ${CVE_FILTER_MARKDOWN_FILE_NAME} ${IMGDEPLOYDIR}/${IMAGE_LINK_NAME}.md
}
3 changes: 3 additions & 0 deletions classes/deploy-license-manifest.bbclass
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
# nooelint: oelint.bbclass.underscores oelint.file.inlinesuppress_na no EXPORT_FUNCTIONS here, so the dash is harmless
ROOTFS_POSTPROCESS_COMMAND += "deploy_license_manifest;"
IMAGE_POSTPROCESS_COMMAND += "link_license_manifest;"

deploy_license_manifest[doc] = "Copy the image license manifest into the deploy directory and generate a CSV variant."
deploy_license_manifest () {
if [ -e "${LICENSE_DIRECTORY}/${IMAGE_NAME}/license.manifest" ]; then
cp ${LICENSE_DIRECTORY}/${IMAGE_NAME}/license.manifest ${IMGDEPLOYDIR}/${IMAGE_NAME}.license_manifest
sed -n '/PACKAGE NAME/{: start; /^ *$/b done; /LICENSE:/{s/: /: "/; s/$/"/;}; s/^.*://; H; n; b start; : done; x; s/^[\n ]*//; s/ *\n */,/g; p}' ${IMGDEPLOYDIR}/${IMAGE_NAME}.license_manifest >${IMGDEPLOYDIR}/${IMAGE_NAME}.license_manifest.csv
fi
}

link_license_manifest[doc] = "Create stable-named symlinks to the deployed license manifest and its CSV variant."
link_license_manifest () {
if [ -e "${IMGDEPLOYDIR}/${IMAGE_NAME}.license_manifest" ]; then
ln -sf ${IMAGE_NAME}.license_manifest ${IMGDEPLOYDIR}/${IMAGE_LINK_NAME}.license_manifest
Expand Down
1 change: 1 addition & 0 deletions classes/easysplash-animation.bbclass
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# nooelint: oelint.bbclass.underscores oelint.file.inlinesuppress_na no EXPORT_FUNCTIONS here, so the dash is harmless
# -*- python -*-
# easysplash-animation.bbclass allows for easy packaging of EasySplash
# animation packages.
Expand Down
5 changes: 3 additions & 2 deletions classes/image-license-checker.bbclass
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# nooelint: oelint.bbclass.underscores oelint.file.inlinesuppress_na no EXPORT_FUNCTIONS here, so the dash is harmless
# Copyright (c) 2018 Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: MIT
Expand Down Expand Up @@ -43,7 +44,6 @@
IMAGE_LICENSE_CHECKER_ROOTFS_DENYLIST ?= ""
IMAGE_LICENSE_CHECKER_NON_ROOTFS_DENYLIST ?= ""


def bad_license(d, license, denylist):
"""
Check if a license string is denylisted. The license string will be
Expand Down Expand Up @@ -134,9 +134,9 @@ python check_rootfs_licenses() {
if bad_packages:
bb.fatal("Packages have denylisted licenses: {}".format(", ".join(bad_packages)))
}
check_rootfs_licenses[doc] = "Fail the build if any package installed on the rootfs has a denylisted license."
ROOTFS_POSTPROCESS_COMMAND:prepend = "check_rootfs_licenses; "


python check_deploy_licenses() {
"""
Check recipes that deploy files used in an image (e.g. U-Boot) for
Expand All @@ -153,4 +153,5 @@ python check_deploy_licenses() {
if bad_recipes:
bb.fatal("Deployed image dependencies have denylisted licenses: {}".format(", ".join(bad_recipes)))
}
check_deploy_licenses[doc] = "Fail the build if any recipe deploying files into the image has a denylisted license."
IMAGE_POSTPROCESS_COMMAND:prepend = "check_deploy_licenses; "
1 change: 1 addition & 0 deletions classes/layerdirs.bbclass
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ def save_layerdirs(d):
for layername in (l.getVar('BBFILE_COLLECTIONS', True) or '').split():
d.setVar('LAYERDIR_%s' % layername, layerpath)

cfg_save_layerdirs[doc] = "Record each layer's directory in LAYERDIR_<collection> at config-parse time."
python cfg_save_layerdirs () {
save_layerdirs(d)
}
Expand Down
34 changes: 18 additions & 16 deletions classes/mirrors.bbclass
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
# nooelint: oelint.vars.bbvars.PREMIRRORS set here on purpose: this is the project mirror class
PREMIRRORS:append = " \
git://sources.redhat.com/ git://sourceware.org/ \n\
git://sources.redhat.com/ git://sourceware.org/ \
"

# nooelint: oelint.vars.bbvars.MIRRORS set here on purpose: this is the project mirror class
MIRRORS += "\
${KERNELORG_MIRROR}/ https://kernel.googlesource.com/ \n\
${KERNELORG_MIRROR}/ http://mirror.nexcess.net/kernel.org/ \n\
${KERNELORG_MIRROR}/ http://mirror.gbxs.net/pub/ \n\
${APACHE_MIRROR}/ http://archive.apache.org/dist/ \n\
${DEBIAN_MIRROR}/ ftp://archive.debian.org/debian/pool/ \n\
git://git.kernel.org/pub/ http://mirror.nexcess.net/kernel.org/ \n\
\
(ftp|https?)://.*/.* http://autobuilder.yoctoproject.org/sources/ \n\
(ftp|https?)://.*/.* http://sources.openembedded.org/ \n\
(ftp|https?)://.*/.* http://www.angstrom-distribution.org/unstable/sources/ \n\
\
(cvs|svn|git|gitsm|hg|bzr|osc|p4|svk)://.*/.* http://downloads.yoctoproject.org/mirror/sources/ \n\
(cvs|svn|git|gitsm|hg|bzr|osc|p4|svk)://.*/.* http://autobuilder.yoctoproject.org/sources/ \n\
(cvs|svn|git|gitsm|hg|bzr|osc|p4|svk)://.*/.* http://sources.openembedded.org/ \n\
(cvs|svn|git|gitsm|hg|bzr|osc|p4|svk)://.*/.* http://www.angstrom-distribution.org/unstable/sources/ \n\
${KERNELORG_MIRROR}/ https://kernel.googlesource.com/ \
${KERNELORG_MIRROR}/ http://mirror.nexcess.net/kernel.org/ \
${KERNELORG_MIRROR}/ http://mirror.gbxs.net/pub/ \
${APACHE_MIRROR}/ http://archive.apache.org/dist/ \
${DEBIAN_MIRROR}/ ftp://archive.debian.org/debian/pool/ \
git://git.kernel.org/pub/ http://mirror.nexcess.net/kernel.org/ \
\
(ftp|https?)://.*/.* http://autobuilder.yoctoproject.org/sources/ \
(ftp|https?)://.*/.* http://sources.openembedded.org/ \
(ftp|https?)://.*/.* http://www.angstrom-distribution.org/unstable/sources/ \
\
(cvs|svn|git|gitsm|hg|bzr|osc|p4|svk)://.*/.* http://downloads.yoctoproject.org/mirror/sources/ \
(cvs|svn|git|gitsm|hg|bzr|osc|p4|svk)://.*/.* http://autobuilder.yoctoproject.org/sources/ \
(cvs|svn|git|gitsm|hg|bzr|osc|p4|svk)://.*/.* http://sources.openembedded.org/ \
(cvs|svn|git|gitsm|hg|bzr|osc|p4|svk)://.*/.* http://www.angstrom-distribution.org/unstable/sources/ \
"
1 change: 1 addition & 0 deletions classes/ossystems-distro-version.bbclass
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# nooelint: oelint.bbclass.underscores oelint.file.inlinesuppress_na no EXPORT_FUNCTIONS here, so the dash is harmless
# -*- python -*-
# ossystems-distro-version.bbclass provides a DISTRO_VERSION variable
# that can be used to identify the release of a product.
Expand Down
1 change: 1 addition & 0 deletions classes/ossystems-factory-defaults-base.bbclass
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# nooelint: oelint.bbclass.underscores oelint.file.inlinesuppress_na no EXPORT_FUNCTIONS here, so the dash is harmless
OSSYSTEMS_FACTORY_DEFAULTS_DIR ?= "${datadir}/factory-defaults"
OSSYSTEMS_FACTORY_DEFAULTS_FILES ?= ""
OSSYSTEMS_FACTORY_DEFAULTS_HOOKS ?= ""
Expand Down
1 change: 1 addition & 0 deletions classes/ossystems-factory-defaults.bbclass
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# nooelint: oelint.bbclass.underscores oelint.file.inlinesuppress_na no EXPORT_FUNCTIONS here, so the dash is harmless
# Copyright (c) 2015-2020 O.S. Systems Software LTDA.
#
# The ossystems-factory-defaults class provides some variables that
Expand Down
3 changes: 3 additions & 0 deletions classes/ossystems-onsite-only-recipe-handler.bbclass
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# nooelint: oelint.bbclass.underscores oelint.file.inlinesuppress_na no EXPORT_FUNCTIONS here, so the dash is harmless
# -*- python -*-
# ossystems-onsite-only-recipe-handler.bbclass
# Copyright (C) 2015-2020 O.S. Systems Software Ltda. All Rights Reserved
Expand Down Expand Up @@ -43,11 +44,13 @@ def ossystems_onsite_only_recipe_check(d):
raise bb.parse.SkipPackage("O.S. Systems OnSite-Only Recipes handler: recipe skipped.")

addhandler ossystems_onsite_only_recipe_eventhandler
ossystems_onsite_only_recipe_eventhandler[doc] = "Disable on-site-only recipes at ConfigParsed when building off-site."
python ossystems_onsite_only_recipe_eventhandler() {
if bb.event.getName(e) == "ConfigParsed":
ossystems_onsite_only_recipe_handler(e.data)
}

# nooelint: oelint.task.noanonpython required to SkipPackage per-recipe at parse time
python () {
ossystems_onsite_only_recipe_check(d)
}
2 changes: 2 additions & 0 deletions classes/ossystems-srcrev-handler.bbclass
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# nooelint: oelint.bbclass.underscores oelint.file.inlinesuppress_na no EXPORT_FUNCTIONS here, so the dash is harmless
# -*- python -*-
# ossystems-srcrev-handler.bbclass
# Copyright (C) 2013, 2014 O.S. Systems Software Ltda. All Rights Reserved
Expand Down Expand Up @@ -52,6 +53,7 @@ def ossystems_srcrev_handler(d):
d.setVar("SRCREV:pn-%s" % pkg, rev)

addhandler ossystems_srcrev_eventhandler
ossystems_srcrev_eventhandler[doc] = "Apply the project per-recipe SRCREV overrides at ConfigParsed."
python ossystems_srcrev_eventhandler() {
if bb.event.getName(e) == "ConfigParsed":
ossystems_srcrev_handler(e.data)
Expand Down
3 changes: 3 additions & 0 deletions classes/release-bundle-generation.bbclass
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# nooelint: oelint.bbclass.underscores oelint.file.inlinesuppress_na no EXPORT_FUNCTIONS here, so the dash is harmless
# -*- python -*-
# release-bundle-generation.bbclass
#
Expand Down Expand Up @@ -45,6 +46,7 @@ do_build[recrdeptask] = ""
do_release_bundle_finalize[depends] += "${@' '.join('%s:do_collect_recipe_source' % recipe for recipe in d.getVar('RELEASE_BUNDLE_RECIPES_WITH_SOURCE').split())}"

addtask collect_platform_source before do_release_bundle_finalize
do_collect_platform_source[doc] = "Garbage-collect and copy the platform source tree (.repo, sources, setup-environment) into the release bundle workdir."
do_collect_platform_source[cleandirs] = "${RELEASE_BUNDLE_WORKDIR}"
do_collect_platform_source[depends] += "repo-native:do_populate_sysroot "
do_collect_platform_source[doc] = "Collect platform repositories into the release bundle work directory."
Expand Down Expand Up @@ -79,6 +81,7 @@ fakeroot tar_release_bundle() {
}

addtask release_bundle_finalize after do_unpack do_collect_platform_source before do_build
do_release_bundle_finalize[doc] = "Assemble the final self-extracting release bundle from the collected sources and download cache."
do_release_bundle_finalize[dirs] = "${RELEASE_BUNDLE_WORKDIR}/download"
do_release_bundle_finalize[depends] += "pbzip2-native:do_populate_sysroot "
do_release_bundle_finalize[doc] = "Finalize and emit the self-extracting release bundle."
Expand Down
1 change: 1 addition & 0 deletions classes/release-bundle.bbclass
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# nooelint: oelint.bbclass.underscores oelint.file.inlinesuppress_na no EXPORT_FUNCTIONS here, so the dash is harmless
# -*- python -*-
# release-bundle.bbclass
#
Expand Down
2 changes: 2 additions & 0 deletions classes/restore-dumped-headrevs.bbclass
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# nooelint: oelint.bbclass.underscores oelint.file.inlinesuppress_na no EXPORT_FUNCTIONS here, so the dash is harmless
def copy_persist_domain(d, domain, other_db_path, restore=False):
import contextlib

Expand All @@ -18,6 +19,7 @@ def restore_headrevs(d, dump_db_path):
DUMP_HEADREVS_DB ?= '${COREBASE}/saved_persist_data.db'
DUMP_HEADREVS_STAMP ?= '${STAMP}.restored_headrevs'

restore_dumped_headrevs[doc] = "Restore dumped BB_URI_HEADREVS persistent data once, at config-parse time, when a dump database is present."
python restore_dumped_headrevs() {
stamp_path = d.getVar('DUMP_HEADREVS_STAMP', True)
dump_db_path = d.getVar('DUMP_HEADREVS_DB', True)
Expand Down
37 changes: 37 additions & 0 deletions contrib/oelint/run-oelint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#!/bin/sh
# Run oelint-adv over meta-ossystems-base. Requires oelint-adv on PATH.
#
# All linter configuration is declarative and lives at the layer root, so this
# script only has to enumerate the files (oelint-adv does not recurse into
# directories):
# * .oelint.cfg - sets '--release' and the single layer-wide
# suppression (oelint.var.bbclassextend); auto-loaded
# from the working directory
# * oelint.constants.json - the layer constant-DB additions, auto-loaded by
# oelint-adv from the layer root (no --constantmods)
#
# Aside from oelint.var.bbclassextend (which never applies to a target-only
# layer), exceptions stay inline as '# nooelint: <rule.id>' comments next to the
# finding, so new recipes are always fully linted and each exception is
# documented in place (and flagged by oelint.file.inlinesuppress_na once stale).
set -eu

# Neutralise CDPATH so 'cd' below can't print or jump to an unexpected dir.
unset CDPATH

here=$(cd -- "$(dirname -- "$0")" && pwd)
layer=$(cd -- "$here/../.." && pwd)

# Run from the layer root so '.oelint.cfg' (probed in the working directory) and
# 'oelint.constants.json' (probed in the file's layer root) are both picked up.
cd -- "$layer"

files=$(find . \
\( -name '*.bb' -o -name '*.bbappend' -o -name '*.bbclass' -o -name '*.inc' \) \
| sort)

# Run serially: oelint-adv's parallel workers race while loading the layer
# constants, intermittently emitting false "unknown variable/override" findings.
# Serial execution is deterministic. Pass '--jobs N' to override.
# shellcheck disable=SC2086
exec oelint-adv --jobs 1 "$@" $files
Loading
Loading