infrahub-server 1.1.6__py3-none-any.whl → 1.2.0rc0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (346) hide show
  1. infrahub/api/artifact.py +16 -4
  2. infrahub/api/dependencies.py +8 -0
  3. infrahub/api/oauth2.py +0 -1
  4. infrahub/api/oidc.py +0 -1
  5. infrahub/api/query.py +18 -7
  6. infrahub/api/schema.py +32 -6
  7. infrahub/api/transformation.py +12 -5
  8. infrahub/{message_bus/messages/check_artifact_create.py → artifacts/models.py} +2 -4
  9. infrahub/{message_bus/operations/check/artifact.py → artifacts/tasks.py} +26 -25
  10. infrahub/cli/__init__.py +0 -2
  11. infrahub/cli/db.py +6 -7
  12. infrahub/cli/events.py +8 -3
  13. infrahub/cli/git_agent.py +9 -7
  14. infrahub/cli/tasks.py +4 -6
  15. infrahub/computed_attribute/tasks.py +63 -17
  16. infrahub/computed_attribute/triggers.py +90 -0
  17. infrahub/config.py +1 -1
  18. infrahub/context.py +39 -0
  19. infrahub/core/account.py +5 -8
  20. infrahub/core/attribute.py +53 -21
  21. infrahub/core/branch/models.py +4 -4
  22. infrahub/core/branch/tasks.py +89 -130
  23. infrahub/core/changelog/__init__.py +0 -0
  24. infrahub/core/changelog/diff.py +232 -0
  25. infrahub/core/changelog/models.py +488 -0
  26. infrahub/core/constants/__init__.py +19 -2
  27. infrahub/core/constants/infrahubkind.py +1 -0
  28. infrahub/core/diff/combiner.py +12 -8
  29. infrahub/core/diff/coordinator.py +49 -70
  30. infrahub/core/diff/data_check_synchronizer.py +86 -7
  31. infrahub/core/diff/enricher/aggregated.py +3 -3
  32. infrahub/core/diff/enricher/cardinality_one.py +2 -7
  33. infrahub/core/diff/enricher/hierarchy.py +5 -3
  34. infrahub/core/diff/enricher/labels.py +14 -4
  35. infrahub/core/diff/enricher/path_identifier.py +3 -9
  36. infrahub/core/diff/enricher/summary_counts.py +3 -1
  37. infrahub/core/diff/merger/merger.py +8 -4
  38. infrahub/core/diff/model/path.py +47 -29
  39. infrahub/core/diff/query/all_conflicts.py +6 -3
  40. infrahub/core/diff/query/artifact.py +1 -1
  41. infrahub/core/diff/query/delete_query.py +1 -1
  42. infrahub/core/diff/query/diff_get.py +3 -2
  43. infrahub/core/diff/query/diff_summary.py +1 -1
  44. infrahub/core/diff/query/field_specifiers.py +3 -1
  45. infrahub/core/diff/query/field_summary.py +3 -2
  46. infrahub/core/diff/query/filters.py +12 -1
  47. infrahub/core/diff/query/get_conflict_query.py +1 -1
  48. infrahub/core/diff/query/has_conflicts_query.py +6 -3
  49. infrahub/core/diff/query/merge.py +3 -3
  50. infrahub/core/diff/query/{drop_tracking_id.py → merge_tracking_id.py} +4 -4
  51. infrahub/core/diff/query/roots_metadata.py +9 -2
  52. infrahub/core/diff/query/save.py +151 -66
  53. infrahub/core/diff/query/summary_counts_enricher.py +220 -0
  54. infrahub/core/diff/query/time_range_query.py +3 -2
  55. infrahub/core/diff/query/update_conflict_query.py +1 -1
  56. infrahub/core/diff/query_parser.py +49 -24
  57. infrahub/core/diff/repository/deserializer.py +24 -25
  58. infrahub/core/diff/repository/repository.py +76 -20
  59. infrahub/core/diff/tasks.py +9 -8
  60. infrahub/core/enums.py +1 -1
  61. infrahub/core/integrity/object_conflict/conflict_recorder.py +1 -1
  62. infrahub/core/ipam/reconciler.py +1 -1
  63. infrahub/core/ipam/tasks.py +2 -3
  64. infrahub/core/manager.py +18 -13
  65. infrahub/core/merge.py +5 -2
  66. infrahub/core/migrations/graph/m001_add_version_to_graph.py +1 -1
  67. infrahub/core/migrations/graph/m002_attribute_is_default.py +2 -2
  68. infrahub/core/migrations/graph/m003_relationship_parent_optional.py +2 -2
  69. infrahub/core/migrations/graph/m004_add_attr_documentation.py +1 -1
  70. infrahub/core/migrations/graph/m005_add_rel_read_only.py +1 -1
  71. infrahub/core/migrations/graph/m006_add_rel_on_delete.py +1 -1
  72. infrahub/core/migrations/graph/m007_add_rel_allow_override.py +1 -1
  73. infrahub/core/migrations/graph/m008_add_human_friendly_id.py +1 -1
  74. infrahub/core/migrations/graph/m009_add_generate_profile_attr.py +1 -1
  75. infrahub/core/migrations/graph/m010_add_generate_profile_attr_generic.py +1 -1
  76. infrahub/core/migrations/graph/m011_remove_profile_relationship_schema.py +2 -2
  77. infrahub/core/migrations/graph/m012_convert_account_generic.py +12 -23
  78. infrahub/core/migrations/graph/m013_convert_git_password_credential.py +7 -11
  79. infrahub/core/migrations/graph/m014_remove_index_attr_value.py +2 -2
  80. infrahub/core/migrations/graph/m015_diff_format_update.py +1 -1
  81. infrahub/core/migrations/graph/m016_diff_delete_bug_fix.py +1 -1
  82. infrahub/core/migrations/graph/m017_add_core_profile.py +1 -1
  83. infrahub/core/migrations/graph/m018_uniqueness_nulls.py +2 -2
  84. infrahub/core/migrations/query/attribute_add.py +1 -1
  85. infrahub/core/migrations/query/attribute_rename.py +1 -1
  86. infrahub/core/migrations/query/delete_element_in_schema.py +1 -1
  87. infrahub/core/migrations/query/node_duplicate.py +1 -1
  88. infrahub/core/migrations/query/relationship_duplicate.py +1 -1
  89. infrahub/core/migrations/query/schema_attribute_update.py +1 -1
  90. infrahub/core/migrations/schema/node_attribute_remove.py +1 -1
  91. infrahub/core/migrations/schema/node_remove.py +1 -1
  92. infrahub/core/migrations/schema/tasks.py +5 -5
  93. infrahub/core/migrations/shared.py +4 -4
  94. infrahub/core/models.py +7 -8
  95. infrahub/core/node/__init__.py +161 -40
  96. infrahub/core/node/base.py +1 -1
  97. infrahub/core/node/constraints/grouped_uniqueness.py +9 -2
  98. infrahub/core/node/delete_validator.py +4 -4
  99. infrahub/core/node/ipam.py +13 -8
  100. infrahub/core/node/permissions.py +4 -0
  101. infrahub/core/node/resource_manager/ip_prefix_pool.py +8 -5
  102. infrahub/core/node/standard.py +3 -5
  103. infrahub/core/property.py +1 -1
  104. infrahub/core/protocols.py +4 -0
  105. infrahub/core/protocols_base.py +4 -2
  106. infrahub/core/query/__init__.py +2 -5
  107. infrahub/core/query/attribute.py +9 -9
  108. infrahub/core/query/branch.py +5 -5
  109. infrahub/core/query/delete.py +1 -1
  110. infrahub/core/query/diff.py +45 -7
  111. infrahub/core/query/ipam.py +4 -4
  112. infrahub/core/query/node.py +19 -14
  113. infrahub/core/query/relationship.py +10 -11
  114. infrahub/core/query/resource_manager.py +13 -11
  115. infrahub/core/query/standard_node.py +6 -6
  116. infrahub/core/query/task.py +3 -3
  117. infrahub/core/query/task_log.py +1 -1
  118. infrahub/core/query/utils.py +5 -5
  119. infrahub/core/registry.py +0 -2
  120. infrahub/core/relationship/constraints/count.py +1 -1
  121. infrahub/core/relationship/constraints/peer_kind.py +1 -1
  122. infrahub/core/relationship/model.py +66 -26
  123. infrahub/core/schema/__init__.py +6 -4
  124. infrahub/core/schema/basenode_schema.py +1 -3
  125. infrahub/core/schema/definitions/core.py +14 -2
  126. infrahub/core/schema/definitions/internal.py +16 -0
  127. infrahub/core/schema/generated/genericnode_schema.py +5 -0
  128. infrahub/core/schema/generated/node_schema.py +5 -0
  129. infrahub/core/schema/generic_schema.py +5 -1
  130. infrahub/core/schema/manager.py +45 -42
  131. infrahub/core/schema/node_schema.py +4 -0
  132. infrahub/core/schema/profile_schema.py +4 -0
  133. infrahub/core/schema/relationship_schema.py +2 -2
  134. infrahub/core/schema/schema_branch.py +248 -14
  135. infrahub/core/schema/template_schema.py +36 -0
  136. infrahub/core/task/user_task.py +7 -5
  137. infrahub/core/timestamp.py +1 -1
  138. infrahub/core/utils.py +3 -2
  139. infrahub/core/validators/attribute/choices.py +1 -1
  140. infrahub/core/validators/attribute/enum.py +1 -1
  141. infrahub/core/validators/attribute/kind.py +1 -1
  142. infrahub/core/validators/attribute/length.py +1 -1
  143. infrahub/core/validators/attribute/optional.py +1 -1
  144. infrahub/core/validators/attribute/regex.py +1 -1
  145. infrahub/core/validators/attribute/unique.py +1 -1
  146. infrahub/core/validators/checks_runner.py +37 -0
  147. infrahub/core/validators/node/generate_profile.py +1 -1
  148. infrahub/core/validators/node/hierarchy.py +1 -1
  149. infrahub/core/validators/query.py +1 -1
  150. infrahub/core/validators/relationship/count.py +1 -1
  151. infrahub/core/validators/relationship/optional.py +1 -1
  152. infrahub/core/validators/relationship/peer.py +1 -1
  153. infrahub/core/validators/tasks.py +8 -6
  154. infrahub/core/validators/uniqueness/query.py +20 -17
  155. infrahub/database/__init__.py +15 -2
  156. infrahub/database/memgraph.py +1 -1
  157. infrahub/dependencies/builder/constraint/grouped/node_runner.py +0 -2
  158. infrahub/dependencies/builder/diff/combiner.py +1 -1
  159. infrahub/dependencies/builder/diff/conflicts_enricher.py +1 -1
  160. infrahub/dependencies/builder/diff/coordinator.py +0 -2
  161. infrahub/dependencies/builder/diff/deserializer.py +1 -1
  162. infrahub/dependencies/builder/diff/enricher/summary_counts.py +1 -1
  163. infrahub/events/branch_action.py +47 -21
  164. infrahub/events/group_action.py +73 -0
  165. infrahub/events/models.py +159 -51
  166. infrahub/events/node_action.py +74 -8
  167. infrahub/events/repository_action.py +8 -8
  168. infrahub/events/schema_action.py +21 -8
  169. infrahub/generators/tasks.py +12 -13
  170. infrahub/git/base.py +3 -5
  171. infrahub/git/constants.py +0 -1
  172. infrahub/git/integrator.py +36 -35
  173. infrahub/git/repository.py +7 -8
  174. infrahub/git/tasks.py +43 -107
  175. infrahub/git_credential/helper.py +2 -3
  176. infrahub/graphql/analyzer.py +572 -11
  177. infrahub/graphql/app.py +34 -26
  178. infrahub/graphql/auth/query_permission_checker/anonymous_checker.py +5 -5
  179. infrahub/graphql/auth/query_permission_checker/default_branch_checker.py +4 -4
  180. infrahub/graphql/auth/query_permission_checker/merge_operation_checker.py +4 -4
  181. infrahub/graphql/auth/query_permission_checker/object_permission_checker.py +28 -35
  182. infrahub/graphql/auth/query_permission_checker/super_admin_checker.py +5 -5
  183. infrahub/graphql/enums.py +1 -1
  184. infrahub/graphql/initialization.py +5 -1
  185. infrahub/graphql/loaders/node.py +2 -2
  186. infrahub/graphql/manager.py +59 -54
  187. infrahub/graphql/mutations/account.py +20 -13
  188. infrahub/graphql/mutations/artifact_definition.py +16 -12
  189. infrahub/graphql/mutations/branch.py +61 -40
  190. infrahub/graphql/mutations/computed_attribute.py +19 -13
  191. infrahub/graphql/mutations/diff.py +37 -9
  192. infrahub/graphql/mutations/diff_conflict.py +9 -8
  193. infrahub/graphql/mutations/graphql_query.py +19 -11
  194. infrahub/graphql/mutations/ipam.py +21 -19
  195. infrahub/graphql/mutations/main.py +197 -44
  196. infrahub/graphql/mutations/menu.py +8 -8
  197. infrahub/graphql/mutations/proposed_change.py +36 -28
  198. infrahub/graphql/mutations/relationship.py +302 -105
  199. infrahub/graphql/mutations/repository.py +41 -35
  200. infrahub/graphql/mutations/resource_manager.py +26 -26
  201. infrahub/graphql/mutations/schema.py +51 -33
  202. infrahub/graphql/mutations/tasks.py +16 -10
  203. infrahub/graphql/parser.py +1 -1
  204. infrahub/graphql/permissions.py +6 -4
  205. infrahub/graphql/queries/account.py +22 -18
  206. infrahub/graphql/queries/branch.py +6 -4
  207. infrahub/graphql/queries/diff/tree.py +48 -42
  208. infrahub/graphql/queries/event.py +112 -0
  209. infrahub/graphql/queries/internal.py +3 -3
  210. infrahub/graphql/queries/ipam.py +23 -18
  211. infrahub/graphql/queries/relationship.py +11 -10
  212. infrahub/graphql/queries/resource_manager.py +43 -27
  213. infrahub/graphql/queries/search.py +9 -8
  214. infrahub/graphql/queries/status.py +12 -9
  215. infrahub/graphql/queries/task.py +11 -9
  216. infrahub/graphql/resolvers/resolver.py +69 -43
  217. infrahub/graphql/resolvers/single_relationship.py +16 -10
  218. infrahub/graphql/schema.py +2 -0
  219. infrahub/graphql/subscription/__init__.py +1 -1
  220. infrahub/graphql/subscription/events.py +1 -1
  221. infrahub/graphql/subscription/graphql_query.py +8 -8
  222. infrahub/graphql/types/branch.py +2 -2
  223. infrahub/graphql/types/common.py +6 -1
  224. infrahub/graphql/types/enums.py +2 -0
  225. infrahub/graphql/types/event.py +100 -0
  226. infrahub/graphql/types/interface.py +2 -2
  227. infrahub/graphql/types/node.py +3 -3
  228. infrahub/graphql/types/permission.py +2 -2
  229. infrahub/graphql/types/relationship.py +3 -3
  230. infrahub/graphql/types/standard_node.py +9 -11
  231. infrahub/graphql/utils.py +28 -182
  232. infrahub/groups/tasks.py +2 -3
  233. infrahub/lock.py +1 -1
  234. infrahub/menu/constants.py +1 -0
  235. infrahub/menu/generator.py +14 -3
  236. infrahub/menu/menu.py +116 -127
  237. infrahub/menu/models.py +4 -4
  238. infrahub/message_bus/messages/__init__.py +0 -4
  239. infrahub/message_bus/messages/event_branch_merge.py +3 -0
  240. infrahub/message_bus/messages/request_proposedchange_pipeline.py +2 -0
  241. infrahub/message_bus/operations/__init__.py +3 -5
  242. infrahub/message_bus/operations/check/__init__.py +2 -2
  243. infrahub/message_bus/operations/check/generator.py +1 -3
  244. infrahub/message_bus/operations/check/repository.py +1 -1
  245. infrahub/message_bus/operations/event/branch.py +7 -3
  246. infrahub/message_bus/operations/event/schema.py +1 -1
  247. infrahub/message_bus/operations/finalize/validator.py +1 -1
  248. infrahub/message_bus/operations/git/file.py +2 -2
  249. infrahub/message_bus/operations/git/repository.py +1 -1
  250. infrahub/message_bus/operations/requests/__init__.py +0 -2
  251. infrahub/message_bus/operations/requests/generator_definition.py +1 -1
  252. infrahub/message_bus/operations/requests/proposed_change.py +26 -11
  253. infrahub/message_bus/operations/requests/repository.py +2 -2
  254. infrahub/message_bus/operations/send/echo.py +1 -1
  255. infrahub/message_bus/types.py +1 -1
  256. infrahub/permissions/__init__.py +2 -1
  257. infrahub/permissions/types.py +26 -0
  258. infrahub/pools/prefix.py +29 -165
  259. infrahub/prefect_server/__init__.py +0 -0
  260. infrahub/prefect_server/app.py +18 -0
  261. infrahub/prefect_server/database.py +20 -0
  262. infrahub/prefect_server/events.py +28 -0
  263. infrahub/prefect_server/models.py +46 -0
  264. infrahub/proposed_change/models.py +15 -1
  265. infrahub/proposed_change/tasks.py +173 -35
  266. infrahub/pytest_plugin.py +4 -4
  267. infrahub/server.py +12 -11
  268. infrahub/services/__init__.py +147 -62
  269. infrahub/services/adapters/cache/__init__.py +7 -5
  270. infrahub/services/adapters/cache/nats.py +40 -22
  271. infrahub/services/adapters/cache/redis.py +0 -4
  272. infrahub/services/adapters/event/__init__.py +10 -18
  273. infrahub/services/adapters/http/__init__.py +0 -5
  274. infrahub/services/adapters/http/httpx.py +22 -15
  275. infrahub/services/adapters/message_bus/__init__.py +23 -6
  276. infrahub/services/adapters/message_bus/local.py +8 -6
  277. infrahub/services/adapters/message_bus/nats.py +12 -6
  278. infrahub/services/adapters/message_bus/rabbitmq.py +22 -9
  279. infrahub/services/adapters/workflow/__init__.py +11 -8
  280. infrahub/services/adapters/workflow/local.py +28 -7
  281. infrahub/services/adapters/workflow/worker.py +23 -7
  282. infrahub/services/component.py +38 -35
  283. infrahub/services/scheduler.py +32 -29
  284. infrahub/storage.py +2 -4
  285. infrahub/task_manager/constants.py +1 -1
  286. infrahub/task_manager/event.py +182 -0
  287. infrahub/task_manager/models.py +125 -1
  288. infrahub/task_manager/task.py +1 -1
  289. infrahub/tasks/artifact.py +14 -16
  290. infrahub/tasks/registry.py +1 -1
  291. infrahub/tasks/telemetry.py +13 -14
  292. infrahub/transformations/tasks.py +3 -5
  293. infrahub/trigger/__init__.py +0 -0
  294. infrahub/trigger/catalogue.py +15 -0
  295. infrahub/trigger/constants.py +9 -0
  296. infrahub/trigger/models.py +69 -0
  297. infrahub/trigger/tasks.py +85 -0
  298. infrahub/types.py +1 -1
  299. infrahub/utils.py +1 -1
  300. infrahub/webhook/constants.py +0 -2
  301. infrahub/webhook/models.py +8 -2
  302. infrahub/webhook/tasks.py +20 -73
  303. infrahub/webhook/triggers.py +20 -0
  304. infrahub/workers/infrahub_async.py +36 -25
  305. infrahub/workers/utils.py +63 -0
  306. infrahub/workflows/catalogue.py +13 -37
  307. infrahub/workflows/initialization.py +6 -8
  308. infrahub/workflows/models.py +3 -5
  309. infrahub/workflows/utils.py +1 -1
  310. infrahub_sdk/ctl/check.py +3 -3
  311. infrahub_sdk/ctl/cli_commands.py +11 -10
  312. infrahub_sdk/ctl/exceptions.py +0 -6
  313. infrahub_sdk/ctl/exporter.py +1 -1
  314. infrahub_sdk/ctl/generator.py +5 -5
  315. infrahub_sdk/ctl/importer.py +3 -2
  316. infrahub_sdk/ctl/menu.py +1 -1
  317. infrahub_sdk/ctl/object.py +1 -1
  318. infrahub_sdk/ctl/repository.py +23 -15
  319. infrahub_sdk/ctl/schema.py +2 -2
  320. infrahub_sdk/ctl/utils.py +4 -3
  321. infrahub_sdk/ctl/validate.py +2 -1
  322. infrahub_sdk/exceptions.py +6 -0
  323. infrahub_sdk/generator.py +3 -0
  324. infrahub_sdk/node.py +2 -2
  325. infrahub_sdk/schema/__init__.py +14 -2
  326. infrahub_sdk/schema/main.py +7 -0
  327. infrahub_sdk/utils.py +11 -1
  328. infrahub_sdk/yaml.py +2 -3
  329. {infrahub_server-1.1.6.dist-info → infrahub_server-1.2.0rc0.dist-info}/METADATA +46 -12
  330. {infrahub_server-1.1.6.dist-info → infrahub_server-1.2.0rc0.dist-info}/RECORD +338 -321
  331. infrahub_testcontainers/container.py +14 -6
  332. infrahub_testcontainers/docker-compose.test.yml +24 -5
  333. infrahub_testcontainers/haproxy.cfg +43 -0
  334. infrahub_testcontainers/helpers.py +85 -1
  335. infrahub/core/branch/constants.py +0 -2
  336. infrahub/graphql/query.py +0 -52
  337. infrahub/message_bus/messages/request_artifactdefinition_check.py +0 -17
  338. infrahub/message_bus/operations/requests/artifact_definition.py +0 -148
  339. infrahub/schema/constants.py +0 -1
  340. infrahub/schema/tasks.py +0 -76
  341. infrahub/services/adapters/database/__init__.py +0 -9
  342. infrahub_sdk/ctl/_file.py +0 -13
  343. /infrahub/{schema → artifacts}/__init__.py +0 -0
  344. {infrahub_server-1.1.6.dist-info → infrahub_server-1.2.0rc0.dist-info}/LICENSE.txt +0 -0
  345. {infrahub_server-1.1.6.dist-info → infrahub_server-1.2.0rc0.dist-info}/WHEEL +0 -0
  346. {infrahub_server-1.1.6.dist-info → infrahub_server-1.2.0rc0.dist-info}/entry_points.txt +0 -0
