infrahub-server 1.1.6__py3-none-any.whl → 1.2.0b1__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 (407) 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} +5 -3
  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/models.py +1 -1
  16. infrahub/computed_attribute/tasks.py +64 -17
  17. infrahub/computed_attribute/triggers.py +90 -0
  18. infrahub/config.py +1 -1
  19. infrahub/context.py +39 -0
  20. infrahub/core/account.py +5 -8
  21. infrahub/core/attribute.py +54 -22
  22. infrahub/core/branch/models.py +4 -4
  23. infrahub/core/branch/tasks.py +137 -129
  24. infrahub/core/changelog/__init__.py +0 -0
  25. infrahub/core/changelog/diff.py +283 -0
  26. infrahub/core/changelog/models.py +499 -0
  27. infrahub/core/constants/__init__.py +43 -2
  28. infrahub/core/constants/infrahubkind.py +1 -0
  29. infrahub/core/constants/schema.py +2 -0
  30. infrahub/core/diff/combiner.py +12 -8
  31. infrahub/core/diff/coordinator.py +49 -70
  32. infrahub/core/diff/data_check_synchronizer.py +86 -7
  33. infrahub/core/diff/enricher/aggregated.py +3 -3
  34. infrahub/core/diff/enricher/cardinality_one.py +7 -7
  35. infrahub/core/diff/enricher/hierarchy.py +22 -7
  36. infrahub/core/diff/enricher/labels.py +19 -4
  37. infrahub/core/diff/enricher/path_identifier.py +7 -9
  38. infrahub/core/diff/enricher/summary_counts.py +3 -1
  39. infrahub/core/diff/merger/merger.py +8 -4
  40. infrahub/core/diff/model/path.py +76 -35
  41. infrahub/core/diff/parent_node_adder.py +78 -0
  42. infrahub/core/diff/payload_builder.py +13 -2
  43. infrahub/core/diff/query/all_conflicts.py +6 -3
  44. infrahub/core/diff/query/artifact.py +1 -1
  45. infrahub/core/diff/query/delete_query.py +1 -1
  46. infrahub/core/diff/query/diff_get.py +3 -2
  47. infrahub/core/diff/query/diff_summary.py +1 -1
  48. infrahub/core/diff/query/field_specifiers.py +3 -1
  49. infrahub/core/diff/query/field_summary.py +3 -2
  50. infrahub/core/diff/query/filters.py +14 -3
  51. infrahub/core/diff/query/get_conflict_query.py +1 -1
  52. infrahub/core/diff/query/has_conflicts_query.py +6 -3
  53. infrahub/core/diff/query/merge.py +3 -3
  54. infrahub/core/diff/query/{drop_tracking_id.py → merge_tracking_id.py} +4 -4
  55. infrahub/core/diff/query/roots_metadata.py +9 -2
  56. infrahub/core/diff/query/save.py +233 -142
  57. infrahub/core/diff/query/summary_counts_enricher.py +267 -0
  58. infrahub/core/diff/query/time_range_query.py +3 -2
  59. infrahub/core/diff/query/update_conflict_query.py +1 -1
  60. infrahub/core/diff/query_parser.py +49 -24
  61. infrahub/core/diff/repository/deserializer.py +32 -28
  62. infrahub/core/diff/repository/repository.py +215 -41
  63. infrahub/core/diff/tasks.py +13 -12
  64. infrahub/core/enums.py +1 -1
  65. infrahub/core/graph/__init__.py +1 -1
  66. infrahub/core/graph/index.py +3 -0
  67. infrahub/core/integrity/object_conflict/conflict_recorder.py +1 -1
  68. infrahub/core/ipam/reconciler.py +1 -1
  69. infrahub/core/ipam/tasks.py +2 -3
  70. infrahub/core/manager.py +20 -15
  71. infrahub/core/merge.py +5 -2
  72. infrahub/core/migrations/graph/__init__.py +4 -0
  73. infrahub/core/migrations/graph/m001_add_version_to_graph.py +1 -1
  74. infrahub/core/migrations/graph/m002_attribute_is_default.py +2 -2
  75. infrahub/core/migrations/graph/m003_relationship_parent_optional.py +2 -2
  76. infrahub/core/migrations/graph/m004_add_attr_documentation.py +1 -1
  77. infrahub/core/migrations/graph/m005_add_rel_read_only.py +1 -1
  78. infrahub/core/migrations/graph/m006_add_rel_on_delete.py +1 -1
  79. infrahub/core/migrations/graph/m007_add_rel_allow_override.py +1 -1
  80. infrahub/core/migrations/graph/m008_add_human_friendly_id.py +1 -1
  81. infrahub/core/migrations/graph/m009_add_generate_profile_attr.py +1 -1
  82. infrahub/core/migrations/graph/m010_add_generate_profile_attr_generic.py +1 -1
  83. infrahub/core/migrations/graph/m011_remove_profile_relationship_schema.py +2 -2
  84. infrahub/core/migrations/graph/m012_convert_account_generic.py +12 -23
  85. infrahub/core/migrations/graph/m013_convert_git_password_credential.py +7 -11
  86. infrahub/core/migrations/graph/m014_remove_index_attr_value.py +2 -2
  87. infrahub/core/migrations/graph/m015_diff_format_update.py +1 -1
  88. infrahub/core/migrations/graph/m016_diff_delete_bug_fix.py +1 -1
  89. infrahub/core/migrations/graph/m017_add_core_profile.py +1 -1
  90. infrahub/core/migrations/graph/m018_uniqueness_nulls.py +2 -2
  91. infrahub/core/migrations/graph/m019_restore_rels_to_time.py +256 -0
  92. infrahub/core/migrations/graph/m020_add_generate_template_attr.py +48 -0
  93. infrahub/core/migrations/query/attribute_add.py +1 -1
  94. infrahub/core/migrations/query/attribute_rename.py +1 -1
  95. infrahub/core/migrations/query/delete_element_in_schema.py +1 -1
  96. infrahub/core/migrations/query/node_duplicate.py +39 -19
  97. infrahub/core/migrations/query/relationship_duplicate.py +1 -1
  98. infrahub/core/migrations/query/schema_attribute_update.py +1 -1
  99. infrahub/core/migrations/schema/node_attribute_remove.py +1 -1
  100. infrahub/core/migrations/schema/node_remove.py +27 -13
  101. infrahub/core/migrations/schema/tasks.py +5 -5
  102. infrahub/core/migrations/shared.py +4 -4
  103. infrahub/core/models.py +7 -8
  104. infrahub/core/node/__init__.py +170 -46
  105. infrahub/core/node/base.py +1 -1
  106. infrahub/core/node/constraints/grouped_uniqueness.py +9 -2
  107. infrahub/core/node/delete_validator.py +4 -4
  108. infrahub/core/node/ipam.py +13 -8
  109. infrahub/core/node/permissions.py +4 -0
  110. infrahub/core/node/resource_manager/ip_prefix_pool.py +8 -5
  111. infrahub/core/node/standard.py +3 -5
  112. infrahub/core/property.py +1 -1
  113. infrahub/core/protocols.py +6 -0
  114. infrahub/core/protocols_base.py +4 -2
  115. infrahub/core/query/__init__.py +2 -5
  116. infrahub/core/query/attribute.py +9 -9
  117. infrahub/core/query/branch.py +5 -5
  118. infrahub/core/query/delete.py +1 -1
  119. infrahub/core/query/diff.py +45 -7
  120. infrahub/core/query/ipam.py +4 -4
  121. infrahub/core/query/node.py +19 -14
  122. infrahub/core/query/relationship.py +213 -26
  123. infrahub/core/query/resource_manager.py +13 -11
  124. infrahub/core/query/standard_node.py +6 -6
  125. infrahub/core/query/task.py +3 -3
  126. infrahub/core/query/task_log.py +1 -1
  127. infrahub/core/query/utils.py +5 -5
  128. infrahub/core/registry.py +0 -2
  129. infrahub/core/relationship/constraints/count.py +1 -1
  130. infrahub/core/relationship/constraints/peer_kind.py +1 -1
  131. infrahub/core/relationship/model.py +76 -38
  132. infrahub/core/schema/__init__.py +6 -4
  133. infrahub/core/schema/attribute_schema.py +8 -0
  134. infrahub/core/schema/basenode_schema.py +13 -3
  135. infrahub/core/schema/definitions/core/__init__.py +153 -0
  136. infrahub/core/schema/definitions/core/account.py +168 -0
  137. infrahub/core/schema/definitions/core/artifact.py +127 -0
  138. infrahub/core/schema/definitions/core/builtin.py +21 -0
  139. infrahub/core/schema/definitions/core/check.py +60 -0
  140. infrahub/core/schema/definitions/core/generator.py +96 -0
  141. infrahub/core/schema/definitions/core/graphql_query.py +77 -0
  142. infrahub/core/schema/definitions/core/group.py +105 -0
  143. infrahub/core/schema/definitions/core/ipam.py +252 -0
  144. infrahub/core/schema/definitions/core/lineage.py +17 -0
  145. infrahub/core/schema/definitions/core/menu.py +46 -0
  146. infrahub/core/schema/definitions/core/permission.py +161 -0
  147. infrahub/core/schema/definitions/core/profile.py +29 -0
  148. infrahub/core/schema/definitions/core/propose_change.py +88 -0
  149. infrahub/core/schema/definitions/core/propose_change_comment.py +188 -0
  150. infrahub/core/schema/definitions/core/propose_change_validator.py +326 -0
  151. infrahub/core/schema/definitions/core/repository.py +280 -0
  152. infrahub/core/schema/definitions/core/resource_pool.py +180 -0
  153. infrahub/core/schema/definitions/core/template.py +12 -0
  154. infrahub/core/schema/definitions/core/transform.py +87 -0
  155. infrahub/core/schema/definitions/core/webhook.py +108 -0
  156. infrahub/core/schema/definitions/internal.py +16 -0
  157. infrahub/core/schema/generated/genericnode_schema.py +5 -0
  158. infrahub/core/schema/generated/node_schema.py +5 -0
  159. infrahub/core/schema/generic_schema.py +5 -1
  160. infrahub/core/schema/manager.py +45 -42
  161. infrahub/core/schema/node_schema.py +4 -0
  162. infrahub/core/schema/profile_schema.py +4 -0
  163. infrahub/core/schema/relationship_schema.py +10 -2
  164. infrahub/core/schema/schema_branch.py +260 -16
  165. infrahub/core/schema/template_schema.py +36 -0
  166. infrahub/core/task/user_task.py +7 -5
  167. infrahub/core/timestamp.py +3 -3
  168. infrahub/core/utils.py +3 -2
  169. infrahub/core/validators/attribute/choices.py +1 -1
  170. infrahub/core/validators/attribute/enum.py +1 -1
  171. infrahub/core/validators/attribute/kind.py +1 -1
  172. infrahub/core/validators/attribute/length.py +1 -1
  173. infrahub/core/validators/attribute/optional.py +1 -1
  174. infrahub/core/validators/attribute/regex.py +1 -1
  175. infrahub/core/validators/attribute/unique.py +1 -1
  176. infrahub/core/validators/checks_runner.py +37 -0
  177. infrahub/core/validators/node/generate_profile.py +1 -1
  178. infrahub/core/validators/node/hierarchy.py +1 -1
  179. infrahub/core/validators/query.py +1 -1
  180. infrahub/core/validators/relationship/count.py +1 -1
  181. infrahub/core/validators/relationship/optional.py +1 -1
  182. infrahub/core/validators/relationship/peer.py +1 -1
  183. infrahub/core/validators/tasks.py +8 -6
  184. infrahub/core/validators/uniqueness/query.py +20 -17
  185. infrahub/database/__init__.py +16 -2
  186. infrahub/database/memgraph.py +1 -1
  187. infrahub/dependencies/builder/constraint/grouped/node_runner.py +0 -2
  188. infrahub/dependencies/builder/diff/combiner.py +1 -1
  189. infrahub/dependencies/builder/diff/conflicts_enricher.py +1 -1
  190. infrahub/dependencies/builder/diff/coordinator.py +0 -2
  191. infrahub/dependencies/builder/diff/deserializer.py +4 -2
  192. infrahub/dependencies/builder/diff/enricher/hierarchy.py +3 -1
  193. infrahub/dependencies/builder/diff/enricher/summary_counts.py +1 -1
  194. infrahub/dependencies/builder/diff/parent_node_adder.py +8 -0
  195. infrahub/events/artifact_action.py +76 -0
  196. infrahub/events/branch_action.py +50 -21
  197. infrahub/events/group_action.py +117 -0
  198. infrahub/events/models.py +164 -51
  199. infrahub/events/node_action.py +70 -8
  200. infrahub/events/repository_action.py +8 -8
  201. infrahub/events/schema_action.py +21 -8
  202. infrahub/exceptions.py +9 -0
  203. infrahub/generators/models.py +1 -0
  204. infrahub/generators/tasks.py +34 -15
  205. infrahub/git/base.py +3 -5
  206. infrahub/git/constants.py +0 -1
  207. infrahub/git/integrator.py +60 -36
  208. infrahub/git/models.py +80 -1
  209. infrahub/git/repository.py +7 -8
  210. infrahub/git/tasks.py +432 -112
  211. infrahub/git_credential/helper.py +2 -3
  212. infrahub/graphql/analyzer.py +572 -11
  213. infrahub/graphql/app.py +34 -26
  214. infrahub/graphql/auth/query_permission_checker/anonymous_checker.py +5 -5
  215. infrahub/graphql/auth/query_permission_checker/default_branch_checker.py +4 -4
  216. infrahub/graphql/auth/query_permission_checker/merge_operation_checker.py +4 -4
  217. infrahub/graphql/auth/query_permission_checker/object_permission_checker.py +28 -35
  218. infrahub/graphql/auth/query_permission_checker/super_admin_checker.py +5 -5
  219. infrahub/graphql/context.py +33 -0
  220. infrahub/graphql/enums.py +1 -1
  221. infrahub/graphql/initialization.py +5 -1
  222. infrahub/graphql/loaders/node.py +2 -2
  223. infrahub/graphql/manager.py +63 -63
  224. infrahub/graphql/mutations/account.py +20 -13
  225. infrahub/graphql/mutations/artifact_definition.py +16 -12
  226. infrahub/graphql/mutations/branch.py +86 -40
  227. infrahub/graphql/mutations/computed_attribute.py +24 -13
  228. infrahub/graphql/mutations/diff.py +54 -14
  229. infrahub/graphql/mutations/diff_conflict.py +14 -8
  230. infrahub/graphql/mutations/generator.py +83 -0
  231. infrahub/graphql/mutations/graphql_query.py +19 -11
  232. infrahub/graphql/mutations/ipam.py +25 -23
  233. infrahub/graphql/mutations/main.py +243 -50
  234. infrahub/graphql/mutations/menu.py +10 -10
  235. infrahub/graphql/mutations/proposed_change.py +36 -28
  236. infrahub/graphql/mutations/relationship.py +343 -104
  237. infrahub/graphql/mutations/repository.py +41 -35
  238. infrahub/graphql/mutations/resource_manager.py +26 -26
  239. infrahub/graphql/mutations/schema.py +66 -33
  240. infrahub/graphql/mutations/tasks.py +16 -10
  241. infrahub/graphql/parser.py +1 -1
  242. infrahub/graphql/permissions.py +3 -10
  243. infrahub/graphql/queries/account.py +22 -18
  244. infrahub/graphql/queries/branch.py +6 -4
  245. infrahub/graphql/queries/diff/tree.py +63 -52
  246. infrahub/graphql/queries/event.py +115 -0
  247. infrahub/graphql/queries/internal.py +3 -3
  248. infrahub/graphql/queries/ipam.py +23 -18
  249. infrahub/graphql/queries/relationship.py +11 -10
  250. infrahub/graphql/queries/resource_manager.py +43 -27
  251. infrahub/graphql/queries/search.py +9 -8
  252. infrahub/graphql/queries/status.py +12 -9
  253. infrahub/graphql/queries/task.py +11 -9
  254. infrahub/graphql/resolvers/resolver.py +69 -43
  255. infrahub/graphql/resolvers/single_relationship.py +16 -10
  256. infrahub/graphql/schema.py +4 -0
  257. infrahub/graphql/subscription/__init__.py +1 -1
  258. infrahub/graphql/subscription/events.py +1 -1
  259. infrahub/graphql/subscription/graphql_query.py +8 -8
  260. infrahub/graphql/types/branch.py +2 -2
  261. infrahub/graphql/types/common.py +6 -1
  262. infrahub/graphql/types/context.py +12 -0
  263. infrahub/graphql/types/enums.py +2 -0
  264. infrahub/graphql/types/event.py +158 -0
  265. infrahub/graphql/types/interface.py +2 -2
  266. infrahub/graphql/types/node.py +3 -3
  267. infrahub/graphql/types/permission.py +2 -2
  268. infrahub/graphql/types/relationship.py +3 -3
  269. infrahub/graphql/types/standard_node.py +9 -11
  270. infrahub/graphql/utils.py +28 -182
  271. infrahub/groups/tasks.py +2 -3
  272. infrahub/lock.py +21 -21
  273. infrahub/menu/generator.py +0 -1
  274. infrahub/menu/menu.py +116 -138
  275. infrahub/menu/models.py +4 -4
  276. infrahub/message_bus/__init__.py +11 -13
  277. infrahub/message_bus/messages/__init__.py +0 -14
  278. infrahub/message_bus/messages/check_generator_run.py +1 -3
  279. infrahub/message_bus/messages/event_branch_merge.py +3 -0
  280. infrahub/message_bus/messages/proposed_change/request_proposedchange_refreshartifacts.py +6 -0
  281. infrahub/message_bus/messages/request_proposedchange_pipeline.py +2 -0
  282. infrahub/message_bus/messages/send_echo_request.py +1 -1
  283. infrahub/message_bus/operations/__init__.py +4 -13
  284. infrahub/message_bus/operations/check/__init__.py +2 -2
  285. infrahub/message_bus/operations/check/generator.py +1 -3
  286. infrahub/message_bus/operations/event/branch.py +7 -3
  287. infrahub/message_bus/operations/event/schema.py +1 -1
  288. infrahub/message_bus/operations/event/worker.py +0 -3
  289. infrahub/message_bus/operations/finalize/validator.py +1 -1
  290. infrahub/message_bus/operations/git/file.py +2 -2
  291. infrahub/message_bus/operations/git/repository.py +1 -1
  292. infrahub/message_bus/operations/requests/__init__.py +0 -4
  293. infrahub/message_bus/operations/requests/generator_definition.py +2 -4
  294. infrahub/message_bus/operations/requests/proposed_change.py +37 -20
  295. infrahub/message_bus/operations/send/echo.py +1 -1
  296. infrahub/message_bus/types.py +1 -1
  297. infrahub/permissions/__init__.py +2 -1
  298. infrahub/permissions/globals.py +15 -0
  299. infrahub/permissions/types.py +26 -0
  300. infrahub/pools/prefix.py +29 -165
  301. infrahub/prefect_server/__init__.py +0 -0
  302. infrahub/prefect_server/app.py +18 -0
  303. infrahub/prefect_server/database.py +20 -0
  304. infrahub/prefect_server/events.py +28 -0
  305. infrahub/prefect_server/models.py +46 -0
  306. infrahub/proposed_change/models.py +18 -1
  307. infrahub/proposed_change/tasks.py +195 -53
  308. infrahub/pytest_plugin.py +4 -4
  309. infrahub/server.py +13 -12
  310. infrahub/services/__init__.py +148 -63
  311. infrahub/services/adapters/cache/__init__.py +11 -11
  312. infrahub/services/adapters/cache/nats.py +42 -25
  313. infrahub/services/adapters/cache/redis.py +3 -11
  314. infrahub/services/adapters/event/__init__.py +10 -18
  315. infrahub/services/adapters/http/__init__.py +0 -5
  316. infrahub/services/adapters/http/httpx.py +22 -15
  317. infrahub/services/adapters/message_bus/__init__.py +25 -8
  318. infrahub/services/adapters/message_bus/local.py +9 -7
  319. infrahub/services/adapters/message_bus/nats.py +14 -8
  320. infrahub/services/adapters/message_bus/rabbitmq.py +23 -10
  321. infrahub/services/adapters/workflow/__init__.py +11 -8
  322. infrahub/services/adapters/workflow/local.py +27 -6
  323. infrahub/services/adapters/workflow/worker.py +23 -7
  324. infrahub/services/component.py +43 -40
  325. infrahub/services/protocols.py +7 -7
  326. infrahub/services/scheduler.py +30 -29
  327. infrahub/storage.py +2 -4
  328. infrahub/task_manager/constants.py +1 -1
  329. infrahub/task_manager/event.py +261 -0
  330. infrahub/task_manager/models.py +147 -3
  331. infrahub/task_manager/task.py +1 -1
  332. infrahub/tasks/artifact.py +19 -18
  333. infrahub/tasks/registry.py +1 -1
  334. infrahub/tasks/telemetry.py +13 -14
  335. infrahub/transformations/tasks.py +3 -5
  336. infrahub/trigger/__init__.py +0 -0
  337. infrahub/trigger/catalogue.py +16 -0
  338. infrahub/trigger/constants.py +9 -0
  339. infrahub/trigger/models.py +105 -0
  340. infrahub/trigger/tasks.py +91 -0
  341. infrahub/types.py +1 -1
  342. infrahub/utils.py +1 -1
  343. infrahub/webhook/constants.py +0 -2
  344. infrahub/webhook/models.py +161 -40
  345. infrahub/webhook/tasks.py +123 -202
  346. infrahub/webhook/triggers.py +27 -0
  347. infrahub/workers/infrahub_async.py +36 -25
  348. infrahub/workers/utils.py +63 -0
  349. infrahub/workflows/catalogue.py +71 -52
  350. infrahub/workflows/initialization.py +14 -8
  351. infrahub/workflows/models.py +28 -4
  352. infrahub/workflows/utils.py +1 -1
  353. infrahub_sdk/client.py +8 -0
  354. infrahub_sdk/ctl/branch.py +3 -2
  355. infrahub_sdk/ctl/check.py +3 -3
  356. infrahub_sdk/ctl/cli_commands.py +16 -11
  357. infrahub_sdk/ctl/exceptions.py +0 -6
  358. infrahub_sdk/ctl/exporter.py +1 -1
  359. infrahub_sdk/ctl/generator.py +5 -5
  360. infrahub_sdk/ctl/importer.py +3 -2
  361. infrahub_sdk/ctl/menu.py +1 -1
  362. infrahub_sdk/ctl/object.py +1 -1
  363. infrahub_sdk/ctl/repository.py +23 -15
  364. infrahub_sdk/ctl/schema.py +2 -2
  365. infrahub_sdk/ctl/utils.py +4 -19
  366. infrahub_sdk/ctl/validate.py +2 -1
  367. infrahub_sdk/exceptions.py +12 -0
  368. infrahub_sdk/generator.py +3 -0
  369. infrahub_sdk/node.py +4 -4
  370. infrahub_sdk/protocols.py +21 -8
  371. infrahub_sdk/schema/__init__.py +14 -2
  372. infrahub_sdk/schema/main.py +7 -0
  373. infrahub_sdk/task/__init__.py +1 -0
  374. infrahub_sdk/task/constants.py +3 -0
  375. infrahub_sdk/task/exceptions.py +25 -0
  376. infrahub_sdk/task/manager.py +545 -0
  377. infrahub_sdk/task/models.py +74 -0
  378. infrahub_sdk/timestamp.py +134 -33
  379. infrahub_sdk/utils.py +39 -1
  380. infrahub_sdk/yaml.py +2 -3
  381. {infrahub_server-1.1.6.dist-info → infrahub_server-1.2.0b1.dist-info}/METADATA +47 -12
  382. infrahub_server-1.2.0b1.dist-info/RECORD +725 -0
  383. infrahub_testcontainers/container.py +14 -6
  384. infrahub_testcontainers/docker-compose.test.yml +24 -5
  385. infrahub_testcontainers/haproxy.cfg +43 -0
  386. infrahub_testcontainers/helpers.py +85 -1
  387. infrahub/core/branch/constants.py +0 -2
  388. infrahub/core/schema/definitions/core.py +0 -2274
  389. infrahub/graphql/query.py +0 -52
  390. infrahub/message_bus/messages/check_repository_checkdefinition.py +0 -20
  391. infrahub/message_bus/messages/check_repository_mergeconflicts.py +0 -16
  392. infrahub/message_bus/messages/check_repository_usercheck.py +0 -26
  393. infrahub/message_bus/messages/request_artifactdefinition_check.py +0 -17
  394. infrahub/message_bus/messages/request_repository_checks.py +0 -12
  395. infrahub/message_bus/messages/request_repository_userchecks.py +0 -18
  396. infrahub/message_bus/operations/check/repository.py +0 -293
  397. infrahub/message_bus/operations/requests/artifact_definition.py +0 -148
  398. infrahub/message_bus/operations/requests/repository.py +0 -133
  399. infrahub/schema/constants.py +0 -1
  400. infrahub/schema/tasks.py +0 -76
  401. infrahub/services/adapters/database/__init__.py +0 -9
  402. infrahub_sdk/ctl/_file.py +0 -13
  403. infrahub_server-1.1.6.dist-info/RECORD +0 -681
  404. /infrahub/{schema → artifacts}/__init__.py +0 -0
  405. {infrahub_server-1.1.6.dist-info → infrahub_server-1.2.0b1.dist-info}/LICENSE.txt +0 -0
  406. {infrahub_server-1.1.6.dist-info → infrahub_server-1.2.0b1.dist-info}/WHEEL +0 -0
  407. {infrahub_server-1.1.6.dist-info → infrahub_server-1.2.0b1.dist-info}/entry_points.txt +0 -0
