Skip to content

Commit

Permalink
Add initial permission support to schema
Browse files Browse the repository at this point in the history
Update menu labels and positions
  • Loading branch information
dgarros committed Oct 24, 2024
1 parent 8d288ec commit e52e6be
Show file tree
Hide file tree
Showing 10 changed files with 201 additions and 90 deletions.
9 changes: 3 additions & 6 deletions backend/infrahub/api/menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from infrahub.core.branch import Branch # noqa: TCH001
from infrahub.core.protocols import CoreMenuItem
from infrahub.log import get_logger
from infrahub.menu.generator import generate_menu
from infrahub.menu.generator import generate_restricted_menu
from infrahub.menu.models import Menu # noqa: TCH001

if TYPE_CHECKING:
Expand All @@ -29,9 +29,6 @@ async def get_menu(
) -> Menu:
log.info("menu_request", branch=branch.name)

menu_items = await registry.manager.query(
db=db, schema=CoreMenuItem, branch=branch
) # , prefetch_relationships=True)
menu = await generate_menu(db=db, branch=branch, account=account_session, menu_items=menu_items)

menu_items = await registry.manager.query(db=db, schema=CoreMenuItem, branch=branch)
menu = await generate_restricted_menu(db=db, branch=branch, account=account_session, menu_items=menu_items)
return menu.to_rest()
18 changes: 18 additions & 0 deletions backend/infrahub/core/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
from dataclasses import dataclass
from typing import TYPE_CHECKING, Any, Optional, Union

from typing_extensions import Self

from infrahub.core.constants import InfrahubKind, PermissionDecision
from infrahub.core.query import Query
from infrahub.core.registry import registry
Expand Down Expand Up @@ -30,6 +32,22 @@ def __str__(self) -> str:
decision = PermissionDecision(self.decision)
return f"global:{self.action}:{decision.name.lower()}"

@classmethod
def from_string(cls, input: str) -> Self:
parts = input.split(":")
if len(parts) != 3 and parts[0] != "global":
raise ValueError(f"{input} is not a valid format for a Global permission")

# FIXME there is probably a better way to convert the decision
decision = PermissionDecision.DENY
if parts[2] == "allow_default":
decision = PermissionDecision.ALLOW_DEFAULT
elif parts[2] == "allow_all":
decision = PermissionDecision.ALLOW_ALL
elif parts[2] == "allow_other":
decision = PermissionDecision.ALLOW_OTHER
return cls(id="", name="", action=str(parts[1]), decision=decision)


@dataclass
class ObjectPermission(Permission):
Expand Down
1 change: 1 addition & 0 deletions backend/infrahub/core/protocols.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ class CoreMenu(CoreNode):
icon: StringOptional
protected: Boolean
order_weight: Integer
required_permissions: ListAttributeOptional
section: Enum
parent: RelationshipManager
children: RelationshipManager
Expand Down
3 changes: 2 additions & 1 deletion backend/infrahub/core/schema/definitions/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,13 @@
{"name": "icon", "kind": "Text", "optional": True, "order_weight": 4000},
{"name": "protected", "kind": "Boolean", "default_value": False, "read_only": True, "order_weight": 5000},
{"name": "order_weight", "kind": "Number", "default_value": 2000, "order_weight": 6000},
{"name": "required_permissions", "kind": "List", "optional": True, "order_weight": 7000},
{
"name": "section",
"kind": "Text",
"enum": ["object", "internal"],
"default_value": "object",
"order_weight": 7000,
"order_weight": 8000,
},
],
}
Expand Down
33 changes: 27 additions & 6 deletions backend/infrahub/menu/generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,16 @@
from typing import TYPE_CHECKING

from infrahub.core import registry
from infrahub.core.branch import Branch # noqa: TCH001
from infrahub.core.protocols import CoreMenuItem
from infrahub.log import get_logger
from infrahub.permissions.local_backend import LocalPermissionBackend

from .constants import FULL_DEFAULT_MENU
from .models import MenuDict, MenuItemDict

if TYPE_CHECKING:
from infrahub.auth import AccountSession
from infrahub.core.branch import Branch
from infrahub.database import InfrahubDatabase

log = get_logger()
Expand All @@ -21,13 +22,33 @@ def get_full_name(obj: CoreMenuItem) -> str:
return f"{obj.namespace.value}{obj.name.value}"