@@ -1,35 +1,56 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import TYPE_CHECKING
3
+ from enum import Enum
4
+ from typing import TYPE_CHECKING, Self
4
5
 
5
6
  from graphene import Boolean, InputField, InputObjectType, List, Mutation, String
6
7
  from infrahub_sdk.utils import compare_lists
7
8
 
8
- from infrahub.core.constants import InfrahubKind, RelationshipCardinality
9
+ from infrahub import config
10
+ from infrahub.core.account import GlobalPermission, ObjectPermission
11
+ from infrahub.core.changelog.models import NodeChangelog
12
+ from infrahub.core.constants import (
13
+ InfrahubKind,
14
+ MutationAction,
15
+ PermissionAction,
16
+ PermissionDecision,
17
+ RelationshipCardinality,
18
+ )
9
19
  from infrahub.core.manager import NodeManager
20
+ from infrahub.core.query.node import NodeGetKindQuery
10
21
  from infrahub.core.query.relationship import (
11
22
  RelationshipGetPeerQuery,
12
23
  RelationshipPeerData,
13
24
  )
14
25
  from infrahub.core.relationship import Relationship
15
26
  from infrahub.database import retry_db_transaction
27
+ from infrahub.events import EventMeta, NodeMutatedEvent
28
+ from infrahub.events.group_action import GroupMemberAddedEvent, GroupMemberRemovedEvent
29
+ from infrahub.events.models import EventNode
16
30
  from infrahub.exceptions import NodeNotFoundError, ValidationError
31
+ from infrahub.permissions import get_global_permission_for_kind
17
32
 
18
33
  from ..types import RelatedNodeInput
19
34
 
20
35
  if TYPE_CHECKING:
21
36
  from graphql import GraphQLResolveInfo
22
37
 
38
+ from infrahub.core.node import Node
23
39
  from infrahub.core.relationship import RelationshipManager
40
+ from infrahub.core.schema.relationship_schema import RelationshipSchema
24
41
 
25
42
  from ..initialization import GraphqlContext
26
43
 
27
44
 
28
- # pylint: disable=unused-argument,too-many-branches
29
-
30
45
  RELATIONSHIP_PEERS_TO_IGNORE = [InfrahubKind.NODE]
31
46
 
32
47
 
48
+ class GroupUpdateType(str, Enum):
49
+ NONE = "none"
50
+ MEMBERS = "members"
51
+ MEMBER_OF_GROUPS = "member_of_groups"
52
+
53
+
33
54
  class RelationshipNodesInput(InputObjectType):
34
55
  id = InputField(String(required=True), description="ID of the node at the source of the relationship")
35
56
  name = InputField(String(required=True), description="Name of the relationship to add or remove nodes")
@@ -38,131 +59,307 @@ class RelationshipNodesInput(InputObjectType):
38
59
  )
39
60
 
40
61
 
41
- class RelationshipMixin:
62
+ class RelationshipAdd(Mutation):
63
+ class Arguments:
64
+ data = RelationshipNodesInput(required=True)
65
+
66
+ ok = Boolean()
67
+
42
68
  @classmethod
69
+ @retry_db_transaction(name="relationship_add")
43
70
  async def mutate(
44
71
  cls,
45
- root: dict,
72
+ root: dict, # noqa: ARG003
46
73
  info: GraphQLResolveInfo,
47
74
  data: RelationshipNodesInput,
48
- ):
49
- context: GraphqlContext = info.context
50
- input_id = str(data.id)
51
-
52
- if not (
53
- source := await NodeManager.get_one(
54
- db=context.db,
55
- id=input_id,
56
- branch=context.branch,
57
- include_owner=True,
58
- include_source=True,
59
- )
60
- ):
61
- raise NodeNotFoundError(context.branch, None, input_id)
62
-
63
- # Check if the name of the relationship provided exist for this node and is of cardinality Many
64
- if data.get("name") not in source._schema.relationship_names:
65
- raise ValidationError(
66
- {"name": f"'{data.get('name')}' is not a valid relationship for '{source.get_kind()}'"}
67
- )
68
-
69
- rel_schema = source._schema.get_relationship(name=data.get("name"))
70
- if rel_schema.cardinality != RelationshipCardinality.MANY:
71
- raise ValidationError({"name": f"'{data.get('name')}' must be a relationship of cardinality Many"})
72
-
73
- # Query the node in the database and validate that all of them exist and are if the correct kind
74
- node_ids: list[str] = [node_data["id"] for node_data in data.get("nodes") if "id" in node_data]
75
- nodes = await NodeManager.get_many(
76
- db=context.db, ids=node_ids, fields={"display_label": None}, branch=context.branch
75
+ ) -> Self:
76
+ graphql_context: GraphqlContext = info.context
77
+ relationship_name = str(data.name)
78
+
79
+ source = await _validate_node(info=info, data=data)
80
+ nodes = await _validate_peers(info=info, data=data)
81
+ await _validate_permissions(info=info, source_node=source, peers=nodes)
82
+ await _validate_peer_types(info=info, data=data, source_node=source, peers=nodes)
83
+
84
+ rel_schema = source.get_schema().get_relationship(name=relationship_name)
85
+ display_label: str = await source.render_display_label(db=graphql_context.db)
86
+ node_changelog = NodeChangelog(
87
+ node_id=source.get_id(), node_kind=source.get_kind(), display_label=display_label
77
88
  )
78
89
 
79
- _, _, in_list2 = compare_lists(list1=list(nodes.keys()), list2=node_ids)
80
- if in_list2:
81
- for node_id in in_list2:
82
- raise ValidationError(f"{node_id!r}: Unable to find the node in the database.")
83
-
84
- for node_id, node in nodes.items():
85
- if rel_schema.peer in RELATIONSHIP_PEERS_TO_IGNORE:
86
- continue
87
- if rel_schema.peer not in node.get_labels():
88
- raise ValidationError(f"{node_id!r} {node.get_kind()!r} is not a valid peer for '{rel_schema.peer}'")
89
-
90
- peer_relationships = [rel for rel in node._schema.relationships if rel.identifier == rel_schema.identifier]
91
- if (
92
- rel_schema.identifier
93
- and len(peer_relationships) == 1
94
- and peer_relationships[0].cardinality == RelationshipCardinality.ONE
95
- ):
96
- peer_relationship: RelationshipManager = getattr(node, peer_relationships[0].name)
97
- if peer := await peer_relationship.get_peer(db=context.db):
98
- if peer.id != input_id:
99
- raise ValidationError(
100
- f"{node_id!r} {node.get_kind()!r} is already related to another peer on '{peer_relationships[0].name}'"
90
+ existing_peers = await _collect_current_peers(info=info, data=data, source_node=source)
91
+
92
+ async with graphql_context.db.start_transaction() as db:
93
+ peers: list[EventNode] = []
94
+ for node_data in data.get("nodes"):
95
+ # Instantiate and resolve a relationship
96
+ # This will take care of allocating a node from a pool if needed
97
+ rel = Relationship(schema=rel_schema, branch=graphql_context.branch, node=source)
98
+ await rel.new(db=db, data=node_data)
99
+ await rel.resolve(db=db)
100
+ # Save it only if it does not exist
101
+ if rel.get_peer_id() not in existing_peers.keys():
102
+ peers.append(EventNode(id=rel.get_peer_id(), kind=rel.get_peer_kind()))
103
+ node_changelog.create_relationship(relationship=rel)
104
+ await rel.save(db=db)
105
+
106
+ if config.SETTINGS.broker.enable and graphql_context.background and node_changelog.has_changes:
107
+ group_event_type = _get_group_event_type(
108
+ node=source, relationship_schema=rel_schema, relationship_name=relationship_name
109
+ )
110
+ if group_event_type == GroupUpdateType.MEMBERS:
111
+ group_add_event = GroupMemberAddedEvent(
112
+ node_id=source.id,
113
+ kind=source.get_schema().kind,
114
+ members=peers,
115
+ meta=EventMeta(branch=graphql_context.branch, context=graphql_context.get_context()),
116
+ )
117
+ graphql_context.background.add_task(graphql_context.active_service.event.send, group_add_event)
118
+
119
+ elif group_event_type == GroupUpdateType.MEMBER_OF_GROUPS:
120
+ group_ids = [node.id for node in peers]
121
+ async with graphql_context.db.start_session() as db:
122
+ node_kind_query = await NodeGetKindQuery.init(db=db, branch=graphql_context.branch, ids=group_ids)
123
+ await node_kind_query.execute(db=db)
124
+ node_kind_map = await node_kind_query.get_node_kind_map()
125
+
126
+ for node_id, node_kind in node_kind_map.items():
127
+ group_add_event = GroupMemberAddedEvent(
128
+ node_id=node_id,
129
+ kind=node_kind,
130
+ members=[EventNode(id=source.get_id(), kind=source.get_kind())],
131
+ meta=EventMeta(branch=graphql_context.branch, context=graphql_context.get_context()),
101
132
  )
102
-
103
- # The nodes that are already present in the db
104
- query = await RelationshipGetPeerQuery.init(
105
- db=context.db,
106
- source=source,
107
- rel=Relationship(schema=rel_schema, branch=context.branch, node=source),
108
- )
109
- await query.execute(db=context.db)
110
- existing_peers: dict[str, RelationshipPeerData] = {peer.peer_id: peer for peer in query.get_peers()}
111
-
112
- async with context.db.start_transaction() as db:
113
- if cls.__name__ == "RelationshipAdd":
114
- for node_data in data.get("nodes"):
115
- # Instantiate and resolve a relationship
116
- # This will take care of allocating a node from a pool if needed
117
- rel = Relationship(schema=rel_schema, branch=context.branch, node=source)
118
- await rel.new(db=db, data=node_data)
119
- await rel.resolve(db=db)
120
- # Save it only if it does not exist
121
- if rel.get_peer_id() not in existing_peers.keys():
122
- await rel.save(db=db)
123
-
124
- elif cls.__name__ == "RelationshipRemove":
125
- for node_data in data.get("nodes"):
126
- if node_data.get("id") in existing_peers.keys():
127
- # TODO once https://github.com/opsmill/infrahub/issues/792 has been fixed
128
- # we should use RelationshipDataDeleteQuery to delete the relationship
129
- # it would be more query efficient
130
- rel = Relationship(schema=rel_schema, branch=context.branch, node=source)
131
- await rel.load(db=db, data=existing_peers[node_data.get("id")])
132
- await rel.delete(db=db)
133
+ graphql_context.background.add_task(graphql_context.active_service.event.send, group_add_event)
134
+
135
+ else:
136
+ event = NodeMutatedEvent(
137
+ kind=source.get_schema().kind,
138
+ node_id=source.id,
139
+ data=node_changelog,
140
+ action=MutationAction.UPDATED,
141
+ fields=[relationship_name],
142
+ meta=EventMeta(branch=graphql_context.branch, context=graphql_context.get_context()),
143
+ )
144
+ graphql_context.background.add_task(graphql_context.active_service.event.send, event)
133
145
 
134
146
  return cls(ok=True)
135
147
 
136
148
 
137
- class RelationshipAdd(RelationshipMixin, Mutation):
149
+ class RelationshipRemove(Mutation):
138
150
  class Arguments:
139
151
  data = RelationshipNodesInput(required=True)
140
152
 
141
153
  ok = Boolean()
142
154
 
143
155
  @classmethod
144
- @retry_db_transaction(name="relationship_add")
156
+ @retry_db_transaction(name="relationship_remove")
145
157
  async def mutate(
146
158
  cls,
147
- root: dict,
159
+ root: dict, # noqa: ARG003
148
160
  info: GraphQLResolveInfo,
149
161
  data: RelationshipNodesInput,
150
- ):
151
- return await super().mutate(root=root, info=info, data=data)
162
+ ) -> Self:
163
+ graphql_context: GraphqlContext = info.context
164
+ relationship_name = str(data.name)
165
+
166
+ source = await _validate_node(info=info, data=data)
167
+ nodes = await _validate_peers(info=info, data=data)
168
+ await _validate_permissions(info=info, source_node=source, peers=nodes)
169
+ await _validate_peer_types(info=info, data=data, source_node=source, peers=nodes)
170
+
171
+ rel_schema = source.get_schema().get_relationship(name=relationship_name)
172
+ display_label: str = await source.render_display_label(db=graphql_context.db)
173
+ node_changelog = NodeChangelog(
174
+ node_id=source.get_id(), node_kind=source.get_kind(), display_label=display_label
175
+ )
176
+
177
+ existing_peers = await _collect_current_peers(info=info, data=data, source_node=source)
178
+
179
+ async with graphql_context.db.start_transaction() as db:
180
+ peers: list[EventNode] = []
181
+
182
+ for node_data in data.get("nodes"):
183
+ if node_data.get("id") in existing_peers.keys():
184
+ # TODO once https://github.com/opsmill/infrahub/issues/792 has been fixed
185
+ # we should use RelationshipDataDeleteQuery to delete the relationship
186
+ # it would be more query efficient
187
+ rel = Relationship(schema=rel_schema, branch=graphql_context.branch, node=source)
188
+ await rel.load(db=db, data=existing_peers[node_data.get("id")])
189
+ peers.append(EventNode(id=rel.get_peer_id(), kind=rel.get_peer_kind()))
190
+ node_changelog.delete_relationship(relationship=rel)
191
+ await rel.delete(db=db)
192
+
193
+ if config.SETTINGS.broker.enable and graphql_context.background and node_changelog.has_changes:
194
+ group_event_type = _get_group_event_type(
195
+ node=source, relationship_schema=rel_schema, relationship_name=relationship_name
196
+ )
197
+ if group_event_type == GroupUpdateType.MEMBERS:
198
+ group_remove_event = GroupMemberRemovedEvent(
199
+ node_id=source.id,
200
+ kind=source.get_schema().kind,
201
+ members=peers,
202
+ meta=EventMeta(branch=graphql_context.branch, context=graphql_context.get_context()),
203
+ )
204
+ graphql_context.background.add_task(graphql_context.active_service.event.send, group_remove_event)
205
+ elif group_event_type == GroupUpdateType.MEMBER_OF_GROUPS:
206
+ group_ids = [node.id for node in peers]
207
+ async with graphql_context.db.start_session() as db:
208
+ node_kind_query = await NodeGetKindQuery.init(db=db, branch=graphql_context.branch, ids=group_ids)
209
+ await node_kind_query.execute(db=db)
210
+ node_kind_map = await node_kind_query.get_node_kind_map()
211
+
212
+ for node_id, node_kind in node_kind_map.items():
213
+ group_remove_event = GroupMemberRemovedEvent(
214
+ node_id=node_id,
215
+ kind=node_kind,
216
+ members=[EventNode(id=source.get_id(), kind=source.get_kind())],
217
+ meta=EventMeta(branch=graphql_context.branch, context=graphql_context.get_context()),
218
+ )
219
+ graphql_context.background.add_task(
220
+ graphql_context.active_service.event.send, group_remove_event
221
+ )
222
+ else:
223
+ event = NodeMutatedEvent(
224
+ kind=source.get_schema().kind,
225
+ node_id=source.id,
226
+ data=node_changelog,
227
+ action=MutationAction.UPDATED,
228
+ fields=[relationship_name],
229
+ meta=EventMeta(branch=graphql_context.branch, context=graphql_context.get_context()),
230
+ )
231
+ graphql_context.background.add_task(graphql_context.active_service.event.send, event)
152
232
 
