diff --git a/conftest.py b/conftest.py index 6b4211e..74816d9 100644 --- a/conftest.py +++ b/conftest.py @@ -10,7 +10,6 @@ from aws.client import BotocoreClient from gcp.client import GCPClient from gsuite.client import GsuiteClient -from heroku.client import HerokuAdminClient from github.client import GitHubClient import custom_config @@ -19,7 +18,6 @@ botocore_client = None gcp_client = None gsuite_client = None -heroku_client = None github_client = None # globals in conftest.py are hard to import from several levels down, so provide access function @@ -79,7 +77,6 @@ def pytest_configure(config): global botocore_client global gcp_client global gsuite_client - global heroku_client global github_client # monkeypatch cache.set to serialize datetime.datetime's @@ -105,15 +102,6 @@ def pytest_configure(config): offline=config.getoption("--offline"), ) - heroku_client = HerokuAdminClient( - organization=organization, - # cache=config.cache, - cache=None, - debug_calls=config.getoption("--debug-calls"), - debug_cache=config.getoption("--debug-cache"), - offline=config.getoption("--offline"), - ) - github_client = GitHubClient( debug_calls=config.getoption("--debug-calls"), offline=config.getoption("--offline"), @@ -139,8 +127,7 @@ def aws_config(pytestconfig): def pytest_runtest_setup(item): - """ - """ + """""" if not isinstance(item, DoctestItem): item.config.custom_config.add_markers(item) @@ -252,8 +239,7 @@ def get_outcome_and_reason(report, markers, call): def clean_docstring(docstr): - """ - Transforms a docstring into a properly formatted single line string. + """Transforms a docstring into a properly formatted single line string. >>> clean_docstring("\\nfoo\\n bar\\n") 'foo bar' diff --git a/heroku/__init__.py b/heroku/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/heroku/client.py b/heroku/client.py deleted file mode 100644 index ad12d39..0000000 --- a/heroku/client.py +++ /dev/null @@ -1,192 +0,0 @@ -# from herokuadmintools import verify_access, session -from herokuadmintools import find_users_missing_2fa, find_affected_apps - - -def cache_key(organization, method, *args, **kwargs): - """Returns the fullname (directory and filename) for a Heroku API call. - - >>> cache_key( - ... 'organization_name', - ... 'method_name', - ... 'arg1', 'arg2', - ... kwarg1=True, - ... ) - 'pytest_heroku:organization_name:method_name:arg1,arg2:kwarg1=True.json' - """ - return ( - ":".join( - [ - "pytest_heroku", - str(organization), - str(method), - ",".join(args), - ",".join(f"{k}={v}" for (k, v) in kwargs.items()), - ] - ) - + ".json" - ) - - -def get_heroku_resource( - organization, - method_name, - call_args, - call_kwargs, - cache=None, - result_from_error=None, - debug_calls=False, - debug_cache=False, -): - """Fetches and return final data. - - TODO: more refactoring of herokuadmintools needed, so can: - - cache all members - - cache all apps of member - """ - if debug_calls: - print("calling", method_name, "on", organization) - - result = None - if cache is not None: - ckey = cache_key(organization, method_name) - result = cache.get(ckey, None) - - if debug_cache and result is not None: - print("found cached value for", ckey) - - if result is None: - # convert from defaultdict with values as sets - users = {k: list(v) for k, v in find_users_missing_2fa(organization).items()} - apps = {k: list(v) for k, v in find_affected_apps(users, organization).items()} - result = [{HerokuDataSets.ROLE_USER: users, HerokuDataSets.APP_USER: apps}] - - if cache is not None: - if debug_cache: - print("setting cache value for", ckey) - - cache.set(ckey, result) - - return result - - -class HerokuDataSets: - # We use an IntEnum so keys can be ordered, which is done deep in some - # libraries when we use the enums as dict keys - ROLE_USER = 1 # tuple of (role, user) - APP_USER = 2 # tuple of (app, user) - - -class HerokuAdminClient: - - # ensure we have access from instance - data_set_names = HerokuDataSets - - def __init__(self, organization, cache, debug_calls, debug_cache, offline): - self.organization = organization - self.cache = cache - - self.debug_calls = debug_calls - self.debug_cache = debug_cache - self.offline = offline - - self.results = [] - - def get( - self, - method_name, - call_args, - call_kwargs, - result_from_error=None, - do_not_cache=False, - ): - - if self.offline: - self.results = [] - else: - self.results = list( - get_heroku_resource( - self.organization, - method_name, - call_args, - call_kwargs, - cache=self.cache if not do_not_cache else None, - result_from_error=result_from_error, - debug_calls=self.debug_calls, - debug_cache=self.debug_cache, - ) - ) - - return self - - def find_users_missing_2fa(self): - return self.extract_key(HerokuDataSets.ROLE_USER, {}) - - def find_affected_apps(self): - return self.extract_key(HerokuDataSets.APP_USER, {}) - - def values(self): - """Returns the wrapped value. - - >>> c = HerokuAdminClient([None], None, None, None, offline=True) - >>> c.results = [] - >>> c.values() - [] - """ - return self.results - - def extract_key(self, key, default=None): - """From an iterable of dicts returns the value with the given keys - discarding other values: - - >>> c = HerokuAdminClient([None], None, None, None, offline=True) - >>> c.results = [{'id': 1}, {'id': 2}] - >>> c.extract_key('id').results - [1, 2] - - When the key does not exist it returns the second arg which defaults to None: - - >>> c = HerokuAdminClient([None], None, None, None, offline=True) - >>> c.results = [{'id': 1}, {}] - >>> c.extract_key('id').results - [1, None] - - But not to primitives: - - >>> c.results = [{'PolicyNames': ['P1', 'P2']}] - >>> c.extract_key('PolicyNames').results - [['P1', 'P2']] - """ - tmp = [] - for result in self.results: - keyed_result = default - - if key in result: - keyed_result = result[key] - - tmp.append(keyed_result) - - self.results = tmp - return self - - def flatten(self): - """Flattens one level of a nested list: - - >>> c = HerokuAdminClient([None], None, None, None, offline=True) - >>> c.results = [['A', 1], ['B']] - >>> c.flatten().values() - ['A', 1, 'B'] - - Only works for a list of lists: - - >>> c.results = [{'A': 1}, {'B': 2}] - >>> c.flatten().values() - Traceback (most recent call last): - ... - TypeError: can only concatenate list (not "dict") to list - """ - self.results = sum(self.results, []) - return self - - def debug(self): - print(self.results) - return self diff --git a/heroku/resources.py b/heroku/resources.py deleted file mode 100644 index e66a54f..0000000 --- a/heroku/resources.py +++ /dev/null @@ -1,29 +0,0 @@ -from conftest import heroku_client - - -def users_no_2fa(): - """ - """ - raw = heroku_client.get("all", [], {}) - just_key = raw.extract_key(heroku_client.data_set_names.ROLE_USER, []) - datum = just_key.results or [{}] - return datum - # ##return heroku_client.get( - # ## 'all', [], {})\ - # ## .extract_key('role_users')\ - # ## .flatten()\ - # ## .values() - - -def app_users_no_2fa(): - """ - """ - raw = heroku_client.get("all", [], {}) - just_key = raw.extract_key(heroku_client.data_set_names.APP_USER, []) - datum = just_key.results or [{}] - return datum - # ##return heroku_client.get( - # ## 'all', [], {})\ - # ## .extract_key('app_users')\ - # ## .flatten()\ - # ## .values() diff --git a/heroku/test_heroku_2fa.py b/heroku/test_heroku_2fa.py deleted file mode 100755 index d7f4772..0000000 --- a/heroku/test_heroku_2fa.py +++ /dev/null @@ -1,67 +0,0 @@ -# TODO: discover why/how the exemptions.py & regressions.py processess screw up -# normal pytest operations. All the fixtures below could/should be in -# the heroku/conftest.py file, and no mark.parametrize would be needed on -# the actual tests. -# -# With the local conftest.py setup, the tests work, but the warnings are -# quite noisy. :/ We're trading off (for the moment at least) test -# readability for output readability. - -# code for heroku/conftest.py START -import pytest -from heroku.resources import users_no_2fa, app_users_no_2fa - - -@pytest.fixture -def affected_users(): - roles = users_no_2fa() - # assert isinstance(roles, type([])) - role = roles[0] - # assert isinstance(role, type({})) - return role - - -@pytest.fixture -def affected_apps(): - apps = app_users_no_2fa() - # assert isinstance(apps, type([])) - app = apps[0] - # assert isinstance(app, type({})) - return app - - -@pytest.fixture -def role_user(): - result = [ - (role, email) for role, emails in affected_users().items() for email in emails - ] - # assert len(result) > 0 - return result - - -@pytest.fixture -def app_user(): - result = [ - (app, email) for app, emails in affected_apps().items() for email in emails - ] - # assert len(result) > 0 - return result - - -# ##def pytest_generate_tests(metafunc): -# ## if 'role_user' in metafunc.fixturenames: -# ## metafunc.parametrize('role_user', role_user()) -# ## elif 'app_user' in metafunc.fixturenames: -# ## metafunc.parametrize('app_user', app_user()) - -# code for heroku/conftest.py END -@pytest.mark.heroku -@pytest.mark.parametrize("role_user", role_user()) -def test_users_have_2fa_enabled(role_user): - assert not role_user - - -@pytest.mark.heroku -@pytest.mark.parametrize("app_user", app_user()) -def test_no_apps_impacted(app_user): - assert not app_user diff --git a/requirements.txt b/requirements.txt index 1b2119f..e528c1f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,7 +6,6 @@ pytest-json==0.4.0 pytest-metadata==1.8.0 pytest==3.10.1 python-dateutil==2.7.5 -git+https://github.com/hwine/python-herokuadmintools.git#egg=herokuadmintools pre-commit==2.5.1 ruamel.yaml==0.15.85 wheel==0.33.1