# -*- coding:utf-8 -*- # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from __future__ import print_function import sys import six from stevedore import extension from bandit.core import utils class Manager(object): # These IDs are for bandit built in tests builtin = [ 'B001' # Built in blacklist test ] def __init__(self, formatters_namespace='bandit.formatters', plugins_namespace='bandit.plugins', blacklists_namespace='bandit.blacklists'): # Cache the extension managers, loaded extensions, and extension names self.load_formatters(formatters_namespace) self.load_plugins(plugins_namespace) self.load_blacklists(blacklists_namespace) def load_formatters(self, formatters_namespace): self.formatters_mgr = extension.ExtensionManager( namespace=formatters_namespace, invoke_on_load=False, verify_requirements=False, ) self.formatters = list(self.formatters_mgr) self.formatter_names = self.formatters_mgr.names() def load_plugins(self, plugins_namespace): self.plugins_mgr = extension.ExtensionManager( namespace=plugins_namespace, invoke_on_load=False, verify_requirements=False, ) def test_has_id(plugin): if not hasattr(plugin.plugin, "_test_id"): # logger not setup yet, so using print print("WARNING: Test '%s' has no ID, skipping." % plugin.name, file=sys.stderr) return False return True self.plugins = list(filter(test_has_id, list(self.plugins_mgr))) self.plugin_names = [plugin.name for plugin in self.plugins] self.plugins_by_id = {p.plugin._test_id: p for p in self.plugins} self.plugins_by_name = {p.name: p for p in self.plugins} def get_plugin_id(self, plugin_name): if plugin_name in self.plugins_by_name: return self.plugins_by_name[plugin_name].plugin._test_id return None def load_blacklists(self, blacklist_namespace): self.blacklists_mgr = extension.ExtensionManager( namespace=blacklist_namespace, invoke_on_load=False, verify_requirements=False, ) self.blacklist = {} blacklist = list(self.blacklists_mgr) for item in blacklist: for key, val in item.plugin().items(): utils.check_ast_node(key) self.blacklist.setdefault(key, []).extend(val) self.blacklist_by_id = {} self.blacklist_by_name = {} for val in six.itervalues(self.blacklist): for b in val: self.blacklist_by_id[b['id']] = b self.blacklist_by_name[b['name']] = b def validate_profile(self, profile): '''Validate that everything in the configured profiles looks good.''' for inc in profile['include']: if not self.check_id(inc): raise ValueError('Unknown test found in profile: %s' % inc) for exc in profile['exclude']: if not self.check_id(exc): raise ValueError('Unknown test found in profile: %s' % exc) union = set(profile['include']) & set(profile['exclude']) if len(union) > 0: raise ValueError('Non-exclusive include/exclude test sets: %s' % union) def check_id(self, test): return ( test in self.plugins_by_id or test in self.blacklist_by_id or test in self.builtin) # Using entry-points and pkg_resources *can* be expensive. So let's load these # once, store them on the object, and have a module global object for # accessing them. After the first time this module is imported, it should save # this attribute on the module and not have to reload the entry-points. MANAGER = Manager()