def check_summary(self, pkg, lang, ignored_words): summary = pkg.langtag(rpm.RPMTAG_SUMMARY, lang) if use_utf8: if not Pkg.is_utf8_bytestr(summary): printError(pkg, 'tag-not-utf8', 'Summary', lang) summary = Pkg.to_unicode(summary) else: summary = Pkg.b2s(summary) self._unexpanded_macros(pkg, 'Summary(%s)' % lang, summary) spell_check(pkg, summary, 'Summary(%s)', lang, ignored_words) if '\n' in summary: printError(pkg, 'summary-on-multiple-lines', lang) if (summary[0] != summary[0].upper() and summary.partition(' ')[0] not in CAPITALIZED_IGNORE_LIST): printWarning(pkg, 'summary-not-capitalized', lang, summary) if summary[-1] == '.': printWarning(pkg, 'summary-ended-with-dot', lang, summary) if len(summary) > max_line_len: printError(pkg, 'summary-too-long', lang, summary) if leading_space_regex.search(summary): printError(pkg, 'summary-has-leading-spaces', lang, summary) res = forbidden_words_regex.search(summary) if res and Config.getOption('ForbiddenWords'): printWarning(pkg, 'summary-use-invalid-word', lang, res.group(1)) if pkg.name: sepchars = r'[\s%s]' % punct res = re.search( r'(?:^|\s)(%s)(?:%s|$)' % (re.escape(pkg.name), sepchars), summary, re.IGNORECASE | re.UNICODE) if res: printWarning(pkg, 'name-repeated-in-summary', lang, res.group(1))
def __comparePRCOs(self, old, new, name): try: oldflags = old[name[:-1] + 'FLAGS'] except ValueError: # assume tag not supported, e.g. Recommends with older rpm return newflags = new[name[:-1] + 'FLAGS'] # fix buggy rpm binding not returning list for single entries if not isinstance(oldflags, list): oldflags = [oldflags] if not isinstance(newflags, list): newflags = [newflags] o = zip(old[name], oldflags, old[name[:-1] + 'VERSION']) if not isinstance(o, list): o = list(o) n = zip(new[name], newflags, new[name[:-1] + 'VERSION']) if not isinstance(n, list): n = list(n) # filter self provides, TODO: self %name(%_isa) as well if name == 'PROVIDES': oldE = old['epoch'] is not None and str(old['epoch']) + ":" or "" oldV = "%s%s" % (oldE, old.format("%{VERSION}-%{RELEASE}")) oldNV = (old['name'], rpm.RPMSENSE_EQUAL, oldV.encode()) newE = new['epoch'] is not None and str(new['epoch']) + ":" or "" newV = "%s%s" % (newE, new.format("%{VERSION}-%{RELEASE}")) newNV = (new['name'], rpm.RPMSENSE_EQUAL, newV.encode()) o = [entry for entry in o if entry != oldNV] n = [entry for entry in n if entry != newNV] for oldentry in o: if oldentry not in n: namestr = name if namestr == 'REQUIRES': namestr = self.req2str(oldentry[1]) self.__add(self.DEPFORMAT, (self.REMOVED, namestr, Pkg.b2s(oldentry[0]), self.sense2str(oldentry[1]), Pkg.b2s(oldentry[2]))) for newentry in n: if newentry not in o: namestr = name if namestr == 'REQUIRES': namestr = self.req2str(newentry[1]) self.__add(self.DEPFORMAT, (self.ADDED, namestr, Pkg.b2s(newentry[0]), self.sense2str(newentry[1]), Pkg.b2s(newentry[2])))
def check(self, pkg): for fname, pkgfile in pkg.files().items(): path = pkgfile.path if zip_regex.search(fname) and os.path.exists(path) and \ stat.S_ISREG(os.lstat(path)[stat.ST_MODE]) and \ zipfile.is_zipfile(path): z = None # TODO ZipFile is context manager in 2.7+ try: z = zipfile.ZipFile(path, 'r') badcrc = z.testzip() if badcrc: printError(pkg, 'bad-crc-in-zip', badcrc, fname) except zipfile.error: printWarning(pkg, 'unable-to-read-zip', '%s: %s' % (fname, sys.exc_info()[1])) else: compressed = False for zinfo in z.infolist(): if zinfo.compress_type != zipfile.ZIP_STORED: compressed = True break if not compressed: printWarning(pkg, 'uncompressed-zip', fname) # additional jar checks if jar_regex.search(fname): try: mf = Pkg.b2s(z.read('META-INF/MANIFEST.MF')) if classpath_regex.search(mf): printWarning(pkg, 'class-path-in-manifest', fname) except KeyError: # META-INF/* are optional: # http://java.sun.com/j2se/1.4/docs/guide/jar/jar.html pass try: zinfo = z.getinfo('META-INF/INDEX.LIST') if not want_indexed_jars: printWarning(pkg, 'jar-indexed', fname) except KeyError: if want_indexed_jars: printWarning(pkg, 'jar-not-indexed', fname) pass z and z.close()
def check_description(self, pkg, lang, ignored_words): description = pkg.langtag(rpm.RPMTAG_DESCRIPTION, lang) if use_utf8: if not Pkg.is_utf8_bytestr(description): printError(pkg, 'tag-not-utf8', '%description', lang) description = Pkg.to_unicode(description) else: description = Pkg.b2s(description) self._unexpanded_macros(pkg, '%%description -l %s' % lang, description) spell_check(pkg, description, '%%description -l %s', lang, ignored_words) for l in description.splitlines(): if len(l) > max_line_len: printError(pkg, 'description-line-too-long', lang, l) res = forbidden_words_regex.search(l) if res and Config.getOption('ForbiddenWords'): printWarning(pkg, 'description-use-invalid-word', lang, res.group(1)) res = tag_regex.search(l) if res: printWarning(pkg, 'tag-in-description', lang, res.group(1))
def __init__(self, pkg, path, fname, is_ar, is_shlib): self.readelf_error = False self.needed = [] self.rpath = [] self.undef = [] self.unused = [] self.comment = False self.soname = False self.non_pic = True self.stack = False self.exec_stack = False self.exit_calls = [] self.forbidden_calls = [] fork_called = False self.tail = '' self.setgid = False self.setuid = False self.setgroups = False self.chroot = False self.chdir = False self.chroot_near_chdir = False self.mktemp = False self.forbidden_functions = Config.getOption("WarnOnFunction") if self.forbidden_functions: for name, func in self.forbidden_functions.items(): # precompile regexps f_name = func['f_name'] func['f_regex'] = create_nonlibc_regexp_call(f_name) if 'good_param' in func: func['waiver_regex'] = re.compile(func['good_param']) # register descriptions addDetails(name, func['description']) is_debug = path.endswith('.debug') # Currently this implementation works only on specific # architectures due to reliance on arch specific assembly. if (pkg.arch.startswith('armv') or pkg.arch == 'aarch64'): # 10450: ebffffec bl 10408 <chroot@plt> self.objdump_call_regex = re.compile(br'\sbl\s+(.*)') elif (pkg.arch.endswith('86') or pkg.arch == 'x86_64'): # 401eb8: e8 c3 f0 ff ff callq 400f80 <chdir@plt> self.objdump_call_regex = re.compile(br'callq?\s(.*)') else: self.objdump_call_regex = None res = Pkg.getstatusoutput( ('readelf', '-W', '-S', '-l', '-d', '-s', path)) if not res[0]: lines = res[1].splitlines() for line in lines: r = self.needed_regex.search(line) if r: self.needed.append(r.group(1)) continue r = self.rpath_regex.search(line) if r: for p in r.group(1).split(':'): self.rpath.append(p) continue if self.comment_regex.search(line): self.comment = True continue if self.pic_regex.search(line): self.non_pic = False continue r = self.soname_regex.search(line) if r: self.soname = r.group(1) continue r = self.stack_regex.search(line) if r: self.stack = True flags = r.group(1) if flags and self.stack_exec_regex.search(flags): self.exec_stack = True continue if line.startswith("Symbol table"): break for line in lines: r = self.call_regex.search(line) if not r: continue line = r.group(1) if self.mktemp_call_regex.search(line): self.mktemp = True if self.setgid_call_regex.search(line): self.setgid = True if self.setuid_call_regex.search(line): self.setuid = True if self.setgroups_call_regex.search(line): self.setgroups = True if self.chdir_call_regex.search(line): self.chdir = True if self.chroot_call_regex.search(line): self.chroot = True if self.forbidden_functions: for r_name, func in self.forbidden_functions.items(): ret = func['f_regex'].search(line) if ret: self.forbidden_calls.append(r_name) if is_shlib: r = self.exit_call_regex.search(line) if r: self.exit_calls.append(r.group(1)) continue r = self.fork_call_regex.search(line) if r: fork_called = True continue # check if we don't have a string that will automatically # waive the presence of a forbidden call if self.forbidden_calls: res = Pkg.getstatusoutput(('strings', path)) if not res[0]: for line in res[1].splitlines(): # as we need to remove elements, iterate backwards for i in range(len(self.forbidden_calls) - 1, -1, -1): func = self.forbidden_calls[i] f = self.forbidden_functions[func] if 'waiver_regex' not in f: continue r = f['waiver_regex'].search(line) if r: del self.forbidden_calls[i] if self.non_pic: self.non_pic = 'TEXTREL' in res[1] # Ignore all exit() calls if fork() is being called. # Does not have any context at all but without this kludge, the # number of false positives would probably be intolerable. if fork_called: self.exit_calls = [] # check if chroot is near chdir (since otherwise, chroot is called # without chdir) if not self.objdump_call_regex and self.chroot and self.chdir: # On some architectures, e.g. PPC, it is to difficult to # find the actual invocations of chroot/chdir, if both # exist assume chroot is fine self.chroot_near_chdir = True elif self.chroot and self.chdir: p = subprocess.Popen(('objdump', '-d', path), stdout=subprocess.PIPE, bufsize=-1, env=dict(os.environ, LC_ALL="C")) with p.stdout: index = 0 chroot_index = -99 chdir_index = -99 for line in p.stdout: res = self.objdump_call_regex.search(line) if not res: continue if b'@plt' not in res.group(1): pass elif b'chroot@plt' in res.group(1): chroot_index = index if abs(chroot_index - chdir_index) <= 2: self.chroot_near_chdir = True break elif b'chdir@plt' in res.group(1): chdir_index = index if abs(chroot_index - chdir_index) <= 2: self.chroot_near_chdir = True break index += 1 if p.wait() and not self.chroot_near_chdir: printWarning(pkg, 'binaryinfo-objdump-failed', fname) self.chroot_near_chdir = True # avoid false positive elif chroot_index == -99 and chdir_index == -99: self.chroot_near_chdir = True # avoid false positive else: self.readelf_error = True # Go and others are producing ar archives that don't have ELF # headers, so don't complain about it if not is_ar: printWarning(pkg, 'binaryinfo-readelf-failed', fname, re.sub('\n.*', '', res[1])) try: with open(path, 'rb') as fobj: fobj.seek(-12, os.SEEK_END) self.tail = Pkg.b2s(fobj.read()) except Exception as e: printWarning(pkg, 'binaryinfo-tail-failed %s: %s' % (fname, e)) # Undefined symbol and unused direct dependency checks make sense only # for installed packages. # skip debuginfo: https://bugzilla.redhat.com/190599 if not is_ar and not is_debug and isinstance(pkg, Pkg.InstalledPkg): # We could do this with objdump, but it's _much_ simpler with ldd. res = Pkg.getstatusoutput(('ldd', '-d', '-r', path)) if not res[0]: for line in res[1].splitlines(): undef = self.undef_regex.search(line) if undef: self.undef.append(undef.group(1)) if self.undef: try: res = Pkg.getstatusoutput(['c++filt'] + self.undef) if not res[0]: self.undef = res[1].splitlines() except OSError: pass else: printWarning(pkg, 'ldd-failed', fname) res = Pkg.getstatusoutput(('ldd', '-r', '-u', path)) if res[0]: # Either ldd doesn't grok -u (added in glibc 2.3.4) or we have # unused direct dependencies in_unused = False for line in res[1].splitlines(): if not line.rstrip(): pass elif line.startswith('Unused direct dependencies'): in_unused = True elif in_unused: unused = self.unused_regex.search(line) if unused: self.unused.append(unused.group(1)) else: in_unused = False
def check(self, pkg): packager = pkg[rpm.RPMTAG_PACKAGER] if packager: self._unexpanded_macros(pkg, 'Packager', packager) if Config.getOption('Packager') and \ not packager_regex.search(packager): printWarning(pkg, 'invalid-packager', packager) else: printError(pkg, 'no-packager-tag') version = pkg[rpm.RPMTAG_VERSION] if version: self._unexpanded_macros(pkg, 'Version', version) res = invalid_version_regex.search(version) if res: printError(pkg, 'invalid-version', version) else: printError(pkg, 'no-version-tag') release = pkg[rpm.RPMTAG_RELEASE] if release: self._unexpanded_macros(pkg, 'Release', release) if release_ext and not extension_regex.search(release): printWarning(pkg, 'not-standard-release-extension', release) else: printError(pkg, 'no-release-tag') epoch = pkg[rpm.RPMTAG_EPOCH] if epoch is None: if use_epoch: printError(pkg, 'no-epoch-tag') else: if epoch > 99: printWarning(pkg, 'unreasonable-epoch', epoch) epoch = str(epoch) if use_epoch: for tag in ("obsoletes", "conflicts", "provides", "recommends", "suggests", "enhances", "supplements"): for x in (x for x in getattr(pkg, tag)() if x[1] and x[2][0] is None): printWarning(pkg, 'no-epoch-in-%s' % tag, Pkg.formatRequire(*x)) name = pkg.name deps = pkg.requires() + pkg.prereq() devel_depend = False is_devel = FilesCheck.devel_regex.search(name) is_source = pkg.isSource() for d in deps: value = Pkg.formatRequire(*d) if use_epoch and d[1] and d[2][0] is None and \ not d[0].startswith('rpmlib('): printWarning(pkg, 'no-epoch-in-dependency', value) for r in INVALID_REQUIRES: if r.search(d[0]): printError(pkg, 'invalid-dependency', d[0]) if d[0].startswith('/usr/local/'): printError(pkg, 'invalid-dependency', d[0]) if is_source: if lib_devel_number_regex.search(d[0]): printError(pkg, 'invalid-build-requires', d[0]) elif not is_devel: if not devel_depend and FilesCheck.devel_regex.search(d[0]): printError(pkg, 'devel-dependency', d[0]) devel_depend = True if not d[1]: res = lib_package_regex.search(d[0]) if res and not res.group(1): printError(pkg, 'explicit-lib-dependency', d[0]) if d[1] == rpm.RPMSENSE_EQUAL and d[2][2] is not None: printWarning(pkg, 'requires-on-release', value) self._unexpanded_macros(pkg, 'dependency %s' % (value, ), value) self._unexpanded_macros(pkg, 'Name', name) if not name: printError(pkg, 'no-name-tag') else: if is_devel and not is_source: base = is_devel.group(1) dep = None has_so = False for fname in pkg.files(): if fname.endswith('.so'): has_so = True break if has_so: base_or_libs = base + '/' + base + '-libs/lib' + base # try to match *%_isa as well (e.g. "(x86-64)", "(x86-32)") base_or_libs_re = re.compile( r'^(lib)?%s(-libs)?(\(\w+-\d+\))?$' % re.escape(base)) for d in deps: if base_or_libs_re.match(d[0]): dep = d break if not dep: printWarning(pkg, 'no-dependency-on', base_or_libs) elif version: exp = (epoch, version, None) sexp = Pkg.versionToString(exp) if not dep[1]: printWarning(pkg, 'no-version-dependency-on', base_or_libs, sexp) elif dep[2][:2] != exp[:2]: printWarning( pkg, 'incoherent-version-dependency-on', base_or_libs, Pkg.versionToString( (dep[2][0], dep[2][1], None)), sexp) res = devel_number_regex.search(name) if not res: printWarning(pkg, 'no-major-in-name', name) else: if res.group(3): prov = res.group(1) + res.group(2) + '-devel' else: prov = res.group(1) + '-devel' if prov not in (x[0] for x in pkg.provides()): printWarning(pkg, 'no-provides', prov) # List of words to ignore in spell check ignored_words = set() for pf in pkg.files(): ignored_words.update(pf.split('/')) ignored_words.update((x[0] for x in pkg.provides())) ignored_words.update((x[0] for x in pkg.requires())) ignored_words.update((x[0] for x in pkg.conflicts())) ignored_words.update((x[0] for x in pkg.obsoletes())) langs = pkg[rpm.RPMTAG_HEADERI18NTABLE] summary = pkg[rpm.RPMTAG_SUMMARY] if summary: if not langs: self._unexpanded_macros(pkg, 'Summary', Pkg.b2s(summary)) else: for lang in langs: self.check_summary(pkg, lang, ignored_words) else: printError(pkg, 'no-summary-tag') description = pkg[rpm.RPMTAG_DESCRIPTION] if description: if not langs: self._unexpanded_macros(pkg, '%description', Pkg.b2s(description)) else: for lang in langs: self.check_description(pkg, lang, ignored_words) if len(Pkg.b2s(description)) < len(pkg[rpm.RPMTAG_SUMMARY]): printWarning(pkg, 'description-shorter-than-summary') else: printError(pkg, 'no-description-tag') group = pkg[rpm.RPMTAG_GROUP] self._unexpanded_macros(pkg, 'Group', group) if not group: printError(pkg, 'no-group-tag') elif VALID_GROUPS and group not in VALID_GROUPS: printWarning(pkg, 'non-standard-group', group) buildhost = pkg[rpm.RPMTAG_BUILDHOST] self._unexpanded_macros(pkg, 'BuildHost', buildhost) if not buildhost: printError(pkg, 'no-buildhost-tag') elif Config.getOption('ValidBuildHost') and \ not valid_buildhost_regex.search(buildhost): printWarning(pkg, 'invalid-buildhost', buildhost) changelog = pkg[rpm.RPMTAG_CHANGELOGNAME] if not changelog: printError(pkg, 'no-changelogname-tag') else: clt = pkg[rpm.RPMTAG_CHANGELOGTEXT] if use_version_in_changelog: ret = changelog_version_regex.search(Pkg.b2s(changelog[0])) if not ret and clt: # we also allow the version specified as the first # thing on the first line of the text ret = changelog_text_version_regex.search(Pkg.b2s(clt[0])) if not ret: printWarning(pkg, 'no-version-in-last-changelog') elif version and release: srpm = pkg[rpm.RPMTAG_SOURCERPM] or '' # only check when source name correspond to name if srpm[0:-8] == '%s-%s-%s' % (name, version, release): expected = [version + '-' + release] if epoch is not None: # regardless of use_epoch expected[0] = str(epoch) + ':' + expected[0] # Allow EVR in changelog without release extension, # the extension is often a macro or otherwise dynamic. if release_ext: expected.append( extension_regex.sub('', expected[0])) if ret.group(1) not in expected: if len(expected) == 1: expected = expected[0] printWarning(pkg, 'incoherent-version-in-changelog', ret.group(1), expected) if use_utf8: if clt: changelog = changelog + clt for s in changelog: if not Pkg.is_utf8_bytestr(s): printError(pkg, 'tag-not-utf8', '%changelog') break clt = pkg[rpm.RPMTAG_CHANGELOGTIME][0] if clt: clt -= clt % (24 * 3600) # roll back to 00:00:00, see #246 if clt < oldest_changelog_timestamp: printWarning(pkg, 'changelog-time-overflow', time.strftime("%Y-%m-%d", time.gmtime(clt))) elif clt > time.time(): printError(pkg, 'changelog-time-in-future', time.strftime("%Y-%m-%d", time.gmtime(clt))) # for provide_name in (x[0] for x in pkg.provides()): # if name == provide_name: # printWarning(pkg, 'package-provides-itself') # break def split_license(license): return (x.strip() for x in (l for l in license_regex.split(license) if l)) rpm_license = pkg[rpm.RPMTAG_LICENSE] if not rpm_license: printError(pkg, 'no-license') else: valid_license = True if rpm_license not in VALID_LICENSES: for l1 in split_license(rpm_license): if l1 in VALID_LICENSES: continue for l2 in split_license(l1): if l2 not in VALID_LICENSES: printWarning(pkg, 'invalid-license', l2) valid_license = False if not valid_license: self._unexpanded_macros(pkg, 'License', rpm_license) for tag in ('URL', 'DistURL', 'BugURL'): if hasattr(rpm, 'RPMTAG_%s' % tag.upper()): url = Pkg.b2s(pkg[getattr(rpm, 'RPMTAG_%s' % tag.upper())]) self._unexpanded_macros(pkg, tag, url, is_url=True) if url: (scheme, netloc) = urlparse(url)[0:2] if not scheme or not netloc or "." not in netloc or \ scheme not in ('http', 'https', 'ftp') or \ (Config.getOption('InvalidURL') and invalid_url_regex.search(url)): printWarning(pkg, 'invalid-url', tag, url) else: self.check_url(pkg, tag, url) elif tag == 'URL': printWarning(pkg, 'no-url-tag') obs_names = [x[0] for x in pkg.obsoletes()] prov_names = [x[0] for x in pkg.provides()] for o in (x for x in obs_names if x not in prov_names): printWarning(pkg, 'obsolete-not-provided', o) for o in pkg.obsoletes(): value = Pkg.formatRequire(*o) self._unexpanded_macros(pkg, 'Obsoletes %s' % (value, ), value) # TODO: should take versions, <, <=, =, >=, > into account here # https://bugzilla.redhat.com/460872 useless_provides = set() for p in prov_names: if (prov_names.count(p) != 1 and not p.startswith('debuginfo(') and p not in useless_provides): useless_provides.add(p) for p in sorted(useless_provides): printError(pkg, 'useless-provides', p) for tagname, items in (('Provides', pkg.provides()), ('Conflicts', pkg.conflicts()), ('Obsoletes', pkg.obsoletes()), ('Supplements', pkg.supplements()), ('Suggests', pkg.suggests()), ('Enhances', pkg.enhances()), ('Recommends', pkg.recommends())): for p in items: value = Pkg.formatRequire(*p) self._unexpanded_macros(pkg, '%s %s' % (tagname, value), value) obss = pkg.obsoletes() if obss: provs = pkg.provides() for prov in provs: for obs in obss: if Pkg.rangeCompare(obs, prov): printWarning( pkg, 'self-obsoletion', '%s obsoletes %s' % (Pkg.formatRequire(*obs), Pkg.formatRequire(*prov))) expfmt = rpm.expandMacro("%{_build_name_fmt}") if pkg.isSource(): # _build_name_fmt often (always?) ends up not outputting src/nosrc # as arch for source packages, do it ourselves expfmt = re.sub(r'(?i)%\{?ARCH\b\}?', pkg.arch, expfmt) expected = pkg.header.sprintf(expfmt).split("/")[-1] basename = os.path.basename(pkg.filename) if basename != expected: printWarning(pkg, 'non-coherent-filename', basename, expected) for tag in ('Distribution', 'DistTag', 'ExcludeArch', 'ExcludeOS', 'Vendor'): if hasattr(rpm, 'RPMTAG_%s' % tag.upper()): res = Pkg.b2s(pkg[getattr(rpm, 'RPMTAG_%s' % tag.upper())]) self._unexpanded_macros(pkg, tag, res) for path in private_so_paths: for fname, pkgfile in pkg.files().items(): if fname.startswith(path): for prov in pkgfile.provides: if so_dep_regex.search(prov[0]): printWarning(pkg, "private-shared-object-provides", fname, Pkg.formatRequire(*prov))
def check_aux(self, pkg, files, prog, script, tag, prereq): if script: script_str = Pkg.b2s(script) if prog: if prog not in valid_shells: printError(pkg, 'invalid-shell-in-' + tag, prog) if prog in empty_shells: printError(pkg, 'non-empty-' + tag, prog) if prog in syntaxcheck_shells or prog == '/usr/bin/perl': if percent_regex.search(script_str): printWarning(pkg, 'percent-in-' + tag) if bracket_regex.search(script_str): printWarning(pkg, 'spurious-bracket-in-' + tag) res = dangerous_command_regex.search(script_str) if res: printWarning(pkg, 'dangerous-command-in-' + tag, res.group(2)) res = selinux_regex.search(script_str) if res: printError(pkg, 'forbidden-selinux-command-in-' + tag, res.group(2)) if 'update-menus' in script_str: menu_error = True for f in files: if menu_regex.search(f): menu_error = False break if menu_error: printError(pkg, 'update-menus-without-menu-file-in-' + tag) if tmp_regex.search(script_str): printError(pkg, 'use-tmp-in-' + tag) for c in prereq_assoc: if c[0].search(script_str): found = False for p in c[1]: if p in prereq or p in files: found = True break if not found: printError(pkg, 'no-prereq-on', c[1][0]) if prog in syntaxcheck_shells: if incorrect_shell_script(prog, script): printError(pkg, 'shell-syntax-error-in-' + tag) if home_regex.search(script_str): printError(pkg, 'use-of-home-in-' + tag) res = bogus_var_regex.search(script_str) if res: printWarning(pkg, 'bogus-variable-use-in-' + tag, res.group(1)) if prog == '/usr/bin/perl': if incorrect_perl_script(prog, script): printError(pkg, 'perl-syntax-error-in-' + tag) elif prog.endswith('sh'): res = single_command_regex.search(script_str) if res: printWarning(pkg, 'one-line-command-in-' + tag, res.group(1)) elif prog not in empty_shells and prog in valid_shells: printWarning(pkg, 'empty-' + tag)
def test_b2s(): for thing in ("foo", ["foo"], None, []): assert thing == Pkg.b2s(thing) assert "foo" == Pkg.b2s(b"foo") assert ["foo"] == Pkg.b2s([b"foo"])