Skip to content

Commit 9bcb57c

Browse files
authored
Merge pull request #5903 from opsmill/pog-context-override-permission-IFC-1333
Add override_context global permission
2 parents 6878f6f + 772f5fd commit 9bcb57c

File tree

6 files changed

+153
-33
lines changed

6 files changed

+153
-33
lines changed

backend/infrahub/core/constants/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ class GlobalPermissions(InfrahubStringEnum):
8383
MANAGE_ACCOUNTS = "manage_accounts"
8484
MANAGE_PERMISSIONS = "manage_permissions"
8585
MANAGE_REPOSITORIES = "manage_repositories"
86+
OVERRIDE_CONTEXT = "override_context"
8687

8788

8889
class PermissionAction(InfrahubStringEnum):

backend/infrahub/graphql/context.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22

33
from typing import TYPE_CHECKING
44

5-
from infrahub.core.constants import InfrahubKind
5+
from infrahub.core.constants import GlobalPermissions, InfrahubKind
66
from infrahub.core.manager import NodeManager
77
from infrahub.exceptions import NodeNotFoundError, ValidationError
8+
from infrahub.permissions.globals import define_global_permission_from_branch
89

910
if TYPE_CHECKING:
1011
from .initialization import GraphqlContext
@@ -16,6 +17,12 @@ async def apply_external_context(graphql_context: GraphqlContext, context_input:
1617
if not context_input or not context_input.account:
1718
return
1819

20+
permission = define_global_permission_from_branch(
21+
permission=GlobalPermissions.OVERRIDE_CONTEXT, branch_name=graphql_context.branch.name
22+
)
23+
24+
graphql_context.active_permissions.raise_for_permission(permission=permission)
25+
1926
try:
2027
account = await NodeManager.get_one_by_id_or_default_filter(
2128
db=graphql_context.db, id=str(context_input.account.id), kind=InfrahubKind.GENERICACCOUNT
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from infrahub.core.account import GlobalPermission
2+
from infrahub.core.constants import GLOBAL_BRANCH_NAME, GlobalPermissions, PermissionDecision
3+
from infrahub.core.registry import registry
4+
5+
6+
def define_global_permission_from_branch(permission: GlobalPermissions, branch_name: str) -> GlobalPermission:
7+
if branch_name in (GLOBAL_BRANCH_NAME, registry.default_branch):
8+
decision = PermissionDecision.ALLOW_DEFAULT
9+
else:
10+
decision = PermissionDecision.ALLOW_OTHER
11+
12+
return GlobalPermission(
13+
action=permission.value,
14+
decision=decision.value,
15+
)
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
from __future__ import annotations
2+
3+
from typing import TYPE_CHECKING
4+
5+
from infrahub.core import registry
6+
from infrahub.core.constants import InfrahubKind
7+
from infrahub.core.node import Node
8+
from infrahub.core.protocols import CoreAccountGroup
9+
from infrahub.database import InfrahubDatabase
10+
from infrahub.permissions import LocalPermissionBackend
11+
12+
if TYPE_CHECKING:
13+
from infrahub.core.account import GlobalPermission, ObjectPermission
14+
from infrahub.database import InfrahubDatabase
15+
16+
17+
async def define_permissions(
18+
account: Node,
19+
db: InfrahubDatabase,
20+
object_permissions: list[ObjectPermission] | None = None,
21+
global_permissions: list[GlobalPermission] | None = None,
22+
) -> None:
23+
registry.permission_backends = [LocalPermissionBackend()]
24+
25+
object_permissions = object_permissions or []
26+
global_permissions = global_permissions or []
27+
permissions = []
28+
for object_permission in object_permissions:
29+
obj = await Node.init(db=db, schema=InfrahubKind.OBJECTPERMISSION)
30+
await obj.new(
31+
db=db,
32+
namespace=object_permission.namespace,
33+
name=object_permission.name,
34+
action=object_permission.action,
35+
decision=object_permission.decision,
36+
)
37+
await obj.save(db=db)
38+
permissions.append(obj)
39+
40+
for global_permission in global_permissions:
41+
obj = await Node.init(db=db, schema=InfrahubKind.GLOBALPERMISSION)
42+
await obj.new(
43+
db=db,
44+
action=global_permission.action,
45+
decision=global_permission.decision,
46+
)
47+
await obj.save(db=db)
48+
permissions.append(obj)
49+
50+
role = await Node.init(db=db, schema=InfrahubKind.ACCOUNTROLE)
51+
await role.new(db=db, name="chief-people-officer", permissions=permissions)
52+
await role.save(db=db)
53+
54+
group = await Node.init(db=db, schema=CoreAccountGroup)
55+
await group.new(db=db, name="hr", roles=[role])
56+
await group.save(db=db)
57+
58+
await group.members.add(db=db, data={"id": account.id})
59+
await group.members.save(db=db)

backend/tests/unit/graphql/mutations/test_mutation_context.py

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,17 @@
22

33
from typing import TYPE_CHECKING
44

5+
from infrahub.auth import AccountSession
6+
from infrahub.core.account import GlobalPermission
57
from infrahub.core.branch import Branch
8+
from infrahub.core.constants import GlobalPermissions, PermissionDecision
69
from infrahub.database import InfrahubDatabase
710
from infrahub.events.node_action import NodeMutatedEvent
811
from infrahub.graphql.initialization import prepare_graphql_params
912
from infrahub.services import InfrahubServices
1013
from tests.adapters.event import MemoryInfrahubEvent
1114
from tests.helpers.graphql import graphql
15+
from tests.helpers.permissions import define_permissions
1216

1317
if TYPE_CHECKING:
1418
from infrahub.auth import AccountSession
@@ -22,7 +26,19 @@ async def test_add_context_invalid_account(
2226
default_branch: Branch,
2327
car_person_schema: None,
2428
first_account: Node,
29+
session_first_account: AccountSession,
2530
):
31+
await define_permissions(
32+
account=first_account,
33+
db=db,
34+
global_permissions=[
35+
GlobalPermission(
36+
action=GlobalPermissions.OVERRIDE_CONTEXT.value,
37+
decision=PermissionDecision.ALLOW_ALL.value,
38+
),
39+
],
40+
)
41+
2642
query = """
2743
mutation {
2844
TestPersonCreate(data: {name: { value: "John"}, height: {value: 182}}, context: { account: { id: "very-invalid" }}) {
@@ -33,7 +49,9 @@ async def test_add_context_invalid_account(
3349
}
3450
}
3551
"""
36-
gql_params = await prepare_graphql_params(db=db, include_subscription=False, branch=default_branch)
52+
gql_params = await prepare_graphql_params(
53+
db=db, include_subscription=False, branch=default_branch, account_session=session_first_account
54+
)
3755
result = await graphql(
3856
schema=gql_params.schema,
3957
source=query,
@@ -54,6 +72,17 @@ async def test_add_context_valid_account(
5472
first_account: Node,
5573
second_account: Node,
5674
):
75+
await define_permissions(
76+
account=first_account,
77+
db=db,
78+
global_permissions=[
79+
GlobalPermission(
80+
action=GlobalPermissions.OVERRIDE_CONTEXT.value,
81+
decision=PermissionDecision.ALLOW_ALL.value,
82+
),
83+
],
84+
)
85+
5786
query = """
5887
mutation {
5988
TestPersonCreate(data: {name: { value: "John"}, height: {value: 182}}, context: { account: { id: "%s" }}) {
@@ -86,3 +115,39 @@ async def test_add_context_valid_account(
86115
node_event = memory_event.events[0]
87116
assert isinstance(node_event, NodeMutatedEvent)
88117
assert node_event.meta.account_id == second_account.id
118+
119+
120+
async def test_add_context_missing_permissions(
121+
db: InfrahubDatabase,
122+
default_branch: Branch,
123+
car_person_schema: None,
124+
session_second_account: AccountSession,
125+
first_account: Node,
126+
second_account: Node,
127+
):
128+
query = """
129+
mutation {
130+
TestPersonCreate(data: {name: { value: "John"}, height: {value: 182}}, context: { account: { id: "%s" }}) {
131+
ok
132+
object {
133+
id
134+
}
135+
}
136+
}
137+
""" % (first_account.id)
138+
139+
gql_params = await prepare_graphql_params(
140+
db=db,
141+
include_subscription=False,
142+
branch=default_branch,
143+
account_session=session_second_account,
144+
)
145+
result = await graphql(
146+
schema=gql_params.schema,
147+
source=query,
148+
context_value=gql_params.context,
149+
root_value=None,
150+
variable_values={},
151+
)
152+
assert result.errors
153+
assert "You do not have the following permission: global:override_context:allow_default" in str(result.errors)

backend/tests/unit/graphql/test_mutation_relationship.py

Lines changed: 4 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
from infrahub.services import InfrahubServices
2424
from tests.adapters.event import MemoryInfrahubEvent
2525
from tests.helpers.graphql import graphql
26+
from tests.helpers.permissions import define_permissions
2627

2728
if TYPE_CHECKING:
2829
from infrahub.core.branch import Branch
@@ -41,7 +42,7 @@ async def test_relationship_add(
4142
session_first_account: AccountSession,
4243
first_account: Node,
4344
):
44-
await _define_permissions(
45+
await define_permissions(
4546
account=first_account,
4647
db=db,
4748
object_permissions=[
@@ -391,7 +392,7 @@ async def test_relationship_groups_add(
391392
session_first_account: AccountSession,
392393
first_account: Node,
393394
):
394-
await _define_permissions(
395+
await define_permissions(
395396
account=first_account,
396397
db=db,
397398
object_permissions=[
@@ -538,7 +539,7 @@ async def test_relationship_groups_remove(
538539
session_first_account: AccountSession,
539540
first_account: Node,
540541
):
541-
await _define_permissions(
542+
await define_permissions(
542543
account=first_account,
543544
db=db,
544545
object_permissions=[
@@ -1074,31 +1075,3 @@ async def test_without_permissions(
10741075

10751076
assert result.errors
10761077
assert "You do not have one of the following permissions" in result.errors[0].message
1077-
1078-
1079-
async def _define_permissions(account: Node, db: InfrahubDatabase, object_permissions: list[ObjectPermission]) -> None:
1080-
registry.permission_backends = [LocalPermissionBackend()]
1081-
1082-
permissions = []
1083-
for object_permission in object_permissions:
1084-
obj = await Node.init(db=db, schema=InfrahubKind.OBJECTPERMISSION)
1085-
await obj.new(
1086-
db=db,
1087-
namespace=object_permission.namespace,
1088-
name=object_permission.name,
1089-
action=object_permission.action,
1090-
decision=object_permission.decision,
1091-
)
1092-
await obj.save(db=db)
1093-
permissions.append(obj)
1094-
1095-
role = await Node.init(db=db, schema=InfrahubKind.ACCOUNTROLE)
1096-
await role.new(db=db, name="chief-people-officer", permissions=permissions)
1097-
await role.save(db=db)
1098-
1099-
group = await Node.init(db=db, schema=InfrahubKind.ACCOUNTGROUP)
1100-
await group.new(db=db, name="hr", roles=[role])
1101-
await group.save(db=db)
1102-
1103-
await group.members.add(db=db, data={"id": account.id})
1104-
await group.members.save(db=db)

0 commit comments

Comments
 (0)