233
+ return cls(ok=True)
153
234
 
154
- class RelationshipRemove(RelationshipMixin, Mutation):
155
- class Arguments:
156
- data = RelationshipNodesInput(required=True)
157
235
 
158
- ok = Boolean()
236
+ async def _validate_node(info: GraphQLResolveInfo, data: RelationshipNodesInput) -> Node:
237
+ graphql_context: GraphqlContext = info.context
238
+ input_id = str(data.id)
239
+ relationship_name = str(data.name)
159
240
 
160
- @classmethod
161
- @retry_db_transaction(name="relationship_remove")
162
- async def mutate(
163
- cls,
164
- root: dict,
165
- info: GraphQLResolveInfo,
166
- data: RelationshipNodesInput,
241
+ if not (
242
+ source := await NodeManager.get_one(
243
+ db=graphql_context.db,
244
+ id=input_id,
245
+ branch=graphql_context.branch,
246
+ include_owner=False,
247
+ include_source=False,
248
+ )
167
249
  ):
168
- return await super().mutate(root=root, info=info, data=data)
250
+ raise NodeNotFoundError(node_type="node", identifier=input_id, branch_name=graphql_context.branch.name)
251
+
252
+ # Check if the name of the relationship provided exist for this node and is of cardinality Many
253
+ if relationship_name not in source.get_schema().relationship_names:
254
+ raise ValidationError({"name": f"'{relationship_name}' is not a valid relationship for '{source.get_kind()}'"})
255
+
256
+ rel_schema = source.get_schema().get_relationship(name=relationship_name)
257
+ if rel_schema.cardinality != RelationshipCardinality.MANY:
258
+ raise ValidationError({"name": f"'{relationship_name}' must be a relationship of cardinality Many"})
259
+
260
+ return source
261
+
262
+
263
+ async def _validate_peers(info: GraphQLResolveInfo, data: RelationshipNodesInput) -> dict[str, Node]:
264
+ graphql_context: GraphqlContext = info.context
265
+
266
+ # Query the node in the database and validate that all of them exist and are if the correct kind
267
+ node_ids: list[str] = [node_data["id"] for node_data in data.get("nodes") if "id" in node_data]
268
+ nodes = await NodeManager.get_many(
269
+ db=graphql_context.db, ids=node_ids, fields={"display_label": None}, branch=graphql_context.branch
270
+ )
271
+ _, _, in_list2 = compare_lists(list1=list(nodes.keys()), list2=node_ids)
272
+ if in_list2:
273
+ for node_id in in_list2:
274
+ raise ValidationError(f"{node_id!r}: Unable to find the node in the database.")
275
+ return nodes
276
+
277
+
278
+ async def _validate_permissions(info: GraphQLResolveInfo, source_node: Node, peers: dict[str, Node]) -> None:
279
+ graphql_context: GraphqlContext = info.context
280
+
281
+ if graphql_context.account_session:
282
+ impacted_schemas = {node.get_schema() for node in [source_node] + list(peers.values())}
283
+ required_permissions: list[GlobalPermission | ObjectPermission] = []
284
+ decision = (
285
+ PermissionDecision.ALLOW_DEFAULT.value
286
+ if graphql_context.branch.is_default
287
+ else PermissionDecision.ALLOW_OTHER.value
288
+ )
289
+
290
+ for impacted_schema in impacted_schemas:
291
+ global_action = get_global_permission_for_kind(schema=impacted_schema)
292
+
293
+ if global_action:
294
+ required_permissions.append(GlobalPermission(action=global_action, decision=decision))
295
+ else:
296
+ required_permissions.append(
297
+ ObjectPermission(
298
+ namespace=impacted_schema.namespace,
299
+ name=impacted_schema.name,
300
+ action=PermissionAction.UPDATE.value,
301
+ decision=decision,
302
+ )
303
+ )
304
+
305
+ graphql_context.active_permissions.raise_for_permissions(permissions=required_permissions)
306
+
307
+
308
+ async def _validate_peer_types(
309
+ info: GraphQLResolveInfo, data: RelationshipNodesInput, source_node: Node, peers: dict[str, Node]
310
+ ) -> None:
311
+ graphql_context: GraphqlContext = info.context
312
+ relationship_name = str(data.name)
313
+ input_id = str(data.id)
314
+ rel_schema = source_node.get_schema().get_relationship(name=relationship_name)
315
+ for node_id, node in peers.items():
316
+ if rel_schema.peer in RELATIONSHIP_PEERS_TO_IGNORE:
317
+ continue
318
+ if rel_schema.peer not in node.get_labels():
319
+ raise ValidationError(f"{node_id!r} {node.get_kind()!r} is not a valid peer for '{rel_schema.peer}'")
320
+
321
+ peer_relationships = [rel for rel in node.get_schema().relationships if rel.identifier == rel_schema.identifier]
322
+ if (
323
+ rel_schema.identifier
324
+ and len(peer_relationships) == 1
325
+ and peer_relationships[0].cardinality == RelationshipCardinality.ONE
326
+ ):
327
+ peer_relationship: RelationshipManager = getattr(node, peer_relationships[0].name)
328
+ if peer := await peer_relationship.get_peer(db=graphql_context.db):
329
+ if peer.id != input_id:
330
+ raise ValidationError(
331
+ f"{node_id!r} {node.get_kind()!r} is already related to another peer on '{peer_relationships[0].name}'"
332
+ )
333
+
334
+
335
+ async def _collect_current_peers(
336
+ info: GraphQLResolveInfo, data: RelationshipNodesInput, source_node: Node
337
+ ) -> dict[str, RelationshipPeerData]:
338
+ graphql_context: GraphqlContext = info.context
339
+ relationship_name = str(data.name)
340
+
341
+ rel_schema = source_node.get_schema().get_relationship(name=relationship_name)
342
+
343
+ # The nodes that are already present in the db
344
+ query = await RelationshipGetPeerQuery.init(
345
+ db=graphql_context.db,
346
+ source=source_node,
347
+ rel=Relationship(schema=rel_schema, branch=graphql_context.branch, node=source_node),
348
+ )
349
+ await query.execute(db=graphql_context.db)
350
+ return {str(peer.peer_id): peer for peer in query.get_peers()}
351
+
352
+
353
+ def _get_group_event_type(
354
+ node: Node, relationship_schema: RelationshipSchema, relationship_name: str
355
+ ) -> GroupUpdateType:
356
+ group_event_type = GroupUpdateType.NONE
357
+ if relationship_schema.identifier == "group_member":
358
+ if "CoreGroup" in node.get_schema().inherit_from and relationship_name == "members":
359
+ # Updating members of a group
360
+ group_event_type = GroupUpdateType.MEMBERS
361
+
362
+ elif relationship_name == "member_of_groups":
363
+ # Modifying the membership of the current node
364
+ group_event_type = GroupUpdateType.MEMBER_OF_GROUPS
365
+ return group_event_type
@@ -45,7 +45,7 @@ log = get_logger()
45
45
 
46
46
  class InfrahubRepositoryMutation(InfrahubMutationMixin, Mutation):
47
47
  @classmethod
48
- def __init_subclass_with_meta__(cls, schema: Optional[NodeSchema] = None, _meta=None, **options): # pylint: disable=arguments-differ
48
+ def __init_subclass_with_meta__(cls, schema: Optional[NodeSchema] = None, _meta=None, **options):
49
49
  # Make sure schema is a valid NodeSchema Node Class
50
50
  if not isinstance(schema, NodeSchema):
51
51
  raise ValueError(f"You need to pass a valid NodeSchema in '{cls.__name__}.Meta', received '{schema}'")
@@ -63,9 +63,9 @@ class InfrahubRepositoryMutation(InfrahubMutationMixin, Mutation):
63
63
  info: GraphQLResolveInfo,
64
64
  data: InputObjectType,
65
65
  branch: Branch,
66
- database: Optional[InfrahubDatabase] = None,
66
+ database: Optional[InfrahubDatabase] = None, # noqa: ARG003
67
67
  ):
