def get_apikey_permissions(path):
    """
    Returns a list of api keys to allow an integration to run.
    :param path: Location to file with api keys one per line.
    :return apikey_permissions: Return list of api keys.
    """

    try:
        # Read the apikey_permissions.txt file into a List
        apikey_permissions_lines = sdk_helpers.read_file(path)

    except Exception as err:
        raise SDKException(u"Failed to parse configs from apikey_permissions.txt file\nThe apikey_permissions.txt file may "
                           u"be corrupt. Visit the App Exchange to contact the developer\nReason: {0}".format(err))

    # Raise an error if nothing found in the file
    if not apikey_permissions_lines:
        raise SDKException(u"No content found in provided apikey_permissions.txt file: {0}".format(path))

    # Get permissions. Ignore comments where 1st non-whitespace character is a '#'.
    apikey_permissions = [p.strip() for p in apikey_permissions_lines if not p.lstrip().startswith("#")]

    # Do basic check on api keys to see if they are in correct format.
    for p in apikey_permissions:
        if not re.match("[_a-zA-Z]*$", p):
            raise SDKException(u"Value '{0}' in file '{1}' is not a valid api key value.".format(p, path))

    # Ensure that the permissions includes at minimum the set of base permissions.
    if not all(p in apikey_permissions for p in BASE_PERMISSIONS):
        raise SDKException(u"'The file '{0}' is missing one of the base api key permissions.".format(path))

    return apikey_permissions
Exemplo n.º 2
0
def test_read_write_file(fx_mk_temp_dir):
    temp_file = os.path.join(mock_paths.TEST_TEMP_DIR, "mock_file.txt")
    sdk_helpers.write_file(temp_file, mock_data.mock_file_contents)
    assert os.path.isfile(temp_file)

    file_lines = sdk_helpers.read_file(temp_file)
    assert mock_data.mock_file_contents in file_lines
Exemplo n.º 3
0
def test_get_setup_callable():
    # Test callable section returned correctly.
    # Read the mock setup.py content.
    setup_content = sdk_helpers.read_file(mock_paths.MOCK_SETUP_PY)
    setup_callable = package_helpers.get_setup_callable(setup_content)
    # Read the mocked callable from processed setup.py
    with io.open(mock_paths.MOCK_SETUP_CALLABLE, mode="rt", encoding="utf-8") as the_file:
        mock_setup_callable = the_file.read()
    assert mock_setup_callable == setup_callable
Exemplo n.º 4
0
def test_execute_command_no_samples(fx_copy_fn_main_mock_integration,
                                    fx_get_sub_parser,
                                    fx_cmd_line_args_package):
    mock_integration_name = fx_copy_fn_main_mock_integration[0]
    path_fn_main_mock_integration = fx_copy_fn_main_mock_integration[1]

    # Replace cmd line arg "fn_main_mock_integration" with path to temp dir location
    sys.argv[sys.argv.index(
        mock_integration_name)] = path_fn_main_mock_integration

    # Append --no-samples command line arg
    sys.argv.append("--no-samples")

    # Package the app
    cmd_package = CmdPackage(fx_get_sub_parser)
    args = cmd_package.parser.parse_known_args()[0]
    path_the_app_zip = cmd_package.execute_command(args)

    # Test app.zip contents
    assert zipfile.is_zipfile(path_the_app_zip)
    with zipfile.ZipFile((path_the_app_zip), 'r') as app_zip:
        assert helpers.verify_expected_list(EXPECTED_FILES_APP_ZIP[:-1],
                                            app_zip.namelist())

    # Test app.zip/app.json contents
    app_json_contents = sdk_helpers.read_zip_file(path_the_app_zip, "app.json")
    mock_app_json_contents = sdk_helpers.read_file(
        mock_paths.MOCK_APP_ZIP_APP_JSON)[0]
    assert app_json_contents == mock_app_json_contents

    # Test app.zip/export.res contents
    export_res_contents = sdk_helpers.read_zip_file(path_the_app_zip,
                                                    "export.res")
    mock_export_res_contents = sdk_helpers.read_file(
        mock_paths.MOCK_APP_ZIP_EXPORT_RES)[0]
    assert json.loads(export_res_contents) == json.loads(
        mock_export_res_contents)
def test_app_log_results_are_used(fx_copy_fn_main_mock_integration,
                                  fx_get_sub_parser, fx_cmd_line_args_docgen):

    mock_integration_name = fx_copy_fn_main_mock_integration[0]
    path_fn_main_mock_integration = fx_copy_fn_main_mock_integration[1]

    # Replace cmd line arg "fn_main_mock_integration" with path to temp dir location
    sys.argv[sys.argv.index(
        mock_integration_name)] = path_fn_main_mock_integration

    cmd_docgen = CmdDocgen(fx_get_sub_parser)
    args = cmd_docgen.parser.parse_known_args()[0]
    cmd_docgen.execute_command(args)

    readme_file = sdk_helpers.read_file(
        os.path.join(path_fn_main_mock_integration,
                     package_helpers.BASE_NAME_README))

    assert '  "custom_results": "these are my custom results!"' in "\n".join(
        readme_file)
