# -*- coding:utf-8 -*- # # Copyright 2014 Hewlett-Packard Development Company, L.P. # # 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. import importlib import logging from bandit.core import blacklisting from bandit.core import extension_loader LOG = logging.getLogger(__name__) class BanditTestSet(object): def __init__(self, config, profile=None): if not profile: profile = {} extman = extension_loader.MANAGER filtering = self._get_filter(config, profile) self.plugins = [p for p in extman.plugins if p.plugin._test_id in filtering] self.plugins.extend(self._load_builtins(filtering, profile)) self._load_tests(config, self.plugins) @staticmethod def _get_filter(config, profile): extman = extension_loader.MANAGER inc = set(profile.get('include', [])) exc = set(profile.get('exclude', [])) all_blacklist_tests = set() for _node, tests in extman.blacklist.items(): all_blacklist_tests.update(t['id'] for t in tests) # this block is purely for backwards compatibility, the rules are as # follows: # B001,B401 means B401 # B401 means B401 # B001 means all blacklist tests if 'B001' in inc: if not inc.intersection(all_blacklist_tests): inc.update(all_blacklist_tests) inc.discard('B001') if 'B001' in exc: if not exc.intersection(all_blacklist_tests): exc.update(all_blacklist_tests) exc.discard('B001') if inc: filtered = inc else: filtered = set(extman.plugins_by_id.keys()) filtered.update(extman.builtin) filtered.update(all_blacklist_tests) return filtered - exc def _load_builtins(self, filtering, profile): '''loads up builtin functions, so they can be filtered.''' class Wrapper(object): def __init__(self, name, plugin): self.name = name self.plugin = plugin extman = extension_loader.MANAGER blacklist = profile.get('blacklist') if not blacklist: # not overridden by legacy data blacklist = {} for node, tests in extman.blacklist.items(): values = [t for t in tests if t['id'] in filtering] if values: blacklist[node] = values if not blacklist: return [] # this dresses up the blacklist to look like a plugin, but # the '_checks' data comes from the blacklist information. # the '_config' is the filtered blacklist data set. setattr(blacklisting.blacklist, "_test_id", 'B001') setattr(blacklisting.blacklist, "_checks", blacklist.keys()) setattr(blacklisting.blacklist, "_config", blacklist) return [Wrapper('blacklist', blacklisting.blacklist)] def _load_tests(self, config, plugins): '''Builds a dict mapping tests to node types.''' self.tests = {} for plugin in plugins: if hasattr(plugin.plugin, '_takes_config'): # TODO(??): config could come from profile ... cfg = config.get_option(plugin.plugin._takes_config) if cfg is None: genner = importlib.import_module(plugin.plugin.__module__) cfg = genner.gen_config(plugin.plugin._takes_config) plugin.plugin._config = cfg for check in plugin.plugin._checks: self.tests.setdefault(check, []).append(plugin.plugin) LOG.debug('added function %s (%s) targeting %s', plugin.name, plugin.plugin._test_id, check) def get_tests(self, checktype): '''Returns all tests that are of type checktype :param checktype: The type of test to filter on :return: A list of tests which are of the specified type ''' return self.tests.get(checktype) or []