@@ -13,14 +13,14 @@ from infrahub.core import registry, utils
13
13
  from infrahub.core.branch import Branch
14
14
  from infrahub.core.constants import InfrahubKind
15
15
  from infrahub.core.graph.schema import GRAPH_SCHEMA
16
- from infrahub.services import InfrahubServices, services
16
+ from infrahub.services import InfrahubServices
17
17
 
18
18
  TELEMETRY_KIND: str = "community"
19
19
  TELEMETRY_VERSION: str = "20240524"
20
20
 
21
21
 
22
- @task(name="telemetry-gather-db", task_run_name="Gather Database Information", cache_policy=NONE)
23
- async def gather_database_information(service: InfrahubServices, branch: Branch) -> dict: # pylint: disable=unused-argument
22
+ @task(name="telemetry-gather-db", task_run_name="Gather Database Information", cache_policy=NONE) # type: ignore[arg-type]
23
+ async def gather_database_information(service: InfrahubServices) -> dict:
24
24
  async with service.database.start_session() as db:
25
25
  data: dict[str, Any] = {
26
26
  "database_type": db.db_type.value,
@@ -37,8 +37,8 @@ async def gather_database_information(service: InfrahubServices, branch: Branch)
37
37
  return data
38
38
 
39
39
 
40
- @task(name="telemetry-schema-information", task_run_name="Gather Schema Information", cache_policy=NONE)
41
- async def gather_schema_information(service: InfrahubServices, branch: Branch) -> dict: # pylint: disable=unused-argument
40
+ @task(name="telemetry-schema-information", task_run_name="Gather Schema Information", cache_policy=NONE) # type: ignore[arg-type]
41
+ async def gather_schema_information(branch: Branch) -> dict:
42
42
  data: dict[str, Any] = {}
43
43
  main_schema = registry.schema.get_schema_branch(name=branch.name)
44
44
  data["node_count"] = len(main_schema.node_names)
@@ -48,8 +48,8 @@ async def gather_schema_information(service: InfrahubServices, branch: Branch) -
48
48
  return data
49
49
 
50
50
 
51
- @task(name="telemetry-feature-information", task_run_name="Gather Feature Information", cache_policy=NONE)
52
- async def gather_feature_information(service: InfrahubServices, branch: Branch) -> dict: # pylint: disable=unused-argument
51
+ @task(name="telemetry-feature-information", task_run_name="Gather Feature Information", cache_policy=NONE) # type: ignore[arg-type]
52
+ async def gather_feature_information(service: InfrahubServices) -> dict:
53
53
  async with service.database.start_session() as db:
54
54
  data = {}
55
55
  features_to_count = [
@@ -67,7 +67,7 @@ async def gather_feature_information(service: InfrahubServices, branch: Branch)
67
67
  return data
68
68
 
69
69
 
70
- @task(name="telemetry-gather-data", task_run_name="Gather Anonynous Data", cache_policy=NONE)
70
+ @task(name="telemetry-gather-data", task_run_name="Gather Anonynous Data", cache_policy=NONE) # type: ignore[arg-type]
71
71
  async def gather_anonymous_telemetry_data(service: InfrahubServices) -> dict:
72
72
  start_time = time.time()
73
73
 
@@ -87,9 +87,9 @@ async def gather_anonymous_telemetry_data(service: InfrahubServices) -> dict:
87
87
  "branches": {
88
88
  "total": len(registry.branch),
89
89
  },
90
- "features": await gather_feature_information(service=service, branch=default_branch),
91
- "schema": await gather_schema_information(service=service, branch=default_branch),
92
- "database": await gather_database_information(service=service, branch=default_branch),
90
+ "features": await gather_feature_information(service=service),
91
+ "schema": await gather_schema_information(branch=default_branch),
92
+ "database": await gather_database_information(service=service),
93
93
  }
94
94
 
95
95
  data["execution_time"] = time.time() - start_time
@@ -97,7 +97,7 @@ async def gather_anonymous_telemetry_data(service: InfrahubServices) -> dict:
97
97
  return data
98
98
 
99
99
 
100
- @task(name="telemetry-post-data", task_run_name="Upload data", retries=5, cache_policy=NONE)
100
+ @task(name="telemetry-post-data", task_run_name="Upload data", retries=5, cache_policy=NONE) # type: ignore[arg-type]
101
101
  async def post_telemetry_data(service: InfrahubServices, url: str, payload: dict[str, Any]) -> None:
102
102
  """Send the telemetry data to the specified URL, using HTTP POST."""
103
103
  response = await service.http.post(url=url, json=payload)
@@ -105,8 +105,7 @@ async def post_telemetry_data(service: InfrahubServices, url: str, payload: dict
105
105
 
106
106
 
107
107
  @flow(name="anonymous_telemetry_send", flow_run_name="Send anonymous telemetry")
108
- async def send_telemetry_push() -> None:
109
- service = services.service
108
+ async def send_telemetry_push(service: InfrahubServices) -> None:
110
109
  log = get_run_logger()
111
110
  if config.SETTINGS.main.telemetry_optout:
112
111
  log.info("Skipping, User opted out of this service.")
@@ -4,7 +4,7 @@ from prefect import flow
4
4
 
5
5
  from infrahub.git.repository import get_initialized_repo
6
6
  from infrahub.log import get_logger
7
- from infrahub.services import services
7
+ from infrahub.services import InfrahubServices
8
8
  from infrahub.workflows.utils import add_branch_tag
9
9
 
10
10
  from .models import TransformJinjaTemplateData, TransformPythonData
@@ -13,8 +13,7 @@ log = get_logger()
13
13
 
14
14
 
15
15
  @flow(name="transform_render_python", flow_run_name="Render transform python", persist_result=True)
16
- async def transform_python(message: TransformPythonData) -> Any:
17
- service = services.service
16
+ async def transform_python(message: TransformPythonData, service: InfrahubServices) -> Any:
18
17
  await add_branch_tag(branch_name=message.branch)
19
18
 
20
19
  repo = await get_initialized_repo(
@@ -37,8 +36,7 @@ async def transform_python(message: TransformPythonData) -> Any:
37
36
 
38
37
 
39
38
  @flow(name="transform_render_jinja2_template", flow_run_name="Render transform Jinja2", persist_result=True)
40
- async def transform_render_jinja2_template(message: TransformJinjaTemplateData) -> str:
41
- service = services.service
39
+ async def transform_render_jinja2_template(message: TransformJinjaTemplateData, service: InfrahubServices) -> str:
42
40
  await add_branch_tag(branch_name=message.branch)
43
41
 
44
42
  repo = await get_initialized_repo(
File without changes
@@ -0,0 +1,16 @@
1
+ from infrahub.computed_attribute.triggers import (
2
+ TRIGGER_COMPUTED_ATTRIBUTE_ALL_SCHEMA,
3
+ TRIGGER_COMPUTED_ATTRIBUTE_PYTHON_CLEAN_BRANCH,
4
+ TRIGGER_COMPUTED_ATTRIBUTE_PYTHON_SETUP_BRANCH,
5
+ TRIGGER_COMPUTED_ATTRIBUTE_PYTHON_SETUP_COMMIT,
6
+ )
7
+ from infrahub.trigger.models import TriggerDefinition
8
+ from infrahub.webhook.triggers import TRIGGER_WEBHOOK_SETUP_UPDATE
9
+
10
+ builtin_triggers: list[TriggerDefinition] = [
11
+ TRIGGER_COMPUTED_ATTRIBUTE_ALL_SCHEMA,
12
+ TRIGGER_COMPUTED_ATTRIBUTE_PYTHON_CLEAN_BRANCH,
13
+ TRIGGER_COMPUTED_ATTRIBUTE_PYTHON_SETUP_BRANCH,
14
+ TRIGGER_COMPUTED_ATTRIBUTE_PYTHON_SETUP_COMMIT,
15
+ TRIGGER_WEBHOOK_SETUP_UPDATE,
16
+ ]
@@ -0,0 +1,9 @@
1
+ DEPRECATED_STATIC_TRIGGER_NAMES = [
2
+ "Trigger-branch-create-events", # used in 1.1.x
3
+ "Trigger-branch-remove-events", # used in 1.1.x
4
+ "Trigger-webhook-update-configuration", # used in 1.1.x
5
+ "Trigger-repository-commit-update-event", # used in 1.1.x
6
+ "Trigger-schema-update-event", # used in 1.1.x
7
+ ]
8
+
9
+ NAME_SEPARATOR = "::"
@@ -0,0 +1,105 @@
1
+ from __future__ import annotations
2
+
3
+ from datetime import timedelta
4
+ from enum import Enum
5
+ from typing import TYPE_CHECKING, Any
6
+
7
+ from prefect.events.actions import RunDeployment
8
+ from prefect.events.schemas.automations import EventTrigger as PrefectEventTrigger
9
+ from prefect.events.schemas.automations import Posture
10
+ from prefect.events.schemas.events import ResourceSpecification
11
+ from pydantic import BaseModel, Field
12
+
13
+ from infrahub.workflows.models import WorkflowDefinition # noqa: TC001
14
+
15
+ from .constants import NAME_SEPARATOR
16
+
17
+ if TYPE_CHECKING:
18
+ from uuid import UUID
19
+
20
+
21
+ class TriggerType(str, Enum):
22
+ BUILTIN = "builtin"
23
+ WEBHOOK = "webhook"
24
+ # OBJECT = "object"
25
+ # COMPUTED_ATTR = "computed_attr"
26
+
27
+
28
+ class EventTrigger(BaseModel):
29
+ events: set = Field(default_factory=set)
30
+ match: dict[str, Any] = Field(default_factory=dict)
31
+ match_related: dict[str, Any] = Field(default_factory=dict)
32
+
33
+ def get_prefect(self) -> PrefectEventTrigger:
34
+ return PrefectEventTrigger(
35
+ posture=Posture.Reactive,
36
+ expect=self.events,
37
+ within=timedelta(0),
38
+ match=ResourceSpecification(self.match),
39
+ match_related=ResourceSpecification(self.match_related),
40
+ threshold=1,
41
+ )
42
+
43
+
44
+ class ExecuteWorkflow(BaseModel):
45
+ workflow: WorkflowDefinition
46
+ parameters: dict[str, Any] = Field(default_factory=dict)
47
+
48
+ @property
49
+ def name(self) -> str:
50
+ return self.workflow.name
51
+
52
+ def get_prefect(self, mapping: dict[str, UUID]) -> RunDeployment:
53
+ deployment_id = mapping[self.name]
54
+ return self.get(deployment_id)
55
+
56
+ def get(self, id: UUID) -> RunDeployment:
57
+ return RunDeployment(
58
+ source="selected",
59
+ deployment_id=id,
60
+ parameters=self.parameters,
61
+ job_variables={},
62
+ )
63
+
64
+ def validate_parameters(self) -> None:
65
+ if not self.parameters:
66
+ return
67
+
68
+ workflow_params = self.workflow.get_parameters()
69
+ workflow_required_params = [p.name for p in workflow_params.values() if p.required]
70
+ trigger_params = list(self.parameters.keys())
71
+
72
+ missing_required_params = set(workflow_required_params) - set(trigger_params)
73
+ wrong_params = set(trigger_params) - set(workflow_params)
74
+
75
+ if missing_required_params:
76
+ raise ValueError(
77
+ f"Missing required parameters: {missing_required_params} for workflow {self.workflow.name}"
78
+ )
79
+
80
+ if wrong_params:
81
+ raise ValueError(f"Workflow {self.workflow.name} doesn't support parameters: {wrong_params}")
82
+
83
+
84
+ class TriggerDefinition(BaseModel):
85
+ name: str
86
+ type: TriggerType
87
+ previous_names: set = Field(default_factory=set)
88
+ description: str = ""
89
+ trigger: EventTrigger
90
+ actions: list[ExecuteWorkflow]
91
+
92
+ def get_deployment_names(self) -> list[str]:
93
+ """Return the name of all deployments used by this trigger"""
94
+ return [action.name for action in self.actions]
95
+
96
+ def generate_name(self) -> str:
97
+ return f"{self.type.value}{NAME_SEPARATOR}{self.name}"
98
+
99
+ def validate_actions(self) -> None:
100
+ for action in self.actions:
101
+ action.validate_parameters()
102
+
103
+
104
+ class BuiltinTriggerDefinition(TriggerDefinition):
105
+ type: TriggerType = TriggerType.BUILTIN
@@ -0,0 +1,91 @@
1
+ from typing import TYPE_CHECKING
2
+
3
+ from prefect import get_run_logger, task
4
+ from prefect.automations import AutomationCore
5
+ from prefect.cache_policies import NONE
6
+ from prefect.client.orchestration import PrefectClient
7
+ from prefect.client.schemas.filters import DeploymentFilter, DeploymentFilterName
8
+
9
+ from infrahub.trigger.models import TriggerDefinition
10
+
11
+ # from .catalogue import triggers
12
+ from .models import TriggerType
13
+
14
+ if TYPE_CHECKING:
15
+ from uuid import UUID
16
+
17
+
18
+ @task(name="trigger-setup", task_run_name="Setup triggers of type {trigger_type.value}", cache_policy=NONE) # type: ignore[arg-type]
19
+ async def setup_triggers(
20
+ client: PrefectClient,
21
+ triggers: list[TriggerDefinition],
22
+ trigger_type: TriggerType = TriggerType.BUILTIN,
23
+ deprecated_triggers: list[str] | None = None,
24
+ ) -> None:
25
+ log = get_run_logger()
26
+
27
+ # -------------------------------------------------------------
28
+ # Retrieve existing Deployments and Automation from the server
29
+ # -------------------------------------------------------------
30
+ deployment_names = list({name for trigger in triggers for name in trigger.get_deployment_names()})
31
+ deployments = {
32
+ item.name: item
33
+ for item in await client.read_deployments(
34
+ deployment_filter=DeploymentFilter(name=DeploymentFilterName(any_=deployment_names))
35
+ )
36
+ }
37
+ deployments_mapping: dict[str, UUID] = {name: item.id for name, item in deployments.items()}
38
+ existing_automations = {item.name: item for item in await client.read_automations()}
39
+
40
+ trigger_automations = [
41
+ item.name for item in await client.read_automations() if item.name.startswith(trigger_type.value)
42
+ ]
43
+ trigger_names = [trigger.generate_name() for trigger in triggers]
44
+
45
+ to_delete = set(trigger_automations) - set(trigger_names)
46
+
47
+ # -------------------------------------------------------------
48
+ # Create or Update all triggers
49
+ # -------------------------------------------------------------
50
+ for trigger in triggers:
51
+ automation = AutomationCore(
52
+ name=trigger.generate_name(),
53
+ description=trigger.description,
54
+ enabled=True,
55
+ trigger=trigger.trigger.get_prefect(),
56
+ actions=[action.get_prefect(mapping=deployments_mapping) for action in trigger.actions],
57
+ )
58
+
59
+ existing_automation = existing_automations.get(trigger.name, None)
60
+
61
+ if existing_automation:
62
+ await client.update_automation(automation_id=existing_automation.id, automation=automation)
63
+ log.info(f"{trigger.name} Updated")
64
+ else:
65
+ await client.create_automation(automation=automation)
66
+ log.info(f"{trigger.name} Created")
67
+
68
+ # -------------------------------------------------------------
69
+ # Delete Triggers that shouldn't be there
70
+ # -------------------------------------------------------------
71
+ for item_to_delete in to_delete:
72
+ existing_automation = existing_automations.get(item_to_delete)
73
+
74
+ if not existing_automation:
75
+ continue
76
+
77
+ await client.delete_automation(automation_id=existing_automation.id)
78
+ log.info(f"{item_to_delete} Deleted")
79
+
80
+ # -------------------------------------------------------------
81
+ # Delete Deprecated triggers
82
+ # -------------------------------------------------------------
83
+ if deprecated_triggers:
84
+ for trigger_name in deprecated_triggers:
85
+ existing_automation = existing_automations.get(trigger_name)
86
+
87
+ if not existing_automation:
88
+ continue
89
+
90
+ await client.delete_automation(automation_id=existing_automation.id)
91
+ log.info(f"{trigger_name} Deleted")
infrahub/types.py CHANGED
@@ -354,7 +354,7 @@ ATTRIBUTE_PYTHON_TYPES: dict[str, type] = {
354
354
  "Color": str, # Colors often represented as hex strings
355
355
  "Number": float, # Numbers can be floats for general use
356
356
  "Bandwidth": float, # Bandwidth in some units, represented as a float
357
- "IPHost": IPvAnyAddress,
357
+ "IPHost": IPvAnyAddress, # type: ignore[dict-item]
358
358
  "IPNetwork": str,
359
359
  "Boolean": bool,
360
360
  "Checkbox": bool, # Checkboxes represent boolean values
infrahub/utils.py CHANGED
@@ -36,7 +36,7 @@ def format_label(slug: str) -> str:
36
36
  class MetaEnum(EnumMeta):
37
37
  def __contains__(cls, item: Any) -> bool:
38
38
  try:
39
- cls(item) # pylint: disable=no-value-for-parameter
39
+ cls(item)
40
40
  except ValueError:
41
41
  return False
42
42
  return True
@@ -1,3 +1 @@
1
- AUTOMATION_NAME = "Trigger-webhook-update-configuration"
2
-
3
1
  AUTOMATION_NAME_RUN = "Trigger-webhook-execution"
@@ -1,64 +1,158 @@
1
+ from __future__ import annotations
2
+
1
3
  import base64
2
4
  import hashlib
3
5
  import hmac
4
- from datetime import datetime, timezone
5
- from math import floor
6
- from typing import Any, Optional, Union
7
- from uuid import uuid4
6
+ from typing import TYPE_CHECKING, Any, Optional, Union
7
+ from uuid import UUID, uuid4
8
8
 
9
- from infrahub_sdk.protocols import CoreTransformPython
10
- from pydantic import BaseModel, ConfigDict, Field
9
+ from pydantic import BaseModel, ConfigDict, Field, computed_field
10
+ from typing_extensions import Self
11
11
 
12
+ from infrahub.core import registry
12
13
  from infrahub.core.constants import InfrahubKind
14
+ from infrahub.core.timestamp import Timestamp
13
15
  from infrahub.git.repository import InfrahubReadOnlyRepository, InfrahubRepository
14
- from infrahub.services import InfrahubServices
15
- from infrahub.transformations.constants import DEFAULT_TRANSFORM_TIMEOUT
16
+ from infrahub.trigger.models import EventTrigger, ExecuteWorkflow, TriggerDefinition, TriggerType
17
+ from infrahub.workflows.catalogue import WEBHOOK_PROCESS
18
+
19
+ if TYPE_CHECKING:
20
+ from httpx import Response
21
+ from infrahub_sdk.protocols import CoreCustomWebhook, CoreStandardWebhook, CoreTransformPython, CoreWebhook
22
+
23
+ from infrahub.services import InfrahubServices
24
+
25
+
26
+ class WebhookTriggerDefinition(TriggerDefinition):
27
+ type: TriggerType = TriggerType.WEBHOOK
28
+
29
+ @classmethod
30
+ def from_object(cls, obj: CoreWebhook) -> Self:
31
+ event_trigger = EventTrigger()
32
+ if obj.event_type.value == "all":
33
+ event_trigger.events.add("infrahub.*")
34
+ else:
35
+ event_trigger.events.add(obj.event_type.value)
36
+
37
+ if obj.branch_scope.value == "default_branch":
38
+ event_trigger.match_related = {
39
+ "prefect.resource.role": "infrahub.branch",
40
+ "infrahub.resource.label": registry.default_branch,
41
+ }
42
+ elif obj.branch_scope.value == "other_branches":
43
+ event_trigger.match_related = {
44
+ "prefect.resource.role": "infrahub.branch",
45
+ "infrahub.resource.label": f"!{registry.default_branch}",
46
+ }
47
+
48
+ definition = cls(
49
+ name=obj.name.value,
50
+ trigger=event_trigger,
51
+ actions=[
52
+ ExecuteWorkflow(
53
+ workflow=WEBHOOK_PROCESS,
54
+ parameters={
55
+ "webhook_id": obj.id,
56
+ "webhook_kind": obj.get_kind(),
57
+ "event_id": "{{ event.id }}",
58
+ "event_type": "{{ event.event }}",
59
+ "event_occured_at": "{{ event.occurred }}",
60
+ "event_payload": {
61
+ "__prefect_kind": "json",
62
+ "value": {"__prefect_kind": "jinja", "template": "{{ event.payload | tojson }}"},
63
+ },
64
+ },
65
+ ),
66
+ ],
67
+ )
68
+
69
+ return definition
16
70
 
17
71
 
18
- class SendWebhookData(BaseModel):
19
- """Sent a webhook to an external source."""
72
+ class EventContext(BaseModel):
73
+ id: str = Field(..., description="The internal id of the event")
74
+ branch: str | None = Field(None, description="The branch associated with the event")
75
+ account_id: str | None = Field(None, description="The id of the account associated with the event")
76
+ occured_at: str = Field(..., description="The time when the event occurred")
77
+ event: str = Field(..., description="The event type")
20
78
 
21
- webhook_id: str = Field(..., description="The unique ID of the webhook")
22
- event_type: str = Field(..., description="The event type")
23
- event_data: dict = Field(..., description="The data tied to the event")
79
+ @classmethod
80
+ def from_event(cls, event_id: str, event_type: str, event_occured_at: str, event_payload: dict[str, Any]) -> Self:
81
+ """Extract the context from the raw event we are getting from Prefect."""
82
+
83
+ infrahub_context: dict[str, Any] = event_payload.get("context", {})
84
+ account_info: dict[str, Any] = infrahub_context.get("account", {})
85
+ branch_info: dict[str, Any] = infrahub_context.get("branch", {})
86
+
87
+ return cls(
88
+ id=event_id,
89
+ branch=branch_info.get("name")
90
+ if branch_info and branch_info.get("name") != registry.get_global_branch().name
91
+ else None,
92
+ account_id=account_info.get("account_id"),
93
+ occured_at=event_occured_at,
94
+ event=event_type,
95
+ )
24
96
 
25
97
 
26
98
  class Webhook(BaseModel):
27
99
  model_config = ConfigDict(arbitrary_types_allowed=True)
28
- service: InfrahubServices = Field(...)
100
+ name: str = Field(...)
29
101
  url: str = Field(...)
30
102
  event_type: str = Field(...)
31
- data: dict[str, Any] = Field(...)
32
103
  validate_certificates: bool = Field(...)
33
104
  _payload: Any = None
34
105
  _headers: Optional[dict[str, Any]] = None
35
106
 
36
- async def _prepare_payload(self) -> None:
37
- self._payload = {"event_type": self.event_type, "data": self.data}
107
+ async def _prepare_payload(self, data: dict[str, Any], context: EventContext, service: InfrahubServices) -> None: # noqa: ARG002
108
+ self._payload = {"data": data, **context.model_dump()}
38
109
 
39
110
  def _assign_headers(self) -> None:
40
111
  self._headers = {}
41
112
 
113
+ @computed_field # type: ignore[prop-decorator]
42
114
  @property
43
115
  def webhook_type(self) -> str:
44
116
  return self.__class__.__name__
45
117
 
46
- async def send(self) -> None:
47
- await self._prepare_payload()
118
+ async def prepare(self, data: dict[str, Any], context: EventContext, service: InfrahubServices) -> None:
119
+ await self._prepare_payload(data=data, context=context, service=service)
48
120
  self._assign_headers()
49
- await self.service.http.post(url=self.url, json=self._payload, headers=self._headers)
121
+
122
+ async def send(self, data: dict[str, Any], context: EventContext, service: InfrahubServices) -> Response:
123
+ await self.prepare(data=data, context=context, service=service)
124
+ return await service.http.post(url=self.url, json=self.get_payload(), headers=self._headers)
125
+
126
+ def get_payload(self) -> dict[str, Any]:
127
+ return self._payload
128
+
129
+ def to_cache(self) -> dict[str, Any]:
130
+ return self.model_dump()
131
+
132
+ @classmethod
133
+ def from_cache(cls, data: dict[str, Any]) -> Self:
134
+ return cls(**data)
50
135
 
51
136
 
52
137
  class CustomWebhook(Webhook):
53
138
  """Custom webhook"""
54
139
 
140
+ @classmethod
141
+ def from_object(cls, obj: CoreCustomWebhook) -> Self:
142
+ return cls(
143
+ name=obj.name.value,
144
+ url=obj.url.value,
145
+ event_type=obj.event_type.value,
146
+ validate_certificates=obj.validate_certificates.value or False,
147
+ )
148
+
55
149
 
56
150
  class StandardWebhook(Webhook):
57
- shared_key: bytes = Field(...)
151
+ shared_key: str = Field(...)
58
152
 
59
- def _assign_headers(self) -> None:
60
- message_id = f"msg_{uuid4().hex}"
61
- timestamp = str(floor(datetime.now(tz=timezone.utc).timestamp()))
153
+ def _assign_headers(self, uuid: UUID | None = None, at: Timestamp | None = None) -> None:
154
+ message_id = f"msg_{uuid.hex}" if uuid else f"msg_{uuid4().hex}"
155
+ timestamp = str(at.to_timestamp()) if at else str(Timestamp().to_timestamp())
62
156
  payload = self._payload or {}
63
157
  unsigned_data = f"{message_id}.{timestamp}.{payload}".encode()
64
158
  signature = self._sign(data=unsigned_data)
@@ -72,7 +166,17 @@ class StandardWebhook(Webhook):
72
166
  }
73
167
 
74
168
  def _sign(self, data: bytes) -> bytes:
75
- return hmac.new(key=self.shared_key, msg=data, digestmod=hashlib.sha256).digest()
169
+ return hmac.new(key=self.shared_key.encode(), msg=data, digestmod=hashlib.sha256).digest()
170
+
171
+ @classmethod
172
+ def from_object(cls, obj: CoreStandardWebhook) -> Self:
173
+ return cls(
174
+ name=obj.name.value,
175
+ url=obj.url.value,
176
+ event_type=obj.event_type.value,
177
+ validate_certificates=obj.validate_certificates.value or False,
178
+ shared_key=obj.shared_key.value,
179
+ )
76
180
 
77
181
 
78
182
  class TransformWebhook(Webhook):
@@ -82,31 +186,48 @@ class TransformWebhook(Webhook):
82
186
  transform_name: str = Field(...)
83
187
  transform_class: str = Field(...)
84
188
  transform_file: str = Field(...)
189
+ transform_timeout: int = Field(...)
85
190
 
86
- async def _prepare_payload(self) -> None:
191
+ async def _prepare_payload(self, data: dict[str, Any], context: EventContext, service: InfrahubServices) -> None:
87
192
  repo: Union[InfrahubReadOnlyRepository, InfrahubRepository]
88
193
  if self.repository_kind == InfrahubKind.READONLYREPOSITORY:
89
194
  repo = await InfrahubReadOnlyRepository.init(
90
- id=self.repository_id, name=self.repository_name, client=self.service.client
195
+ id=self.repository_id,
196
+ name=self.repository_name,
197
+ client=service.client,
198
+ service=service,
91
199
  )
92
200
  else:
93
201
  repo = await InfrahubRepository.init(
94
- id=self.repository_id, name=self.repository_name, client=self.service.client
202
+ id=self.repository_id,
203
+ name=self.repository_name,
204
+ client=service.client,
205
+ service=service,
95
206
  )
96
207
 
97
- default_branch = repo.default_branch
98
- commit = repo.get_commit_value(branch_name=default_branch)
99
-
100
- timeout = DEFAULT_TRANSFORM_TIMEOUT
101
- if transform := await self.service.client.get(
102
- kind=CoreTransformPython, name__value=self.transform_name, raise_when_missing=False
103
- ):
104
- timeout = transform.timeout.value
208
+ branch = context.branch or repo.default_branch
209
+ commit = repo.get_commit_value(branch_name=branch)
105
210
 
106
- self._payload = await repo.execute_python_transform.with_options(timeout_seconds=timeout)(
107
- branch_name=default_branch,
211
+ self._payload = await repo.execute_python_transform.with_options(timeout_seconds=self.transform_timeout)(
212
+ branch_name=branch,
108
213
  commit=commit,
109
214
  location=f"{self.transform_file}::{self.transform_class}",
110
- data={"event_type": self.event_type, "data": self.data},
111
- client=self.service.client,
215
+ data={"data": data, **context.model_dump()},
216
+ client=service.client,
217
+ )
218
+
219
+ @classmethod
220
+ def from_object(cls, obj: CoreCustomWebhook, transform: CoreTransformPython) -> Self:
221
+ return cls(
222
+ name=obj.name.value,
223
+ url=obj.url.value,
224
+ event_type=obj.event_type.value,
225
+ validate_certificates=obj.validate_certificates.value or False,
226
+ repository_id=transform.repository.id,
227
+ repository_name=transform.repository.peer.name.value,
228
+ repository_kind=transform.repository.peer.get_kind(),
229
+ transform_name=transform.name.value,
230
+ transform_class=transform.class_name.value,
231
+ transform_file=transform.file_path.value,
232
+ transform_timeout=transform.timeout.value,
112
233
  )