diff --git a/src/pkgcheck/checks/codingstyle.py b/src/pkgcheck/checks/codingstyle.py index c99a8ecac..0e2188dbf 100644 --- a/src/pkgcheck/checks/codingstyle.py +++ b/src/pkgcheck/checks/codingstyle.py @@ -1363,3 +1363,37 @@ def feed(self, pkg): call_name = pkg.node_str(call_node.child_by_field_name("name")) if call_name in ("head", "tail"): yield from self.check_head_tail(pkg, call_node, call_name) + + +class GlobDistdir(results.LineResult, results.Warning): + """Filename expansion with ``${DISTDIR}`` is unsafe. + + Filename expansion could accidentally match irrelevant files in + ``${DISTDIR}``, e.g. from other packages or other versions of the + same package. + """ + + @property + def desc(self): + return f"line {self.lineno}: unsafe filename expansion used with DISTDIR: {self.line}" + + +class GlobCheck(Check): + """Scan ebuilds for unsafe glob usage.""" + + _source = sources.EbuildParseRepoSource + known_results = frozenset({GlobDistdir}) + + def __init__(self, options, **kwargs): + super().__init__(options, **kwargs) + self.glob_query = bash.query('(concatenation (word) @word (.match? @word "[*?]")) @usage') + + def feed(self, pkg): + for node, capture in self.glob_query.captures(pkg.tree.root_node): + if capture == "usage": + for var_node, _ in bash.var_query.captures(node): + var_name = pkg.node_str(var_node) + if var_name == "DISTDIR": + lineno, _colno = node.start_point + yield GlobDistdir(line=pkg.node_str(node), lineno=lineno + 1, pkg=pkg) + break diff --git a/testdata/data/repos/standalone/GlobCheck/GlobDistdir/expected.json b/testdata/data/repos/standalone/GlobCheck/GlobDistdir/expected.json new file mode 100644 index 000000000..56e00b6cf --- /dev/null +++ b/testdata/data/repos/standalone/GlobCheck/GlobDistdir/expected.json @@ -0,0 +1,3 @@ +{"__class__": "GlobDistdir", "category": "GlobCheck", "package": "GlobDistdir", "version": "0", "line": "\"${DISTDIR}\"/foo-*.bar", "lineno": 7} +{"__class__": "GlobDistdir", "category": "GlobCheck", "package": "GlobDistdir", "version": "0", "line": "\"${DISTDIR}\"/\"${DISTDIR}\"/foo-?.bar", "lineno": 8} +{"__class__": "GlobDistdir", "category": "GlobCheck", "package": "GlobDistdir", "version": "0", "line": "\"${DISTDIR}\"/foo-?-*.bar", "lineno": 9} diff --git a/testdata/repos/standalone/GlobCheck/GlobDistdir/GlobDistdir-0.ebuild b/testdata/repos/standalone/GlobCheck/GlobDistdir/GlobDistdir-0.ebuild new file mode 100644 index 000000000..a0480fa75 --- /dev/null +++ b/testdata/repos/standalone/GlobCheck/GlobDistdir/GlobDistdir-0.ebuild @@ -0,0 +1,15 @@ +DESCRIPTION="Ebuild with unsafe glob around DISTDIR" +HOMEPAGE="https://github.com/pkgcore/pkgcheck" +SLOT="0" +LICENSE="BSD" + +src_install() { + doins "${DISTDIR}"/foo-*.bar # bad + doins "${DISTDIR}"/"${DISTDIR}"/foo-?.bar # bad + doins "${DISTDIR}"/foo-?-*.bar # bad + + doins "${T}"/foo-*.bar # not unsafe dir + doins "${DISTDIR}"/foo-1.bar # no glob + doins "${DISTDIR}"/"foo-*.bar" # quoted + doins "${DISTDIR}"/'foo-*.bar' # quoted +}