infrahub-server 1.2.0rc0__py3-none-any.whl → 1.2.1__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 (365) hide show
  1. infrahub/api/dependencies.py +6 -6
  2. infrahub/api/diff/validation_models.py +7 -7
  3. infrahub/api/schema.py +1 -1
  4. infrahub/artifacts/models.py +5 -3
  5. infrahub/artifacts/tasks.py +3 -5
  6. infrahub/cli/__init__.py +13 -9
  7. infrahub/cli/constants.py +3 -0
  8. infrahub/cli/db.py +165 -183
  9. infrahub/cli/upgrade.py +146 -0
  10. infrahub/computed_attribute/gather.py +185 -0
  11. infrahub/computed_attribute/models.py +240 -12
  12. infrahub/computed_attribute/tasks.py +77 -441
  13. infrahub/computed_attribute/triggers.py +13 -47
  14. infrahub/config.py +43 -32
  15. infrahub/context.py +14 -0
  16. infrahub/core/account.py +4 -4
  17. infrahub/core/attribute.py +58 -58
  18. infrahub/core/branch/tasks.py +74 -22
  19. infrahub/core/changelog/diff.py +95 -36
  20. infrahub/core/changelog/models.py +217 -43
  21. infrahub/core/constants/__init__.py +28 -0
  22. infrahub/core/constants/infrahubkind.py +2 -0
  23. infrahub/core/constants/schema.py +2 -0
  24. infrahub/core/constraint/node/runner.py +9 -8
  25. infrahub/core/diff/branch_differ.py +10 -10
  26. infrahub/core/diff/enricher/cardinality_one.py +5 -0
  27. infrahub/core/diff/enricher/hierarchy.py +17 -4
  28. infrahub/core/diff/enricher/labels.py +5 -0
  29. infrahub/core/diff/enricher/path_identifier.py +4 -0
  30. infrahub/core/diff/ipam_diff_parser.py +4 -5
  31. infrahub/core/diff/model/diff.py +27 -27
  32. infrahub/core/diff/model/path.py +32 -9
  33. infrahub/core/diff/parent_node_adder.py +78 -0
  34. infrahub/core/diff/payload_builder.py +13 -2
  35. infrahub/core/diff/query/filters.py +2 -2
  36. infrahub/core/diff/query/merge.py +20 -17
  37. infrahub/core/diff/query/save.py +188 -182
  38. infrahub/core/diff/query/summary_counts_enricher.py +51 -4
  39. infrahub/core/diff/query_parser.py +4 -4
  40. infrahub/core/diff/repository/deserializer.py +8 -3
  41. infrahub/core/diff/repository/repository.py +156 -38
  42. infrahub/core/diff/tasks.py +4 -4
  43. infrahub/core/graph/__init__.py +1 -1
  44. infrahub/core/graph/index.py +3 -0
  45. infrahub/core/initialization.py +1 -10
  46. infrahub/core/ipam/constants.py +3 -4
  47. infrahub/core/ipam/reconciler.py +12 -12
  48. infrahub/core/ipam/utilization.py +10 -13
  49. infrahub/core/manager.py +36 -36
  50. infrahub/core/merge.py +7 -7
  51. infrahub/core/migrations/__init__.py +2 -3
  52. infrahub/core/migrations/graph/__init__.py +12 -3
  53. infrahub/core/migrations/graph/m017_add_core_profile.py +1 -5
  54. infrahub/core/migrations/graph/m018_uniqueness_nulls.py +4 -4
  55. infrahub/core/migrations/graph/m019_restore_rels_to_time.py +256 -0
  56. infrahub/core/migrations/graph/m020_duplicate_edges.py +160 -0
  57. infrahub/core/migrations/graph/m021_missing_hierarchy_merge.py +51 -0
  58. infrahub/core/migrations/graph/m022_add_generate_template_attr.py +48 -0
  59. infrahub/core/migrations/graph/m023_deduplicate_cardinality_one_relationships.py +96 -0
  60. infrahub/core/migrations/query/attribute_add.py +2 -2
  61. infrahub/core/migrations/query/node_duplicate.py +43 -26
  62. infrahub/core/migrations/query/schema_attribute_update.py +2 -2
  63. infrahub/core/migrations/schema/models.py +19 -4
  64. infrahub/core/migrations/schema/node_remove.py +26 -12
  65. infrahub/core/migrations/schema/tasks.py +2 -2
  66. infrahub/core/migrations/shared.py +16 -16
  67. infrahub/core/models.py +15 -6
  68. infrahub/core/node/__init__.py +43 -39
  69. infrahub/core/node/base.py +2 -4
  70. infrahub/core/node/constraints/attribute_uniqueness.py +2 -2
  71. infrahub/core/node/constraints/grouped_uniqueness.py +99 -47
  72. infrahub/core/node/constraints/interface.py +1 -2
  73. infrahub/core/node/delete_validator.py +3 -5
  74. infrahub/core/node/ipam.py +4 -4
  75. infrahub/core/node/permissions.py +7 -7
  76. infrahub/core/node/resource_manager/ip_address_pool.py +6 -6
  77. infrahub/core/node/resource_manager/ip_prefix_pool.py +6 -6
  78. infrahub/core/node/resource_manager/number_pool.py +3 -3
  79. infrahub/core/path.py +12 -12
  80. infrahub/core/property.py +11 -11
  81. infrahub/core/protocols.py +7 -0
  82. infrahub/core/protocols_base.py +21 -21
  83. infrahub/core/query/__init__.py +33 -33
  84. infrahub/core/query/attribute.py +6 -4
  85. infrahub/core/query/diff.py +3 -3
  86. infrahub/core/query/node.py +82 -32
  87. infrahub/core/query/relationship.py +228 -40
  88. infrahub/core/query/resource_manager.py +2 -0
  89. infrahub/core/query/standard_node.py +3 -3
  90. infrahub/core/query/subquery.py +9 -9
  91. infrahub/core/registry.py +13 -15
  92. infrahub/core/relationship/constraints/count.py +3 -4
  93. infrahub/core/relationship/constraints/peer_kind.py +3 -4
  94. infrahub/core/relationship/constraints/profiles_kind.py +2 -2
  95. infrahub/core/relationship/model.py +51 -59
  96. infrahub/core/schema/attribute_schema.py +16 -8
  97. infrahub/core/schema/basenode_schema.py +105 -44
  98. infrahub/core/schema/computed_attribute.py +3 -3
  99. infrahub/core/schema/definitions/core/__init__.py +147 -0
  100. infrahub/core/schema/definitions/core/account.py +171 -0
  101. infrahub/core/schema/definitions/core/artifact.py +136 -0
  102. infrahub/core/schema/definitions/core/builtin.py +24 -0
  103. infrahub/core/schema/definitions/core/check.py +68 -0
  104. infrahub/core/schema/definitions/core/core.py +17 -0
  105. infrahub/core/schema/definitions/core/generator.py +100 -0
  106. infrahub/core/schema/definitions/core/graphql_query.py +79 -0
  107. infrahub/core/schema/definitions/core/group.py +108 -0
  108. infrahub/core/schema/definitions/core/ipam.py +193 -0
  109. infrahub/core/schema/definitions/core/lineage.py +19 -0
  110. infrahub/core/schema/definitions/core/menu.py +48 -0
  111. infrahub/core/schema/definitions/core/permission.py +163 -0
  112. infrahub/core/schema/definitions/core/profile.py +18 -0
  113. infrahub/core/schema/definitions/core/propose_change.py +97 -0
  114. infrahub/core/schema/definitions/core/propose_change_comment.py +193 -0
  115. infrahub/core/schema/definitions/core/propose_change_validator.py +328 -0
  116. infrahub/core/schema/definitions/core/repository.py +286 -0
  117. infrahub/core/schema/definitions/core/resource_pool.py +170 -0
  118. infrahub/core/schema/definitions/core/template.py +27 -0
  119. infrahub/core/schema/definitions/core/transform.py +96 -0
  120. infrahub/core/schema/definitions/core/webhook.py +134 -0
  121. infrahub/core/schema/definitions/internal.py +16 -16
  122. infrahub/core/schema/dropdown.py +3 -4
  123. infrahub/core/schema/generated/attribute_schema.py +15 -18
  124. infrahub/core/schema/generated/base_node_schema.py +12 -14
  125. infrahub/core/schema/generated/node_schema.py +3 -5
  126. infrahub/core/schema/generated/relationship_schema.py +9 -11
  127. infrahub/core/schema/generic_schema.py +2 -2
  128. infrahub/core/schema/manager.py +20 -9
  129. infrahub/core/schema/node_schema.py +4 -2
  130. infrahub/core/schema/relationship_schema.py +14 -6
  131. infrahub/core/schema/schema_branch.py +292 -144
  132. infrahub/core/schema/schema_branch_computed.py +41 -4
  133. infrahub/core/task/task.py +3 -3
  134. infrahub/core/task/user_task.py +15 -15
  135. infrahub/core/timestamp.py +3 -3
  136. infrahub/core/utils.py +20 -18
  137. infrahub/core/validators/__init__.py +1 -3
  138. infrahub/core/validators/aggregated_checker.py +2 -2
  139. infrahub/core/validators/attribute/choices.py +2 -2
  140. infrahub/core/validators/attribute/enum.py +2 -2
  141. infrahub/core/validators/attribute/kind.py +2 -2
  142. infrahub/core/validators/attribute/length.py +2 -2
  143. infrahub/core/validators/attribute/optional.py +2 -2
  144. infrahub/core/validators/attribute/regex.py +2 -2
  145. infrahub/core/validators/attribute/unique.py +2 -2
  146. infrahub/core/validators/checks_runner.py +25 -2
  147. infrahub/core/validators/determiner.py +1 -3
  148. infrahub/core/validators/interface.py +6 -2
  149. infrahub/core/validators/model.py +22 -3
  150. infrahub/core/validators/models/validate_migration.py +17 -4
  151. infrahub/core/validators/node/attribute.py +2 -2
  152. infrahub/core/validators/node/generate_profile.py +2 -2
  153. infrahub/core/validators/node/hierarchy.py +3 -5
  154. infrahub/core/validators/node/inherit_from.py +27 -5
  155. infrahub/core/validators/node/relationship.py +2 -2
  156. infrahub/core/validators/relationship/count.py +4 -4
  157. infrahub/core/validators/relationship/optional.py +2 -2
  158. infrahub/core/validators/relationship/peer.py +2 -2
  159. infrahub/core/validators/shared.py +2 -2
  160. infrahub/core/validators/tasks.py +8 -0
  161. infrahub/core/validators/uniqueness/checker.py +22 -21
  162. infrahub/core/validators/uniqueness/index.py +2 -2
  163. infrahub/core/validators/uniqueness/model.py +11 -11
  164. infrahub/database/__init__.py +27 -22
  165. infrahub/database/metrics.py +7 -1
  166. infrahub/dependencies/builder/constraint/grouped/node_runner.py +1 -3
  167. infrahub/dependencies/builder/diff/deserializer.py +3 -1
  168. infrahub/dependencies/builder/diff/enricher/hierarchy.py +3 -1
  169. infrahub/dependencies/builder/diff/parent_node_adder.py +8 -0
  170. infrahub/dependencies/component/registry.py +2 -2
  171. infrahub/events/__init__.py +25 -2
  172. infrahub/events/artifact_action.py +64 -0
  173. infrahub/events/branch_action.py +33 -22
  174. infrahub/events/generator.py +71 -0
  175. infrahub/events/group_action.py +51 -21
  176. infrahub/events/models.py +18 -19
  177. infrahub/events/node_action.py +88 -37
  178. infrahub/events/repository_action.py +5 -18
  179. infrahub/events/schema_action.py +4 -9
  180. infrahub/events/utils.py +16 -0
  181. infrahub/events/validator_action.py +55 -0
  182. infrahub/exceptions.py +32 -24
  183. infrahub/generators/models.py +2 -3
  184. infrahub/generators/tasks.py +24 -4
  185. infrahub/git/base.py +7 -7
  186. infrahub/git/integrator.py +48 -24
  187. infrahub/git/models.py +101 -9
  188. infrahub/git/repository.py +3 -3
  189. infrahub/git/tasks.py +408 -6
  190. infrahub/git/utils.py +48 -0
  191. infrahub/git/worktree.py +1 -2
  192. infrahub/git_credential/askpass.py +1 -2
  193. infrahub/graphql/analyzer.py +12 -0
  194. infrahub/graphql/app.py +13 -15
  195. infrahub/graphql/context.py +39 -0
  196. infrahub/graphql/initialization.py +3 -0
  197. infrahub/graphql/loaders/node.py +2 -12
  198. infrahub/graphql/loaders/peers.py +77 -0
  199. infrahub/graphql/loaders/shared.py +13 -0
  200. infrahub/graphql/manager.py +17 -19
  201. infrahub/graphql/mutations/artifact_definition.py +5 -5
  202. infrahub/graphql/mutations/branch.py +26 -1
  203. infrahub/graphql/mutations/computed_attribute.py +9 -5
  204. infrahub/graphql/mutations/diff.py +23 -11
  205. infrahub/graphql/mutations/diff_conflict.py +5 -0
  206. infrahub/graphql/mutations/generator.py +83 -0
  207. infrahub/graphql/mutations/graphql_query.py +5 -5
  208. infrahub/graphql/mutations/ipam.py +54 -74
  209. infrahub/graphql/mutations/main.py +195 -132
  210. infrahub/graphql/mutations/menu.py +7 -7
  211. infrahub/graphql/mutations/models.py +2 -4
  212. infrahub/graphql/mutations/node_getter/by_default_filter.py +10 -10
  213. infrahub/graphql/mutations/node_getter/by_hfid.py +1 -3
  214. infrahub/graphql/mutations/node_getter/by_id.py +1 -3
  215. infrahub/graphql/mutations/node_getter/interface.py +1 -2
  216. infrahub/graphql/mutations/proposed_change.py +7 -7
  217. infrahub/graphql/mutations/relationship.py +93 -19
  218. infrahub/graphql/mutations/repository.py +8 -8
  219. infrahub/graphql/mutations/resource_manager.py +3 -3
  220. infrahub/graphql/mutations/schema.py +19 -4
  221. infrahub/graphql/mutations/webhook.py +137 -0
  222. infrahub/graphql/parser.py +4 -4
  223. infrahub/graphql/permissions.py +1 -10
  224. infrahub/graphql/queries/diff/tree.py +19 -14
  225. infrahub/graphql/queries/event.py +5 -2
  226. infrahub/graphql/queries/ipam.py +2 -2
  227. infrahub/graphql/queries/relationship.py +2 -2
  228. infrahub/graphql/queries/search.py +2 -2
  229. infrahub/graphql/resolvers/many_relationship.py +264 -0
  230. infrahub/graphql/resolvers/resolver.py +13 -110
  231. infrahub/graphql/schema.py +2 -0
  232. infrahub/graphql/subscription/graphql_query.py +2 -0
  233. infrahub/graphql/types/context.py +12 -0
  234. infrahub/graphql/types/event.py +84 -17
  235. infrahub/graphql/types/node.py +2 -2
  236. infrahub/graphql/utils.py +2 -2
  237. infrahub/groups/ancestors.py +29 -0
  238. infrahub/groups/parsers.py +107 -0
  239. infrahub/lock.py +20 -20
  240. infrahub/menu/constants.py +0 -1
  241. infrahub/menu/generator.py +9 -21
  242. infrahub/menu/menu.py +17 -38
  243. infrahub/menu/models.py +117 -16
  244. infrahub/menu/repository.py +111 -0
  245. infrahub/menu/utils.py +5 -8
  246. infrahub/message_bus/__init__.py +11 -13
  247. infrahub/message_bus/messages/__init__.py +1 -21
  248. infrahub/message_bus/messages/check_generator_run.py +3 -3
  249. infrahub/message_bus/messages/finalize_validator_execution.py +3 -0
  250. infrahub/message_bus/messages/proposed_change/request_proposedchange_refreshartifacts.py +6 -0
  251. infrahub/message_bus/messages/request_generatordefinition_check.py +2 -0
  252. infrahub/message_bus/messages/send_echo_request.py +1 -1
  253. infrahub/message_bus/operations/__init__.py +1 -10
  254. infrahub/message_bus/operations/check/__init__.py +2 -2
  255. infrahub/message_bus/operations/check/generator.py +1 -0
  256. infrahub/message_bus/operations/event/__init__.py +2 -2
  257. infrahub/message_bus/operations/event/worker.py +0 -3
  258. infrahub/message_bus/operations/finalize/validator.py +51 -1
  259. infrahub/message_bus/operations/requests/__init__.py +0 -2
  260. infrahub/message_bus/operations/requests/generator_definition.py +21 -23
  261. infrahub/message_bus/operations/requests/proposed_change.py +14 -10
  262. infrahub/permissions/globals.py +15 -0
  263. infrahub/pools/number.py +2 -4
  264. infrahub/proposed_change/models.py +3 -0
  265. infrahub/proposed_change/tasks.py +58 -45
  266. infrahub/pytest_plugin.py +13 -10
  267. infrahub/server.py +2 -3
  268. infrahub/services/__init__.py +2 -2
  269. infrahub/services/adapters/cache/__init__.py +4 -6
  270. infrahub/services/adapters/cache/nats.py +4 -5
  271. infrahub/services/adapters/cache/redis.py +3 -7
  272. infrahub/services/adapters/event/__init__.py +1 -1
  273. infrahub/services/adapters/message_bus/__init__.py +3 -3
  274. infrahub/services/adapters/message_bus/local.py +2 -2
  275. infrahub/services/adapters/message_bus/nats.py +4 -4
  276. infrahub/services/adapters/message_bus/rabbitmq.py +4 -4
  277. infrahub/services/adapters/workflow/local.py +2 -2
  278. infrahub/services/component.py +5 -5
  279. infrahub/services/protocols.py +7 -7
  280. infrahub/services/scheduler.py +1 -3
  281. infrahub/task_manager/event.py +102 -9
  282. infrahub/task_manager/models.py +27 -7
  283. infrahub/tasks/artifact.py +7 -6
  284. infrahub/telemetry/__init__.py +0 -0
  285. infrahub/telemetry/constants.py +9 -0
  286. infrahub/telemetry/database.py +86 -0
  287. infrahub/telemetry/models.py +65 -0
  288. infrahub/telemetry/task_manager.py +77 -0
  289. infrahub/{tasks/telemetry.py → telemetry/tasks.py} +49 -56
  290. infrahub/telemetry/utils.py +11 -0
  291. infrahub/trace.py +4 -4
  292. infrahub/transformations/tasks.py +2 -2
  293. infrahub/trigger/catalogue.py +4 -6
  294. infrahub/trigger/constants.py +0 -8
  295. infrahub/trigger/models.py +54 -5
  296. infrahub/trigger/setup.py +90 -0
  297. infrahub/trigger/tasks.py +35 -84
  298. infrahub/utils.py +11 -1
  299. infrahub/validators/__init__.py +0 -0
  300. infrahub/validators/events.py +42 -0
  301. infrahub/validators/tasks.py +41 -0
  302. infrahub/webhook/gather.py +17 -0
  303. infrahub/webhook/models.py +176 -44
  304. infrahub/webhook/tasks.py +154 -155
  305. infrahub/webhook/triggers.py +31 -7
  306. infrahub/workers/infrahub_async.py +2 -2
  307. infrahub/workers/utils.py +2 -2
  308. infrahub/workflows/catalogue.py +86 -35
  309. infrahub/workflows/initialization.py +8 -2
  310. infrahub/workflows/models.py +27 -1
  311. infrahub/workflows/utils.py +10 -1
  312. infrahub_sdk/client.py +35 -8
  313. infrahub_sdk/config.py +3 -0
  314. infrahub_sdk/context.py +13 -0
  315. infrahub_sdk/ctl/branch.py +3 -2
  316. infrahub_sdk/ctl/cli_commands.py +5 -1
  317. infrahub_sdk/ctl/utils.py +0 -16
  318. infrahub_sdk/exceptions.py +12 -0
  319. infrahub_sdk/generator.py +4 -1
  320. infrahub_sdk/graphql.py +45 -13
  321. infrahub_sdk/node.py +71 -22
  322. infrahub_sdk/protocols.py +21 -8
  323. infrahub_sdk/protocols_base.py +32 -11
  324. infrahub_sdk/query_groups.py +6 -35
  325. infrahub_sdk/schema/__init__.py +55 -26
  326. infrahub_sdk/schema/main.py +8 -0
  327. infrahub_sdk/task/__init__.py +11 -0
  328. infrahub_sdk/task/constants.py +3 -0
  329. infrahub_sdk/task/exceptions.py +25 -0
  330. infrahub_sdk/task/manager.py +551 -0
  331. infrahub_sdk/task/models.py +74 -0
  332. infrahub_sdk/testing/schemas/animal.py +9 -0
  333. infrahub_sdk/timestamp.py +142 -33
  334. infrahub_sdk/utils.py +29 -1
  335. {infrahub_server-1.2.0rc0.dist-info → infrahub_server-1.2.1.dist-info}/METADATA +8 -6
  336. {infrahub_server-1.2.0rc0.dist-info → infrahub_server-1.2.1.dist-info}/RECORD +349 -293
  337. {infrahub_server-1.2.0rc0.dist-info → infrahub_server-1.2.1.dist-info}/entry_points.txt +1 -0
  338. infrahub_testcontainers/constants.py +2 -0
  339. infrahub_testcontainers/container.py +157 -12
  340. infrahub_testcontainers/docker-compose.test.yml +31 -6
  341. infrahub_testcontainers/helpers.py +18 -73
  342. infrahub_testcontainers/host.py +41 -0
  343. infrahub_testcontainers/measurements.py +93 -0
  344. infrahub_testcontainers/models.py +38 -0
  345. infrahub_testcontainers/performance_test.py +166 -0
  346. infrahub_testcontainers/plugin.py +136 -0
  347. infrahub_testcontainers/prometheus.yml +30 -0
  348. infrahub/core/schema/definitions/core.py +0 -2286
  349. infrahub/message_bus/messages/check_repository_checkdefinition.py +0 -20
  350. infrahub/message_bus/messages/check_repository_mergeconflicts.py +0 -16
  351. infrahub/message_bus/messages/check_repository_usercheck.py +0 -26
  352. infrahub/message_bus/messages/event_branch_create.py +0 -11
  353. infrahub/message_bus/messages/event_branch_delete.py +0 -11
  354. infrahub/message_bus/messages/event_branch_rebased.py +0 -9
  355. infrahub/message_bus/messages/event_node_mutated.py +0 -15
  356. infrahub/message_bus/messages/event_schema_update.py +0 -9
  357. infrahub/message_bus/messages/request_repository_checks.py +0 -12
  358. infrahub/message_bus/messages/request_repository_userchecks.py +0 -18
  359. infrahub/message_bus/operations/check/repository.py +0 -293
  360. infrahub/message_bus/operations/event/node.py +0 -20
  361. infrahub/message_bus/operations/event/schema.py +0 -17
  362. infrahub/message_bus/operations/requests/repository.py +0 -133
  363. infrahub/webhook/constants.py +0 -1
  364. {infrahub_server-1.2.0rc0.dist-info → infrahub_server-1.2.1.dist-info}/LICENSE.txt +0 -0
  365. {infrahub_server-1.2.0rc0.dist-info → infrahub_server-1.2.1.dist-info}/WHEEL +0 -0
infrahub/git/tasks.py CHANGED
@@ -1,23 +1,42 @@
1
1
  from infrahub_sdk import InfrahubClient
2
- from infrahub_sdk.protocols import CoreArtifact, CoreArtifactDefinition, CoreRepository
2
+ from infrahub_sdk.protocols import (
3
+ CoreArtifact,
4
+ CoreArtifactDefinition,
5
+ CoreCheckDefinition,
6
+ CoreRepository,
7
+ CoreRepositoryValidator,
8
+ CoreUserValidator,
9
+ )
10
+ from infrahub_sdk.uuidt import UUIDT
3
11
  from prefect import flow, task
4
12
  from prefect.cache_policies import NONE
5
13
  from prefect.logging import get_run_logger
6
14
 
7
15
  from infrahub import lock
8
16
  from infrahub.context import InfrahubContext
9
- from infrahub.core.constants import InfrahubKind, RepositoryInternalStatus
17
+ from infrahub.core.constants import InfrahubKind, RepositoryInternalStatus, ValidatorConclusion
10
18
  from infrahub.core.registry import registry
11
- from infrahub.exceptions import RepositoryError
19
+ from infrahub.exceptions import CheckError, RepositoryError
12
20
  from infrahub.message_bus import Meta, messages
13
21
  from infrahub.services import InfrahubServices