# pylint: disable=too-many-branches,too-many-statements
async def generate_menu(
db: InfrahubDatabase, branch: Branch, menu_items: list[CoreMenuItem], account: AccountSession | None = None
async def generate_restricted_menu(
db: InfrahubDatabase, branch: Branch, menu_items: list[CoreMenuItem], account: AccountSession
) -> MenuDict:
# FIXME temp hack to avoid pylint to complain
account = account # noqa: PLW0127
menu = await generate_menu(db=db, branch=branch, menu_items=menu_items)

perm_backend = LocalPermissionBackend()
permissions = await perm_backend.load_permissions(db=db, account_id=account.account_id, branch=branch)

for item in menu.data.values():
has_permission: bool | None = None
for permission in item.get_global_permissions():
has_permission = perm_backend.resolve_global_permission(
permissions=permissions["global_permissions"], permission_to_check=permission
)
if has_permission:
has_permission = True
elif has_permission is None:
has_permission = False

if has_permission is False:
item.hidden = True

return menu


# pylint: disable=too-many-branches,too-many-statements
async def generate_menu(db: InfrahubDatabase, branch: Branch, menu_items: list[CoreMenuItem]) -> MenuDict:
structure = MenuDict()
full_schema = registry.schema.get_full(branch=branch, duplicate=False)

Expand Down
165 changes: 94 additions & 71 deletions backend/infrahub/menu/menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,17 @@ def _extract_node_icon(model: MainSchemaTypes) -> str:
icon="mdi:cube-outline",
section=MenuSection.OBJECT,
order_weight=10000,
children=[
MenuItemDefinition(
namespace="Builtin",
name="Tag",
label="tags",
protected=True,
icon=_extract_node_icon(infrahub_schema.get(InfrahubKind.TAG)),
section=MenuSection.OBJECT,
order_weight=10000,
),
],
),
MenuItemDefinition(
namespace="Builtin",
Expand Down Expand Up @@ -166,14 +177,65 @@ def _extract_node_icon(model: MainSchemaTypes) -> str:
),
],
),
MenuItemDefinition(
namespace="Builtin",
name="UnifiedStorage",
label="Unified Storage",
icon="mdi:nas",
protected=True,
section=MenuSection.INTERNAL,
order_weight=2500,
children=[
MenuItemDefinition(
namespace="Builtin",
name="Schema",
label="Schema",
path="/schema",
icon="mdi:file-code",
protected=True,
section=MenuSection.INTERNAL,
order_weight=1000,
),
MenuItemDefinition(
namespace="Builtin",
name="Git Repository",
label="Repository",
kind=InfrahubKind.GENERICREPOSITORY,
icon=_extract_node_icon(infrahub_schema.get(InfrahubKind.GENERICREPOSITORY)),
protected=True,
section=MenuSection.INTERNAL,
order_weight=2000,
),
MenuItemDefinition(
namespace="Builtin",
name="Credentials",
label="Credentials",
kind=InfrahubKind.CREDENTIAL,
icon=_extract_node_icon(infrahub_schema.get(InfrahubKind.CREDENTIAL)),
protected=True,
section=MenuSection.INTERNAL,
order_weight=2000,
),
MenuItemDefinition(
namespace="Builtin",
name="GraphqlQuery",
label="GraphQL Query",
kind=InfrahubKind.GRAPHQLQUERY,
icon=_extract_node_icon(infrahub_schema.get(InfrahubKind.GRAPHQLQUERY)),
protected=True,
section=MenuSection.INTERNAL,
order_weight=3000,
),
],
),
MenuItemDefinition(
namespace="Builtin",
name="Deployment",
label="Deployment",
icon="mdi:rocket-launch",
protected=True,
section=MenuSection.INTERNAL,
order_weight=2500,
order_weight=3000,
children=[
MenuItemDefinition(
namespace="Builtin",
Expand Down Expand Up @@ -249,42 +311,43 @@ def _extract_node_icon(model: MainSchemaTypes) -> str:
),
MenuItemDefinition(
namespace="Builtin",
name="UnifiedStorage",
label="Unified Storage",
icon="mdi:nas",
name="Integration",
label="Integrations",
icon="mdi:connection",
protected=True,
section=MenuSection.INTERNAL,
order_weight=3000,
order_weight=3500,
children=[
MenuItemDefinition(
namespace="Builtin",
name="Schema",
label="Schema",
path="/schema",
icon="mdi:file-code",
protected=True,
section=MenuSection.INTERNAL,
order_weight=1000,
),
MenuItemDefinition(
namespace="Builtin",
name="Git Repository",
label="Repository",
kind=InfrahubKind.GENERICREPOSITORY,
icon=_extract_node_icon(infrahub_schema.get(InfrahubKind.GENERICREPOSITORY)),
protected=True,
section=MenuSection.INTERNAL,
order_weight=2000,
),
MenuItemDefinition(
namespace="Builtin",
name="GraphqlQuery",
label="GraphQL Query",
kind=InfrahubKind.GRAPHQLQUERY,
icon=_extract_node_icon(infrahub_schema.get(InfrahubKind.GRAPHQLQUERY)),
name="Webhooks",
label="Webhooks",
icon=_extract_node_icon(infrahub_schema.get(InfrahubKind.CUSTOMWEBHOOK)),
protected=True,
section=MenuSection.INTERNAL,
order_weight=3000,
children=[
MenuItemDefinition(
namespace="Builtin",
name="WebhookStandard",
label="Webhook",
kind=InfrahubKind.STANDARDWEBHOOK,
icon=_extract_node_icon(infrahub_schema.get(InfrahubKind.STANDARDWEBHOOK)),
protected=True,
section=MenuSection.INTERNAL,
order_weight=1000,
),
MenuItemDefinition(
namespace="Builtin",
name="WebhookCustom",
label="Custom Webhook",
kind=InfrahubKind.CUSTOMWEBHOOK,
icon=_extract_node_icon(infrahub_schema.get(InfrahubKind.CUSTOMWEBHOOK)),
protected=True,
section=MenuSection.INTERNAL,
order_weight=2000,
),
],
),
],
),
Expand All @@ -296,27 +359,18 @@ def _extract_node_icon(model: MainSchemaTypes) -> str:
protected=True,
section=MenuSection.INTERNAL,
order_weight=10000,
permissions=["global:super_admin:allow_all"],
children=[
MenuItemDefinition(
namespace="Builtin",
name="RoleManagement",
label="Role Management",
label="Users & Permissions",
path="/role-management",
icon=_extract_node_icon(infrahub_schema.get(InfrahubKind.BASEPERMISSION)),
protected=True,
section=MenuSection.INTERNAL,
order_weight=1000,
),
MenuItemDefinition(
namespace="Builtin",
name="Credentials",
label="Credentials",
kind=InfrahubKind.CREDENTIAL,
icon=_extract_node_icon(infrahub_schema.get(InfrahubKind.CREDENTIAL)),
protected=True,
section=MenuSection.INTERNAL,
order_weight=2000,
),
MenuItemDefinition(
namespace="Builtin",
name="Menu",
Expand All @@ -327,37 +381,6 @@ def _extract_node_icon(model: MainSchemaTypes) -> str:
section=MenuSection.INTERNAL,
order_weight=2500,
),
MenuItemDefinition(
namespace="Builtin",
name="Webhooks",
label="Webhooks",
icon=_extract_node_icon(infrahub_schema.get(InfrahubKind.CUSTOMWEBHOOK)),
protected=True,
section=MenuSection.INTERNAL,
order_weight=3000,
children=[
MenuItemDefinition(
namespace="Builtin",
name="WebhookStandard",
label="Webhook",
kind=InfrahubKind.STANDARDWEBHOOK,
icon=_extract_node_icon(infrahub_schema.get(InfrahubKind.STANDARDWEBHOOK)),
protected=True,
section=MenuSection.INTERNAL,
order_weight=1000,
),
MenuItemDefinition(
namespace="Builtin",
name="WebhookCustom",
label="Custom Webhook",
kind=InfrahubKind.CUSTOMWEBHOOK,
icon=_extract_node_icon(infrahub_schema.get(InfrahubKind.CUSTOMWEBHOOK)),
protected=True,
section=MenuSection.INTERNAL,
order_weight=2000,
),
],
),
],
),
]
Loading

0 comments on commit e52e6be

Please sign in to comment.