68
- context: GraphqlContext = info.context
68
+ graphql_context: GraphqlContext = info.context
69
69
 
70
70
  cleanup_payload(data)
71
71
  # Create the object in the database
@@ -74,17 +74,17 @@ class InfrahubRepositoryMutation(InfrahubMutationMixin, Mutation):
74
74
 
75
75
  # First check the connectivity to the remote repository
76
76
  # If the connectivity is not good, we remove the repository to allow the user to add a new one
77
- if context.service:
77
+ if graphql_context.service:
78
78
  message = messages.GitRepositoryConnectivity(
79
79
  repository_name=obj.name.value,
80
80
  repository_location=obj.location.value,
81
81
  )
82
- response = await context.service.message_bus.rpc(
82
+ response = await graphql_context.service.message_bus.rpc(
83
83
  message=message, response_class=GitRepositoryConnectivityResponse
84
84
  )
85
85
 
86
86
  if response.data.success is False:
87
- await obj.delete(db=context.db)
87
+ await obj.delete(db=graphql_context.db)
88
88
  raise ValidationError(response.data.message)
89
89
 
90
90
  # If we are in the default branch, we set the sync status to Active
@@ -93,13 +93,13 @@ class InfrahubRepositoryMutation(InfrahubMutationMixin, Mutation):
93
93
  obj.internal_status.value = RepositoryInternalStatus.ACTIVE.value
94
94
  else:
95
95
  obj.internal_status.value = RepositoryInternalStatus.STAGING.value
96
- await obj.save(db=context.db)
96
+ await obj.save(db=graphql_context.db)
97
97
 
98
98
  # Create the new repository in the filesystem.
99
99
  log.info("create_repository", name=obj.name.value)
100
100
  authenticated_user = None
101
- if context.account_session and context.account_session.authenticated:
102
- authenticated_user = context.account_session.account_id
101
+ if graphql_context.account_session and graphql_context.account_session.authenticated:
102
+ authenticated_user = graphql_context.account_session.account_id
103
103
  if obj.get_kind() == InfrahubKind.READONLYREPOSITORY:
104
104
  obj = cast(CoreReadOnlyRepository, obj)
105
105
  model = GitRepositoryAddReadOnly(
@@ -112,9 +112,11 @@ class InfrahubRepositoryMutation(InfrahubMutationMixin, Mutation):
112
112
  internal_status=obj.internal_status.value,
113
113
  created_by=authenticated_user,
114
114
  )
115
- if context.service:
116
- await context.service.workflow.submit_workflow(
117
- workflow=GIT_REPOSITORY_ADD_READ_ONLY, parameters={"model": model}
115
+ if graphql_context.service:
116
+ await graphql_context.service.workflow.submit_workflow(
117
+ workflow=GIT_REPOSITORY_ADD_READ_ONLY,
118
+ context=graphql_context.get_context(),
119
+ parameters={"model": model},
118
120
  )
119
121
 
120
122
  else:
@@ -130,9 +132,11 @@ class InfrahubRepositoryMutation(InfrahubMutationMixin, Mutation):
130
132
  created_by=authenticated_user,
131
133
  )
132
134
 
133
- if context.service:
134
- await context.service.workflow.submit_workflow(
135
- workflow=GIT_REPOSITORY_ADD, parameters={"model": git_repo_add_model}
135
+ if graphql_context.service:
136
+ await graphql_context.service.workflow.submit_workflow(
137
+ workflow=GIT_REPOSITORY_ADD,
138
+ context=graphql_context.get_context(),
139
+ parameters={"model": git_repo_add_model},
136
140
  )
137
141
 
138
142
  # TODO Validate that the creation of the repository went as expected
@@ -145,15 +149,15 @@ class InfrahubRepositoryMutation(InfrahubMutationMixin, Mutation):
145
149
  info: GraphQLResolveInfo,
146
150
  data: InputObjectType,
147
151
  branch: Branch,
148
- database: Optional[InfrahubDatabase] = None,
152
+ database: Optional[InfrahubDatabase] = None, # noqa: ARG003
149
153
  node: Optional[Node] = None,
150
154
  ):
151
- context: GraphqlContext = info.context
155
+ graphql_context: GraphqlContext = info.context
152
156
 
153
157
  cleanup_payload(data)
154
158
  if not node:
155
159
  node: CoreReadOnlyRepository | CoreRepository = await NodeManager.get_one_by_id_or_default_filter(
156
- db=context.db,
160
+ db=graphql_context.db,
157
161
  kind=cls._meta.schema.kind,
158
162
  id=data.get("id"),
159
163
  branch=branch,
@@ -161,7 +165,7 @@ class InfrahubRepositoryMutation(InfrahubMutationMixin, Mutation):
161
165
  include_source=True,
162
166
  )
163
167
  if node.get_kind() != InfrahubKind.READONLYREPOSITORY:
164
- return await super().mutate_update(info, data, branch, database=context.db, node=node)
168
+ return await super().mutate_update(info, data, branch, database=graphql_context.db, node=node)
165
169
 
166
170
  node = cast(CoreReadOnlyRepository, node)
167
171
  current_commit = node.commit.value
@@ -173,7 +177,7 @@ class InfrahubRepositoryMutation(InfrahubMutationMixin, Mutation):
173
177
  if data.ref and data.ref.value:
174
178
  new_ref = data.ref.value
175
179
 
176
- obj, result = await super().mutate_update(info, data, branch, database=context.db, node=node)
180
+ obj, result = await super().mutate_update(info, data, branch, database=graphql_context.db, node=node)
177
181
  obj = cast(CoreReadOnlyRepository, obj)
178
182
 
179
183
  send_update_message = (new_commit and new_commit != current_commit) or (new_ref and new_ref != current_ref)
@@ -196,9 +200,11 @@ class InfrahubRepositoryMutation(InfrahubMutationMixin, Mutation):
196
200
  infrahub_branch_name=branch.name,
197
201
  infrahub_branch_id=str(branch.get_uuid()),
198
202
  )