22
+ from infrahub.validators.tasks import start_validator
14
23
  from infrahub.worker import WORKER_IDENTITY
15
24
 
25
+ from ..core.manager import NodeManager
26
+ from ..core.timestamp import Timestamp
27
+ from ..core.validators.checks_runner import run_checks_and_update_validator
16
28
  from ..log import get_log_data
17
29
  from ..tasks.artifact import define_artifact
18
- from ..workflows.catalogue import REQUEST_ARTIFACT_DEFINITION_GENERATE, REQUEST_ARTIFACT_GENERATE
30
+ from ..workflows.catalogue import (
31
+ GIT_REPOSITORY_MERGE_CONFLICTS_CHECKS_RUN,
32
+ GIT_REPOSITORY_USER_CHECK_RUN,
33
+ GIT_REPOSITORY_USER_CHECKS_DEFINITIONS_TRIGGER,
34
+ REQUEST_ARTIFACT_DEFINITION_GENERATE,
35
+ REQUEST_ARTIFACT_GENERATE,
36
+ )
19
37
  from ..workflows.utils import add_branch_tag, add_tags
20
38
  from .models import (
39
+ CheckRepositoryMergeConflicts,
21
40
  GitDiffNamesOnly,
22
41
  GitDiffNamesOnlyResponse,
23
42
  GitRepositoryAdd,
@@ -27,6 +46,10 @@ from .models import (
27
46
  GitRepositoryPullReadOnly,
28
47
  RequestArtifactDefinitionGenerate,
29
48
  RequestArtifactGenerate,
49
+ TriggerRepositoryInternalChecks,
50
+ TriggerRepositoryUserChecks,
51
+ UserCheckData,
52
+ UserCheckDefinitionData,
30
53
  )
31
54
  from .repository import InfrahubReadOnlyRepository, InfrahubRepository, get_initialized_repo
32
55
 
@@ -257,10 +280,10 @@ async def generate_artifact(model: RequestArtifactGenerate, service: InfrahubSer
257
280
  commit=model.commit,
258
281
  )
259
282
 
260
- artifact = await define_artifact(model=model, service=service)
283
+ artifact, artifact_created = await define_artifact(model=model, service=service)
261
284
 
262
285
  try:
263
- result = await repo.render_artifact(artifact=artifact, message=model)
286
+ result = await repo.render_artifact(artifact=artifact, artifact_created=artifact_created, message=model)
264
287
  log.debug(
265
288
  f"Generated artifact | changed: {result.changed} | {result.checksum} | {result.storage_id}",
266
289
  )
@@ -343,7 +366,9 @@ async def generate_request_artifact_definition(
343
366
  variables=member.extract(params=artifact_definition.parameters.value),
344
367
  target_id=member.id,
345
368
  target_name=member.display_label,
369
+ target_kind=member.get_kind(),
346
370
  timeout=transform.timeout.value,
371
+ context=context,
347
372
  )
348
373
 
349
374
  await service.workflow.submit_workflow(
@@ -486,3 +511,380 @@ async def git_repository_diff_names_only(
486
511
  files_added=files_added, files_changed=files_changed, files_removed=files_removed
487
512
  )
488
513
  return response
514
+
515
+
516
+ @flow(
517
+ name="git-repository-user-checks-definition-trigger",
518
+ flow_run_name="Trigger user defined checks for repository {model.repository_name}",
519
+ )
520
+ async def trigger_repository_user_checks_definitions(
521
+ model: UserCheckDefinitionData, context: InfrahubContext, service: InfrahubServices
522
+ ) -> None:
523
+ await add_tags(branches=[model.branch_name], nodes=[model.proposed_change])
524
+ log = get_run_logger()
525
+
526
+ definition = await service.client.get(
527
+ kind=CoreCheckDefinition, id=model.check_definition_id, branch=model.branch_name
528
+ )
529
+ proposed_change = await service.client.get(kind=InfrahubKind.PROPOSEDCHANGE, id=model.proposed_change)
530
+ validator_execution_id = str(UUIDT())
531
+ check_execution_ids: list[str] = []
532
+ await proposed_change.validations.fetch()
533
+
534
+ previous_validator: CoreUserValidator | None = None
535
+ for relationship in proposed_change.validations.peers:
536
+ existing_validator = relationship.peer
537
+
538
+ if (
539
+ existing_validator.typename == InfrahubKind.USERVALIDATOR
540
+ and existing_validator.repository.id == model.repository_id
541
+ and existing_validator.check_definition.id == model.check_definition_id
542
+ ):
543
+ previous_validator = existing_validator
544
+ service.log.info("Found the same validator", validator=previous_validator)
545
+
546
+ validator = await start_validator(
547
+ service=service,
548
+ validator=previous_validator,
549
+ validator_type=CoreUserValidator,
550
+ proposed_change=model.proposed_change,
551
+ data={
552
+ "label": f"Check: {definition.name.value}",
553
+ "repository": model.repository_id,
554
+ "check_definition": model.check_definition_id,
555
+ },
556
+ context=context,
557
+ )
558
+
559
+ if definition.targets.id:
560
+ # Check against a group of targets
561
+ await definition.targets.fetch()
562
+ group = definition.targets.peer
563
+ await group.members.fetch()
564
+ check_models = []
565
+ for relationship in group.members.peers:
566
+ member = relationship.peer
567
+
568
+ check_execution_id = str(UUIDT())
569
+ check_execution_ids.append(check_execution_id)
570
+ check_model = UserCheckData(
571
+ name=member.display_label,
572
+ validator_id=validator.id,
573
+ validator_execution_id=validator_execution_id,
574
+ check_execution_id=check_execution_id,
575
+ repository_id=model.repository_id,
576
+ repository_name=model.repository_name,
577
+ commit=model.commit,
578
+ file_path=model.file_path,
579
+ class_name=model.class_name,
580
+ branch_name=model.branch_name,
581
+ check_definition_id=model.check_definition_id,
582
+ proposed_change=model.proposed_change,
583
+ variables=member.extract(params=definition.parameters.value),
584
+ branch_diff=model.branch_diff,
585
+ timeout=definition.timeout.value,
586
+ )
587
+ check_models.append(check_model)
588
+ else:
589
+ check_execution_id = str(UUIDT())
590
+ check_execution_ids.append(check_execution_id)
591
+ check_models = [
592
+ UserCheckData(
593
+ name=definition.name.value,
594
+ validator_id=validator.id,
595
+ validator_execution_id=validator_execution_id,
596
+ check_execution_id=check_execution_id,
597
+ repository_id=model.repository_id,
598
+ repository_name=model.repository_name,
599
+ commit=model.commit,
600
+ file_path=model.file_path,
601
+ class_name=model.class_name,
602
+ branch_name=model.branch_name,
603
+ check_definition_id=model.check_definition_id,
604
+ proposed_change=model.proposed_change,
605
+ branch_diff=model.branch_diff,
606
+ timeout=definition.timeout.value,
607
+ )
608
+ ]
609
+
610
+ checks_in_execution = ",".join(check_execution_ids)
611
+ log.info(f"Checks in execution {checks_in_execution}")
612
+
613
+ checks_coroutines = [
614
+ service.workflow.execute_workflow(
615
+ workflow=GIT_REPOSITORY_USER_CHECK_RUN, parameters={"model": model}, expected_return=ValidatorConclusion
616
+ )
617
+ for model in check_models
618
+ ]
619
+
620
+ await run_checks_and_update_validator(
621
+ checks=checks_coroutines,
622
+ validator=validator,
623
+ context=context,
624
+ service=service,
625
+ proposed_change_id=model.proposed_change,
626
+ )
627
+
628
+
629
+ @flow(
630
+ name="git-repository-trigger-user-checks",
631
+ flow_run_name="Evaluating user-defined checks on repository {model.repository_name}",
632
+ )
633
+ async def trigger_user_checks(
634
+ model: TriggerRepositoryUserChecks, service: InfrahubServices, context: InfrahubContext
635
+ ) -> None:
636
+ """Request to start validation checks on a specific repository for User-defined checks."""
637
+
638
+ await add_tags(branches=[model.source_branch], nodes=[model.proposed_change])
639
+ log = get_run_logger()
640
+
641
+ repository = await service.client.get(
642
+ kind=InfrahubKind.GENERICREPOSITORY, id=model.repository_id, branch=model.source_branch, fragment=True
643
+ )
644
+ await repository.checks.fetch()
645
+
646
+ for relationship in repository.checks.peers:
647
+ log.info("Adding check for user defined check")
648
+ check_definition = relationship.peer
649
+ user_check_definition_model = UserCheckDefinitionData(
650
+ check_definition_id=check_definition.id,
651
+ repository_id=repository.id,
652
+ repository_name=repository.name.value,
653
+ commit=repository.commit.value,
654
+ file_path=check_definition.file_path.value,
655
+ class_name=check_definition.class_name.value,
656
+ branch_name=model.source_branch,
657
+ proposed_change=model.proposed_change,
658
+ branch_diff=model.branch_diff,
659
+ )
660
+ await service.workflow.submit_workflow(
661
+ workflow=GIT_REPOSITORY_USER_CHECKS_DEFINITIONS_TRIGGER,
662
+ context=context,
663
+ parameters={"model": user_check_definition_model},
664
+ )
665
+
666
+
667
+ @flow(
668
+ name="git-repository-trigger-internal-checks",
669
+ flow_run_name="Running repository checks for repository {model.repository}",
670
+ )
671
+ async def trigger_internal_checks(
672
+ model: TriggerRepositoryInternalChecks, service: InfrahubServices, context: InfrahubContext
673
+ ) -> None:
674
+ """Request to start validation checks on a specific repository."""
675
+ await add_tags(branches=[model.source_branch], nodes=[model.proposed_change])
676
+ log = get_run_logger()
677
+
678
+ repository = await service.client.get(
679
+ kind=InfrahubKind.GENERICREPOSITORY, id=model.repository, branch=model.source_branch
680
+ )
681
+ proposed_change = await service.client.get(kind=InfrahubKind.PROPOSEDCHANGE, id=model.proposed_change)
682
+
683
+ validator_execution_id = str(UUIDT())
684
+ check_execution_ids: list[str] = []
685
+ await proposed_change.validations.fetch()
686
+ await repository.checks.fetch()
687
+
688
+ validator_name = f"Repository Validator: {repository.name.value}"
689
+ previous_validator: CoreRepositoryValidator | None = None
690
+ for relationship in proposed_change.validations.peers:
691
+ existing_validator = relationship.peer
692
+
693
+ if (
694
+ existing_validator.typename == InfrahubKind.REPOSITORYVALIDATOR
695
+ and existing_validator.repository.id == model.repository
696
+ ):
697
+ previous_validator = existing_validator
698
+
699
+ validator = await start_validator(
700
+ service=service,
701
+ validator=previous_validator,
702
+ validator_type=CoreRepositoryValidator,
703
+ proposed_change=model.proposed_change,
704
+ data={
705
+ "label": validator_name,
706
+ "repository": model.repository,
707
+ },
708
+ context=context,
709
+ )
710
+
711
+ check_execution_id = str(UUIDT())
712
+ check_execution_ids.append(check_execution_id)
713
+ log.info("Adding check for merge conflict")
714
+ checks_in_execution = ",".join(check_execution_ids)
715
+ log.info(f"Checks in execution {checks_in_execution}")
716
+
717
+ check_merge_conflict_model = CheckRepositoryMergeConflicts(
718
+ validator_id=validator.id,
719
+ validator_execution_id=validator_execution_id,
720
+ check_execution_id=check_execution_id,
721
+ proposed_change=model.proposed_change,
722
+ repository_id=model.repository,
723
+ repository_name=repository.name.value,
724
+ source_branch=model.source_branch,
725
+ target_branch=model.target_branch,
726
+ )
727
+ check_coroutine = service.workflow.execute_workflow(
728
+ workflow=GIT_REPOSITORY_MERGE_CONFLICTS_CHECKS_RUN,
729
+ parameters={"model": check_merge_conflict_model},
730
+ expected_return=ValidatorConclusion,
731
+ )
732
+
733
+ await run_checks_and_update_validator(
734
+ checks=[check_coroutine],
735
+ validator=validator,
736
+ context=context,
737
+ service=service,
738
+ proposed_change_id=model.proposed_change,
739
+ )
740
+
741
+
742
+ @flow(
743
+ name="git-repository-check-merge-conflict",
744
+ flow_run_name="Check for merge conflicts between {model.source_branch} and {model.target_branch}",
745
+ )
746
+ async def run_check_merge_conflicts(
747
+ model: CheckRepositoryMergeConflicts, service: InfrahubServices
748
+ ) -> ValidatorConclusion:
749
+ """Runs a check to see if there are merge conflicts between two branches."""
750
+ await add_tags(branches=[model.source_branch], nodes=[model.proposed_change])
751
+
752
+ success_condition = "-"
753
+ validator = await service.client.get(kind=InfrahubKind.REPOSITORYVALIDATOR, id=model.validator_id)
754
+ await validator.checks.fetch()
755
+
756
+ repo = await InfrahubRepository.init(id=model.repository_id, name=model.repository_name, service=service)
757
+ async with lock.registry.get(name=model.repository_name, namespace="repository"):
758
+ conflicts = await repo.get_conflicts(source_branch=model.source_branch, dest_branch=model.target_branch)
759
+
760
+ existing_checks = {}
761
+ for relationship in validator.checks.peers:
762
+ existing_check = relationship.peer
763
+ if existing_check.typename == InfrahubKind.FILECHECK and existing_check.kind.value == "MergeConflictCheck":
764
+ check_key = ""
765
+ if existing_check.files.value:
766
+ check_key = "".join(existing_check.files.value)
767
+ check_key = f"-{check_key}"
768
+ existing_checks[check_key] = existing_check
769
+
770
+ if conflicts:
771
+ validator_conclusion = ValidatorConclusion.FAILURE
772
+ for conflict in conflicts:
773
+ conflict_key = f"-{conflict}"
774
+ if conflict_key in existing_checks:
775
+ existing_checks[conflict_key].created_at.value = Timestamp().to_string()
776
+ await existing_checks[conflict_key].save()
777
+ existing_checks.pop(conflict_key)
778
+ else:
779
+ check = await service.client.create(
780
+ kind=InfrahubKind.FILECHECK,
781
+ data={
782
+ "name": conflict,
783
+ "origin": "ConflictCheck",
784
+ "kind": "MergeConflictCheck",
785
+ "validator": model.validator_id,
786
+ "created_at": Timestamp().to_string(),
787
+ "files": [conflict],
788
+ "conclusion": "failure",
789
+ "severity": "critical",
790
+ },
791
+ )
792
+ await check.save()
793
+
794
+ elif success_condition in existing_checks:
795
+ validator_conclusion = ValidatorConclusion.SUCCESS
796
+ existing_checks[success_condition].created_at.value = Timestamp().to_string()
797
+ await existing_checks[success_condition].save()
798
+ existing_checks.pop(success_condition)
799
+
800
+ else:
801
+ validator_conclusion = ValidatorConclusion.SUCCESS
802
+ check = await service.client.create(
803
+ kind=InfrahubKind.FILECHECK,
804
+ data={
805
+ "name": "Merge Conflict Check",
806
+ "origin": "ConflictCheck",
807
+ "kind": "MergeConflictCheck",
808
+ "validator": model.validator_id,
809
+ "created_at": Timestamp().to_string(),
810
+ "conclusion": validator_conclusion.value,
811
+ "severity": "info",
812
+ },
813
+ )
814
+ await check.save()
815
+
816
+ async with service.database.start_session() as db:
817
+ await NodeManager.delete(db=db, nodes=list(existing_checks.values()))
818
+
819
+ return validator_conclusion
820
+
821
+
822
+ @flow(name="git-repository-run-user-check", flow_run_name="Execute user defined Check '{model.name}'")
823
+ async def run_user_check(model: UserCheckData, service: InfrahubServices) -> ValidatorConclusion:
824
+ await add_tags(branches=[model.branch_name], nodes=[model.proposed_change])
825
+ log = get_run_logger()
826
+
827
+ validator = await service.client.get(kind=InfrahubKind.USERVALIDATOR, id=model.validator_id)
828
+ await validator.checks.fetch()
829
+
830
+ repo = await InfrahubRepository.init(
831
+ id=model.repository_id, name=model.repository_name, commit=model.commit, service=service
832
+ )
833
+ conclusion = ValidatorConclusion.FAILURE
834
+ severity = "critical"
835
+ try:
836
+ check_run = await repo.execute_python_check.with_options(timeout_seconds=model.timeout)(
837
+ branch_name=model.branch_name,
838
+ location=model.file_path,
839
+ class_name=model.class_name,
840
+ client=service.client,
841
+ commit=model.commit,
842
+ params=model.variables,
843
+ ) # type: ignore[misc]
844
+ if check_run.passed:
845
+ conclusion = ValidatorConclusion.SUCCESS
846
+ severity = "info"
847
+ log.info("The check passed")
848
+ else:
849
+ log.warning("The check reported failures")
850
+ for log_entry in check_run.log_entries:
851
+ log.warning(log_entry)
852
+ log_entries = check_run.log_entries
853
+ except CheckError as exc:
854
+ log.warning("The check failed to run")
855
+ log.error(exc.message)
856
+ log_entries = f"FATAL Error/n:{exc.message}"
857
+
858
+ check = None
859
+ for relationship in validator.checks.peers:
860
+ existing_check = relationship.peer
861
+ if (
862
+ existing_check.typename == InfrahubKind.STANDARDCHECK
863
+ and existing_check.kind.value == "CheckDefinition"
864
+ and existing_check.name.value == model.name
865
+ ):
866
+ check = existing_check
867
+
868
+ if check:
869
+ check.created_at.value = Timestamp().to_string()
870
+ check.message.value = log_entries
871
+ check.conclusion.value = conclusion.value
872
+ check.severity.value = severity
873
+ await check.save()
874
+ else:
875
+ check = await service.client.create(
876
+ kind=InfrahubKind.STANDARDCHECK,
877
+ data={
878
+ "name": model.name,
879
+ "origin": model.repository_id,
880
+ "kind": "CheckDefinition",
881
+ "validator": model.validator_id,
882
+ "created_at": Timestamp().to_string(),
883
+ "message": log_entries,
884
+ "conclusion": conclusion.value,
885
+ "severity": severity,
886
+ },
887
+ )
888
+ await check.save()
889
+
890
+ return conclusion
infrahub/git/utils.py ADDED
@@ -0,0 +1,48 @@
1
+ from typing import TYPE_CHECKING
2
+
3
+ from infrahub.core import registry
4
+ from infrahub.core.constants import InfrahubKind
5
+ from infrahub.core.manager import NodeManager
6
+ from infrahub.database import InfrahubDatabase
7
+
8
+ from .models import RepositoryBranchInfo, RepositoryData
9
+
10
+ if TYPE_CHECKING:
11
+ from infrahub.core.protocols import CoreGenericRepository
12
+
13
+
14
+ async def get_repositories_commit_per_branch(
15
+ db: InfrahubDatabase,
16
+ ) -> dict[str, RepositoryData]:
17
+ """Get a list of all repositories and their commit on each branches.
18
+
19
+ This method is similar to 'get_list_repositories' method in the Python SDK.
20
+
21
+ NOTE: At some point, we should refactor this function to use a single Database query instead of one per branch
22
+ """
23
+
24
+ repositories: dict[str, RepositoryData] = {}
25
+
26
+ for branch in list(registry.branch.values()):
27
+ repos: list[CoreGenericRepository] = await NodeManager.query(
28
+ db=db,
29
+ branch=branch,
30
+ fields={"id": None, "name": None, "commit": None, "internal_status": None},
31
+ schema=InfrahubKind.GENERICREPOSITORY,
32
+ )
33
+
34
+ for repository in repos:
35
+ repo_name = repository.name.value
36
+ if repo_name not in repositories:
37
+ repositories[repo_name] = RepositoryData(
38
+ repository_id=repository.get_id(),
39
+ repository_name=repo_name,
40
+ branches={},
41
+ )
42
+
43
+ repositories[repo_name].branches[branch.name] = repository.commit.value # type: ignore[attr-defined]
44
+ repositories[repo_name].branch_info[branch.name] = RepositoryBranchInfo(
45
+ internal_status=repository.internal_status.value
46
+ )
47
+
48
+ return repositories
infrahub/git/worktree.py CHANGED
@@ -1,7 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from pathlib import Path
4
- from typing import Optional
5
4
 
6
5
  from pydantic import BaseModel
7
6
 
@@ -14,7 +13,7 @@ class Worktree(BaseModel):
14
13
  identifier: str
15
14
  directory: Path
16
15
  commit: str
17
- branch: Optional[str] = None
16
+ branch: str | None = None
18
17
 
19
18
  @classmethod
20
19
  def init(cls, text: str) -> Worktree:
@@ -1,6 +1,5 @@
1
1
  import re
2
2
  import sys
3
- from typing import Optional
4
3
 
5
4
  import typer
6
5
  from infrahub_sdk import Config, InfrahubClientSync
@@ -16,7 +15,7 @@ REGEX_PASSWORD = r"^Password.*\'(.*\:\/\/)(.*)@(.*)\'"
16
15
 
17
16
  @app.command()
18
17
  def askpass(
19
- text: Optional[list[str]] = typer.Argument(None),
18
+ text: list[str] | None = typer.Argument(None),
20
19
  config_file: str = typer.Option("infrahub.toml", envvar="INFRAHUB_CONFIG"),
21
20
  ) -> None:
22
21
  config.SETTINGS.initialize_and_exit(config_file=config_file)
@@ -258,6 +258,18 @@ class GraphQLQueryReport:
258
258
 
259
259
  return access
260
260
 
261
+ def fields_by_kind(self, kind: str) -> list[str]:
262
+ fields: list[str] = []
263
+ if access := self.requested_read.get(kind):
264
+ fields.extend(list(access.attributes))
265
+ fields.extend(list(access.relationships))
266
+
267
+ return fields
268
+
269
+ @cached_property
270
+ def top_level_kinds(self) -> list[str]:
271
+ return [query.infrahub_model.kind for query in self.queries if query.infrahub_model]
272
+
261
273
  @cached_property
262
274
  def kind_action_map(self) -> dict[str, set[MutateAction]]:
263
275
  access: dict[str, set[MutateAction]] = {}
infrahub/graphql/app.py CHANGED
@@ -13,9 +13,7 @@ from typing import (
13
13
  AsyncGenerator,
14
14
  Awaitable,
15
15
  Callable,
16
- Optional,
17
16
  Sequence,
18
- Union,
19
17
  cast,
20
18
  )
21
19
 
@@ -87,7 +85,7 @@ GQL_ERROR = "error"
87
85
  GQL_START = "start"
88
86
  GQL_STOP = "stop"
89
87
 
90
- ContextValue = Union[Any, Callable[[HTTPConnection], Any]]
88
+ ContextValue = Any | Callable[[HTTPConnection], Any]
91
89
  RootValue = Any
92
90
 
93
91
 
@@ -95,13 +93,13 @@ class InfrahubGraphQLApp:
95
93
  def __init__(
96
94
  self,
97
95
  permission_checker: GraphQLQueryPermissionChecker,
98
- schema: Optional[graphene.Schema] = None,
96
+ schema: graphene.Schema | None = None,
99
97
  *,
100
- on_get: Optional[Callable[[Request], Union[Response, Awaitable[Response]]]] = None,
98
+ on_get: Callable[[Request], Response | Awaitable[Response]] | None = None,
101
99
  root_value: RootValue = None,
102
- middleware: Optional[Middleware] = None,
100
+ middleware: Middleware | None = None,
103
101
  error_formatter: Callable[[GraphQLError], GraphQLFormattedError] = format_error,
104
- execution_context_class: Optional[type[ExecutionContext]] = None,
102
+ execution_context_class: type[ExecutionContext] | None = None,
105
103
  ) -> None:
106
104
  self._schema = schema
107
105
  self.on_get = on_get
@@ -116,7 +114,7 @@ class InfrahubGraphQLApp:
116
114
  db: InfrahubDatabase
117
115
  if scope["type"] == "http":
118
116
  request = Request(scope=scope, receive=receive)
119
- response: Optional[Response] = None
117
+ response: Response | None = None
120
118
  jwt_auth = await jwt_scheme(request)
121
119
  api_key = await api_key_scheme(request)
122
120
  cookie_auth = await cookie_auth_scheme(request)
@@ -166,7 +164,7 @@ class InfrahubGraphQLApp:
166
164
  else:
167
165
  raise ValueError(f"Unsupported scope type: ${scope['type']}")
168
166
 
169
- async def _get_on_get(self, request: Request) -> Optional[Response]:
167
+ async def _get_on_get(self, request: Request) -> Response | None:
170
168
  handler = self.on_get
171
169
 
172
170
  if handler is None:
@@ -388,8 +386,8 @@ class InfrahubGraphQLApp:
388
386
  graphql_params = await prepare_graphql_params(db=db, branch=branch)
389
387
 
390
388
  errors: list[GraphQLError] = []
391
- operation: Optional[OperationDefinitionNode] = None
392
- document: Optional[DocumentNode] = None
389
+ operation: OperationDefinitionNode | None = None
390
+ document: DocumentNode | None = None
393
391
 
394
392
  try:
395
393
  document = parse(query)
@@ -474,11 +472,11 @@ class InfrahubGraphQLApp:
474
472
  await websocket.send_json({"type": GQL_COMPLETE, "id": operation_id})
475
473
 
476
474
 
477
- async def _get_operation_from_request(request: Request) -> Union[dict[str, Any], list[Any]]:
475
+ async def _get_operation_from_request(request: Request) -> dict[str, Any] | list[Any]:
478
476
  content_type = request.headers.get("Content-Type", "").split(";")[0]
479
477
  if content_type == "application/json":
480
478
  try:
481
- return cast(Union[dict[str, Any], list[Any]], await request.json())
479
+ return cast(dict[str, Any] | list[Any], await request.json())
482
480
  except (TypeError, ValueError) as err:
483
481
  raise ValueError("Request body is not a valid JSON") from err
484
482
  elif content_type == "multipart/form-data":
@@ -487,7 +485,7 @@ async def _get_operation_from_request(request: Request) -> Union[dict[str, Any],
487
485
  raise ValueError("Content-type must be application/json or multipart/form-data")
488
486
 
489
487
 
490
- async def _get_operation_from_multipart(request: Request) -> Union[dict[str, Any], list[Any]]:
488
+ async def _get_operation_from_multipart(request: Request) -> dict[str, Any] | list[Any]:
491
489
  try:
492
490
  request_body = await request.form()
493
491
  except Exception as err:
@@ -526,7 +524,7 @@ async def _get_operation_from_multipart(request: Request) -> Union[dict[str, Any
526
524
 
527
525
  def _inject_file_to_operations(ops_tree: Any, _file: UploadFile, path: Sequence[str]) -> None:
528
526
  k = path[0]
529
- key: Union[str, int]
527
+ key: str | int
530
528
  try:
531
529
  key = int(k)
532
530
  except ValueError: