infrahub-server 1.4.12__py3-none-any.whl → 1.5.0__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 (234) hide show
  1. infrahub/actions/tasks.py +208 -16
  2. infrahub/api/artifact.py +3 -0
  3. infrahub/api/diff/diff.py +1 -1
  4. infrahub/api/internal.py +2 -0
  5. infrahub/api/query.py +2 -0
  6. infrahub/api/schema.py +27 -3
  7. infrahub/auth.py +5 -5
  8. infrahub/cli/__init__.py +2 -0
  9. infrahub/cli/db.py +160 -157
  10. infrahub/cli/dev.py +118 -0
  11. infrahub/cli/tasks.py +46 -0
  12. infrahub/cli/upgrade.py +56 -9
  13. infrahub/computed_attribute/tasks.py +19 -7
  14. infrahub/config.py +7 -2
  15. infrahub/core/attribute.py +35 -24
  16. infrahub/core/branch/enums.py +1 -1
  17. infrahub/core/branch/models.py +9 -5
  18. infrahub/core/branch/needs_rebase_status.py +11 -0
  19. infrahub/core/branch/tasks.py +72 -10
  20. infrahub/core/changelog/models.py +2 -10
  21. infrahub/core/constants/__init__.py +4 -0
  22. infrahub/core/constants/infrahubkind.py +1 -0
  23. infrahub/core/convert_object_type/object_conversion.py +201 -0
  24. infrahub/core/convert_object_type/repository_conversion.py +89 -0
  25. infrahub/core/convert_object_type/schema_mapping.py +27 -3
  26. infrahub/core/diff/calculator.py +2 -2
  27. infrahub/core/diff/model/path.py +4 -0
  28. infrahub/core/diff/payload_builder.py +1 -1
  29. infrahub/core/diff/query/artifact.py +1 -0
  30. infrahub/core/diff/query/delete_query.py +9 -5
  31. infrahub/core/diff/query/field_summary.py +1 -0
  32. infrahub/core/diff/query/merge.py +39 -23
  33. infrahub/core/graph/__init__.py +1 -1
  34. infrahub/core/initialization.py +7 -4
  35. infrahub/core/manager.py +3 -81
  36. infrahub/core/migrations/__init__.py +3 -0
  37. infrahub/core/migrations/exceptions.py +4 -0
  38. infrahub/core/migrations/graph/__init__.py +13 -10
  39. infrahub/core/migrations/graph/load_schema_branch.py +21 -0
  40. infrahub/core/migrations/graph/m013_convert_git_password_credential.py +1 -1
  41. infrahub/core/migrations/graph/m037_index_attr_vals.py +11 -30
  42. infrahub/core/migrations/graph/m039_ipam_reconcile.py +9 -7
  43. infrahub/core/migrations/graph/m041_deleted_dup_edges.py +149 -0
  44. infrahub/core/migrations/graph/m042_profile_attrs_in_db.py +147 -0
  45. infrahub/core/migrations/graph/m043_create_hfid_display_label_in_db.py +164 -0
  46. infrahub/core/migrations/graph/m044_backfill_hfid_display_label_in_db.py +864 -0
  47. infrahub/core/migrations/query/__init__.py +7 -8
  48. infrahub/core/migrations/query/attribute_add.py +8 -6
  49. infrahub/core/migrations/query/attribute_remove.py +134 -0
  50. infrahub/core/migrations/runner.py +54 -0
  51. infrahub/core/migrations/schema/attribute_kind_update.py +9 -3
  52. infrahub/core/migrations/schema/attribute_supports_profile.py +90 -0
  53. infrahub/core/migrations/schema/node_attribute_add.py +26 -5
  54. infrahub/core/migrations/schema/node_attribute_remove.py +13 -109
  55. infrahub/core/migrations/schema/node_kind_update.py +2 -1
  56. infrahub/core/migrations/schema/node_remove.py +2 -1
  57. infrahub/core/migrations/schema/placeholder_dummy.py +3 -2
  58. infrahub/core/migrations/shared.py +66 -19
  59. infrahub/core/models.py +2 -2
  60. infrahub/core/node/__init__.py +207 -54
  61. infrahub/core/node/create.py +53 -49
  62. infrahub/core/node/lock_utils.py +124 -0
  63. infrahub/core/node/node_property_attribute.py +230 -0
  64. infrahub/core/node/resource_manager/ip_address_pool.py +2 -1
  65. infrahub/core/node/resource_manager/ip_prefix_pool.py +2 -1
  66. infrahub/core/node/resource_manager/number_pool.py +2 -1
  67. infrahub/core/node/standard.py +1 -1
  68. infrahub/core/property.py +11 -0
  69. infrahub/core/protocols.py +8 -1
  70. infrahub/core/query/attribute.py +82 -15
  71. infrahub/core/query/diff.py +61 -16
  72. infrahub/core/query/ipam.py +16 -4
  73. infrahub/core/query/node.py +92 -212
  74. infrahub/core/query/relationship.py +44 -26
  75. infrahub/core/query/subquery.py +0 -8
  76. infrahub/core/relationship/model.py +69 -24
  77. infrahub/core/schema/__init__.py +56 -0
  78. infrahub/core/schema/attribute_schema.py +4 -2
  79. infrahub/core/schema/basenode_schema.py +42 -2
  80. infrahub/core/schema/definitions/core/__init__.py +2 -0
  81. infrahub/core/schema/definitions/core/check.py +1 -1
  82. infrahub/core/schema/definitions/core/generator.py +2 -0
  83. infrahub/core/schema/definitions/core/group.py +16 -2
  84. infrahub/core/schema/definitions/core/repository.py +7 -0
  85. infrahub/core/schema/definitions/core/transform.py +1 -1
  86. infrahub/core/schema/definitions/internal.py +12 -3
  87. infrahub/core/schema/generated/attribute_schema.py +2 -2
  88. infrahub/core/schema/generated/base_node_schema.py +6 -1
  89. infrahub/core/schema/manager.py +3 -0
  90. infrahub/core/schema/node_schema.py +1 -0
  91. infrahub/core/schema/relationship_schema.py +0 -1
  92. infrahub/core/schema/schema_branch.py +295 -10
  93. infrahub/core/schema/schema_branch_display.py +135 -0
  94. infrahub/core/schema/schema_branch_hfid.py +120 -0
  95. infrahub/core/validators/aggregated_checker.py +1 -1
  96. infrahub/database/graph.py +21 -0
  97. infrahub/display_labels/__init__.py +0 -0
  98. infrahub/display_labels/gather.py +48 -0
  99. infrahub/display_labels/models.py +240 -0
  100. infrahub/display_labels/tasks.py +192 -0
  101. infrahub/display_labels/triggers.py +22 -0
  102. infrahub/events/branch_action.py +27 -1
  103. infrahub/events/group_action.py +1 -1
  104. infrahub/events/node_action.py +1 -1
  105. infrahub/generators/constants.py +7 -0
  106. infrahub/generators/models.py +38 -12
  107. infrahub/generators/tasks.py +34 -16
  108. infrahub/git/base.py +42 -2
  109. infrahub/git/integrator.py +22 -14
  110. infrahub/git/tasks.py +52 -2
  111. infrahub/graphql/analyzer.py +9 -0
  112. infrahub/graphql/api/dependencies.py +2 -4
  113. infrahub/graphql/api/endpoints.py +16 -6
  114. infrahub/graphql/app.py +2 -4
  115. infrahub/graphql/initialization.py +2 -3
  116. infrahub/graphql/manager.py +213 -137
  117. infrahub/graphql/middleware.py +12 -0
  118. infrahub/graphql/mutations/branch.py +16 -0
  119. infrahub/graphql/mutations/computed_attribute.py +110 -3
  120. infrahub/graphql/mutations/convert_object_type.py +44 -13
  121. infrahub/graphql/mutations/display_label.py +118 -0
  122. infrahub/graphql/mutations/generator.py +25 -7
  123. infrahub/graphql/mutations/hfid.py +125 -0
  124. infrahub/graphql/mutations/ipam.py +73 -41
  125. infrahub/graphql/mutations/main.py +61 -178
  126. infrahub/graphql/mutations/profile.py +195 -0
  127. infrahub/graphql/mutations/proposed_change.py +8 -1
  128. infrahub/graphql/mutations/relationship.py +2 -2
  129. infrahub/graphql/mutations/repository.py +22 -83
  130. infrahub/graphql/mutations/resource_manager.py +2 -2
  131. infrahub/graphql/mutations/webhook.py +1 -1
  132. infrahub/graphql/queries/resource_manager.py +1 -1
  133. infrahub/graphql/registry.py +173 -0
  134. infrahub/graphql/resolvers/resolver.py +2 -0
  135. infrahub/graphql/schema.py +8 -1
  136. infrahub/graphql/schema_sort.py +170 -0
  137. infrahub/graphql/types/branch.py +4 -1
  138. infrahub/graphql/types/enums.py +3 -0
  139. infrahub/groups/tasks.py +1 -1
  140. infrahub/hfid/__init__.py +0 -0
  141. infrahub/hfid/gather.py +48 -0
  142. infrahub/hfid/models.py +240 -0
  143. infrahub/hfid/tasks.py +191 -0
  144. infrahub/hfid/triggers.py +22 -0
  145. infrahub/lock.py +119 -42
  146. infrahub/locks/__init__.py +0 -0
  147. infrahub/locks/tasks.py +37 -0
  148. infrahub/message_bus/types.py +1 -0
  149. infrahub/patch/plan_writer.py +2 -2
  150. infrahub/permissions/constants.py +2 -0
  151. infrahub/profiles/__init__.py +0 -0
  152. infrahub/profiles/node_applier.py +101 -0
  153. infrahub/profiles/queries/__init__.py +0 -0
  154. infrahub/profiles/queries/get_profile_data.py +98 -0
  155. infrahub/profiles/tasks.py +63 -0
  156. infrahub/proposed_change/tasks.py +67 -14
  157. infrahub/repositories/__init__.py +0 -0
  158. infrahub/repositories/create_repository.py +113 -0
  159. infrahub/server.py +9 -1
  160. infrahub/services/__init__.py +8 -5
  161. infrahub/services/adapters/http/__init__.py +5 -0
  162. infrahub/services/adapters/workflow/worker.py +14 -3
  163. infrahub/task_manager/event.py +5 -0
  164. infrahub/task_manager/models.py +7 -0
  165. infrahub/task_manager/task.py +73 -0
  166. infrahub/tasks/registry.py +6 -4
  167. infrahub/trigger/catalogue.py +4 -0
  168. infrahub/trigger/models.py +2 -0
  169. infrahub/trigger/setup.py +13 -4
  170. infrahub/trigger/tasks.py +6 -0
  171. infrahub/webhook/models.py +1 -1
  172. infrahub/workers/dependencies.py +3 -1
  173. infrahub/workers/infrahub_async.py +10 -2
  174. infrahub/workflows/catalogue.py +118 -3
  175. infrahub/workflows/initialization.py +21 -0
  176. infrahub/workflows/models.py +17 -2
  177. infrahub/workflows/utils.py +2 -1
  178. infrahub_sdk/branch.py +17 -8
  179. infrahub_sdk/checks.py +1 -1
  180. infrahub_sdk/client.py +376 -95
  181. infrahub_sdk/config.py +29 -2
  182. infrahub_sdk/convert_object_type.py +61 -0
  183. infrahub_sdk/ctl/branch.py +3 -0
  184. infrahub_sdk/ctl/check.py +2 -3
  185. infrahub_sdk/ctl/cli_commands.py +20 -12
  186. infrahub_sdk/ctl/config.py +8 -2
  187. infrahub_sdk/ctl/generator.py +6 -3
  188. infrahub_sdk/ctl/graphql.py +184 -0
  189. infrahub_sdk/ctl/repository.py +39 -1
  190. infrahub_sdk/ctl/schema.py +40 -10
  191. infrahub_sdk/ctl/task.py +110 -0
  192. infrahub_sdk/ctl/utils.py +4 -0
  193. infrahub_sdk/ctl/validate.py +5 -3
  194. infrahub_sdk/diff.py +4 -5
  195. infrahub_sdk/exceptions.py +2 -0
  196. infrahub_sdk/generator.py +7 -1
  197. infrahub_sdk/graphql/__init__.py +12 -0
  198. infrahub_sdk/graphql/constants.py +1 -0
  199. infrahub_sdk/graphql/plugin.py +85 -0
  200. infrahub_sdk/graphql/query.py +77 -0
  201. infrahub_sdk/{graphql.py → graphql/renderers.py} +88 -75
  202. infrahub_sdk/graphql/utils.py +40 -0
  203. infrahub_sdk/node/attribute.py +2 -0
  204. infrahub_sdk/node/node.py +28 -20
  205. infrahub_sdk/node/relationship.py +1 -3
  206. infrahub_sdk/playback.py +1 -2
  207. infrahub_sdk/protocols.py +54 -6
  208. infrahub_sdk/pytest_plugin/plugin.py +7 -4
  209. infrahub_sdk/pytest_plugin/utils.py +40 -0
  210. infrahub_sdk/repository.py +1 -2
  211. infrahub_sdk/schema/__init__.py +70 -4
  212. infrahub_sdk/schema/main.py +1 -0
  213. infrahub_sdk/schema/repository.py +8 -0
  214. infrahub_sdk/spec/models.py +7 -0
  215. infrahub_sdk/spec/object.py +54 -6
  216. infrahub_sdk/spec/processors/__init__.py +0 -0
  217. infrahub_sdk/spec/processors/data_processor.py +10 -0
  218. infrahub_sdk/spec/processors/factory.py +34 -0
  219. infrahub_sdk/spec/processors/range_expand_processor.py +56 -0
  220. infrahub_sdk/spec/range_expansion.py +118 -0
  221. infrahub_sdk/task/models.py +6 -4
  222. infrahub_sdk/timestamp.py +18 -6
  223. infrahub_sdk/transforms.py +1 -1
  224. {infrahub_server-1.4.12.dist-info → infrahub_server-1.5.0.dist-info}/METADATA +9 -10
  225. {infrahub_server-1.4.12.dist-info → infrahub_server-1.5.0.dist-info}/RECORD +233 -176
  226. infrahub_testcontainers/container.py +114 -2
  227. infrahub_testcontainers/docker-compose-cluster.test.yml +5 -0
  228. infrahub_testcontainers/docker-compose.test.yml +5 -0
  229. infrahub_testcontainers/models.py +2 -2
  230. infrahub_testcontainers/performance_test.py +4 -4
  231. infrahub/core/convert_object_type/conversion.py +0 -134
  232. {infrahub_server-1.4.12.dist-info → infrahub_server-1.5.0.dist-info}/LICENSE.txt +0 -0
  233. {infrahub_server-1.4.12.dist-info → infrahub_server-1.5.0.dist-info}/WHEEL +0 -0
  234. {infrahub_server-1.4.12.dist-info → infrahub_server-1.5.0.dist-info}/entry_points.txt +0 -0
infrahub/actions/tasks.py CHANGED
@@ -1,17 +1,114 @@
1
1
  from __future__ import annotations
2
2
 
3
- from infrahub_sdk.graphql import Mutation
3
+ from collections import defaultdict
4
+ from typing import TYPE_CHECKING, Any
5
+
6
+ from infrahub_sdk.graphql import Mutation, Query
7
+ from infrahub_sdk.types import Order
4
8
  from prefect import flow
5
9
 
6
10
  from infrahub.context import InfrahubContext # noqa: TC001 needed for prefect flow
11
+ from infrahub.core.constants import InfrahubKind
12
+ from infrahub.generators.models import (
13
+ GeneratorDefinitionModel,
14
+ RequestGeneratorRun,
15
+ )
7
16
  from infrahub.services import InfrahubServices # noqa: TC001 needed for prefect flow
8
17
  from infrahub.trigger.models import TriggerType
9
18
  from infrahub.trigger.setup import setup_triggers_specific
19
+ from infrahub.workers.dependencies import get_client, get_workflow
20
+ from infrahub.workflows.catalogue import REQUEST_GENERATOR_RUN
10
21
  from infrahub.workflows.utils import add_tags
11
22
 
12
23
  from .gather import gather_trigger_action_rules
13
24
  from .models import EventGroupMember # noqa: TC001 needed for prefect flow
14
25
 
26
+ if TYPE_CHECKING:
27
+ from infrahub_sdk.client import InfrahubClient
28
+ from infrahub_sdk.node import InfrahubNode
29
+
30
+
31
+ def get_generator_run_query(definition_id: str, target_ids: list[str]) -> Query:
32
+ return Query(
33
+ name=InfrahubKind.GENERATORDEFINITION,
34
+ query={
35
+ InfrahubKind.GENERATORDEFINITION: {
36
+ "@filters": {
37
+ "ids": [definition_id],
38
+ },
39
+ "edges": {
40
+ "node": {
41
+ "id": None,
42
+ "name": {
43
+ "value": None,
44
+ },
45
+ "class_name": {
46
+ "value": None,
47
+ },
48
+ "file_path": {
49
+ "value": None,
50
+ },
51
+ "query": {
52
+ "node": {
53
+ "name": {
54
+ "value": None,
55
+ },
56
+ },
57
+ },
58
+ "convert_query_response": {
59
+ "value": None,
60
+ },
61
+ "parameters": {
62
+ "value": None,
63
+ },
64
+ "execute_in_proposed_change": {
65
+ "value": None,
66
+ },
67
+ "execute_after_merge": {
68
+ "value": None,
69
+ },
70
+ "targets": {
71
+ "node": {
72
+ "id": None,
73
+ "members": {
74
+ "@filters": {
75
+ "ids": target_ids,
76
+ },
77
+ "edges": {
78
+ "node": {
79
+ "__typename": None,
80
+ "id": None,
81
+ "display_label": None,
82
+ },
83
+ },
84
+ },
85
+ },
86
+ },
87
+ "repository": {
88
+ "node": {
89
+ "__typename": None,
90
+ "id": None,
91
+ "name": {
92
+ "value": None,
93
+ },
94
+ f"... on {InfrahubKind.REPOSITORY}": {
95
+ "commit": {
96
+ "value": None,
97
+ },
98
+ },
99
+ f"... on {InfrahubKind.READONLYREPOSITORY}": {
100
+ "commit": {
101
+ "value": None,
102
+ },
103
+ },
104
+ },
105
+ },
106
+ },
107
+ },
108
+ },
109
+ },
110
+ )
111
+
15
112
 
16
113
  @flow(
17
114
  name="action-add-node-to-group",
@@ -65,12 +162,19 @@ async def run_generator(
65
162
  branch_name: str,
66
163
  node_ids: list[str],
67
164
  generator_definition_id: str,
68
- context: InfrahubContext, # noqa: ARG001
69
- service: InfrahubServices,
165
+ context: InfrahubContext,
166
+ service: InfrahubServices, # noqa: ARG001
70
167
  ) -> None:
71
168
  await add_tags(branches=[branch_name], nodes=node_ids + [generator_definition_id])
72
- await _run_generator(
73
- branch_name=branch_name, generator_definition_id=generator_definition_id, node_ids=node_ids, service=service
169
+
170
+ client = get_client()
171
+
172
+ await _run_generators(
173
+ branch_name=branch_name,
174
+ node_ids=node_ids,
175
+ generator_definition_id=generator_definition_id,
176
+ client=client,
177
+ context=context,
74
178
  )
75
179
 
76
180
 
@@ -82,13 +186,20 @@ async def run_generator_group_event(
82
186
  branch_name: str,
83
187
  members: list[EventGroupMember],
84
188
  generator_definition_id: str,
85
- context: InfrahubContext, # noqa: ARG001
86
- service: InfrahubServices,
189
+ context: InfrahubContext,
190
+ service: InfrahubServices, # noqa: ARG001
87
191
  ) -> None:
88
192
  node_ids = [node.id for node in members]
89
193
  await add_tags(branches=[branch_name], nodes=node_ids + [generator_definition_id])
90
- await _run_generator(
91
- branch_name=branch_name, generator_definition_id=generator_definition_id, node_ids=node_ids, service=service
194
+
195
+ client = get_client()
196
+
197
+ await _run_generators(
198
+ branch_name=branch_name,
199
+ node_ids=node_ids,
200
+ generator_definition_id=generator_definition_id,
201
+ client=client,
202
+ context=context,
92
203
  )
93
204
 
94
205
 
@@ -104,16 +215,97 @@ async def configure_action_rules(
104
215
  ) # type: ignore[misc]
105
216
 
106
217
 
107
- async def _run_generator(
218
+ async def _get_targets(
219
+ branch_name: str,
220
+ targets: list[dict[str, Any]],
221
+ client: InfrahubClient,
222
+ ) -> dict[str, dict[str, InfrahubNode]]:
223
+ """Get the targets per kind in order to extract the variables."""
224
+
225
+ targets_per_kind: dict[str, dict[str, InfrahubNode]] = defaultdict(dict)
226
+
227
+ for target in targets:
228
+ targets_per_kind[target["node"]["__typename"]][target["node"]["id"]] = None
229
+
230
+ for kind, values in targets_per_kind.items():
231
+ nodes = await client.filters(
232
+ kind=kind, branch=branch_name, ids=list(values.keys()), populate_store=False, order=Order(disable=True)
233
+ )
234
+ for node in nodes:
235
+ targets_per_kind[kind][node.id] = node
236
+
237
+ return targets_per_kind
238
+
239
+
240
+ async def _run_generators(
108
241
  branch_name: str,
109
242
  node_ids: list[str],
110
243
  generator_definition_id: str,
111
- service: InfrahubServices,
244
+ client: InfrahubClient,
245
+ context: InfrahubContext | None = None,
112
246
  ) -> None:
113
- mutation = Mutation(
114
- mutation="CoreGeneratorDefinitionRun",
115
- input_data={"data": {"id": generator_definition_id, "nodes": node_ids}},
116
- query={"ok": None},
247
+ """Fetch generator metadata and submit per-target runs.
248
+
249
+ Args:
250
+ branch_name: Branch on which to execute.
251
+ node_ids: Node IDs to run against (restricts selection if provided).
252
+ generator_definition_id: Generator definition to execute.
253
+ client: InfrahubClient to query additional data.
254
+ context: Execution context passed to downstream workflow submissions.
255
+
256
+ Returns:
257
+ None
258
+
259
+ Raises:
260
+ ValueError: If the generator definition is not found or none of the requested
261
+ targets are members of the target group.
262
+ """
263
+ response = await client.execute_graphql(
264
+ query=get_generator_run_query(definition_id=generator_definition_id, target_ids=node_ids).render(),
265
+ branch_name=branch_name,
117
266
  )
267
+ if not response[InfrahubKind.GENERATORDEFINITION]["edges"]:
268
+ raise ValueError(f"Generator definition {generator_definition_id} not found")
118
269
 
119
- await service.client.execute_graphql(query=mutation.render(), branch_name=branch_name)
270
+ data = response[InfrahubKind.GENERATORDEFINITION]["edges"][0]["node"]
271
+
272
+ if not data["targets"]["node"]["members"]["edges"]:
273
+ raise ValueError(f"Target {node_ids[0]} is not part of the group {data['targets']['node']['id']}")
274
+
275
+ targets = data["targets"]["node"]["members"]["edges"]
276
+
277
+ targets_per_kind = await _get_targets(branch_name=branch_name, targets=targets, client=client)
278
+
279
+ workflow = get_workflow()
280
+
281
+ for target in targets:
282
+ node: InfrahubNode | None = None
283
+ if data["parameters"]["value"]:
284
+ node = targets_per_kind[target["node"]["__typename"]][target["node"]["id"]]
285
+
286
+ request_generator_run_model = RequestGeneratorRun(
287
+ generator_definition=GeneratorDefinitionModel(
288
+ definition_id=generator_definition_id,
289
+ definition_name=data["name"]["value"],
290
+ class_name=data["class_name"]["value"],
291
+ file_path=data["file_path"]["value"],
292
+ query_name=data["query"]["node"]["name"]["value"],
293
+ convert_query_response=data["convert_query_response"]["value"],
294
+ group_id=data["targets"]["node"]["id"],
295
+ parameters=data["parameters"]["value"],
296
+ execute_in_proposed_change=data["execute_in_proposed_change"]["value"],
297
+ execute_after_merge=data["execute_after_merge"]["value"],
298
+ ),
299
+ commit=data["repository"]["node"]["commit"]["value"],
300
+ repository_id=data["repository"]["node"]["id"],
301
+ repository_name=data["repository"]["node"]["name"]["value"],
302
+ repository_kind=data["repository"]["node"]["__typename"],
303
+ branch_name=branch_name,
304
+ query=data["query"]["node"]["name"]["value"],
305
+ variables=await node.extract(params=data["parameters"]["value"]) if node else {},
306
+ target_id=target["node"]["id"],
307
+ target_name=target["node"]["display_label"],
308
+ )
309
+ await workflow.submit_workflow(
310
+ workflow=REQUEST_GENERATOR_RUN, context=context, parameters={"model": request_generator_run_model}
311
+ )
infrahub/api/artifact.py CHANGED
@@ -15,6 +15,7 @@ from infrahub.api.dependencies import (
15
15
  )
16
16
  from infrahub.core import registry
17
17
  from infrahub.core.account import ObjectPermission
18
+ from infrahub.core.branch.needs_rebase_status import check_need_rebase_status
18
19
  from infrahub.core.constants import GLOBAL_BRANCH_NAME, InfrahubKind, PermissionAction
19
20
  from infrahub.core.protocols import CoreArtifactDefinition
20
21
  from infrahub.database import InfrahubDatabase # noqa: TC001
@@ -74,6 +75,8 @@ async def generate_artifact(
74
75
  permission_manager: PermissionManager = Depends(get_permission_manager),
75
76
  context: InfrahubContext = Depends(get_context),
76
77
  ) -> None:
78
+ check_need_rebase_status(branch_params.branch)
79
+
77
80
  permission_decision = (
78
81
  PermissionDecisionFlag.ALLOW_DEFAULT
79
82
  if branch_params.branch.name in (GLOBAL_BRANCH_NAME, registry.default_branch)
infrahub/api/diff/diff.py CHANGED
@@ -52,7 +52,7 @@ async def get_diff_files(
52
52
  for branch_name, items in diff_files.items():
53
53
  for item in items:
54
54
  repository_id = item.repository.get_id()
55
- display_label = await item.repository.render_display_label(db=db)
55
+ display_label = await item.repository.get_display_label(db=db)
56
56
  if repository_id not in response[branch_name]:
57
57
  response[branch_name][repository_id] = BranchDiffRepository(
58
58
  id=repository_id,
infrahub/api/internal.py CHANGED
@@ -161,6 +161,8 @@ class SearchResultAPI(BaseModel):
161
161
  async def search_docs(
162
162
  query: str, limit: int | None = None, _: AccountSession = Depends(get_current_user)
163
163
  ) -> list[SearchResultAPI]:
164
+ if not query:
165
+ return []
164
166
  smart_query = smart_queries(query)
165
167
  search_results = search_docs_loader.heading_index.search(smart_query)
166
168
  heading_results = [
infrahub/api/query.py CHANGED
@@ -24,6 +24,7 @@ from infrahub.graphql.metrics import (
24
24
  GRAPHQL_RESPONSE_SIZE_METRICS,
25
25
  GRAPHQL_TOP_LEVEL_QUERIES_METRICS,
26
26
  )
27
+ from infrahub.graphql.middleware import raise_on_mutation_on_branch_needing_rebase
27
28
  from infrahub.graphql.utils import extract_data
28
29
  from infrahub.groups.models import RequestGraphQLQueryGroupUpdate
29
30
  from infrahub.log import get_logger
@@ -98,6 +99,7 @@ async def execute_query(
98
99
  context_value=gql_params.context,
99
100
  root_value=None,
100
101
  variable_values=params,
102
+ middleware=[raise_on_mutation_on_branch_needing_rebase],
101
103
  )
102
104
 
103
105
  data = extract_data(query_name=gql_query.name.value, result=result)
infrahub/api/schema.py CHANGED
@@ -18,6 +18,7 @@ from infrahub.api.exceptions import SchemaNotValidError
18
18
  from infrahub.core import registry
19
19
  from infrahub.core.account import GlobalPermission
20
20
  from infrahub.core.branch import Branch # noqa: TC001
21
+ from infrahub.core.branch.needs_rebase_status import check_need_rebase_status
21
22
  from infrahub.core.constants import GLOBAL_BRANCH_NAME, GlobalPermissions, PermissionDecision
22
23
  from infrahub.core.migrations.schema.models import SchemaApplyMigrationData
23
24
  from infrahub.core.models import ( # noqa: TC001
@@ -25,7 +26,15 @@ from infrahub.core.models import ( # noqa: TC001
25
26
  SchemaDiff,
26
27
  SchemaUpdateValidationResult,
27
28
  )
28
- from infrahub.core.schema import GenericSchema, MainSchemaTypes, NodeSchema, ProfileSchema, SchemaRoot, TemplateSchema
29
+ from infrahub.core.schema import (
30
+ GenericSchema,
31
+ MainSchemaTypes,
32
+ NodeSchema,
33
+ ProfileSchema,
34
+ SchemaRoot,
35
+ SchemaWarning,
36
+ TemplateSchema,
37
+ )
29
38
  from infrahub.core.schema.constants import SchemaNamespace # noqa: TC001
30
39
  from infrahub.core.validators.models.validate_migration import (
31
40
  SchemaValidateMigrationData,
@@ -129,6 +138,9 @@ class SchemaUpdate(BaseModel):
129
138
  hash: str = Field(..., description="The new hash for the entire schema")
130
139
  previous_hash: str = Field(..., description="The previous hash for the entire schema")
131
140
  diff: SchemaDiff = Field(..., description="The modifications to the schema")
141
+ warnings: list[SchemaWarning] = Field(
142
+ default_factory=list, description="Warnings encountered while loading the schema"
143
+ )
132
144
 
133
145
  @computed_field
134
146
  def schema_updated(self) -> bool:
@@ -287,6 +299,8 @@ async def load_schema(
287
299
  permission_manager: PermissionManager = Depends(get_permission_manager),
288
300
  context: InfrahubContext = Depends(get_context),
289
301
  ) -> SchemaUpdate:
302
+ check_need_rebase_status(branch)
303
+
290
304
  permission_manager.raise_for_permission(
291
305
  permission=define_global_permission_from_branch(
292
306
  permission=GlobalPermissions.MANAGE_SCHEMA, branch_name=branch.name
@@ -304,8 +318,10 @@ async def load_schema(
304
318
  log.info("schema_load_request", branch=branch.name)
305
319
 
306
320
  errors: list[str] = []
321
+ warnings: list[SchemaWarning] = []
307
322
  for schema in schemas.schemas:
308
323
  errors += schema.validate_namespaces()
324
+ warnings += schema.gather_warnings()
309
325
 
310
326
  if errors:
311
327
  raise SchemaNotValidError(message=", ".join(errors))
@@ -399,7 +415,7 @@ async def load_schema(
399
415
  )
400
416
  await service.event.send(event=event)
401
417
 
402
- return SchemaUpdate(hash=updated_hash, previous_hash=original_hash, diff=result.diff)
418
+ return SchemaUpdate(hash=updated_hash, previous_hash=original_hash, diff=result.diff, warnings=warnings)
403
419
 
404
420
 
405
421
  @router.post("/check")
@@ -414,8 +430,10 @@ async def check_schema(
414
430
  log.info("schema_check_request", branch=branch.name)
415
431
 
416
432
  errors: list[str] = []
433
+ warnings: list[SchemaWarning] = []
417
434
  for schema in schemas.schemas:
418
435
  errors += schema.validate_namespaces()
436
+ warnings += schema.gather_warnings()
419
437
 
420
438
  if errors:
421
439
  raise SchemaNotValidError(message=", ".join(errors))
@@ -442,4 +460,10 @@ async def check_schema(
442
460
  if error_messages:
443
461
  raise SchemaNotValidError(message=",\n".join(error_messages))
444
462
 
445
- return JSONResponse(status_code=202, content={"diff": result.diff.model_dump()})
463
+ return JSONResponse(
464
+ status_code=202,
465
+ content={
466
+ "diff": result.diff.model_dump(),
467
+ "warnings": [warning.model_dump(mode="json") for warning in warnings],
468
+ },
469
+ )
infrahub/auth.py CHANGED
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import uuid
4
- from datetime import datetime, timedelta, timezone
4
+ from datetime import UTC, datetime, timedelta
5
5
  from enum import Enum
6
6
  from typing import TYPE_CHECKING, Any
7
7
 
@@ -88,7 +88,7 @@ async def authenticate_with_password(
88
88
  if not valid_credentials:
89
89
  raise AuthorizationError("Incorrect password")
90
90
 
91
- now = datetime.now(tz=timezone.utc)
91
+ now = datetime.now(tz=UTC)
92
92
  refresh_expires = now + timedelta(seconds=config.SETTINGS.security.refresh_token_lifetime)
93
93
 
94
94
  session_id = await create_db_refresh_token(db=db, account_id=account.id, expiration=refresh_expires)
@@ -149,7 +149,7 @@ async def signin_sso_account(db: InfrahubDatabase, account_name: str, sso_groups
149
149
  await group.members.add(db=db, data=account)
150
150
  await group.members.save(db=db)
151
151
 
152
- now = datetime.now(tz=timezone.utc)
152
+ now = datetime.now(tz=UTC)
153
153
  refresh_expires = now + timedelta(seconds=config.SETTINGS.security.refresh_token_lifetime)
154
154
  session_id = await create_db_refresh_token(db=db, account_id=account.id, expiration=refresh_expires)
155
155
  access_token = generate_access_token(account_id=account.id, session_id=session_id)
@@ -158,7 +158,7 @@ async def signin_sso_account(db: InfrahubDatabase, account_name: str, sso_groups
158
158
 
159
159
 
160
160
  def generate_access_token(account_id: str, session_id: uuid.UUID) -> str:
161
- now = datetime.now(tz=timezone.utc)
161
+ now = datetime.now(tz=UTC)
162
162
 
163
163
  access_expires = now + timedelta(seconds=config.SETTINGS.security.access_token_lifetime)
164
164
  access_data = {
@@ -175,7 +175,7 @@ def generate_access_token(account_id: str, session_id: uuid.UUID) -> str:
175
175
 
176
176
 
177
177
  def generate_refresh_token(account_id: str, session_id: uuid.UUID, expiration: datetime) -> str:
178
- now = datetime.now(tz=timezone.utc)
178
+ now = datetime.now(tz=UTC)
179
179
 
180
180
  refresh_data = {
181
181
  "sub": account_id,
infrahub/cli/__init__.py CHANGED
@@ -7,6 +7,7 @@ from infrahub.core.initialization import initialization
7
7
  from ..workers.dependencies import get_database
8
8
  from .context import CliContext
9
9
  from .db import app as db_app
10
+ from .dev import app as dev_app
10
11
  from .events import app as events_app
11
12
  from .git_agent import app as git_app
12
13
  from .server import app as server_app
@@ -27,6 +28,7 @@ app.add_typer(git_app, name="git-agent", hidden=True)
27
28
  app.add_typer(db_app, name="db")
28
29
  app.add_typer(events_app, name="events", help="Interact with the events system.", hidden=True)
29
30
  app.add_typer(tasks_app, name="tasks", hidden=True)
31
+ app.add_typer(dev_app, name="dev", help="Internal development commands.")
30
32
  app.command(name="upgrade")(upgrade_cmd)
31
33
 
32
34