예제 #1
0
def create_policy_from_artifact_and_teardown(request, pytestconfig):
    """
    Implicitly tests ADD and DELETE operations for policies
    """

    _logger.info("Loading Policy Bundle JSON from Artifact")
    with open(
            pytestconfig.rootdir +
            '/tests/functional/artifacts/bundle-with-all-rules-2020-08-20.json'
    ) as file:
        policy_bundle_all_rules = json.load(file)

    resp = http_post(['policies'],
                     policy_bundle_all_rules,
                     config=request.param)
    if resp.code != 200:
        raise RequestFailedError(resp.url, resp.code, resp.body)

    policy_id = resp.body.get('policyId')

    def delete_policies():
        del_resp = http_del(['policies', policy_id], config=request.param)
        if del_resp.code != 200:
            raise RequestFailedError(del_resp.url, del_resp.code,
                                     del_resp.body)

    request.addfinalizer(delete_policies)
    return policy_bundle_all_rules, policy_id, request.param
예제 #2
0
def add_alpine_latest_image(request):
    """
    Note: the test_subscriptions depends on this bit...because a subscription won't exist if there is no image added.
    For now, leave this as session scoped (we can make the subscription test create it's own images later)
    TODO: decouple test_subscriptions from this
    """

    resp = http_post(['images'], {'tag': 'alpine:latest'},
                     config=request.param)
    if resp.code != 200:
        raise RequestFailedError(resp.url, resp.code, resp.body)
    image_id = get_image_id(resp)

    def remove_image_by_id():
        remove_resp = http_del(['images', 'by_id', image_id],
                               query={'force': True},
                               config=request.param)
        if remove_resp.code != 200:
            if not does_ft_account_exist():
                # Because this is a session fixture, can't guarantee the order it runs against the account cleanup
                # Therefore, I've observed this finalizer running after the account is deleted. It's not the end of
                # the world, shouldn't be a failed test. If I make this fixture autouse=True, it has been generating an
                # extra matrix of tests which is worse than just letting the finalizer skip
                _logger.info(
                    "{} account does not exist, ignoring for teardown".format(
                        FT_ACCOUNT))
                return
            raise RequestFailedError(remove_resp.url, remove_resp.code,
                                     remove_resp.body)

    request.addfinalizer(remove_image_by_id)
    return resp, request.param
예제 #3
0
def add_and_teardown_registry(request):
    registry_info = get_registry_info()
    registry_payload = {
        'registry': registry_info['service_name'],
        'registry_name': 'localhost',
        'registry_pass': registry_info['pass'],
        'registry_type': 'docker_v2',
        'registry_user': registry_info['user'],
        'registry_verify': False
    }
    _logger.info("Adding Registry. APIConf={}".format(
        str(request.param.__name__)))
    add_registry_resp = http_post(['registries'],
                                  registry_payload,
                                  config=request.param)
    if add_registry_resp.code != 200:
        raise RequestFailedError(add_registry_resp.url, add_registry_resp.code,
                                 add_registry_resp.body)

    def remove_registry():
        _logger.info("Removing Registry. APIConf={}".format(
            str(request.param.__name__)))
        remove_resp = http_del(
            ['registries', quote(registry_info['service_name'])],
            config=request.param)
        if remove_resp.code != 200:
            raise RequestFailedError(
                remove_resp.url, remove_resp.code,
                '' if not hasattr(remove_resp, 'body') else remove_resp.body)

    request.addfinalizer(remove_registry)
    return add_registry_resp, request.param
예제 #4
0
    def test_system_feeds_sync(self, api_conf):
        """
        Should run fairly close to last to ensure test performance
        """
        resp = http_post(['system', 'feeds'], None, {'sync': True}, config=api_conf)

        assert resp == APIResponse(200)
예제 #5
0
 def test_add_user(self, api_conf):
     create_resp = http_post(['accounts', FT_ACCOUNT, 'users'], {
         'username': '******',
         'password': '******'
     },
                             config=api_conf)
     assert create_resp == APIResponse(200)
     delete_ft_account_user('creation_test', api_conf)
예제 #6
0
def create_ft_account_user(username, password, api_conf: callable):
    create_resp = http_post(['accounts', FT_ACCOUNT, 'users'], {
        'username': username,
        'password': password
    },
                            config=api_conf)
    if create_resp.code != 200:
        raise RequestFailedError(create_resp.url, create_resp.code,
                                 create_resp.body)
예제 #7
0
 def test_add_credential(self, api_conf):
     """
     Do an add-in-place (i.e. do not change the password as it is depended on throughout the other tests)
     """
     resp = http_post(['user', 'credentials'], {
         'type': 'password',
         'value': api_conf()['ANCHORE_API_PASS']
     },
                      config=api_conf)
     assert resp == APIResponse(200)
예제 #8
0
def add_subscription(api_conf: callable):
    added_subscription = None
    resp = http_post(['subscriptions'],
                     ALPINE_LATEST_SUBSCRIPTION,
                     config=api_conf)
    if resp.code == 500 and resp.body.get(
            'message') == 'subscription already exists in DB':
        # Already exists
        resp = http_get(['subscriptions'], config=api_conf)
        subscription_list = resp.body
        for subscription in subscription_list:
            if subscription.get(
                    'subscription_type') == 'tag_update' and subscription.get(
                        'subscription_key') == 'docker.io/alpine:latest':
                added_subscription = subscription
                break
    elif resp.code != 200:
        raise RequestFailedError(resp.url, resp.code, resp.body)
    else:
        added_subscription = resp.body[0]
    return added_subscription
예제 #9
0
 def test_add_repository(self, api_conf):
     resp = http_post(['repositories'],
                      None,
                      query={'repository': 'docker.io/alpine'},
                      config=api_conf)
     assert resp == APIResponse(200)
예제 #10
0
def create_functional_test_account_with_teardown(request):
    _logger = logging.getLogger('conftest')
    """
    This fixture implicitly tests get_by_account_name, create, update state, and delete operations, but essentially,
    creates a functional_test account with a user ('ft_user' unless overridden by environment variables), and then
    deletes this account (blocking until deletion is complete) at the end of the test session
    """
    def disable_and_delete_functional_test_account():
        """
        This method wil dynamically, and in a blocking fashion, handle account deletion, which requires that the
        functional_test account be disabled before deletion. If the functional_test account is currently enabled, it
        will disable and then delete the account, waiting for the deletion to complete. If the functional_test account
        is already disabled, it will delete the account,  and wait for the deletion to complete. If the functional_test
        account is currently awaiting deletion, it will wait for the deletion to complete. If the functional_test
        account is not found, it will exit.
        """
        def await_account_deletion():
            """
            This method is helpful for awaiting account deletion of the functional_test account, with a timeout governed
            by DELETE_ACCOUNT_TIMEOUT_SEC. It awaits in 5 second intervals.
            """
            start_time_sec = time.time()
            result = 200
            while result != 404:
                time.sleep(5)
                ft_get_account_resp = http_get(['accounts', FT_ACCOUNT])
                _logger.info(
                    "Waiting for functional_test account to fully delete. Time Elapsed={}sec"
                    .format(int(time.time() - start_time_sec)))
                if not (ft_get_account_resp.code == 200
                        or ft_get_account_resp.code == 404):
                    _logger.error(ft_get_account_resp)
                    raise RequestFailedError(ft_get_account_resp.url,
                                             ft_get_account_resp.code,
                                             ft_get_account_resp.body)
                if time.time() - start_time_sec >= DELETE_ACCOUNT_TIMEOUT_SEC:
                    raise TimeoutError(
                        'Timed out waiting for functional_test account to delete'
                    )

                result = ft_get_account_resp.code

        ft_account_resp = http_get(['accounts', FT_ACCOUNT])

        if ft_account_resp.code == 404:
            _logger.info('functional_test account not found')
            return

        state = ft_account_resp.body.get('state')
        if state == 'enabled':
            _logger.info(
                'functional_test account found, and enabled. Disabling')
            disable_account_resp = http_put(['accounts', FT_ACCOUNT, 'state'],
                                            {'state': 'disabled'})
            if disable_account_resp.code != 200:
                raise RequestFailedError(disable_account_resp.url,
                                         disable_account_resp.code,
                                         disable_account_resp.body)
        elif state == 'deleting':
            _logger.info(
                'functional_test account found, but is currently being deleted'
            )
            await_account_deletion()
            return

        _logger.info('Deleting functional_test account')
        delete_resp = http_del(['accounts', FT_ACCOUNT])
        if not (delete_resp.code == 200 or delete_resp.code == 404):
            raise RequestFailedError(delete_resp.url, delete_resp.code,
                                     delete_resp.body)
        await_account_deletion()

    # Delete the account if it exists already for some reason (sanity check)
    disable_and_delete_functional_test_account()
    _logger.info("Creating functional_test account")
    create_resp = http_post(['accounts'], {
        'name': FT_ACCOUNT,
        'email': '*****@*****.**'
    })
    if create_resp.code != 200:
        raise RequestFailedError(create_resp.url, create_resp.code,
                                 create_resp.body)

    ft_user = get_ft_user()
    _logger.info("Creating functional_test user: {}".format(
        ft_user['username']))
    create_user_resp = http_post(['accounts', FT_ACCOUNT, 'users'], ft_user)
    if create_user_resp.code != 200:
        raise RequestFailedError(create_user_resp.url, create_user_resp.code,
                                 create_user_resp.body)

    # # Need to reach out to rbac-manager to add the user to the full-control role
    # _logger.info("Giving user full control permissions of account")
    #
    # def get_rbac_api_conf():
    #     rbac_api_conf = copy.copy(get_api_conf())
    #     rbac_base_url = 'http://localhost:8229' if not os.getenv('ANCHORE_TEST_RBAC_BASE_URL') \
    #         else os.getenv('ANCHORE_TEST_RBAC_BASE_URL')
    #     rbac_api_conf['ANCHORE_BASE_URL'] = rbac_base_url
    #     return rbac_api_conf
    #
    # rbac_resp = http_post(['roles', 'full-control', 'members'],
    #                       {'username': ft_user['username'], 'for_account': FT_ACCOUNT},
    #                       config=get_rbac_api_conf)
    # if rbac_resp.code != 200:
    #     raise RequestFailedError(rbac_resp.url, rbac_resp.code, rbac_resp.body)

    request.addfinalizer(disable_and_delete_functional_test_account)
    return ft_user
예제 #11
0
def create_and_teardown_archive_rule(request):
    """
    In order to interact with the archives API, a rule must be added first,
    which depends on there being an image added as well:
    1. Add node:latest image (this isn't currently depended upon in other tests)
    2. Add Archive Rule

    Note: This appears to only work for the root user ATM, so don't run w/ ft_user
    """
    _logger.info("Adding alpine:edge Image for analysis")
    add_image_resp = http_post(['images'], {'tag': 'alpine:edge'},
                               config=request.param)
    if add_image_resp.code != 200:
        raise RequestFailedError(add_image_resp.url, add_image_resp.code,
                                 add_image_resp.body)

    wait_for_image_to_analyze(get_image_id(add_image_resp), request.param)

    archive_rule_json = {
        "analysis_age_days": 0,
        "created_at": "2020-08-25T17:15:16.865Z",
        "last_updated": "2020-08-25T17:15:16.865Z",
        "selector": {
            "registry": "docker.io",
            "repository": "alpine",
            "tag": "edge"
        },
        "system_global": True,
        "tag_versions_newer": 0,
        "transition": "archive"
    }
    _logger.info('Adding Archive Rule')
    archive_rule_resp = http_post(['archives', 'rules'],
                                  archive_rule_json,
                                  config=request.param)
    if archive_rule_resp.code != 200:
        raise RequestFailedError(archive_rule_resp.url, archive_rule_resp.code,
                                 archive_rule_resp.body)

    archive_resp = http_post(['archives', 'images'],
                             [get_image_digest(add_image_resp)],
                             config=request.param)
    if archive_resp.code != 200:
        raise RequestFailedError(archive_resp.url, archive_resp.code,
                                 archive_resp.body)

    def teardown():
        _logger.info('Removing alpine:edge image from anchore')
        remove_image_resp = http_del(
            ['images', 'by_id',
             get_image_id(add_image_resp)],
            query={'force': True})
        if remove_image_resp.code != 200:
            raise RequestFailedError(remove_image_resp.url,
                                     remove_image_resp.code,
                                     remove_image_resp.body)

        _logger.info('Removing Archive Rule: rule_id={}'.format(
            archive_rule_resp.body['rule_id']))
        remove_rule_resp = http_del(
            ['archives', 'rules', archive_rule_resp.body['rule_id']])
        if remove_rule_resp.code != 200:
            raise RequestFailedError(remove_rule_resp.url,
                                     remove_rule_resp.code,
                                     remove_rule_resp.body)

        delete_archive_image_resp = http_del(
            ['archives', 'images',
             get_image_digest(add_image_resp)],
            config=request.param)
        if delete_archive_image_resp.code != 200:
            raise RequestFailedError(delete_archive_image_resp.url,
                                     delete_archive_image_resp.code,
                                     delete_archive_image_resp.body)

    request.addfinalizer(teardown)

    return add_image_resp, archive_rule_resp, archive_resp, request.param