Skip to content

Commit a225161

Browse files
committed
Fix merge conflicts between stable and develop
2 parents cacbea1 + 67b245b commit a225161

28 files changed

+361
-38
lines changed

CHANGELOG.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,28 @@ This project uses [*towncrier*](https://towncrier.readthedocs.io/) and the chang
1111

1212
<!-- towncrier release notes start -->
1313

14+
## [Infrahub - v1.1.7](https://github.com/opsmill/infrahub/tree/infrahub-v1.1.7) - 2025-02-18
15+
16+
### Added
17+
18+
- Data diffs are loaded in sequential batches for faster performance with large changes.
19+
- The diff tree and diff list can now be scrolled independently.
20+
21+
### Changed
22+
23+
- Modified node mutation events to not send metadata properties as part of the mutation payload. The reason is that the property lookup was time consuming. This information will return again in Infrahub 1.2 with a completely updated format. ([#5664](https://github.com/opsmill/infrahub/issues/5664))
24+
25+
### Fixed
26+
27+
- Fix nodes remaining in the database after a create mutation fails when using pools. ([#4303](https://github.com/opsmill/infrahub/issues/4303))
28+
- Modify the query for the current tasks, ensuring the correct determination of the merge button state. ([#5565](https://github.com/opsmill/infrahub/issues/5565))
29+
- Fix Docker `task-manager-db` PostgreSQL health check test by adding database and user parameters. ([#5739](https://github.com/opsmill/infrahub/issues/5739))
30+
- Fixed issue causing a gap in menu sidebar when text is too long.
31+
- Prevent avatar from being cut off in menu sidebar.
32+
- Enforce permission checks when using relationship add or delete mutation.
33+
- Enhance the data integrity checks UI to enable navigation from the check to the diff view.
34+
- Improved performance when updating an existing diff.
35+
1436
## [Infrahub - v1.1.6](https://github.com/opsmill/infrahub/tree/infrahub-v1.1.6) - 2025-01-30
1537

1638
### Artifact improvements

backend/infrahub/graphql/mutations/relationship.py

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,15 @@
77
from infrahub_sdk.utils import compare_lists
88

99
from infrahub import config
10+
from infrahub.core.account import GlobalPermission, ObjectPermission
1011
from infrahub.core.changelog.models import NodeChangelog
11-
from infrahub.core.constants import InfrahubKind, MutationAction, RelationshipCardinality
12+
from infrahub.core.constants import (
13+
InfrahubKind,
14+
MutationAction,
15+
PermissionAction,
16+
PermissionDecision,
17+
RelationshipCardinality,
18+
)
1219
from infrahub.core.manager import NodeManager
1320
from infrahub.core.query.node import NodeGetKindQuery
1421
from infrahub.core.query.relationship import (
@@ -21,6 +28,7 @@
2128
from infrahub.events.group_action import GroupMemberAddedEvent, GroupMemberRemovedEvent
2229
from infrahub.events.models import EventNode
2330
from infrahub.exceptions import NodeNotFoundError, ValidationError
31+
from infrahub.permissions import get_global_permission_for_kind
2432

2533
from ..types import RelatedNodeInput
2634

@@ -51,7 +59,7 @@ class RelationshipNodesInput(InputObjectType):
5159

5260
class RelationshipMixin:
5361
@classmethod
54-
async def mutate( # noqa: PLR0915
62+
async def mutate( # noqa: PLR0915, C901
5563
cls,
5664
root: dict, # noqa: ARG003
5765
info: GraphQLResolveInfo,
@@ -98,6 +106,32 @@ async def mutate( # noqa: PLR0915
98106
db=graphql_context.db, ids=node_ids, fields={"display_label": None}, branch=graphql_context.branch
99107
)
100108

109+
if graphql_context.account_session:
110+
impacted_schemas = {node.get_schema() for node in [source] + list(nodes.values())}
111+
required_permissions: list[GlobalPermission | ObjectPermission] = []
112+
decision = (
113+
PermissionDecision.ALLOW_DEFAULT.value
114+
if graphql_context.branch.is_default
115+
else PermissionDecision.ALLOW_OTHER.value
116+
)
117+
118+
for impacted_schema in impacted_schemas:
119+
global_action = get_global_permission_for_kind(schema=impacted_schema)
120+
121+
if global_action:
122+
required_permissions.append(GlobalPermission(action=global_action, decision=decision))
123+
else:
124+
required_permissions.append(
125+
ObjectPermission(
126+
namespace=impacted_schema.namespace,
127+
name=impacted_schema.name,
128+
action=PermissionAction.UPDATE.value,
129+
decision=decision,
130+
)
131+
)
132+
133+
graphql_context.active_permissions.raise_for_permissions(permissions=required_permissions)
134+
101135
_, _, in_list2 = compare_lists(list1=list(nodes.keys()), list2=node_ids)
102136
if in_list2:
103137
for node_id in in_list2:

backend/infrahub/permissions/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22
from infrahub.permissions.local_backend import LocalPermissionBackend
33
from infrahub.permissions.manager import PermissionManager
44
from infrahub.permissions.report import report_schema_permissions
5-
from infrahub.permissions.types import AssignedPermissions
5+
from infrahub.permissions.types import AssignedPermissions, get_global_permission_for_kind
66

77
__all__ = [
88
"AssignedPermissions",
99
"LocalPermissionBackend",
1010
"PermissionBackend",
1111
"PermissionManager",
12+
"get_global_permission_for_kind",
1213
"report_schema_permissions",
1314
]

backend/infrahub/permissions/types.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,12 @@
22

33
from typing import TYPE_CHECKING, TypedDict
44

5+
from infrahub.core.constants import GlobalPermissions, InfrahubKind
6+
from infrahub.core.schema import NodeSchema
7+
58
if TYPE_CHECKING:
69
from infrahub.core.account import GlobalPermission, ObjectPermission
10+
from infrahub.core.schema import MainSchemaTypes
711
from infrahub.permissions.constants import BranchRelativePermissionDecision
812

913

@@ -18,3 +22,25 @@ class KindPermissions(TypedDict):
1822
delete: BranchRelativePermissionDecision
1923
update: BranchRelativePermissionDecision
2024
view: BranchRelativePermissionDecision
25+
26+
27+
def get_global_permission_for_kind(schema: MainSchemaTypes) -> GlobalPermissions | None:
28+
kind_permission_map = {
29+
InfrahubKind.GENERICACCOUNT: GlobalPermissions.MANAGE_ACCOUNTS,
30+
InfrahubKind.ACCOUNTGROUP: GlobalPermissions.MANAGE_ACCOUNTS,
31+
InfrahubKind.ACCOUNTROLE: GlobalPermissions.MANAGE_ACCOUNTS,
32+
InfrahubKind.BASEPERMISSION: GlobalPermissions.MANAGE_PERMISSIONS,
33+
InfrahubKind.GENERICREPOSITORY: GlobalPermissions.MANAGE_REPOSITORIES,
34+
}
35+
36+
if schema.kind in kind_permission_map:
37+
return kind_permission_map[schema.kind]
38+
39+
if isinstance(schema, NodeSchema):
40+
for base in schema.inherit_from:
41+
try:
42+
return kind_permission_map[base]
43+
except KeyError:
44+
continue
45+
46+
return None

backend/tests/unit/graphql/test_mutation_relationship.py

Lines changed: 133 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,33 @@
1+
from __future__ import annotations
2+
3+
from typing import TYPE_CHECKING
4+
from uuid import uuid4
5+
16
from infrahub_sdk.uuidt import UUIDT
27

3-
from infrahub.auth import AccountSession
8+
from infrahub.auth import AccountSession, AuthType
9+
from infrahub.core import registry
10+
from infrahub.core.account import ObjectPermission
411
from infrahub.core.branch import Branch
512
from infrahub.core.changelog.models import RelationshipCardinalityManyChangelog
6-
from infrahub.core.constants import InfrahubKind
13+
from infrahub.core.constants import InfrahubKind, PermissionAction, PermissionDecision
714
from infrahub.core.manager import NodeManager
815
from infrahub.core.node import Node
916
from infrahub.core.utils import count_relationships
1017
from infrahub.database import InfrahubDatabase
1118
from infrahub.events.group_action import GroupMemberAddedEvent, GroupMemberRemovedEvent
1219
from infrahub.events.node_action import NodeMutatedEvent
1320
from infrahub.graphql.initialization import prepare_graphql_params
21+
from infrahub.permissions import LocalPermissionBackend
1422
from infrahub.services import InfrahubServices
1523
from tests.adapters.event import MemoryInfrahubEvent
1624
from tests.helpers.graphql import graphql
1725

26+
if TYPE_CHECKING:
27+
from infrahub.core.branch import Branch
28+
from infrahub.core.protocols import CoreAccount
29+
from infrahub.database import InfrahubDatabase
30+
1831

1932
async def test_relationship_add(
2033
db: InfrahubDatabase,
@@ -855,3 +868,121 @@ async def test_add_generic_related_node_with_hfid(
855868
assert result.errors is None
856869
assert result.data
857870
assert result.data["TestPersonUpdate"]["object"]["car"]["node"]["name"]["value"] == "testing-car"
871+
872+
873+
async def test_with_permissions(
874+
db: InfrahubDatabase,
875+
register_core_models_schema: None,
876+
default_branch: Branch,
877+
first_account: CoreAccount,
878+
person_jack_main: Node,
879+
tag_blue_main: Node,
880+
):
881+
registry.permission_backends = [LocalPermissionBackend()]
882+
883+
permissions = []
884+
for object_permission in [
885+
ObjectPermission(
886+
namespace="Builtin",
887+
name="Tag",
888+
action=PermissionAction.UPDATE.value,
889+
decision=PermissionDecision.ALLOW_ALL.value,
890+
),
891+
ObjectPermission(
892+
namespace="Test",
893+
name="Person",
894+
action=PermissionAction.UPDATE.value,
895+
decision=PermissionDecision.ALLOW_ALL.value,
896+
),
897+
]:
898+
obj = await Node.init(db=db, schema=InfrahubKind.OBJECTPERMISSION)
899+
await obj.new(
900+
db=db,
901+
namespace=object_permission.namespace,
902+
name=object_permission.name,
903+
action=object_permission.action,
904+
decision=object_permission.decision,
905+
)
906+
await obj.save(db=db)
907+
permissions.append(obj)
908+
909+
role = await Node.init(db=db, schema=InfrahubKind.ACCOUNTROLE)
910+
await role.new(db=db, name="chief-people-officer", permissions=permissions)
911+
await role.save(db=db)
912+
913+
group = await Node.init(db=db, schema=InfrahubKind.ACCOUNTGROUP)
914+
await group.new(db=db, name="hr", roles=[role])
915+
await group.save(db=db)
916+
917+
await group.members.add(db=db, data={"id": first_account.id})
918+
await group.members.save(db=db)
919+
920+
first_session = AccountSession(
921+
authenticated=True, account_id=first_account.id, session_id=str(uuid4()), auth_type=AuthType.JWT
922+
)
923+
924+
query = """
925+
mutation {
926+
RelationshipAdd(data: {
927+
id: "%s",
928+
name: "tags",
929+
nodes: [{id: "%s"}],
930+
}) {
931+
ok
932+
}
933+
}
934+
"""
935+
936+
gql_params = await prepare_graphql_params(
937+
db=db, include_subscription=False, branch=default_branch, account_session=first_session
938+
)
939+
result = await graphql(
940+
schema=gql_params.schema,
941+
source=query % (person_jack_main.id, tag_blue_main.id),
942+
context_value=gql_params.context,
943+
root_value=None,
944+
variable_values={},
945+
)
946+
947+
assert result.errors is None
948+
949+
950+
async def test_without_permissions(
951+
db: InfrahubDatabase,
952+
register_core_models_schema: None,
953+
default_branch: Branch,
954+
first_account: CoreAccount,
955+
person_jack_main: Node,
956+
tag_red_main: Node,
957+
):
958+
registry.permission_backends = [LocalPermissionBackend()]
959+
960+
first_session = AccountSession(
961+
authenticated=True, account_id=first_account.id, session_id=str(uuid4()), auth_type=AuthType.JWT
962+
)
963+
964+
query = """
965+
mutation {
966+
RelationshipAdd(data: {
967+
id: "%s",
968+
name: "tags",
969+
nodes: [{id: "%s"}],
970+
}) {
971+
ok
972+
}
973+
}
974+
"""
975+
976+
gql_params = await prepare_graphql_params(
977+
db=db, include_subscription=False, branch=default_branch, account_session=first_session
978+
)
979+
result = await graphql(
980+
schema=gql_params.schema,
981+
source=query % (person_jack_main.id, tag_red_main.id),
982+
context_value=gql_params.context,
983+
root_value=None,
984+
variable_values={},
985+
)
986+
987+
assert result.errors
988+
assert "You do not have one of the following permissions" in result.errors[0].message
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import pytest
2+
3+
from infrahub.core import registry
4+
from infrahub.core.constants import GlobalPermissions, InfrahubKind
5+
from infrahub.permissions import get_global_permission_for_kind
6+
7+
8+
@pytest.mark.parametrize(
9+
"kinds,permission",
10+
[
11+
(
12+
[InfrahubKind.ACCOUNT, InfrahubKind.ACCOUNTGROUP, InfrahubKind.ACCOUNTROLE],
13+
GlobalPermissions.MANAGE_ACCOUNTS,
14+
),
15+
([InfrahubKind.GLOBALPERMISSION, InfrahubKind.OBJECTPERMISSION], GlobalPermissions.MANAGE_PERMISSIONS),
16+
([InfrahubKind.REPOSITORY, InfrahubKind.READONLYREPOSITORY], GlobalPermissions.MANAGE_REPOSITORIES),
17+
([InfrahubKind.TAG], None),
18+
],
19+
)
20+
def test_get_global_permission_for_kind(
21+
register_core_models_schema: None, kinds: list[str], permission: GlobalPermissions
22+
):
23+
for kind in kinds:
24+
schema = registry.schema.get(name=kind)
25+
assert get_global_permission_for_kind(schema=schema) == permission

changelog/+checks.fixed.md

Lines changed: 0 additions & 1 deletion
This file was deleted.

changelog/+data-diff.added.md

Lines changed: 0 additions & 2 deletions
This file was deleted.

changelog/+diff-performance.fixed.md

Lines changed: 0 additions & 1 deletion
This file was deleted.

changelog/+menu.fixed.md

Lines changed: 0 additions & 2 deletions
This file was deleted.

0 commit comments

Comments
 (0)