199
- if context.service:
200
- await context.service.workflow.submit_workflow(
201
- workflow=GIT_REPOSITORIES_PULL_READ_ONLY, parameters={"model": model}
203
+ if graphql_context.service:
204
+ await graphql_context.service.workflow.submit_workflow(
205
+ workflow=GIT_REPOSITORIES_PULL_READ_ONLY,
206
+ context=graphql_context.get_context(),
207
+ parameters={"model": model},
202
208
  )
203
209
  return obj, result
204
210
 
@@ -226,15 +232,15 @@ class ProcessRepository(Mutation):
226
232
  @classmethod
227
233
  async def mutate(
228
234
  cls,
229
- root: dict, # pylint: disable=unused-argument
235
+ root: dict, # noqa: ARG003
230
236
  info: GraphQLResolveInfo,
231
237
  data: IdentifierInput,
232
238
  ) -> dict[str, bool]:
233
- context: GraphqlContext = info.context
234
- branch = context.branch
239
+ graphql_context: GraphqlContext = info.context
240
+ branch = graphql_context.branch
235
241
  repository_id = str(data.id)
236
242
  repo: CoreReadOnlyRepository | CoreRepository = await NodeManager.get_one_by_id_or_default_filter(
237
- db=context.db,
243
+ db=graphql_context.db,
238
244
  kind=InfrahubKind.GENERICREPOSITORY,
239
245
  id=str(data.id),
240
246
  branch=branch,
@@ -247,8 +253,8 @@ class ProcessRepository(Mutation):
247
253
  commit=str(repo.commit.value),
248
254
  infrahub_branch_name=branch.name,
249
255
  )
250
- workflow = await context.active_service.workflow.submit_workflow(
251
- workflow=GIT_REPOSITORIES_IMPORT_OBJECTS, parameters={"model": model}
256
+ workflow = await graphql_context.active_service.workflow.submit_workflow(
257
+ workflow=GIT_REPOSITORIES_IMPORT_OBJECTS, context=graphql_context.get_context(), parameters={"model": model}
252
258
  )
253
259
  task = {"id": workflow.id}
254
260
  return cls(ok=True, task=task)
@@ -264,15 +270,15 @@ class ValidateRepositoryConnectivity(Mutation):
264
270
  @classmethod
265
271
  async def mutate(
266
272
  cls,
267
- root: dict, # pylint: disable=unused-argument
273
+ root: dict, # noqa: ARG003
268
274
  info: GraphQLResolveInfo,
269
275
  data: IdentifierInput,
270
276
  ) -> dict[str, Any]:
271
- context: GraphqlContext = info.context
272
- branch = context.branch
277
+ graphql_context: GraphqlContext = info.context
278
+ branch = graphql_context.branch
273
279
  repository_id = str(data.id)
274
280
  repo: CoreReadOnlyRepository | CoreRepository = await NodeManager.get_one_by_id_or_default_filter(
275
- db=context.db,
281
+ db=graphql_context.db,
276
282
  kind=InfrahubKind.GENERICREPOSITORY,
277
283
  id=repository_id,
278
284
  branch=branch,
@@ -282,8 +288,8 @@ class ValidateRepositoryConnectivity(Mutation):
282
288
  repository_name=str(repo.name.value),
283
289
  repository_location=str(repo.location.value),
284
290
  )
285
- if context.service:
286
- response = await context.service.message_bus.rpc(
291
+ if graphql_context.service:
292
+ response = await graphql_context.service.message_bus.rpc(
287
293
  message=message, response_class=GitRepositoryConnectivityResponse
288
294
  )
289
295