Skip to content

Commit

Permalink
[BUGFIX] Fix issue with DatabaseRoles not allowed with grants (#145)
Browse files Browse the repository at this point in the history
* Fix issue with DatabaseRoles not allowed with grants

---------

Co-authored-by: TJ Murphy <[email protected]>
  • Loading branch information
teej and teej authored Nov 7, 2024
1 parent 03596fb commit 840e685
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 9 deletions.
26 changes: 26 additions & 0 deletions tests/test_grant.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,3 +237,29 @@ def test_grant_on_dynamic_tables():
assert future_grant._data.in_name == "SOMEDB.SOMESCHEMA"
assert future_grant._data.in_type == ResourceType.SCHEMA
assert future_grant._data.on_type == ResourceType.DYNAMIC_TABLE


def test_grant_database_role_to_database_role():
database = res.Database(name="somedb")
parent = res.DatabaseRole(name="parent", database=database)
child = res.DatabaseRole(name="child", database=database)
grant = res.RoleGrant(role=child, to_role=parent)
assert grant.role.name == "child"
assert grant.to.name == "parent"


def test_grant_database_role_to_account_role():
database = res.Database(name="somedb")
parent = res.Role(name="parent")
child = res.DatabaseRole(name="child", database=database)
grant = res.RoleGrant(role=child, to_role=parent)
assert grant.role.name == "child"
assert grant.to.name == "parent"


def test_grant_database_role_to_system_role():
database = res.Database(name="somedb")
child = res.DatabaseRole(name="child", database=database)
grant = res.RoleGrant(role=child, to_role="SYSADMIN")
assert grant.role.name == "child"
assert grant.to.name == "SYSADMIN"
13 changes: 7 additions & 6 deletions titan/resources/grant.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@

from ..enums import ParseableEnum, ResourceType
from ..identifiers import FQN, parse_FQN, resource_label_for_type, resource_type_for_label
from ..parse import parse_grant, format_collection_string
from ..parse import format_collection_string, parse_grant
from ..privs import all_privs_for_resource_type
from ..props import FlagProp, IdentifierProp, Props
from ..resource_name import ResourceName
from ..role_ref import RoleRef
from ..scope import AccountScope
from .resource import NamedResource, Resource, ResourcePointer, ResourceSpec
from .role import Role
Expand All @@ -23,7 +24,7 @@ class _Grant(ResourceSpec):
priv: str
on: str
on_type: ResourceType
to: Role
to: RoleRef
grant_option: bool = False
owner: Role = field(default=None, metadata={"fetchable": False})
_privs: list[str] = field(default_factory=list, metadata={"triggers_create": True})
Expand Down Expand Up @@ -242,7 +243,7 @@ class _FutureGrant(ResourceSpec):
on_type: ResourceType
in_type: ResourceType
in_name: ResourceName
to: Role
to: RoleRef
grant_option: bool = False

def __post_init__(self):
Expand Down Expand Up @@ -425,7 +426,7 @@ class _GrantOnAll(ResourceSpec):
on_type: ResourceType
in_type: ResourceType
in_name: ResourceName
to: Role
to: RoleRef
grant_option: bool = False

def __post_init__(self):
Expand Down Expand Up @@ -587,8 +588,8 @@ def grant_on_all_fqn(data: _GrantOnAll):

@dataclass(unsafe_hash=True)
class _RoleGrant(ResourceSpec):
role: Role
to_role: Role = None
role: RoleRef
to_role: RoleRef = None
to_user: User = None

def __post_init__(self):
Expand Down
8 changes: 5 additions & 3 deletions titan/resources/resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ def __post_init__(self):
setattr(self, f.name, new_value)
except TypeError as err:
human_readable_classname = self.__class__.__name__[1:]
if issubclass(f.type, Enum):
if isclass(f.type) and issubclass(f.type, Enum):
raise TypeError(
f"Expected {human_readable_classname}.{f.name} to be one of ({', '.join(f.type.__members__.keys())}), got {repr(field_value)} instead"
) from err
Expand Down Expand Up @@ -699,13 +699,15 @@ def convert_role_ref(role_ref: RoleRef) -> Resource:
ResourceType.ROLE,
):
return role_ref
elif isinstance(role_ref, str):
elif isinstance(role_ref, str) or isinstance(role_ref, ResourceName):
return ResourcePointer(name=role_ref, resource_type=infer_role_type_from_name(role_ref))
else:
raise TypeError


def infer_role_type_from_name(name: str) -> ResourceType:
def infer_role_type_from_name(name: Union[str, ResourceName]) -> ResourceType:
if isinstance(name, ResourceName):
name = str(name)
if name == "":
return ResourceType.ROLE
identifier = parse_identifier(name, is_db_scoped=True)
Expand Down

0 comments on commit 840e685

Please sign in to comment.