def test_render_jinja_mapping(fx_mk_temp_dir):

    mock_jinja_data = {
        "functions": [{
            "x_api_name": "fn_mock_function_1"
        }, {
            "x_api_name": "fn_mock_function_2"
        }],
        "export_data": {
            "server_version": {
                "version": "35.0.0"
            }
        }
    }

    jinja_env = sdk_helpers.setup_jinja_env(
        "data/codegen/templates/package_template")

    jinja_mapping_dict = {
        "MANIFEST.in": ("MANIFEST.in.jinja2", mock_jinja_data),
        "README.md": ("README.md.jinja2", mock_jinja_data),
        "setup.py": ("setup.py.jinja2", mock_jinja_data),
        "tox.ini": ("tox.ini.jinja2", mock_jinja_data),
        "Dockerfile": ("Dockerfile.jinja2", mock_jinja_data),
        "entrypoint.sh": ("entrypoint.sh.jinja2", mock_jinja_data),
        "apikey_permissions.txt":
        ("apikey_permissions.txt.jinja2", mock_jinja_data),
        "data": {},
        "icons": {
            "company_logo.png": package_helpers.PATH_DEFAULT_ICON_COMPANY_LOGO,
            "app_logo.png": package_helpers.PATH_DEFAULT_ICON_EXTENSION_LOGO,
        },
        "doc": {
            "screenshots": {
                "main.png": package_helpers.PATH_DEFAULT_SCREENSHOT
            }
        },
        "test_package": {
            "__init__.py": ("package/__init__.py.jinja2", mock_jinja_data),
            "LICENSE": ("package/LICENSE.jinja2", mock_jinja_data),
            "components": {
                "__init__.py":
                ("package/components/__init__.py.jinja2", mock_jinja_data),
            },
            "util": {
                "data": {
                    "export.res":
                    ("package/util/data/export.res.jinja2", mock_jinja_data)
                },
                "__init__.py":
                ("package/util/__init__.py.jinja2", mock_jinja_data),
                "config.py":
                ("package/util/config.py.jinja2", mock_jinja_data),
                "customize.py":
                ("package/util/customize.py.jinja2", mock_jinja_data),
                "selftest.py":
                ("package/util/selftest.py.jinja2", mock_jinja_data),
            }
        }
    }

    CmdCodegen.render_jinja_mapping(jinja_mapping_dict, jinja_env,
                                    mock_paths.TEST_TEMP_DIR,
                                    mock_paths.TEST_TEMP_DIR)

    files_in_dir = sorted(os.listdir(mock_paths.TEST_TEMP_DIR))
    assert files_in_dir == [
        'Dockerfile', 'MANIFEST.in', 'README.md', 'apikey_permissions.txt',
        'data', 'doc', 'entrypoint.sh', 'icons', 'setup.py', 'test_package',
        'tox.ini'
    ]

    files_in_icons_dir = sorted(
        os.listdir(os.path.join(mock_paths.TEST_TEMP_DIR, "icons")))
    assert files_in_icons_dir == ['app_logo.png', 'company_logo.png']

    files_in_test_package = sorted(
        os.listdir(os.path.join(mock_paths.TEST_TEMP_DIR, "test_package")))
    assert files_in_test_package == [
        'LICENSE', '__init__.py', 'components', 'util'
    ]

    files_in_util = sorted(
        os.listdir(
            os.path.join(mock_paths.TEST_TEMP_DIR, "test_package", "util")))
    assert files_in_util == [
        '__init__.py', 'config.py', 'customize.py', 'data', 'selftest.py'
    ]

    files_in_util_data = sorted(
        os.listdir(
            os.path.join(mock_paths.TEST_TEMP_DIR, "test_package",
                         package_helpers.PATH_UTIL_DATA_DIR)))
    assert files_in_util_data == ['export.res']

    files_in_components = sorted(
        os.listdir(
            os.path.join(mock_paths.TEST_TEMP_DIR, "test_package",
                         "components")))
    assert files_in_components == ['__init__.py']

    customize_py = sdk_helpers.read_file(
        os.path.join(mock_paths.TEST_TEMP_DIR, "test_package", "util",
                     "customize.py"))
    assert '        "functions": [u"fn_mock_function_1", u"fn_mock_function_2"],\n' in customize_py
