summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Drake <michael.drake@codethink.co.uk>2015-04-14 11:10:33 +0000
committerMichael Drake <michael.drake@codethink.co.uk>2015-04-15 14:35:26 +0000
commitc244702280771e025bf0e5ed0a83d2ff6921e3ec (patch)
tree5c7199976797c5ea731366fb9cd9a19d512edc82
parentf2384463316e7bd53dc8bb4f52febbf8b4973c30 (diff)
downloadmorph-c244702280771e025bf0e5ed0a83d2ff6921e3ec.tar.gz
Add WIP CVE checking plugin
Change-Id: Iffa52255975eb99f7ca6cf52215cd1f490f5a866
-rw-r--r--morphlib/plugins/cve_check_plugin.py165
1 files changed, 165 insertions, 0 deletions
diff --git a/morphlib/plugins/cve_check_plugin.py b/morphlib/plugins/cve_check_plugin.py
new file mode 100644
index 00000000..8a3694e0
--- /dev/null
+++ b/morphlib/plugins/cve_check_plugin.py
@@ -0,0 +1,165 @@
+# Copyright (C) 2014-2015 Codethink Limited
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# 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.
+
+# This plugin is used as part of the Baserock automated release process.
+#
+# See: <http://wiki.baserock.org/guides/release-process> for more information.
+
+import warnings
+
+import cliapp
+import morphlib
+
+class CVECheckPlugin(cliapp.Plugin):
+
+ def enable(self):
+ self.app.add_subcommand(
+ 'cve-check', self.cve_check,
+ arg_synopsis='REPO REF MORPH [MORPH]...')
+
+ def disable(self):
+ pass
+
+ def cve_check(self, args):
+ '''Certify that any given system definition is reproducable.
+
+ Command line arguments:
+
+ * `REPO` is a git repository URL.
+ * `REF` is a branch or other commit reference in that repository.
+ * `MORPH` is a system morphology name at that ref.
+
+ '''
+
+ if len(args) < 3:
+ raise cliapp.AppException(
+ 'Wrong number of arguments to certify command '
+ '(see help)')
+
+ repo, ref = args[0], args[1]
+ system_filenames = map(morphlib.util.sanitise_morphology_path,
+ args[2:])
+
+ self.lrc, self.rrc = morphlib.util.new_repo_caches(self.app)
+ self.resolver = morphlib.artifactresolver.ArtifactResolver()
+ self.cve_db = CVEDataBase()
+
+ for system_filename in system_filenames:
+ self.certify_system(repo, ref, system_filename)
+
+ def certify_system(self, repo, ref, system_filename):
+ '''Certify reproducibility of system.'''
+
+ self.app.status(
+ msg='Creating source pool for %s' % system_filename, chatty=True)
+ source_pool = morphlib.sourceresolver.create_source_pool(
+ self.lrc, self.rrc, repo, ref, system_filename,
+ cachedir=self.app.settings['cachedir'],
+ update_repos = not self.app.settings['no-git-update'],
+ status_cb=self.app.status)
+
+ self.app.status(
+ msg='Resolving artifacts for %s' % system_filename, chatty=True)
+ root_artifacts = self.resolver.resolve_root_artifacts(source_pool)
+
+ def find_artifact_by_name(artifacts_list, filename):
+ for a in artifacts_list:
+ if a.source.filename == filename:
+ return a
+ raise ValueError
+
+ system_artifact = find_artifact_by_name(root_artifacts,
+ system_filename)
+
+ aliases = self.app.settings['repo-alias']
+ resolver = morphlib.repoaliasresolver.RepoAliasResolver(aliases)
+
+ for source in set(a.source for a in system_artifact.walk()):
+ if source.morphology['kind'] != 'chunk':
+ continue
+
+ name = source.morphology['name']
+ ref = source.original_ref
+
+ print(' Checking chunk: {}'.format(name))
+
+ # Ensure we have a cache of the repo
+ if not self.lrc.has_repo(source.repo_name):
+ self.lrc.cache_repo(source.repo_name)
+
+ cached = self.lrc.get_repo(source.repo_name)
+ version = cached.version_guess(ref)
+
+ self.cve_db.check_vulnerability(name, version)
+
+
+class CVEDetail:
+ """
+ A single CVE
+ """
+
+ def __init__(self, id, ranges):
+ self.id = id
+ self.ranges = ranges
+
+ def check_vulnerability(self, version):
+ for r in self.ranges:
+ print(' {}: version is {}; vulnerable range is: {} to {}'.
+ format(self.id, version, r[0], r[1]))
+
+class CVESoftware:
+ """
+ A piece of software we track CVEs for
+ """
+
+ def __init__(self, name):
+ self.name = name
+ self.cves = []
+
+ def add_cve(self, id, ranges):
+ cve = CVEDetail(id, ranges)
+ self.cves.append(cve)
+
+ def check_vulnerability(self, version):
+ for v in self.cves:
+ v.check_vulnerability(version)
+
+class CVEDataBase:
+ """
+ Provides CVE checking functionality
+ """
+
+ def __init__(self):
+ # TODO: In the future this could connect to a DB or load YAML data
+ # For now it just creates a hardcoded DB
+ self.db = []
+
+ # Add LibPNG
+ libpng = CVESoftware('libpng')
+ libpng.add_cve('CVE-2014-9495',
+ [['0', '1.5.20'],
+ ['1.6.9', '1.6.15']])
+ libpng.add_cve('CVE-2014-0333',
+ [['1.6.0', '1.6.9']])
+
+ self.db.append(libpng)
+
+ def check_vulnerability(self, name, version):
+ for s in self.db:
+ if s.name != name:
+ continue
+
+ s.check_vulnerability(version)
+ break