Exemplo n.º 1
0
    def test_build_commands_names_dict_no_duplicate_names(self):
        """
        Given
        - dictionary containing names of requests from a collection

        When
        - There are no requests with names which have the same kebab case

        Then
        - returns names' dictionary with an entry for each request's name kebab case and the original name
        """
        requests = [{"name": "Test Number One"}, {"name": "Test number two"}]
        names_dict = build_commands_names_dict(requests)
        assert len(names_dict[tools.to_kebab_case("Test Number One")]) == 1
        assert len(names_dict[tools.to_kebab_case("Test number two")]) == 1
        assert len(names_dict) == 2
def build_commands_names_dict(items: list) -> dict:
    names_dict = defaultdict(list)
    for item in items:
        request_name = item.get('name', None)
        if request_name:
            command_name = tools.to_kebab_case(request_name)
            names_dict[command_name].append(request_name)
    return names_dict
Exemplo n.º 3
0
    def test_build_commands_names_dict_none_names(self):
        """
        Given
        - dictionary containing names of requests from a collection

        When
        - There's a request with no name key

        Then
        - returns names' dictionary with an entry for each request's name kebab case and the original name and just them
        """
        requests = [{
            "None": None
        }, {
            "name": "Test number  one"
        }, {
            "name": "Test number two"
        }]
        names_dict = build_commands_names_dict(requests)
        assert len(names_dict[tools.to_kebab_case("Test Number One")]) == 1
        assert len(names_dict[tools.to_kebab_case("Test number two")]) == 1
        assert len(names_dict) == 2
Exemplo n.º 4
0
    def test_build_commands_names_dict_duplicate_names(self):
        """
        Given
        - dictionary containing names of requests from a collection

        When
        - There are requests with names which have the same kebab case

        Then
        - returns names' dictionary with an entry of the matching kebab-case which has a list with the problematic names
        """
        requests = [{
            "name": "Test Number One"
        }, {
            "name": "Test number  one"
        }, {
            "name": "Test number two"
        }]
        names_dict = build_commands_names_dict(requests)
        assert len(names_dict[tools.to_kebab_case("Test Number One")]) == 2
        assert len(names_dict[tools.to_kebab_case("Test number two")]) == 1
        assert len(names_dict) == 2
Exemplo n.º 5
0
def convert_request_to_command(item):
    logger.debug(f'converting request to command: {item.get("name")}')
    command_name = tools.to_kebab_case(item.get('name'))
    context_prefix = tools.to_pascal_case(item.get('name'))

    request = item.get('request', {})

    logger.debug(f'converting postman headers of request: {item.get("name")}')
    headers = postman_headers_to_conf_headers(request.get('header'),
                                              skip_authorization_header=True)

    url_path = ''
    args = []
    outputs = []
    returns_file = False

    logger.debug(f'creating url arguments of request: {item.get("name")}')
    request_url_object = item.get('request').get('url')

    if not request_url_object:
        logger.error(
            f'failed to get item.request.url.path object of request {item.get("name")}. '
            f'Go to Postman, Save the request and try again with the updated collection.'
        )
        return None

    url_path = '/'.join(request_url_object.get('path')).replace('{{',
                                                                '{').replace(
                                                                    '}}', '}')
    for url_path_item in request_url_object.get('path'):
        if re.match(r'\{\{.*\}\}', url_path_item):
            arg = IntegrationGeneratorArg(name=url_path_item.replace(
                '{{', '').replace('}}', ''),
                                          description='',
                                          in_='url')
            args.append(arg)

    logger.debug(f'creating query arguments of request: {item.get("name")}')
    for q in request_url_object.get('query', []):
        arg = IntegrationGeneratorArg(name=q.get('key'),
                                      description='',
                                      in_='query')
        args.append(arg)

    logger.debug(
        f'creating arguments which will be passed to the request body of request: {item.get("name")}'
    )
    request_body = request.get('body')
    body_format = None
    if request_body:
        if request_body.get('mode') == 'raw':
            try:
                body_obj = json.loads(request_body.get('raw'))
                body_format = create_body_format(body_obj)

                for key, value in flatten_json(body_obj).items():
                    path_split = key.split('.')
                    json_path = path_split[:-1]
                    arg_name = path_split[-1]
                    arg = IntegrationGeneratorArg(name=arg_name,
                                                  description='',
                                                  in_='body',
                                                  in_object=json_path)
                    args.append(arg)

            except Exception:
                logger.exception(
                    f'Failed to parse {item.get("name")} request body as JSON.'
                )

    if not item.get('response') or item.get('response') == 0:
        logger.error(
            f'[{item.get("name")}] request is missing response. Make sure to save at least one successful '
            f'response in Postman')
    else:
        response = item.get('response')[0]
        try:
            if response.get('_postman_previewlanguage') == 'json':
                body = json.loads(response.get('body'))
                for key, value in flatten_json(body).items():
                    output = IntegrationGeneratorOutput(
                        name=key, description='', type_=determine_type(value))
                    outputs.append(output)
            elif response.get('_postman_previewlanguage') == 'raw':
                returns_file = True

        except ValueError:
            logger.exception(
                f'Failed to parse to JSON response body of {item.get("name")} request.'
            )

    command = IntegrationGeneratorCommand(
        name=command_name,
        url_path=url_path,
        http_method=request.get('method'),
        headers=headers,
        description=request.get('description'),
        arguments=args,
        outputs=outputs,
        context_path=context_prefix,
        root_object='',
        unique_key='',
        returns_file=returns_file,
        body_format=body_format)

    return command
