basic security checks with bandit
Fixes: https://pagure.io/koji/issue/3042
This commit is contained in:
parent
0e2ebb4e25
commit
ba2e1e520b
13 changed files with 42 additions and 29 deletions
3
Makefile
3
Makefile
|
|
@ -129,6 +129,9 @@ pypi-upload:
|
||||||
flake8:
|
flake8:
|
||||||
tox -e flake8
|
tox -e flake8
|
||||||
|
|
||||||
|
bandit:
|
||||||
|
tox -e bandit
|
||||||
|
|
||||||
tag::
|
tag::
|
||||||
git tag -a $(TAG)
|
git tag -a $(TAG)
|
||||||
@echo "Tagged with: $(TAG)"
|
@echo "Tagged with: $(TAG)"
|
||||||
|
|
|
||||||
|
|
@ -3994,7 +3994,7 @@ class OzImageTask(BaseTaskHandler):
|
||||||
@return:
|
@return:
|
||||||
an absolute path to the modified XML
|
an absolute path to the modified XML
|
||||||
"""
|
"""
|
||||||
newxml = xml.dom.minidom.parseString(xmltext)
|
newxml = xml.dom.minidom.parseString(xmltext) # nosec
|
||||||
ename = newxml.getElementsByTagName('name')[0]
|
ename = newxml.getElementsByTagName('name')[0]
|
||||||
ename.firstChild.nodeValue = self.imgname
|
ename.firstChild.nodeValue = self.imgname
|
||||||
esources = newxml.getElementsByTagName('source')
|
esources = newxml.getElementsByTagName('source')
|
||||||
|
|
@ -4488,7 +4488,7 @@ class BaseImageTask(OzImageTask):
|
||||||
if not opts.get('scratch'):
|
if not opts.get('scratch'):
|
||||||
# fields = ('name', 'version', 'release', 'arch', 'epoch', 'size',
|
# fields = ('name', 'version', 'release', 'arch', 'epoch', 'size',
|
||||||
# 'payloadhash', 'buildtime')
|
# 'payloadhash', 'buildtime')
|
||||||
icicle = xml.dom.minidom.parseString(images['raw']['icicle'])
|
icicle = xml.dom.minidom.parseString(images['raw']['icicle']) # nosec
|
||||||
self.logger.debug('ICICLE: %s' % images['raw']['icicle'])
|
self.logger.debug('ICICLE: %s' % images['raw']['icicle'])
|
||||||
for p in icicle.getElementsByTagName('extra'):
|
for p in icicle.getElementsByTagName('extra'):
|
||||||
bits = p.firstChild.nodeValue.split(',')
|
bits = p.firstChild.nodeValue.split(',')
|
||||||
|
|
|
||||||
|
|
@ -680,7 +680,7 @@ def download_archive(build, archive, topurl, quiet=False, noprogress=False):
|
||||||
if archive['checksum_type'] == koji.CHECKSUM_TYPES['md5']:
|
if archive['checksum_type'] == koji.CHECKSUM_TYPES['md5']:
|
||||||
hash = md5_constructor()
|
hash = md5_constructor()
|
||||||
elif archive['checksum_type'] == koji.CHECKSUM_TYPES['sha1']:
|
elif archive['checksum_type'] == koji.CHECKSUM_TYPES['sha1']:
|
||||||
hash = hashlib.sha1()
|
hash = hashlib.sha1() # nosec
|
||||||
elif archive['checksum_type'] == koji.CHECKSUM_TYPES['sha256']:
|
elif archive['checksum_type'] == koji.CHECKSUM_TYPES['sha256']:
|
||||||
hash = hashlib.sha256()
|
hash = hashlib.sha256()
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ import json
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
import secrets
|
||||||
import shutil
|
import shutil
|
||||||
import stat
|
import stat
|
||||||
import sys
|
import sys
|
||||||
|
|
@ -72,13 +73,6 @@ from koji.util import (
|
||||||
safer_move,
|
safer_move,
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
|
||||||
# py 3.6+
|
|
||||||
import secrets
|
|
||||||
except ImportError:
|
|
||||||
import random
|
|
||||||
secrets = None
|
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger('koji.hub')
|
logger = logging.getLogger('koji.hub')
|
||||||
|
|
||||||
|
|
@ -6272,11 +6266,7 @@ def generate_token(nbytes=32):
|
||||||
"""
|
"""
|
||||||
Generate random hex-string token of length 2 * nbytes
|
Generate random hex-string token of length 2 * nbytes
|
||||||
"""
|
"""
|
||||||
if secrets:
|
return secrets.token_hex(nbytes=nbytes)
|
||||||
return secrets.token_hex(nbytes=nbytes)
|
|
||||||
else:
|
|
||||||
values = ['%02x' % random.randint(0, 255) for x in range(nbytes)]
|
|
||||||
return ''.join(values)
|
|
||||||
|
|
||||||
|
|
||||||
def get_reservation_token(build_id):
|
def get_reservation_token(build_id):
|
||||||
|
|
|
||||||
|
|
@ -1321,13 +1321,13 @@ def parse_pom(path=None, contents=None):
|
||||||
contents = fixEncoding(contents)
|
contents = fixEncoding(contents)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
xml.sax.parseString(contents, handler)
|
xml.sax.parseString(contents, handler) # nosec - trusted data
|
||||||
except xml.sax.SAXParseException:
|
except xml.sax.SAXParseException:
|
||||||
# likely an undefined entity reference, so lets try replacing
|
# likely an undefined entity reference, so lets try replacing
|
||||||
# any entity refs we can find and see if we get something parseable
|
# any entity refs we can find and see if we get something parseable
|
||||||
handler.reset()
|
handler.reset()
|
||||||
contents = ENTITY_RE.sub('?', contents)
|
contents = ENTITY_RE.sub('?', contents)
|
||||||
xml.sax.parseString(contents, handler)
|
xml.sax.parseString(contents, handler) # nosec - trusted data
|
||||||
|
|
||||||
for field in fields:
|
for field in fields:
|
||||||
if field not in util.to_list(values.keys()):
|
if field not in util.to_list(values.keys()):
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ def md5_constructor(*args, **kwargs):
|
||||||
# do not care about FIPS we need md5 for signatures and older hashes
|
# do not care about FIPS we need md5 for signatures and older hashes
|
||||||
# It is still used for *some* security
|
# It is still used for *some* security
|
||||||
kwargs['usedforsecurity'] = False
|
kwargs['usedforsecurity'] = False
|
||||||
return hashlib.md5(*args, **kwargs)
|
return hashlib.md5(*args, **kwargs) # nosec
|
||||||
|
|
||||||
# END kojikamid dup #
|
# END kojikamid dup #
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
import glob
|
||||||
import os
|
import os
|
||||||
import platform
|
import platform
|
||||||
import re
|
import re
|
||||||
|
|
@ -174,7 +175,11 @@ class RunRootTask(koji.tasks.BaseTaskHandler):
|
||||||
broot.init()
|
broot.init()
|
||||||
rootdir = broot.rootdir()
|
rootdir = broot.rootdir()
|
||||||
# workaround for rpm oddness
|
# workaround for rpm oddness
|
||||||
os.system('rm -f "%s"/var/lib/rpm/__db.*' % rootdir)
|
for f in glob.glob(os.path.join(rootdir, '/var/lib/rpm/__db*')):
|
||||||
|
try:
|
||||||
|
os.unlink(f)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
# update buildroot state (so that updateBuildRootList() will work)
|
# update buildroot state (so that updateBuildRootList() will work)
|
||||||
self.session.host.setBuildRootState(broot.id, 'BUILDING')
|
self.session.host.setBuildRootState(broot.id, 'BUILDING')
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import __main__
|
||||||
__main__.BuildRoot = kojid.BuildRoot
|
__main__.BuildRoot = kojid.BuildRoot
|
||||||
|
|
||||||
import koji
|
import koji
|
||||||
|
import koji.util
|
||||||
import runroot
|
import runroot
|
||||||
|
|
||||||
if six.PY2:
|
if six.PY2:
|
||||||
|
|
@ -346,9 +347,9 @@ class TestHandler(unittest.TestCase):
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
runroot.BuildRoot = kojid.BuildRoot
|
runroot.BuildRoot = kojid.BuildRoot
|
||||||
|
|
||||||
|
@mock.patch('os.unlink')
|
||||||
@mock.patch('platform.uname')
|
@mock.patch('platform.uname')
|
||||||
@mock.patch('os.system')
|
def test_handler_simple(self, platform_uname, os_unlink):
|
||||||
def test_handler_simple(self, os_system, platform_uname):
|
|
||||||
platform_uname.return_value = ('system', 'node', 'release', 'version', 'machine', 'arch')
|
platform_uname.return_value = ('system', 'node', 'release', 'version', 'machine', 'arch')
|
||||||
self.session.getBuildConfig.return_value = {
|
self.session.getBuildConfig.return_value = {
|
||||||
'id': 456,
|
'id': 456,
|
||||||
|
|
@ -381,7 +382,7 @@ class TestHandler(unittest.TestCase):
|
||||||
runroot.BuildRoot.assert_called_once_with(self.session, self.t.options,
|
runroot.BuildRoot.assert_called_once_with(self.session, self.t.options,
|
||||||
'tag_name', 'x86_64', self.t.id, repo_id=1, setup_dns=True,
|
'tag_name', 'x86_64', self.t.id, repo_id=1, setup_dns=True,
|
||||||
internal_dev_setup=None)
|
internal_dev_setup=None)
|
||||||
os_system.assert_called_once()
|
os_unlink.assert_not_called()
|
||||||
self.session.host.setBuildRootState.assert_called_once_with(678, 'BUILDING')
|
self.session.host.setBuildRootState.assert_called_once_with(678, 'BUILDING')
|
||||||
self.br.mock.assert_has_calls([
|
self.br.mock.assert_has_calls([
|
||||||
mock.call(['--install', 'rpm_a', 'rpm_b']),
|
mock.call(['--install', 'rpm_a', 'rpm_b']),
|
||||||
|
|
|
||||||
16
tox.ini
16
tox.ini
|
|
@ -1,5 +1,5 @@
|
||||||
[tox]
|
[tox]
|
||||||
envlist = flake8,py2,py3
|
envlist = flake8,py2,py3,bandit
|
||||||
|
|
||||||
[testenv:flake8]
|
[testenv:flake8]
|
||||||
deps =
|
deps =
|
||||||
|
|
@ -73,3 +73,17 @@ commands_pre =
|
||||||
{[testenv:py2]commands_pre}
|
{[testenv:py2]commands_pre}
|
||||||
commands =
|
commands =
|
||||||
{[testenv:py2]commands}
|
{[testenv:py2]commands}
|
||||||
|
|
||||||
|
[testenv:bandit]
|
||||||
|
# B108 - Insecure usage of temp - we're very often handling it in non-standard way
|
||||||
|
# (temp inside mock, etc)
|
||||||
|
# B608 - hardcoded SQL - not everything is turned into Processors
|
||||||
|
deps =
|
||||||
|
bandit
|
||||||
|
commands =
|
||||||
|
bandit -ll -s B108,B608 -r \
|
||||||
|
builder cli hub koji plugins util vm www \
|
||||||
|
builder/kojid \
|
||||||
|
cli/koji \
|
||||||
|
util/koji-gc util/kojira util/koji-shadow util/koji-sweep-db \
|
||||||
|
vm/kojivmd
|
||||||
|
|
|
||||||
|
|
@ -411,7 +411,7 @@ class TrackedBuild(object):
|
||||||
url = "%s/%s" % (pathinfo.build(self.info), pathinfo.rpm(self.srpm))
|
url = "%s/%s" % (pathinfo.build(self.info), pathinfo.rpm(self.srpm))
|
||||||
log("Downloading %s" % url)
|
log("Downloading %s" % url)
|
||||||
# XXX - this is not really the right place for this
|
# XXX - this is not really the right place for this
|
||||||
fsrc = urllib2.urlopen(url)
|
fsrc = urllib2.urlopen(url) # nosec
|
||||||
fn = "%s/%s.src.rpm" % (options.workpath, self.nvr)
|
fn = "%s/%s.src.rpm" % (options.workpath, self.nvr)
|
||||||
koji.ensuredir(os.path.dirname(fn))
|
koji.ensuredir(os.path.dirname(fn))
|
||||||
fdst = open(fn, 'wb')
|
fdst = open(fn, 'wb')
|
||||||
|
|
@ -856,7 +856,7 @@ class BuildTracker(object):
|
||||||
koji.ensuredir(os.path.dirname(dst))
|
koji.ensuredir(os.path.dirname(dst))
|
||||||
os.chown(os.path.dirname(dst), 48, 48) # XXX - hack
|
os.chown(os.path.dirname(dst), 48, 48) # XXX - hack
|
||||||
log("Downloading %s to %s" % (url, dst))
|
log("Downloading %s to %s" % (url, dst))
|
||||||
fsrc = urllib2.urlopen(url)
|
fsrc = urllib2.urlopen(url) # nosec
|
||||||
fdst = open(fn, 'wb')
|
fdst = open(fn, 'wb')
|
||||||
shutil.copyfileobj(fsrc, fdst)
|
shutil.copyfileobj(fsrc, fdst)
|
||||||
fsrc.close()
|
fsrc.close()
|
||||||
|
|
@ -870,7 +870,7 @@ class BuildTracker(object):
|
||||||
koji.ensuredir(options.workpath)
|
koji.ensuredir(options.workpath)
|
||||||
dst = "%s/%s" % (options.workpath, fn)
|
dst = "%s/%s" % (options.workpath, fn)
|
||||||
log("Downloading %s to %s..." % (url, dst))
|
log("Downloading %s to %s..." % (url, dst))
|
||||||
fsrc = urllib2.urlopen(url)
|
fsrc = urllib2.urlopen(url) # nosec
|
||||||
fdst = open(dst, 'wb')
|
fdst = open(dst, 'wb')
|
||||||
shutil.copyfileobj(fsrc, fdst)
|
shutil.copyfileobj(fsrc, fdst)
|
||||||
fsrc.close()
|
fsrc.close()
|
||||||
|
|
|
||||||
|
|
@ -486,7 +486,7 @@ class RepoManager(object):
|
||||||
self.logger.debug('Checking external url: %s' % arch_url)
|
self.logger.debug('Checking external url: %s' % arch_url)
|
||||||
try:
|
try:
|
||||||
r = requests.get(arch_url, timeout=5)
|
r = requests.get(arch_url, timeout=5)
|
||||||
root = ElementTree.fromstring(r.text)
|
root = ElementTree.fromstring(r.text) # nosec
|
||||||
ts_elements = root.iter('{http://linux.duke.edu/metadata/repo}timestamp')
|
ts_elements = root.iter('{http://linux.duke.edu/metadata/repo}timestamp')
|
||||||
arch_ts = max([round(float(child.text)) for child in ts_elements])
|
arch_ts = max([round(float(child.text)) for child in ts_elements])
|
||||||
self.external_repo_ts[arch_url] = arch_ts
|
self.external_repo_ts[arch_url] = arch_ts
|
||||||
|
|
|
||||||
|
|
@ -326,7 +326,7 @@ class WindowsBuild(object):
|
||||||
if 'checksum_type' in fileinfo:
|
if 'checksum_type' in fileinfo:
|
||||||
checksum_type = CHECKSUM_TYPES[fileinfo['checksum_type']] # noqa: F821
|
checksum_type = CHECKSUM_TYPES[fileinfo['checksum_type']] # noqa: F821
|
||||||
if checksum_type == 'sha1':
|
if checksum_type == 'sha1':
|
||||||
checksum = hashlib.sha1()
|
checksum = hashlib.sha1() # nosec
|
||||||
elif checksum_type == 'sha256':
|
elif checksum_type == 'sha256':
|
||||||
checksum = hashlib.sha256()
|
checksum = hashlib.sha256()
|
||||||
elif checksum_type == 'md5':
|
elif checksum_type == 'md5':
|
||||||
|
|
|
||||||
|
|
@ -795,7 +795,7 @@ class VMExecTask(BaseTaskHandler):
|
||||||
raise koji.BuildError('%s does not exist' % local_path)
|
raise koji.BuildError('%s does not exist' % local_path)
|
||||||
|
|
||||||
if algo == 'sha1':
|
if algo == 'sha1':
|
||||||
sum = hashlib.sha1()
|
sum = hashlib.sha1() # nosec
|
||||||
elif algo == 'md5':
|
elif algo == 'md5':
|
||||||
sum = koji.util.md5_constructor()
|
sum = koji.util.md5_constructor()
|
||||||
elif algo == 'sha256':
|
elif algo == 'sha256':
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue