Ejemplo n.º 1
0
    def test_run_query_executes_desired_query(self, mocker):
        mocker.patch("sqlalchemy.create_engine")
        conn = SnowflakeConnector()
        query = "MY FUN TESTING QUERY"

        conn.run_query(query)

        conn.engine.assert_has_calls([mocker.call.connect().__enter__().execute(query)])
    def test_run_query_returns_results(self, mocker):
        mocker.patch("sqlalchemy.create_engine")
        conn = SnowflakeConnector()
        expectedResult = "MY DATABASE RESULT"
        mocker.patch.object(conn.engine.connect().__enter__(),
                            "execute",
                            return_value=expectedResult)

        result = conn.run_query("query")

        assert result is expectedResult
Ejemplo n.º 3
0
    def test_snowflaky(self):

        db1 = "analytics.schema.table"
        db2 = "1234raw.schema.table"
        db3 = '"123-with-quotes".schema.table'
        db4 = "1_db-9-RANDOM.schema.table"

        assert SnowflakeConnector.snowflaky(db1) == "analytics.schema.table"
        assert SnowflakeConnector.snowflaky(db2) == "1234raw.schema.table"
        assert SnowflakeConnector.snowflaky(db3) == '"123-with-quotes".schema.table'
        assert SnowflakeConnector.snowflaky(db4) == '"1_db-9-RANDOM".schema.table'
Ejemplo n.º 4
0
    def test_get_current_user(self, mocker):
        mocker.patch("sqlalchemy.create_engine")
        conn = SnowflakeConnector()
        conn.run_query = mocker.MagicMock()
        mocker.patch.object(
            conn.run_query(), "fetchone", return_value={"user": "******"}
        )

        user = conn.get_current_user()

        conn.run_query.assert_has_calls([mocker.call("SELECT CURRENT_USER() AS USER")])
        assert user == "test_user"
Ejemplo n.º 5
0
    def test_get_current_role(self, mocker):
        mocker.patch("sqlalchemy.create_engine")
        conn = SnowflakeConnector()
        conn.run_query = mocker.MagicMock()
        mocker.patch.object(
            conn.run_query(), "fetchone", return_value={"role": "TEST_ROLE"}
        )

        role = conn.get_current_role()

        conn.run_query.assert_has_calls([mocker.call("SELECT CURRENT_ROLE() AS ROLE")])
        assert role == "test_role"
Ejemplo n.º 6
0
 def test_uses_username_password_by_default(
     selfself, mocker, snowflake_connector_env
 ):
     mocker.patch("sqlalchemy.create_engine")
     SnowflakeConnector()
     sqlalchemy.create_engine.assert_called_with(
         "snowflake://*****:*****@TEST/TEST?role=TEST&warehouse=TEST"
     )
Ejemplo n.º 7
0
 def test_uses_oauth_if_available(selfself, mocker, snowflake_connector_env):
     mocker.patch("sqlalchemy.create_engine")
     os.environ["PERMISSION_BOT_OAUTH_TOKEN"] = "TEST"
     SnowflakeConnector()
     del os.environ["PERMISSION_BOT_OAUTH_TOKEN"]
     sqlalchemy.create_engine.assert_called_with(
         "snowflake://TEST:@TEST/?authenticator=oauth&token=TEST&warehouse=TEST"
     )
Ejemplo n.º 8
0
    def test_show_roles(self, mocker):
        mocker.patch("sqlalchemy.create_engine")
        conn = SnowflakeConnector()
        conn.run_query = mocker.MagicMock()
        mocker.patch.object(
            conn.run_query(),
            "fetchall",
            return_value=[
                {"name": "TEST_ROLE", "owner": "SUPERADMIN"},
                {"name": "SUPERADMIN", "owner": "SUPERADMIN"},
            ],
        )

        roles = conn.show_roles()

        conn.run_query.assert_has_calls([mocker.call("SHOW ROLES")])
        assert roles["test_role"] == "superadmin"
        assert roles["superadmin"] == "superadmin"
Ejemplo n.º 9
0
def grant(spec, dry, diff):
    """Grant the permissions provided in the provided specification file."""
    try:
        spec_loader = SnowflakeSpecLoader(spec)

        sql_grant_queries = spec_loader.generate_permission_queries()

        click.secho()
        if diff:
            click.secho(
                "SQL Commands generated for given spec file (Full diff with both new and already granted commands):"
            )
        else:
            click.secho("SQL Commands generated for given spec file:")
        click.secho()

        conn = SnowflakeConnector()
        for query in sql_grant_queries:
            if not dry:
                status = None
                if not query.get("already_granted"):
                    try:
                        result = conn.run_query(query.get("sql"))
                        outcome = result.fetchall()
                        status = True
                    except:
                        status = False

                    ran_query = query
                    ran_query["run_status"] = status
                    print_command(ran_query, diff)
                # If already granted, print command
                else:
                    print_command(query, diff)
            # If dry, print commands
            else:
                print_command(query, diff)

    except SpecLoadingError as exc:
        for line in str(exc).splitlines():
            click.secho(line, fg="red")
        sys.exit(1)
Ejemplo n.º 10
0
    def check_permissions_on_snowflake_server(self,
                                              conn: SnowflakeConnector = None
                                              ) -> None:
        if conn is None:
            conn = SnowflakeConnector()
        error_messages = []

        click.secho(f"  Current user is: {conn.get_current_user()}.",
                    fg="green")

        current_role = conn.get_current_role()
        if "securityadmin" != current_role:
            error_messages.append(
                f"Current role is not securityadmin! "
                "Permifrost expects to run as securityadmin, please update your connection settings."
            )
        click.secho(f"  Current role is: {current_role}.", fg="green")

        if error_messages:
            raise SpecLoadingError("\n".join(error_messages))