Exemplo n.º 6
0
def postman_to_autogen_configuration(
        collection_path: Union[Path, str],
        name,
        command_prefix,
        context_path_prefix,
        category=None) -> IntegrationGeneratorConfig:
    with open(collection_path, mode='rb') as f:
        postman_collection = json.load(f)

    info = postman_collection.get('info', {})
    items = postman_collection.get('item', [])
    postman_auth = postman_collection.get('auth', {})
    variable = postman_collection.get('variable', [])

    logger.debug('trying to find the default base url')
    host = ''
    for v in variable:
        if v['key'] in ('url', 'server'):
            host = v['value']
            logger.debug(f'base url found: {host}')
            break

    docker_image = get_docker_image()

    description = ''

    commands = []
    for item in items:
        command = convert_request_to_command(item)

        if command is None:
            # skip command in case is None
            # probably something was wrong with the request and command is not created
            continue

        commands.append(command)

    params = [
        IntegrationGeneratorParam(name='url',
                                  display='Server URL',
                                  type_=ParameterType.STRING,
                                  required=True,
                                  defaultvalue=host
                                  or 'https://www.example.com'),
        IntegrationGeneratorParam(name='proxy',
                                  display='Use system proxy',
                                  type_=ParameterType.BOOLEAN,
                                  required=False),
        IntegrationGeneratorParam(name='insecure',
                                  display='Trust any certificate',
                                  type_=ParameterType.BOOLEAN,
                                  required=False)
    ]

    if postman_auth:
        if postman_auth['type'] == 'apikey':
            params.append(
                IntegrationGeneratorParam(name='api_key',
                                          display='API Key',
                                          type_=ParameterType.ENCRYPTED,
                                          required=True))
        elif postman_auth['type'] == 'bearer':
            params.append(
                IntegrationGeneratorParam(name='token',
                                          display='API Token',
                                          type_=ParameterType.ENCRYPTED,
                                          required=True))
        elif postman_auth['type'] == 'basic':
            params.append(
                IntegrationGeneratorParam(name='credentials',
                                          display='Username',
                                          type_=ParameterType.AUTH,
                                          required=True))
    else:
        # look for apikey in headers
        logger.debug('trying to find apikey in request headers')
        auth_header_found = False
        for item in items:
            if auth_header_found:
                break

            request = item.get('request', {})
            for header in request.get('header', []):
                if header.get('key') == 'Authorization':
                    params.append(
                        IntegrationGeneratorParam(
                            name='api_key',
                            display='API Key',
                            type_=ParameterType.ENCRYPTED,
                            required=True))
                    logger.debug('found Authorization header')

                    if '{{' in header.get('value'):
                        # if header value contains {{ means it has a format like 'Authorization': 'SWSS {{apikey}}'
                        # header_format will be f'SWSS {api_key}'
                        header_format = "f'" + re.sub(
                            r'\{\{.*\}\}', '{params["api_key"]}',
                            header.get('value')) + "'"
                    else:
                        header_format = 'params[\'api_key\']'

                    postman_auth = {
                        'type':
                        'apikey',
                        'apikey': [{
                            "key": "format",
                            "value": header_format,
                            "type": "string"
                        }, {
                            "key": "in",
                            "value": "header",
                            "type": "string"
                        }, {
                            "key": "key",
                            "value": "Authorization",
                            "type": "string"
                        }]
                    }

                    auth_header_found = True
                    break

    if name:
        display_name = name
        id_ = ''.join(e for e in name if e.isalnum())
    elif info.get('name'):
        display_name = info.get('name')
        id_ = ''.join(e for e in info.get('name') if e.isalnum())
    else:
        display_name = 'Generated Name Replace It'
        id_ = 'GeneratedNameReplaceIt'

    config = IntegrationGeneratorConfig(
        name=id_,
        display_name=display_name,
        description=description
        or info.get('description', 'Generated description - REPLACE THIS'),
        params=params,
        category=category or 'Utilities',
        command_prefix=command_prefix or tools.to_kebab_case(id_),
        commands=commands,
        docker_image=docker_image,
        context_path=context_path_prefix or id_,
        url=host,
        base_url_path='',
        auth=postman_auth,
    )

    return config
def convert_request_to_command(item: dict):
    logger.debug(f'converting request to command: {item.get("name")}')
    name = item.get('name')
    assert isinstance(
        name,
        str), 'Could not find name. Is this a valid postman 2.1 collection?'
    command_name = tools.to_kebab_case(name)
    context_prefix = tools.to_pascal_case(name)

    request = item.get('request')
    if request is None:
        raise DemistoException(
            'Could not find request in the collection. Is it a valid postman collection?'
        )

    logger.debug(f'converting postman headers of request: {name}')
    headers = postman_headers_to_conf_headers(request.get('header'),
                                              skip_authorization_header=True)

    args = []
    outputs = []
    returns_file = False

    logger.debug(f'creating url arguments of request: {name}')
    request_url_object = request.get('url')

    if not request_url_object:
        logger.error(
            f'failed to get item.request.url.path object of request {name}. '
            f'Go to Postman, Save the request and try again with the updated collection.'
        )
        return None

    url_path = '/'.join(request_url_object.get('path')).replace('{{',
                                                                '{').replace(
                                                                    '}}', '}')
    for url_path_item in request_url_object.get('path'):
        if re.match(r'\{\{.*\}\}', url_path_item):
            arg = IntegrationGeneratorArg(name=url_path_item.replace(
                '{{', '').replace('}}', ''),
                                          description='',
                                          in_='url')
            args.append(arg)

    for url_path_variable in request_url_object.get('variable', []):
        variable_name = url_path_variable.get('key')
        if not variable_name:
            continue
        arg = IntegrationGeneratorArg(name=variable_name,
                                      description='',
                                      in_='url')
        args.append(arg)
        url_path = url_path.replace(f'/:{variable_name}',
                                    f'/{{{variable_name}}}')

    logger.debug(f'creating query arguments of request: {name}')
    for q in request_url_object.get('query', []):
        arg = IntegrationGeneratorArg(name=q.get('key'),
                                      description='',
                                      in_='query')
        args.append(arg)

    logger.debug(
        f'creating arguments which will be passed to the request body of request: {name}'
    )
    request_body = request.get('body')
    body_format = None
    if request_body:
        if request_body.get('mode') == 'raw':
            try:
                body_obj = json.loads(request_body.get('raw'))
                flattened_json = flatten_json(body_obj)
                shared_arg_to_split_position_dict = find_shared_args_path(
                    flattened_json)

                for key, value in flattened_json.items():
                    path_split = key.split('.')
                    json_path = path_split[:-1]
                    min_unique_path_length = shared_arg_to_split_position_dict[
                        path_split[-1].lower()] + 1
                    arg_name = '_'.join(path_split[-min_unique_path_length:])
                    arg = IntegrationGeneratorArg(name=arg_name,
                                                  description='',
                                                  in_='body',
                                                  in_object=json_path)
                    args.append(arg)

                body_format = create_body_format(body_obj, args)

            except Exception:
                logger.exception(
                    f'Failed to parse {name} request body as JSON.')

    if not item.get('response') or item.get('response') == 0:
        logger.error(
            f'[{name}] request is missing response. Make sure to save at least one successful '
            f'response in Postman')
    else:
        try:
            response = item.get('response')[
                0]  # type: ignore[index]  # It will be catched in the except
            if response.get('_postman_previewlanguage') == 'json':
                outputs = generate_command_outputs(
                    json.loads(response.get('body')))
            elif response.get('_postman_previewlanguage') == 'raw':
                returns_file = True

        except (ValueError, IndexError, TypeError):
            logger.exception(
                f'Failed to parse to JSON response body of {name} request.')

    command = IntegrationGeneratorCommand(
        name=command_name,
        url_path=url_path,
        http_method=request.get('method'),
        headers=headers,
        description=request.get('description') or '',
        arguments=args,
        outputs=outputs,
        context_path=context_prefix,
        root_object='',
        unique_key='',
        returns_file=returns_file,
        body_format=body_format)

    return command