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
@@ -30,7 +30,7 @@ class RelationshipCountUpdateValidatorQuery(RelationshipSchemaValidatorQuery):
30
30
  self.max_count_override = max_count_override
31
31
  super().__init__(**kwargs)
32
32
 
33
- async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None:
33
+ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None: # noqa: ARG002
34
34
  branch_filter, branch_params = self.branch.get_query_filter_path(at=self.at.to_string(), is_isolated=False)
35
35
  self.params.update(branch_params)
36
36
 
@@ -20,7 +20,7 @@ if TYPE_CHECKING:
20
20
  class RelationshipOptionalUpdateValidatorQuery(RelationshipSchemaValidatorQuery):
21
21
  name = "relationship_constraints_optional_validator"
22
22
 
23
- async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None:
23
+ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None: # noqa: ARG002
24
24
  branch_filter, branch_params = self.branch.get_query_filter_path(at=self.at.to_string(), is_isolated=False)
25
25
  self.params.update(branch_params)
26
26
 
@@ -21,7 +21,7 @@ if TYPE_CHECKING:
21
21
  class RelationshipPeerUpdateValidatorQuery(RelationshipSchemaValidatorQuery):
22
22
  name = "relationship_constraints_peer_validator"
23
23
 
24
- async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None:
24
+ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None: # noqa: ARG002
25
25
  peer_schema = db.schema.get(name=self.relationship_schema.peer, branch=self.branch)
26
26
  allowed_peer_kinds = [peer_schema.kind]
27
27
  if isinstance(peer_schema, GenericSchema):
@@ -13,14 +13,16 @@ from infrahub.core.validators.model import (
13
13
  SchemaConstraintValidatorRequest,
14
14
  )
15
15
  from infrahub.dependencies.registry import get_component_registry
16
- from infrahub.services import services
16
+ from infrahub.services import InfrahubServices # noqa: TC001 needed for prefect flow
17
17
  from infrahub.workflows.utils import add_tags
18
18
 
19
19
  from .models.validate_migration import SchemaValidateMigrationData, SchemaValidatorPathResponseData
20
20
 
21
21
 
22
22
  @flow(name="schema_validate_migrations", flow_run_name="Validate schema migrations", persist_result=True)
23
- async def schema_validate_migrations(message: SchemaValidateMigrationData) -> list[SchemaValidatorPathResponseData]:
23
+ async def schema_validate_migrations(
24
+ message: SchemaValidateMigrationData, service: InfrahubServices
25
+ ) -> list[SchemaValidatorPathResponseData]:
24
26
  batch = InfrahubBatch(return_exceptions=True)
25
27
  log = get_run_logger()
26
28
  await add_tags(branches=[message.branch.name])
@@ -33,7 +35,7 @@ async def schema_validate_migrations(message: SchemaValidateMigrationData) -> li
33
35
  # NOTE this task is a good candidate to add a progress bar
34
36
  for constraint in message.constraints:
35
37
  schema = message.schema_branch.get(name=constraint.path.schema_kind)
36
- if not isinstance(schema, (GenericSchema, NodeSchema)):
38
+ if not isinstance(schema, GenericSchema | NodeSchema):
37
39
  continue
38
40
  batch.add(
39
41
  task=schema_path_validate,
@@ -41,13 +43,14 @@ async def schema_validate_migrations(message: SchemaValidateMigrationData) -> li
41
43
  constraint_name=constraint.constraint_name,
42
44
  node_schema=schema,
43
45
  schema_path=constraint.path,
46
+ service=service,
44
47
  )
45
48
 
46
49
  results = [result async for _, result in batch.execute()]
47
50
  return results
48
51
 
49
52
 
50
- @task(
53
+ @task( # type: ignore[arg-type]
51
54
  name="schema-path-validate",
52
55
  task_run_name="Validate schema path {constraint_name} in {branch.name}",
53
56
  description="Validate if a given migration is compatible with the existing data",
@@ -59,9 +62,8 @@ async def schema_path_validate(
59
62
  constraint_name: str,
60
63
  node_schema: NodeSchema | GenericSchema,
61
64
  schema_path: SchemaPath,
65
+ service: InfrahubServices,
62
66
  ) -> SchemaValidatorPathResponseData:
63
- service = services.service
64
-
65
67
  async with service.database.start_session() as db:
66
68
  constraint_request = SchemaConstraintValidatorRequest(
67
69
  branch=branch,
@@ -30,7 +30,7 @@ class NodeUniqueAttributeConstraintQuery(Query):
30
30
  def get_context(self) -> dict[str, str]:
31
31
  return {"kind": self.query_request.kind}
32
32
 
33
- async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None:
33
+ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa: ARG002
34
34
  branch_filter, branch_params = self.branch.get_query_filter_path(at=self.at.to_string(), is_isolated=False)
35
35
  self.params.update(branch_params)
36
36
  from_times = db.render_list_comprehension(items="relationships(potential_path)", item_name="from")
@@ -56,6 +56,7 @@ class NodeUniqueAttributeConstraintQuery(Query):
56
56
  relationship_names = set()
57
57
  relationship_attr_paths = []
58
58
  relationship_only_attr_paths = []
59
+ relationship_only_attr_values = []
59
60
  relationship_attr_paths_with_value = []
60
61
  for rel_path in self.query_request.relationship_attribute_paths:
61
62
  relationship_names.add(rel_path.identifier)
@@ -67,6 +68,8 @@ class NodeUniqueAttributeConstraintQuery(Query):
67
68
  relationship_attr_paths.append((rel_path.identifier, rel_path.attribute_name))
68
69
  else:
69
70
  relationship_only_attr_paths.append(rel_path.identifier)
71
+ if rel_path.value:
72
+ relationship_only_attr_values.append(rel_path.value)
70
73
 
71
74
  if (
72
75
  not attr_paths
@@ -89,34 +92,37 @@ class NodeUniqueAttributeConstraintQuery(Query):
89
92
  "relationship_attr_paths": relationship_attr_paths,
90
93
  "relationship_attr_paths_with_value": relationship_attr_paths_with_value,
91
94
  "relationship_only_attr_paths": relationship_only_attr_paths,
95
+ "relationship_only_attr_values": relationship_only_attr_values,
92
96
  "min_count_required": self.min_count_required,
93
97
  }
94
98
  )
95
99
 
96
100
  attr_paths_subquery = """
97
- WITH start_node
98
- MATCH attr_path = (start_node)-[:HAS_ATTRIBUTE]->(attr:Attribute)-[r:HAS_VALUE]->(attr_value:AttributeValue)
101
+ MATCH attr_path = (start_node:%(node_kind)s)-[:HAS_ATTRIBUTE]->(attr:Attribute)-[r:HAS_VALUE]->(attr_value:AttributeValue)
99
102
  WHERE attr.name in $attribute_names
100
103
  AND ([attr.name, type(r)] in $attr_paths
101
104
  OR [attr.name, type(r), attr_value.value] in $attr_paths_with_value)
102
- RETURN attr_path as potential_path, NULL as rel_identifier, attr.name as potential_attr, attr_value.value as potential_attr_value
103
- """
105
+ RETURN start_node, attr_path as potential_path, NULL as rel_identifier, attr.name as potential_attr, attr_value.value as potential_attr_value
106
+ """ % {"node_kind": self.query_request.kind}
104
107
 
105
108
  relationship_attr_paths_with_value_subquery = """
106
- WITH start_node
107
- MATCH rel_path = (start_node)-[:IS_RELATED]-(relationship_node:Relationship)-[:IS_RELATED]-(related_n:Node)-[:HAS_ATTRIBUTE]->(rel_attr:Attribute)-[:HAS_VALUE]->(rel_attr_value:AttributeValue)
109
+ MATCH rel_path = (start_node:%(node_kind)s)-[:IS_RELATED]-(relationship_node:Relationship)-[:IS_RELATED]-(related_n:Node)-[:HAS_ATTRIBUTE]->(rel_attr:Attribute)-[:HAS_VALUE]->(rel_attr_value:AttributeValue)
108
110
  WHERE relationship_node.name in $relationship_names
109
111
  AND ([relationship_node.name, rel_attr.name] in $relationship_attr_paths
110
112
  OR [relationship_node.name, rel_attr.name, rel_attr_value.value] in $relationship_attr_paths_with_value)
111
- RETURN rel_path as potential_path, relationship_node.name as rel_identifier, rel_attr.name as potential_attr, rel_attr_value.value as potential_attr_value
112
- """
113
+ RETURN start_node, rel_path as potential_path, relationship_node.name as rel_identifier, rel_attr.name as potential_attr, rel_attr_value.value as potential_attr_value
114
+ """ % {"node_kind": self.query_request.kind}
113
115
 
114
116
  relationship_only_attr_paths_subquery = """
115
- WITH start_node
116
- MATCH rel_path = (start_node)-[:IS_RELATED]-(relationship_node:Relationship)-[:IS_RELATED]-(related_n:Node)
117
- WHERE relationship_node.name in $relationship_only_attr_paths
118
- RETURN rel_path as potential_path, relationship_node.name as rel_identifier, "id" as potential_attr, related_n.uuid as potential_attr_value
119
- """
117
+ MATCH rel_path = (start_node:%(node_kind)s)-[:IS_RELATED]-(relationship_node:Relationship)-[:IS_RELATED]-(related_n:Node)
118
+ WHERE %(rel_node_filter)s relationship_node.name in $relationship_only_attr_paths
119
+ RETURN start_node, rel_path as potential_path, relationship_node.name as rel_identifier, "id" as potential_attr, related_n.uuid as potential_attr_value
120
+ """ % {
121
+ "node_kind": self.query_request.kind,
122
+ "rel_node_filter": "related_n.uuid IN $relationship_only_attr_values AND "
123
+ if relationship_only_attr_values
124
+ else "",
125
+ }
120
126
 
121
127
  select_subqueries = []
122
128
  if attr_paths or attr_paths_with_value:
@@ -130,8 +136,6 @@ class NodeUniqueAttributeConstraintQuery(Query):
130
136
 
131
137
  # ruff: noqa: E501
132
138
  query = """
133
- // group by node
134
- MATCH (start_node:%(node_kind)s)
135
139
  // get attributes for node and its relationships
136
140
  CALL {
137
141
  %(select_subqueries_str)s
@@ -201,7 +205,6 @@ class NodeUniqueAttributeConstraintQuery(Query):
201
205
  attr_value,
202
206
  relationship_identifier
203
207
  """ % {
204
- "node_kind": self.query_request.kind,
205
208
  "select_subqueries_str": select_subqueries_str,
206
209
  "branch_filter": branch_filter,
207
210
  "from_times": from_times,
@@ -173,6 +173,19 @@ class InfrahubDatabase:
173
173
  elif self.db_type == DatabaseType.MEMGRAPH:
174
174
  self.manager = DatabaseManagerMemgraph(db=self)
175
175
 
176
+ def __del__(self) -> None:
177
+ if not self._session or not self._is_session_local or self._session.closed():
178
+ return
179
+
180
+ try:
181
+ loop = asyncio.get_running_loop()
182
+ except RuntimeError:
183
+ loop = None
184
+ if loop and loop.is_running():
185
+ loop.create_task(self._session.close())
186
+ else:
187
+ asyncio.run(self._session.close())
188
+
176
189
  @property
177
190
  def is_session(self) -> bool:
178
191
  if self._mode == InfrahubDatabaseMode.SESSION:
@@ -307,7 +320,7 @@ class InfrahubDatabase:
307
320
  params: dict[str, Any] | None = None,
308
321
  name: str = "undefined",
309
322
  context: dict[str, str] | None = None,
310
- type: QueryType | None = None, # pylint: disable=redefined-builtin
323
+ type: QueryType | None = None,
311
324
  ) -> list[Record]:
312
325
  results, _ = await self.execute_query_with_metadata(
313
326
  query=query, params=params, name=name, context=context, type=type
@@ -320,7 +333,7 @@ class InfrahubDatabase:
320
333
  params: dict[str, Any] | None = None,
321
334
  name: str = "undefined",
322
335
  context: dict[str, str] | None = None,
323
- type: QueryType | None = None, # pylint: disable=redefined-builtin
336
+ type: QueryType | None = None,
324
337
  ) -> tuple[list[Record], dict[str, Any]]:
325
338
  with trace.get_tracer(__name__).start_as_current_span("execute_db_query_with_metadata") as span:
326
339
  span.set_attribute("query", query)
@@ -21,7 +21,7 @@ class IndexNodeMemgraph(IndexItem):
21
21
 
22
22
 
23
23
  class IndexManagerMemgraph(IndexManagerBase):
24
- def init(self, nodes: list[IndexItem], rels: list[IndexItem]) -> None:
24
+ def init(self, nodes: list[IndexItem], rels: list[IndexItem]) -> None: # noqa: ARG002
25
25
  self.nodes = [IndexNodeMemgraph(**item.model_dump()) for item in nodes]
26
26
  self.initialized = True
27
27
 
@@ -2,7 +2,6 @@ from infrahub.core.constraint.node.runner import NodeConstraintRunner
2
2
  from infrahub.dependencies.interface import DependencyBuilder, DependencyBuilderContext
3
3
 
4
4
  from ..node.grouped_uniqueness import NodeGroupedUniquenessConstraintDependency
5
- from ..node.uniqueness import NodeAttributeUniquenessConstraintDependency
6
5
  from ..relationship_manager.count import RelationshipCountConstraintDependency
7
6
  from ..relationship_manager.peer_kind import RelationshipPeerKindConstraintDependency
8
7
  from ..relationship_manager.profiles_kind import RelationshipProfilesKindConstraintDependency
@@ -15,7 +14,6 @@ class NodeConstraintRunnerDependency(DependencyBuilder[NodeConstraintRunner]):
15
14
  db=context.db,
16
15
  branch=context.branch,
17
16
  node_constraints=[
18
- NodeAttributeUniquenessConstraintDependency.build(context=context),
19
17
  NodeGroupedUniquenessConstraintDependency.build(context=context),
20
18
  ],
21
19
  relationship_manager_constraints=[
@@ -4,5 +4,5 @@ from infrahub.dependencies.interface import DependencyBuilder, DependencyBuilder
4
4
 
5
5
  class DiffCombinerDependency(DependencyBuilder[DiffCombiner]):
6
6
  @classmethod
7
- def build(cls, context: DependencyBuilderContext) -> DiffCombiner:
7
+ def build(cls, context: DependencyBuilderContext) -> DiffCombiner: # noqa: ARG003
8
8
  return DiffCombiner()
@@ -4,5 +4,5 @@ from infrahub.dependencies.interface import DependencyBuilder, DependencyBuilder
4
4
 
5
5
  class DiffConflictsEnricherDependency(DependencyBuilder[ConflictsEnricher]):
6
6
  @classmethod
7
- def build(cls, context: DependencyBuilderContext) -> ConflictsEnricher:
7
+ def build(cls, context: DependencyBuilderContext) -> ConflictsEnricher: # noqa: ARG003
8
8
  return ConflictsEnricher()
@@ -8,7 +8,6 @@ from .conflicts_enricher import DiffConflictsEnricherDependency
8
8
  from .data_check_synchronizer import DiffDataCheckSynchronizerDependency
9
9
  from .enricher.aggregated import DiffAggregatedEnricherDependency
10
10
  from .enricher.labels import DiffLabelsEnricherDependency
11
- from .enricher.summary_counts import DiffSummaryCountsEnricherDependency
12
11
  from .repository import DiffRepositoryDependency
13
12
 
14
13
 
@@ -22,7 +21,6 @@ class DiffCoordinatorDependency(DependencyBuilder[DiffCoordinator]):
22
21
  diff_enricher=DiffAggregatedEnricherDependency.build(context=context),
23
22
  conflicts_enricher=DiffConflictsEnricherDependency.build(context=context),
24
23
  labels_enricher=DiffLabelsEnricherDependency.build(context=context),
25
- summary_counts_enricher=DiffSummaryCountsEnricherDependency.build(context=context),
26
24
  data_check_synchronizer=DiffDataCheckSynchronizerDependency.build(context=context),
27
25
  conflict_transferer=DiffConflictTransfererDependency.build(context=context),
28
26
  )
@@ -4,5 +4,5 @@ from infrahub.dependencies.interface import DependencyBuilder, DependencyBuilder
4
4
 
5
5
  class DiffDeserializerDependency(DependencyBuilder[EnrichedDiffDeserializer]):
6
6
  @classmethod
7
- def build(cls, context: DependencyBuilderContext) -> EnrichedDiffDeserializer:
7
+ def build(cls, context: DependencyBuilderContext) -> EnrichedDiffDeserializer: # noqa: ARG003
8
8
  return EnrichedDiffDeserializer()
@@ -4,5 +4,5 @@ from infrahub.dependencies.interface import DependencyBuilder, DependencyBuilder
4
4
 
5
5
  class DiffSummaryCountsEnricherDependency(DependencyBuilder[DiffSummaryCountsEnricher]):
6
6
  @classmethod
7
- def build(cls, context: DependencyBuilderContext) -> DiffSummaryCountsEnricher:
7
+ def build(cls, context: DependencyBuilderContext) -> DiffSummaryCountsEnricher: # noqa: ARG003
8
8
  return DiffSummaryCountsEnricher()
@@ -1,26 +1,25 @@
1
- from pydantic import Field
1
+ from pydantic import Field, computed_field
2
2
 
3
3
  from infrahub.message_bus import InfrahubMessage
4
4
  from infrahub.message_bus.messages.refresh_registry_branches import RefreshRegistryBranches
5
5
  from infrahub.message_bus.messages.refresh_registry_rebasedbranch import RefreshRegistryRebasedBranch
6
6
 
7
- from .models import InfrahubBranchEvent
7
+ from .constants import EVENT_NAMESPACE
8
+ from .models import InfrahubEvent
8
9
 
9
10
 
10
- class BranchDeleteEvent(InfrahubBranchEvent):
11
+ class BranchDeletedEvent(InfrahubEvent):
11
12
  """Event generated when a branch has been deleted"""
12
13
 
14
+ branch_name: str = Field(..., description="The name of the branch")
13
15
  branch_id: str = Field(..., description="The ID of the mutated node")
14
16
  sync_with_git: bool = Field(..., description="Indicates if the branch was extended to Git")
15
17
 
16
- def get_name(self) -> str:
17
- return f"{self.get_event_namespace()}.branch.deleted"
18
-
19
18
  def get_resource(self) -> dict[str, str]:
20
19
  return {
21
- "prefect.resource.id": f"infrahub.branch.{self.branch}",
20
+ "prefect.resource.id": f"infrahub.branch.{self.branch_name}",
22
21
  "infrahub.branch.id": self.branch_id,
23
- "infrahub.branch.name": self.branch,
22
+ "infrahub.branch.name": self.branch_name,
24
23
  }
25
24
 
26
25
  def get_messages(self) -> list[InfrahubMessage]:
@@ -35,21 +34,23 @@ class BranchDeleteEvent(InfrahubBranchEvent):
35
34
  ]
36
35
  return events
37
36
 
37
+ @computed_field
38
+ def event_name(self) -> str:
39
+ return f"{EVENT_NAMESPACE}.branch.deleted"
40
+
38
41
 
39
- class BranchCreateEvent(InfrahubBranchEvent):
42
+ class BranchCreatedEvent(InfrahubEvent):
40
43
  """Event generated when a branch has been created"""
41
44
 
42
- branch_id: str = Field(..., description="The ID of the mutated node")
45
+ branch_name: str = Field(..., description="The name of the branch")
46
+ branch_id: str = Field(..., description="The ID of the branch")
43
47
  sync_with_git: bool = Field(..., description="Indicates if the branch was extended to Git")
44
48
 
45
- def get_name(self) -> str:
46
- return f"{self.get_event_namespace()}.branch.created"
47
-
48
49
  def get_resource(self) -> dict[str, str]:
49
50
  return {
50
- "prefect.resource.id": f"infrahub.branch.{self.branch}",
51
+ "prefect.resource.id": f"infrahub.branch.{self.branch_name}",
51
52
  "infrahub.branch.id": self.branch_id,
52
- "infrahub.branch.name": self.branch,
53
+ "infrahub.branch.name": self.branch_name,
53
54
  }
54
55
 
55
56
  def get_messages(self) -> list[InfrahubMessage]:
@@ -64,18 +65,39 @@ class BranchCreateEvent(InfrahubBranchEvent):
64
65
  ]
65
66
  return events
66
67
 
68
+ @computed_field
69
+ def event_name(self) -> str:
70
+ return f"{EVENT_NAMESPACE}.branch.created"
71
+
72
+
73
+ class BranchMergedEvent(InfrahubEvent):
74
+ """Event generated when a branch has been merged"""
75
+
76
+ def get_resource(self) -> dict[str, str]:
77
+ return {
78
+ "prefect.resource.id": f"infrahub.branch.{self.meta.get_branch_id()}",
79
+ "infrahub.node.kind": "Branch",
80
+ "infrahub.node.id": self.meta.get_branch_id(),
81
+ "infrahub.node.label": self.meta.context.branch.name,
82
+ }
83
+
84
+ def get_messages(self) -> list[InfrahubMessage]:
85
+ return []
86
+
87
+ @computed_field
88
+ def event_name(self) -> str:
89
+ return f"{EVENT_NAMESPACE}.branch.merged"
90
+
67
91
 
68
- class BranchRebaseEvent(InfrahubBranchEvent):
92
+ class BranchRebasedEvent(InfrahubEvent):
69
93
  """Event generated when a branch has been rebased"""
70
94
 
71
95
  branch_id: str = Field(..., description="The ID of the mutated node")
72
-
73
- def get_name(self) -> str:
74
- return f"{self.get_event_namespace()}.branch.rebased"
96
+ branch_name: str = Field(..., description="The name of the branch")
75
97
 
76
98
  def get_resource(self) -> dict[str, str]:
77
99
  return {
78
- "prefect.resource.id": f"infrahub.branch.{self.branch}",
100
+ "prefect.resource.id": f"infrahub.branch.{self.branch_name}",
79
101
  "infrahub.branch.id": self.branch_id,
80
102
  }
81
103
 
@@ -85,6 +107,10 @@ class BranchRebaseEvent(InfrahubBranchEvent):
85
107
  # branch=self.branch,
86
108
  # meta=self.get_message_meta(),
87
109
  # ),
88
- RefreshRegistryRebasedBranch(branch=self.branch),
110
+ RefreshRegistryRebasedBranch(branch=self.branch_name),
89
111
  ]
90
112
  return events
113
+
114
+ @computed_field
115
+ def event_name(self) -> str:
116
+ return f"{EVENT_NAMESPACE}.branch.rebased"
@@ -0,0 +1,73 @@
1
+ from typing import Any
2
+
3
+ from pydantic import Field, computed_field
4
+
5
+ from infrahub.core.constants import MutationAction
6
+ from infrahub.message_bus import InfrahubMessage
7
+
8
+ from .constants import EVENT_NAMESPACE
9
+ from .models import EventNode, InfrahubEvent
10
+
11
+
12
+ class GroupMutatedEvent(InfrahubEvent):
13
+ """Event generated when a node has been mutated"""
14
+
15
+ kind: str = Field(..., description="The type of updated group")
16
+ node_id: str = Field(..., description="The ID of the updated group")
17
+ action: MutationAction = Field(..., description="The action taken on the node")
18
+ members: list[EventNode] = Field(default_factory=list, description="Updated members during this event.")
19
+
20
+ def get_related(self) -> list[dict[str, str]]:
21
+ related = super().get_related()
22
+ related.append(
23
+ {
24
+ "prefect.resource.id": self.node_id,
25
+ "prefect.resource.role": "infrahub.related.node",
26
+ "infrahub.node.kind": self.kind,
27
+ }
28
+ )
29
+ for member in self.members:
30
+ related.append(
31
+ {
32
+ "prefect.resource.id": member.id,
33
+ "prefect.resource.role": "infrahub.related.node",
34
+ "infrahub.node.kind": member.kind,
35
+ }
36
+ )
37
+
38
+ return related
39
+
40
+ @computed_field
41
+ def event_name(self) -> str:
42
+ return f"{EVENT_NAMESPACE}.group.{self.action.value}"
43
+
44
+ def get_resource(self) -> dict[str, str]:
45
+ return {
46
+ "prefect.resource.id": f"infrahub.node.{self.node_id}",
47
+ "infrahub.node.kind": self.kind,
48
+ "infrahub.node.id": self.node_id,
49
+ "infrahub.node.action": self.action.value,
50
+ "infrahub.node.root_id": self.node_id,
51
+ }
52
+
53
+ def get_payload(self) -> dict[str, Any]:
54
+ return {"members": [member.model_dump() for member in self.members]}
55
+
56
+ def get_messages(self) -> list[InfrahubMessage]:
57
+ return []
58
+
59
+
60
+ class GroupMemberAddedEvent(GroupMutatedEvent):
61
+ action: MutationAction = MutationAction.CREATED
62
+
63
+ @computed_field
64
+ def event_name(self) -> str:
65
+ return f"{EVENT_NAMESPACE}.group.member_added"
66
+
67
+
68
+ class GroupMemberRemovedEvent(GroupMutatedEvent):
69
+ action: MutationAction = MutationAction.DELETED
70
+
71
+ @computed_field
72
+ def event_name(self) -> str:
73
+ return f"{EVENT_NAMESPACE}.group.member_removed"