Exemplo n.º 7
0
def load_customize_py_module(path_customize_py, warn=True):
    """
    Return the path_customize_file as a Python Module.
    We can then access it methods like:
        > result = customize_py_module.codegen_reload_data()

    Raises an SDKException if we fail to load the module

    :param path_customize_py: Path to the customize.py file that contains the module
    :param warn: Boolean to indicate warning should happen, for codegen usage warning not required.
    :return: The customize Python Module, if found
    :rtype: module
    """
    LINE_TO_REPLACE = u"from resilient_circuits"
    REPLACE_TEXT = u"from resilient import ImportDefinition"

    new_lines = []
    current_customize_py_lines = sdk_helpers.read_file(path_customize_py)

    # Check if customize.py has dependencies on resilient-circuits
    for i, line in enumerate(current_customize_py_lines):
        if line.startswith(LINE_TO_REPLACE):
            new_lines = current_customize_py_lines[:i] + [
                REPLACE_TEXT
            ] + current_customize_py_lines[i + 1:]
            if warn:
                LOG.warning(
                    "WARNING: Import References to resilient-circuits are deprecated in v35.0.195. For newer "
                    "versions of resilient-circuits, replace '%s', with '%s' in %s",
                    line.strip(), REPLACE_TEXT, path_customize_py)
            break

    if new_lines:
        # The customize.py has a reference to a deprecated resilient-circuits import. Save the customize.py
        # file as a temporary file with deprecated resilient-circuits import altered then attempt to load
        # the module from the temporary location.
        temp_customize = u"".join(new_lines)

        if sys.version_info.major == 3:
            temp_file_obj = tempfile.NamedTemporaryFile('w',
                                                        suffix=".py",
                                                        encoding="utf8",
                                                        delete=False)
        else:
            temp_customize = temp_customize.encode('utf-8')
            temp_file_obj = tempfile.NamedTemporaryFile('w+b',
                                                        suffix=".py",
                                                        delete=False)

        try:
            # Write the new temporary customize.py (with resilient-circuits replaced with resilient)
            with temp_file_obj as temp_file:
                temp_file.write(temp_customize)
                temp_file.flush()
                module_name = os.path.basename(temp_file.name)[:-3]

            # Attempt to import the module from the temporary file location.
            customize_py_module = sdk_helpers.load_py_module(
                temp_file.name, module_name)

        except IOError as ioerr:
            raise IOError("Unexpected IO error '{0}' for file '{1}".format(
                ioerr, temp_file.name))

        except Exception as err:
            # An an unexpected error trying to load the module temporary customize module.
            raise SDKException(
                u"Got an error attempting to load temporary customize.py module\n{0}"
                .format(err))

        finally:
            os.unlink(temp_file.name)

    else:
        try:
            customize_py_module = sdk_helpers.load_py_module(
                path_customize_py, "customize")
        except Exception as err:
            raise SDKException(
                u"Failed to load customize.py module\n{0}".format(err))

    return customize_py_module
Exemplo n.º 8
0
def parse_setup_py(path, attribute_names):
    """Parse the values of the given attribute_names and return a Dictionary attribute_name:attribute_value

    :param path: Path to setup.py for a package.
    :param attribute_names: List of attribute names to extract from setup.py.
    :return return_dict: Dict of properties from setup.py.
    """
    return_dict = {}
    # Define "True" = bool(True) as value for eval built_ins if using python 2.
    if sys.version_info.major < 3:
        built_ins = {"True": bool(True), "False": bool(False)}
    else:
        built_ins = {}
    # Define a dummy setup function to get the dictionary of parameters returned from evaled setup.py callable.
    def setup(*args, **kwargs):
        return kwargs

    # Read the setup.py content.
    setup_content = sdk_helpers.read_file(path)

    # Raise an error if nothing found in the file.
    if not setup_content:
        raise SDKException(
            u"No content found in provided setup.py file: {0}".format(path))

    # Get the callable section from contents of setup.py.
    setup_callable = get_setup_callable(setup_content)

    # Run eval on callable content to retrieve attributes.
    try:
        result = eval(setup_callable, {'__builtins__': built_ins},
                      {"setup": setup})
    except Exception as err:
        raise SDKException(u"Failed to eval setup callable {0}".format(err))

    # Foreach attribute_name, get/calculate its value and add to return_dict
    for attribute_name in attribute_names:
        if attribute_name == "entry_points":
            entry_point_paths = {}
            # Get the path of the top level for the package.
            path_package = os.path.dirname(path)
            for ep in SUPPORTED_EP:
                if result['entry_points'].get(ep):
                    # Extract the relative dotted module reference from entry point values of following types:
                    #      ["customize = fn_func.util.customize:customization_data"]
                    #      ["gen_config = fn_func.util.config:apphost_config_section_data"]
                    #      ["gen_config = fn_func.util.config:config_section_data"]
                    # e.g. Extract ["customize = fn_func.util.customize:customization_data"] -> fn_func.util.customize
                    parsed_ep = ''.join(result['entry_points'].get(ep)).split(
                        '=')[1].split(':')[0].strip()
                    # Convert a dotted module reference to an actual python module path:
                    # e.g. Convert fn_func.util.customize -> /path_to_package/fn_func/fn_func/util/customize.py
                    entry_point_paths.update({
                        ep:
                        os.path.join(path_package,
                                     parsed_ep.replace(".", os.path.sep)) +
                        ".py"
                    })
            return_dict[attribute_name] = entry_point_paths
        else:
            return_dict[attribute_name] = result.get(attribute_name)

    return return_dict