Ejemplo n.º 11
0
    def test_uses_key_pair_if_available(selfself, mocker, snowflake_connector_env):
        mocker.patch("sqlalchemy.create_engine")

        test_private_key = "TEST_PK"
        mocker.patch.object(
            SnowflakeConnector, "generate_private_key", return_value=test_private_key
        )

        os.environ["PERMISSION_BOT_KEY_PATH"] = "TEST"
        os.environ["PERMISSION_BOT_KEY_PASSPHRASE"] = "TEST"

        SnowflakeConnector()

        del os.environ["PERMISSION_BOT_KEY_PATH"]
        del os.environ["PERMISSION_BOT_KEY_PASSPHRASE"]

        sqlalchemy.create_engine.assert_called_with(
            "snowflake://TEST:@TEST/TEST?role=TEST&warehouse=TEST",
            connect_args={"private_key": test_private_key},
        )
Ejemplo n.º 12
0
    def get_privileges_from_snowflake_server(self,
                                             conn: SnowflakeConnector = None
                                             ) -> None:
        """
        Get the privileges granted to users and roles in the Snowflake account
        Gets the future privileges granted in all database and schema objects
        Consolidates role and future privileges into a single object for self.grants_to_role
        """
        if conn is None:
            conn = SnowflakeConnector()

        future_grants = {}
        for database in self.entities["database_refs"]:
            grant_results = conn.show_future_grants(database=database)

            for role in grant_results:
                for privilege in grant_results[role]:
                    for grant_on in grant_results[role][privilege]:
                        (future_grants.setdefault(role, {}).setdefault(
                            privilege, {}).setdefault(grant_on, []).extend(
                                grant_results[role][privilege][grant_on]))

            # Get all schemas in all ref'd databases. Not all schemas will be
            # ref'd in the spec.
            for schema in conn.show_schemas(database=database):
                grant_results = conn.show_future_grants(schema=schema)

                for role in grant_results:
                    for privilege in grant_results[role]:
                        for grant_on in grant_results[role][privilege]:
                            (future_grants.setdefault(role, {}).setdefault(
                                privilege, {}).setdefault(grant_on, []).extend(
                                    grant_results[role][privilege][grant_on]))

        for role in self.entities["roles"]:
            grant_results = conn.show_grants_to_role(role)
            for privilege in grant_results:
                for grant_on in grant_results[privilege]:
                    (future_grants.setdefault(role, {}).setdefault(
                        privilege, {}).setdefault(grant_on, []).extend(
                            grant_results[privilege][grant_on]))

        self.grants_to_role = future_grants

        for user in self.entities["users"]:
            self.roles_granted_to_user[user] = conn.show_roles_granted_to_user(
                user)
Ejemplo n.º 13
0
    def check_entities_on_snowflake_server(self,
                                           conn: SnowflakeConnector = None
                                           ) -> None:
        """
        Make sure that all [warehouses, dbs, schemas, tables, users, roles]
        referenced in the spec are defined in Snowflake.

        Raises a SpecLoadingError with all the errors found while checking
        Snowflake for missinf entities.
        """
        error_messages = []

        if conn is None:
            conn = SnowflakeConnector()

        if len(self.entities["warehouses"]) > 0:
            warehouses = conn.show_warehouses()
            for warehouse in self.entities["warehouses"]:
                if warehouse not in warehouses:
                    error_messages.append(
                        f"Missing Entity Error: Warehouse {warehouse} was not found on"
                        " Snowflake Server. Please create it before continuing."
                    )
        else:
            logging.debug(
                "`warehouses` not found in spec, skipping SHOW WAREHOUSES call."
            )

        if len(self.entities["databases"]) > 0:
            databases = conn.show_databases()
            for db in self.entities["databases"]:
                if db not in databases:
                    error_messages.append(
                        f"Missing Entity Error: Database {db} was not found on"
                        " Snowflake Server. Please create it before continuing."
                    )
        else:
            logging.debug(
                "`databases` not found in spec, skipping SHOW DATABASES call.")

        if len(self.entities["schema_refs"]) > 0:
            schemas = conn.show_schemas()
            for schema in self.entities["schema_refs"]:
                if "*" not in schema and schema not in schemas:
                    error_messages.append(
                        f"Missing Entity Error: Schema {schema} was not found on"
                        " Snowflake Server. Please create it before continuing."
                    )
        else:
            logging.debug(
                "`schemas` not found in spec, skipping SHOW SCHEMAS call.")

        if len(self.entities["table_refs"]) > 0:
            tables = conn.show_tables()
            views = conn.show_views()
            for table in self.entities["table_refs"]:
                if "*" not in table and table not in tables and table not in views:
                    error_messages.append(
                        f"Missing Entity Error: Table/View {table} was not found on"
                        " Snowflake Server. Please create it before continuing."
                    )
        else:
            logging.debug(
                "`tables` not found in spec, skipping SHOW TABLES/VIEWS call.")

        if len(self.entities["roles"]) > 0:
            roles = conn.show_roles()
            for role in self.entities["roles"]:
                if role not in roles:
                    error_messages.append(
                        f"Missing Entity Error: Role {role} was not found on"
                        " Snowflake Server. Please create it before continuing."
                    )
        else:
            logging.debug(
                "`roles` not found in spec, skipping SHOW ROLES call.")

        if len(self.entities["users"]) > 0:
            users = conn.show_users()
            for user in self.entities["users"]:
                if user not in users:
                    error_messages.append(
                        f"Missing Entity Error: User {user} was not found on"
                        " Snowflake Server. Please create it before continuing."
                    )
        else:
            logging.debug(
                "`users` not found in spec, skipping SHOW USERS call.")

        if error_messages:
            raise SpecLoadingError("\n".join(error_messages))