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
@@ -28,7 +28,7 @@ async def connectivity(message: messages.GitRepositoryConnectivity, service: Inf
28
28
  response = GitRepositoryConnectivityResponse(
29
29
  data=response_data,
30
30
  )
31
- await service.reply(message=response, initiator=message)
31
+ await service.message_bus.reply_if_initiator_meta(message=response, initiator=message)
32
32
 
33
33
 
34
34
  @flow(name="refresh-git-fetch", flow_run_name="Fetch git repository {message.repository_name} on " + WORKER_IDENTITY)
@@ -1,12 +1,10 @@
1
1
  from . import (
2
- artifact_definition,
3
2
  generator_definition,
4
3
  proposed_change,
5
4
  repository,
6
5
  )
7
6
 
8
7
  __all__ = [
9
- "artifact_definition",
10
8
  "generator_definition",
11
9
  "proposed_change",
12
10
  "repository",
@@ -125,7 +125,7 @@ async def check(message: messages.RequestGeneratorDefinitionCheck, service: Infr
125
125
  )
126
126
  for event in events:
127
127
  event.assign_meta(parent=message)
128
- await service.send(message=event)
128
+ await service.message_bus.send(message=event)
129
129
 
130
130
 
131
131
  def _run_generator(instance_id: Optional[str], managed_branch: bool, impacted_instances: list[str]) -> bool:
@@ -20,6 +20,7 @@ from infrahub.message_bus.types import (
20
20
  ProposedChangeSubscriber,
21
21
  )
22
22
  from infrahub.proposed_change.models import (
23
+ RequestArtifactDefinitionCheck,
23
24
  RequestProposedChangeDataIntegrity,
24
25
  RequestProposedChangeRepositoryChecks,
25
26
  RequestProposedChangeRunGenerators,
@@ -28,6 +29,7 @@ from infrahub.proposed_change.models import (
28
29
  )
29
30
  from infrahub.services import InfrahubServices # noqa: TC001
30
31
  from infrahub.workflows.catalogue import (
32
+ REQUEST_ARTIFACT_DEFINITION_CHECK,
31
33
  REQUEST_PROPOSED_CHANGE_DATA_INTEGRITY,
32
34
  REQUEST_PROPOSED_CHANGE_REPOSITORY_CHECKS,
33
35
  REQUEST_PROPOSED_CHANGE_RUN_GENERATORS,
@@ -84,7 +86,7 @@ async def pipeline(message: messages.RequestProposedChangePipeline, service: Inf
84
86
  )
85
87
  for event in events:
86
88
  event.assign_meta(parent=message)
87
- await service.send(message=event)
89
+ await service.message_bus.send(message=event)
88
90
  return
89
91
 
90
92
  await _gather_repository_repository_diffs(repositories=repositories, service=service)
@@ -122,7 +124,9 @@ async def pipeline(message: messages.RequestProposedChangePipeline, service: Inf
122
124
  do_repository_checks=message.check_type is CheckType.ALL,
123
125
  )
124
126
  await service.workflow.submit_workflow(
125
- workflow=REQUEST_PROPOSED_CHANGE_RUN_GENERATORS, parameters={"model": model_proposed_change_run_generator}
127
+ workflow=REQUEST_PROPOSED_CHANGE_RUN_GENERATORS,
128
+ context=message.context,
129
+ parameters={"model": model_proposed_change_run_generator},
126
130
  )
127
131
 
128
132
  if message.check_type in [CheckType.ALL, CheckType.DATA] and branch_diff.has_node_changes(
@@ -136,7 +140,9 @@ async def pipeline(message: messages.RequestProposedChangePipeline, service: Inf
136
140
  branch_diff=branch_diff,
137
141
  )
138
142
  await service.workflow.submit_workflow(
139
- workflow=REQUEST_PROPOSED_CHANGE_DATA_INTEGRITY, parameters={"model": model_proposed_change_data_integrity}
143
+ workflow=REQUEST_PROPOSED_CHANGE_DATA_INTEGRITY,
144
+ context=message.context,
145
+ parameters={"model": model_proposed_change_data_integrity},
140
146
  )
141
147
 
142
148
  if message.check_type in [CheckType.REPOSITORY, CheckType.USER]:
@@ -148,7 +154,9 @@ async def pipeline(message: messages.RequestProposedChangePipeline, service: Inf
148
154
  branch_diff=branch_diff,
149
155
  )
150
156
  await service.workflow.submit_workflow(
151
- workflow=REQUEST_PROPOSED_CHANGE_REPOSITORY_CHECKS, parameters={"model": model_proposed_change_repo_checks}
157
+ workflow=REQUEST_PROPOSED_CHANGE_REPOSITORY_CHECKS,
158
+ context=message.context,
159
+ parameters={"model": model_proposed_change_repo_checks},
152
160
  )
153
161
 
154
162
  if message.check_type in [CheckType.ALL, CheckType.SCHEMA] and branch_diff.has_data_changes(
@@ -156,6 +164,7 @@ async def pipeline(message: messages.RequestProposedChangePipeline, service: Inf
156
164
  ):
157
165
  await service.workflow.submit_workflow(
158
166
  workflow=REQUEST_PROPOSED_CHANGE_SCHEMA_INTEGRITY,
167
+ context=message.context,
159
168
  parameters={
160
169
  "model": RequestProposedChangeSchemaIntegrity(
161
170
  proposed_change=message.proposed_change,
@@ -170,6 +179,7 @@ async def pipeline(message: messages.RequestProposedChangePipeline, service: Inf
170
179
  if message.check_type in [CheckType.ALL, CheckType.TEST]:
171
180
  await service.workflow.submit_workflow(
172
181
  workflow=REQUEST_PROPOSED_CHANGE_USER_TESTS,
182
+ context=message.context,
173
183
  parameters={
174
184
  "model": RequestProposedChangeUserTests(
175
185
  proposed_change=message.proposed_change,
@@ -183,7 +193,7 @@ async def pipeline(message: messages.RequestProposedChangePipeline, service: Inf
183
193
 
184
194
  for event in events:
185
195
  event.assign_meta(parent=message)
186
- await service.send(message=event)
196
+ await service.message_bus.send(message=event)
187
197
 
188
198
 
189
199
  @flow(
@@ -232,7 +242,7 @@ async def refresh_artifacts(message: messages.RequestProposedChangeRefreshArtifa
232
242
 
233
243
  if select:
234
244
  log.info(f"Trigger processing of {artifact_definition.definition_name}")
235
- msg = messages.RequestArtifactDefinitionCheck(
245
+ model = RequestArtifactDefinitionCheck(
236
246
  artifact_definition=artifact_definition,
237
247
  branch_diff=message.branch_diff,
238
248
  proposed_change=message.proposed_change,
@@ -241,8 +251,7 @@ async def refresh_artifacts(message: messages.RequestProposedChangeRefreshArtifa
241
251
  destination_branch=message.destination_branch,
242
252
  )
243
253
 
244
- msg.assign_meta(parent=message)
245
- await service.send(message=msg)
254
+ await service.workflow.submit_workflow(REQUEST_ARTIFACT_DEFINITION_CHECK, parameters={"model": model})
246
255
 
247
256
 
248
257
  GATHER_ARTIFACT_DEFINITIONS = """
@@ -520,7 +529,7 @@ async def _get_proposed_change_repositories(
520
529
  return _parse_proposed_change_repositories(message=message, source=source_all, destination=destination_all)
521
530
 
522
531
 
523
- @task(name="proposed-change-validate-repository-conflicts", task_run_name="Validate conflicts on repository")
532
+ @task(name="proposed-change-validate-repository-conflicts", task_run_name="Validate conflicts on repository") # type: ignore[arg-type]
524
533
  async def _validate_repository_merge_conflicts(
525
534
  repositories: list[ProposedChangeRepository], service: InfrahubServices
526
535
  ) -> bool:
@@ -529,7 +538,10 @@ async def _validate_repository_merge_conflicts(
529
538
  for repo in repositories:
530
539
  if repo.has_diff and not repo.is_staging:
531
540
  git_repo = await InfrahubRepository.init(
532
- id=repo.repository_id, name=repo.repository_name, client=service.client
541
+ id=repo.repository_id,
542
+ name=repo.repository_name,
543
+ client=service.client,
544
+ service=service,
533
545
  )
534
546
  async with lock.registry.get(name=repo.repository_name, namespace="repository"):
535
547
  repo.conflicts = await git_repo.get_conflicts(
@@ -551,7 +563,10 @@ async def _gather_repository_repository_diffs(
551
563
  if repo.has_diff and repo.source_commit and repo.destination_commit:
552
564
  # TODO we need to find a way to return all files in the repo if the repo is new
553
565
  git_repo = await InfrahubRepository.init(
554
- id=repo.repository_id, name=repo.repository_name, client=service.client
566
+ id=repo.repository_id,
567
+ name=repo.repository_name,
568
+ client=service.client,
569
+ service=service,
555
570
  )
556
571
 
557
572
  files_changed: list[str] = []
@@ -91,7 +91,7 @@ async def checks(message: messages.RequestRepositoryChecks, service: InfrahubSer
91
91
 
92
92
  for event in events:
93
93
  event.assign_meta(parent=message)
94
- await service.send(message=event)
94
+ await service.message_bus.send(message=event)
95
95
 
96
96
 
97
97
  @flow(
@@ -130,4 +130,4 @@ async def user_checks(message: messages.RequestRepositoryUserChecks, service: In
130
130
 
131
131
  for event in events:
132
132
  event.assign_meta(parent=message)
133
- await service.send(message=event)
133
+ await service.message_bus.send(message=event)
@@ -10,4 +10,4 @@ async def request(message: messages.SendEchoRequest, service: InfrahubServices)
10
10
  service.log.info(f"Received message: {message.message}")
11
11
  if message.reply_requested:
12
12
  response = SendEchoRequestResponse(data=SendEchoRequestResponseData(response=f"Reply to: {message.message}"))
13
- await service.reply(message=response, initiator=message)
13
+ await service.message_bus.reply_if_initiator_meta(message=response, initiator=message)
@@ -9,7 +9,7 @@ from pydantic import BaseModel, Field
9
9
  from infrahub.core.constants import InfrahubKind, RepositoryInternalStatus
10
10
  from infrahub.exceptions import NodeNotFoundError
11
11
 
12
- SCHEMA_CHANGE = re.compile("^Schema[A-Z]")
12
+ SCHEMA_CHANGE = re.compile(r"^Schema[A-Z]")
13
13
 
14
14
 
15
15
  class MessageTTL(int, Enum):
@@ -2,12 +2,13 @@ from infrahub.permissions.backend import PermissionBackend
2
2
  from infrahub.permissions.local_backend import LocalPermissionBackend
3
3
  from infrahub.permissions.manager import PermissionManager
4
4
  from infrahub.permissions.report import report_schema_permissions
5
- from infrahub.permissions.types import AssignedPermissions
5
+ from infrahub.permissions.types import AssignedPermissions, get_global_permission_for_kind
6
6
 
7
7
  __all__ = [
8
8
  "AssignedPermissions",
9
9
  "LocalPermissionBackend",
10
10
  "PermissionBackend",
11
11
  "PermissionManager",
12
+ "get_global_permission_for_kind",
12
13
  "report_schema_permissions",
13
14
  ]
@@ -2,8 +2,12 @@ from __future__ import annotations
2
2
 
3
3
  from typing import TYPE_CHECKING, TypedDict
4
4
 
5
+ from infrahub.core.constants import GlobalPermissions, InfrahubKind
6
+ from infrahub.core.schema import NodeSchema
7
+
5
8
  if TYPE_CHECKING:
6
9
  from infrahub.core.account import GlobalPermission, ObjectPermission
10
+ from infrahub.core.schema import MainSchemaTypes
7
11
  from infrahub.permissions.constants import BranchRelativePermissionDecision
8
12
 
9
13
 
@@ -18,3 +22,25 @@ class KindPermissions(TypedDict):
18
22
  delete: BranchRelativePermissionDecision
19
23
  update: BranchRelativePermissionDecision
20
24
  view: BranchRelativePermissionDecision
25
+
26
+
27
+ def get_global_permission_for_kind(schema: MainSchemaTypes) -> GlobalPermissions | None:
28
+ kind_permission_map = {
29
+ InfrahubKind.GENERICACCOUNT: GlobalPermissions.MANAGE_ACCOUNTS,
30
+ InfrahubKind.ACCOUNTGROUP: GlobalPermissions.MANAGE_ACCOUNTS,
31
+ InfrahubKind.ACCOUNTROLE: GlobalPermissions.MANAGE_ACCOUNTS,
32
+ InfrahubKind.BASEPERMISSION: GlobalPermissions.MANAGE_PERMISSIONS,
33
+ InfrahubKind.GENERICREPOSITORY: GlobalPermissions.MANAGE_REPOSITORIES,
34
+ }
35
+
36
+ if schema.kind in kind_permission_map:
37
+ return kind_permission_map[schema.kind]
38
+
39
+ if isinstance(schema, NodeSchema):
40
+ for base in schema.inherit_from:
41
+ try:
42
+ return kind_permission_map[base]
43
+ except KeyError:
44
+ continue
45
+
46
+ return None
infrahub/pools/prefix.py CHANGED
@@ -1,174 +1,38 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import ipaddress
4
- from collections import OrderedDict, defaultdict
5
- from ipaddress import IPv4Network, IPv6Network
6
- from typing import Optional, Union
4
+ from typing import TYPE_CHECKING, Literal
7
5
 
6
+ from netaddr import IPSet
8
7
 
9
- class PrefixPool:
10
- """
11
- Class to automatically manage Prefixes and help to carve out sub-prefixes
12
- """
13
-
14
- def __init__(self, network: str) -> None:
15
- self.network = ipaddress.ip_network(network)
16
-
17
- # Define biggest and smallest possible masks
18
- self.mask_biggest = self.network.prefixlen + 1
19
- if self.network.version == 4:
20
- self.mask_smallest = 32
21
- else:
22
- self.mask_smallest = 128
23
-
24
- self.available_subnets = defaultdict(list)
25
- self.sub_by_key: dict[str, Optional[str]] = OrderedDict()
26
- self.sub_by_id: dict[str, str] = OrderedDict()
27
-
28
- # Save the top level available subnet
29
- for subnet in list(self.network.subnets(new_prefix=self.mask_biggest)):
30
- self.available_subnets[self.mask_biggest].append(str(subnet))
31
-
32
- def reserve(self, subnet: str, identifier: Optional[str] = None) -> bool:
33
- """
34
- Indicate that a specific subnet is already reserved/used
35
- """
36
-
37
- # TODO Add check to make sure the subnet provided has the right size
38
- sub = ipaddress.ip_network(subnet)
39
-
40
- if int(sub.prefixlen) <= int(self.network.prefixlen):
41
- raise ValueError(f"{subnet} do not have the right size ({sub.prefixlen},{self.network.prefixlen})")
42
-
43
- if sub.supernet(new_prefix=self.network.prefixlen) != self.network:
44
- raise ValueError(f"{subnet} is not part of this network")
45
-
46
- # Check first if this ID as already done a reservation
47
- if identifier and identifier in self.sub_by_id.keys():
48
- if self.sub_by_id[identifier] == str(sub):
49
- return True
50
- raise ValueError(
51
- f"this identifier ({identifier}) is already used but for a different resource ({self.sub_by_id[identifier]})"
52
- )
53
-
54
- if identifier and str(sub) in self.sub_by_key.keys():
55
- raise ValueError(f"this subnet is already reserved but not with this identifier ({identifier})")
56
-
57
- if str(sub) in self.sub_by_key.keys():
58
- self.remove_subnet_from_available_list(sub)
59
- return True
60
-
61
- # Check if the subnet itself is available
62
- # if available reserve and return
63
- if subnet in self.available_subnets[sub.prefixlen]:
64
- if identifier:
65
- self.sub_by_id[identifier] = subnet
66
- self.sub_by_key[subnet] = identifier
67
- else:
68
- self.sub_by_key[subnet] = None
69
-
70
- self.remove_subnet_from_available_list(sub)
71
- return True
72
-
73
- # If not reserved already, check if the subnet is available
74
- # start at sublen and check all available subnet
75
- # increase 1 by 1 until we find the closer supernet available
76
- # break it down and keep track of the other available subnets
8
+ if TYPE_CHECKING:
9
+ from infrahub.core.ipam.constants import IPNetworkType
77
10
 
78
- for sublen in range(sub.prefixlen - 1, self.network.prefixlen, -1):
79
- supernet = sub.supernet(new_prefix=sublen)
80
- if str(supernet) in self.available_subnets[sublen]:
81
- self.split_supernet(supernet=supernet, subnet=sub)
82
- return self.reserve(subnet=subnet, identifier=identifier)
83
11
 
84
- return False
12
+ def get_next_available_prefix(pool: IPSet, prefix_length: int, prefix_ver: Literal[4, 6] = 4) -> IPNetworkType:
13
+ """Get the next available prefix of a given prefix length from an IPSet.
85
14
 
86
- def get(self, prefixlen: int, identifier: Optional[str] = None) -> Union[IPv4Network, IPv6Network]:
87
- """Return the next available Subnet."""
15
+ Args:
16
+ pool: netaddr IPSet object with available subnets
17
+ prefix_length: length of the desired prefix
18
+ prefix_ver: IPSet can contain a mix of IPv4 and IPv6 subnets. This parameter specifies the IP version of prefix to acquire.
88
19
 
89
- clean_prefixlen = int(prefixlen)
90
-
91
- if identifier and identifier in self.sub_by_id.keys():
92
- net = ipaddress.ip_network(self.sub_by_id[identifier])
93
- if net.prefixlen == clean_prefixlen:
94
- return net
95
- raise ValueError()
96
-
97
- if len(self.available_subnets[clean_prefixlen]) != 0:
98
- sub = self.available_subnets[clean_prefixlen][0]
99
- self.reserve(subnet=sub, identifier=identifier)
100
- return ipaddress.ip_network(sub)
101
-
102
- # if a subnet of this size is not available
103
- # we need to find the closest subnet available and split it
104
- for i in range(clean_prefixlen - 1, self.mask_biggest - 1, -1):
105
- if len(self.available_subnets[i]) != 0:
106
- supernet = ipaddress.ip_network(self.available_subnets[i][0])
107
- # supernet available, will split it
108
- subs = supernet.subnets(new_prefix=clean_prefixlen)
109
- next_sub: Union[IPv4Network, IPv6Network] = next(subs) # type: ignore[assignment]
110
- self.split_supernet(supernet=supernet, subnet=next_sub)
111
- self.reserve(subnet=str(next_sub), identifier=identifier)
112
- return next_sub
113
-
114
- raise IndexError("No More subnet available")
115
-
116
- def get_nbr_available_subnets(self) -> dict[int, int]:
117
- tmp = {}
118
- for i in range(self.mask_biggest, self.mask_smallest + 1):
119
- tmp[i] = len(self.available_subnets[i])
120
-
121
- return tmp
122
-
123
- def check_if_already_allocated(self, identifier: str) -> bool:
124
- """
125
- Check if a subnet has already been allocated based on an identifier
126
-
127
- Need to add the same capability based on Network address
128
- If both identifier and subnet are provided, identifier take precedence
129
- """
130
- if identifier in self.sub_by_id.keys():
131
- return True
132
- return False
133
-
134
- def split_supernet(
135
- self, supernet: Union[IPv4Network, IPv6Network], subnet: Union[IPv4Network, IPv6Network]
136
- ) -> None:
137
- """Split a supernet into smaller networks"""
138
-
139
- # TODO ensure subnet is small than supernet
140
- # TODO ensure that subnet is part of supernet
141
- parent_net = supernet
142
- for i in range(supernet.prefixlen + 1, subnet.prefixlen + 1):
143
- tmp_net: list[Union[IPv4Network, IPv6Network]] = list(parent_net.subnets(new_prefix=i))
144
-
145
- if i == subnet.prefixlen:
146
- for net in tmp_net:
147
- self.available_subnets[i].append(str(net))
148
- else:
149
- if subnet.subnet_of(other=tmp_net[0]): # type: ignore[arg-type]
150
- parent = 0
151
- other = 1
152
- else:
153
- parent = 1
154
- other = 0
155
-
156
- parent_net = tmp_net[parent]
157
- self.available_subnets[i].append(str(tmp_net[other]))
158
-
159
- self.remove_subnet_from_available_list(supernet)
160
-
161
- def remove_subnet_from_available_list(self, subnet: Union[IPv4Network, IPv6Network]) -> None:
162
- """Remove a subnet from the list of available Subnet."""
163
- try:
164
- idx = self.available_subnets[subnet.prefixlen].index(str(subnet))
165
- del self.available_subnets[subnet.prefixlen][idx]
166
- except ValueError:
167
- # Already removed
168
- pass
169
-
170
- # if idx:
171
- # return True
172
- # except:
173
- # log.warn("Unable to remove %s from list of available subnets" % str(subnet))
174
- # return False
20
+ Raises:
21
+ ValueError: If there are no available subnets in the pool
22
+ """
23
+ prefix_ver_map = {
24
+ 4: ipaddress.IPv4Network,
25
+ 6: ipaddress.IPv6Network,
26
+ }
27
+
28
+ filtered_pool = IPSet([])
29
+ for subnet in pool.iter_cidrs():
30
+ if isinstance(ipaddress.ip_network(str(subnet)), prefix_ver_map[prefix_ver]):
31
+ filtered_pool.add(subnet)
32
+
33
+ for cidr in filtered_pool.iter_cidrs():
34
+ if cidr.prefixlen <= prefix_length:
35
+ next_available = ipaddress.ip_network(f"{cidr.network}/{prefix_length}")
36
+ return next_available
37
+
38
+ raise ValueError("No available subnets in pool")
File without changes
@@ -0,0 +1,18 @@
1
+ from __future__ import annotations
2
+
3
+ from fastapi import APIRouter, FastAPI
4
+ from prefect.server.api.server import create_app
5
+
6
+ from . import events
7
+
8
+ router = APIRouter(prefix="/infrahub")
9
+
10
+ router.include_router(events.router)
11
+
12
+
13
+ def create_infrahub_prefect() -> FastAPI:
14
+ app = create_app()
15
+ api_app: FastAPI = app.__dict__["api_app"]
16
+ api_app.include_router(router=router)
17
+
18
+ return app
@@ -0,0 +1,20 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING
4
+
5
+ from prefect.server.events.schemas.events import ReceivedEvent
6
+ from prefect.server.events.storage import INTERACTIVE_PAGE_SIZE
7
+ from prefect.server.events.storage.database import raw_count_events, read_events
8
+
9
+ if TYPE_CHECKING:
10
+ from prefect.server.events.filters import EventFilter
11
+ from sqlalchemy.ext.asyncio import AsyncSession
12
+
13
+
14
+ async def query_events(
15
+ session: AsyncSession, filter: EventFilter, page_size: int = INTERACTIVE_PAGE_SIZE, offset: int | None = None
16
+ ) -> tuple[list[ReceivedEvent], int]:
17
+ count = await raw_count_events(session, filter) # type: ignore[attr-defined]
18
+ page = await read_events(session, filter, limit=page_size, offset=offset) # type: ignore[attr-defined]
19
+ events = [ReceivedEvent.model_validate(e, from_attributes=True) for e in page]
20
+ return events, count
@@ -0,0 +1,28 @@
1
+ from fastapi import APIRouter
2
+ from fastapi.param_functions import Depends
3
+ from prefect.server.database import PrefectDBInterface, provide_database_interface
4
+
5
+ from .database import query_events
6
+ from .models import InfrahubEventfilterInput, InfrahubEventPage
7
+
8
+ router = APIRouter(prefix="/events", tags=["Infrahub"])
9
+
10
+
11
+ @router.post(
12
+ "/filter",
13
+ )
14
+ async def read_events(
15
+ event_filter: InfrahubEventfilterInput,
16
+ db: PrefectDBInterface = Depends(provide_database_interface), # noqa: B008
17
+ ) -> InfrahubEventPage:
18
+ event_filter.filter.set_prefix()
19
+
20
+ async with db.session_context() as session:
21
+ events, total = await query_events(
22
+ session=session, filter=event_filter.filter, page_size=event_filter.limit, offset=event_filter.offset
23
+ )
24
+
25
+ return InfrahubEventPage(
26
+ events=events,
27
+ total=total,
28
+ )
@@ -0,0 +1,46 @@
1
+ from typing import TYPE_CHECKING, Sequence, cast
2
+
3
+ from prefect.server.database import PrefectDBInterface, db_injector
4
+ from prefect.server.events.filters import EventFilter, EventNameFilter, EventOrder, EventRelatedFilter
5
+ from prefect.server.events.schemas.events import ReceivedEvent
6
+ from prefect.server.utilities.schemas import PrefectBaseModel
7
+ from pydantic import BaseModel, Field
8
+
9
+ if TYPE_CHECKING:
10
+ from sqlalchemy.sql.expression import ColumnExpressionArgument
11
+
12
+
13
+ class InfrahubEventFilter(EventFilter):
14
+ matching_related: list[EventRelatedFilter] = Field(default_factory=list)
15
+
16
+ def set_prefix(self) -> None:
17
+ if self.event:
18
+ if self.event.prefix is not None and "infrahub." not in self.event.prefix:
19
+ self.event.prefix.append("infrahub.")
20
+ else:
21
+ self.event = EventNameFilter(prefix=["infrahub."], name=[], exclude_prefix=None, exclude_name=None)
22
+
23
+ @db_injector
24
+ def build_where_clauses(self, db: PrefectDBInterface) -> Sequence["ColumnExpressionArgument[bool]"]:
25
+ result = cast(list["ColumnExpressionArgument[bool]"], super().build_where_clauses())
26
+ top_level_filter = self._scoped_event_resources(db)
27
+ for matching_related in self.matching_related:
28
+ matching_related._top_level_filter = top_level_filter
29
+ result.extend(matching_related.build_where_clauses())
30
+
31
+ return result
32
+
33
+ @classmethod
34
+ def default(cls) -> "InfrahubEventFilter":
35
+ return cls(event=None, any_resource=None, resource=None, related=None, order=EventOrder.DESC)
36
+
37
+
38
+ class InfrahubEventPage(PrefectBaseModel):
39
+ events: list[ReceivedEvent] = Field(..., description="The Events matching the query")
40
+ total: int = Field(..., description="The total number of matching Events")
41
+
42
+
43
+ class InfrahubEventfilterInput(BaseModel):
44
+ limit: int = Field(default=50)
45
+ filter: InfrahubEventFilter = Field(default_factory=InfrahubEventFilter.default)
46
+ offset: int | None = Field(default=None)
@@ -1,6 +1,7 @@
1
- from pydantic import Field
1
+ from pydantic import BaseModel, ConfigDict, Field
2
2
 
3
3
  from infrahub.message_bus.messages.proposed_change.base_with_diff import BaseProposedChangeWithDiffMessage
4
+ from infrahub.message_bus.types import ProposedChangeArtifactDefinition, ProposedChangeBranchDiff
4
5
 
5
6
 
6
7
  class RequestProposedChangeDataIntegrity(BaseProposedChangeWithDiffMessage):
@@ -26,3 +27,16 @@ class RequestProposedChangeSchemaIntegrity(BaseProposedChangeWithDiffMessage):
26
27
 
27
28
  class RequestProposedChangeUserTests(BaseProposedChangeWithDiffMessage):
28
29
  """Sent trigger to run tests (smoke, units, integrations) for a proposed change."""
30
+
31
+
32
+ class RequestArtifactDefinitionCheck(BaseModel):
33
+ """Sent to validate the generation of artifacts in relation to a proposed change."""
34
+
35
+ model_config = ConfigDict(arbitrary_types_allowed=True)
36
+
37
+ artifact_definition: ProposedChangeArtifactDefinition = Field(..., description="The Artifact Definition")
38
+ branch_diff: ProposedChangeBranchDiff = Field(..., description="The calculated diff between the two branches")
39
+ proposed_change: str = Field(..., description="The unique ID of the Proposed Change")
40
+ source_branch: str = Field(..., description="The source branch")
41
+ source_branch_sync_with_git: bool = Field(..., description="Indicates if the source branch should sync with git")
42
+ destination_branch: str = Field(..., description="The target branch")