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.
- infrahub/api/artifact.py +16 -4
- infrahub/api/dependencies.py +8 -0
- infrahub/api/oauth2.py +0 -1
- infrahub/api/oidc.py +0 -1
- infrahub/api/query.py +18 -7
- infrahub/api/schema.py +32 -6
- infrahub/api/transformation.py +12 -5
- infrahub/{message_bus/messages/check_artifact_create.py → artifacts/models.py} +2 -4
- infrahub/{message_bus/operations/check/artifact.py → artifacts/tasks.py} +26 -25
- infrahub/cli/__init__.py +0 -2
- infrahub/cli/db.py +6 -7
- infrahub/cli/events.py +8 -3
- infrahub/cli/git_agent.py +9 -7
- infrahub/cli/tasks.py +4 -6
- infrahub/computed_attribute/tasks.py +63 -17
- infrahub/computed_attribute/triggers.py +90 -0
- infrahub/config.py +1 -1
- infrahub/context.py +39 -0
- infrahub/core/account.py +5 -8
- infrahub/core/attribute.py +53 -21
- infrahub/core/branch/models.py +4 -4
- infrahub/core/branch/tasks.py +89 -130
- infrahub/core/changelog/__init__.py +0 -0
- infrahub/core/changelog/diff.py +232 -0
- infrahub/core/changelog/models.py +488 -0
- infrahub/core/constants/__init__.py +19 -2
- infrahub/core/constants/infrahubkind.py +1 -0
- infrahub/core/diff/combiner.py +12 -8
- infrahub/core/diff/coordinator.py +49 -70
- infrahub/core/diff/data_check_synchronizer.py +86 -7
- infrahub/core/diff/enricher/aggregated.py +3 -3
- infrahub/core/diff/enricher/cardinality_one.py +2 -7
- infrahub/core/diff/enricher/hierarchy.py +5 -3
- infrahub/core/diff/enricher/labels.py +14 -4
- infrahub/core/diff/enricher/path_identifier.py +3 -9
- infrahub/core/diff/enricher/summary_counts.py +3 -1
- infrahub/core/diff/merger/merger.py +8 -4
- infrahub/core/diff/model/path.py +47 -29
- infrahub/core/diff/query/all_conflicts.py +6 -3
- infrahub/core/diff/query/artifact.py +1 -1
- infrahub/core/diff/query/delete_query.py +1 -1
- infrahub/core/diff/query/diff_get.py +3 -2
- infrahub/core/diff/query/diff_summary.py +1 -1
- infrahub/core/diff/query/field_specifiers.py +3 -1
- infrahub/core/diff/query/field_summary.py +3 -2
- infrahub/core/diff/query/filters.py +12 -1
- infrahub/core/diff/query/get_conflict_query.py +1 -1
- infrahub/core/diff/query/has_conflicts_query.py +6 -3
- infrahub/core/diff/query/merge.py +3 -3
- infrahub/core/diff/query/{drop_tracking_id.py → merge_tracking_id.py} +4 -4
- infrahub/core/diff/query/roots_metadata.py +9 -2
- infrahub/core/diff/query/save.py +151 -66
- infrahub/core/diff/query/summary_counts_enricher.py +220 -0
- infrahub/core/diff/query/time_range_query.py +3 -2
- infrahub/core/diff/query/update_conflict_query.py +1 -1
- infrahub/core/diff/query_parser.py +49 -24
- infrahub/core/diff/repository/deserializer.py +24 -25
- infrahub/core/diff/repository/repository.py +76 -20
- infrahub/core/diff/tasks.py +9 -8
- infrahub/core/enums.py +1 -1
- infrahub/core/integrity/object_conflict/conflict_recorder.py +1 -1
- infrahub/core/ipam/reconciler.py +1 -1
- infrahub/core/ipam/tasks.py +2 -3
- infrahub/core/manager.py +18 -13
- infrahub/core/merge.py +5 -2
- infrahub/core/migrations/graph/m001_add_version_to_graph.py +1 -1
- infrahub/core/migrations/graph/m002_attribute_is_default.py +2 -2
- infrahub/core/migrations/graph/m003_relationship_parent_optional.py +2 -2
- infrahub/core/migrations/graph/m004_add_attr_documentation.py +1 -1
- infrahub/core/migrations/graph/m005_add_rel_read_only.py +1 -1
- infrahub/core/migrations/graph/m006_add_rel_on_delete.py +1 -1
- infrahub/core/migrations/graph/m007_add_rel_allow_override.py +1 -1
- infrahub/core/migrations/graph/m008_add_human_friendly_id.py +1 -1
- infrahub/core/migrations/graph/m009_add_generate_profile_attr.py +1 -1
- infrahub/core/migrations/graph/m010_add_generate_profile_attr_generic.py +1 -1
- infrahub/core/migrations/graph/m011_remove_profile_relationship_schema.py +2 -2
- infrahub/core/migrations/graph/m012_convert_account_generic.py +12 -23
- infrahub/core/migrations/graph/m013_convert_git_password_credential.py +7 -11
- infrahub/core/migrations/graph/m014_remove_index_attr_value.py +2 -2
- infrahub/core/migrations/graph/m015_diff_format_update.py +1 -1
- infrahub/core/migrations/graph/m016_diff_delete_bug_fix.py +1 -1
- infrahub/core/migrations/graph/m017_add_core_profile.py +1 -1
- infrahub/core/migrations/graph/m018_uniqueness_nulls.py +2 -2
- infrahub/core/migrations/query/attribute_add.py +1 -1
- infrahub/core/migrations/query/attribute_rename.py +1 -1
- infrahub/core/migrations/query/delete_element_in_schema.py +1 -1
- infrahub/core/migrations/query/node_duplicate.py +1 -1
- infrahub/core/migrations/query/relationship_duplicate.py +1 -1
- infrahub/core/migrations/query/schema_attribute_update.py +1 -1
- infrahub/core/migrations/schema/node_attribute_remove.py +1 -1
- infrahub/core/migrations/schema/node_remove.py +1 -1
- infrahub/core/migrations/schema/tasks.py +5 -5
- infrahub/core/migrations/shared.py +4 -4
- infrahub/core/models.py +7 -8
- infrahub/core/node/__init__.py +161 -40
- infrahub/core/node/base.py +1 -1
- infrahub/core/node/constraints/grouped_uniqueness.py +9 -2
- infrahub/core/node/delete_validator.py +4 -4
- infrahub/core/node/ipam.py +13 -8
- infrahub/core/node/permissions.py +4 -0
- infrahub/core/node/resource_manager/ip_prefix_pool.py +8 -5
- infrahub/core/node/standard.py +3 -5
- infrahub/core/property.py +1 -1
- infrahub/core/protocols.py +4 -0
- infrahub/core/protocols_base.py +4 -2
- infrahub/core/query/__init__.py +2 -5
- infrahub/core/query/attribute.py +9 -9
- infrahub/core/query/branch.py +5 -5
- infrahub/core/query/delete.py +1 -1
- infrahub/core/query/diff.py +45 -7
- infrahub/core/query/ipam.py +4 -4
- infrahub/core/query/node.py +19 -14
- infrahub/core/query/relationship.py +10 -11
- infrahub/core/query/resource_manager.py +13 -11
- infrahub/core/query/standard_node.py +6 -6
- infrahub/core/query/task.py +3 -3
- infrahub/core/query/task_log.py +1 -1
- infrahub/core/query/utils.py +5 -5
- infrahub/core/registry.py +0 -2
- infrahub/core/relationship/constraints/count.py +1 -1
- infrahub/core/relationship/constraints/peer_kind.py +1 -1
- infrahub/core/relationship/model.py +66 -26
- infrahub/core/schema/__init__.py +6 -4
- infrahub/core/schema/basenode_schema.py +1 -3
- infrahub/core/schema/definitions/core.py +14 -2
- infrahub/core/schema/definitions/internal.py +16 -0
- infrahub/core/schema/generated/genericnode_schema.py +5 -0
- infrahub/core/schema/generated/node_schema.py +5 -0
- infrahub/core/schema/generic_schema.py +5 -1
- infrahub/core/schema/manager.py +45 -42
- infrahub/core/schema/node_schema.py +4 -0
- infrahub/core/schema/profile_schema.py +4 -0
- infrahub/core/schema/relationship_schema.py +2 -2
- infrahub/core/schema/schema_branch.py +248 -14
- infrahub/core/schema/template_schema.py +36 -0
- infrahub/core/task/user_task.py +7 -5
- infrahub/core/timestamp.py +1 -1
- infrahub/core/utils.py +3 -2
- infrahub/core/validators/attribute/choices.py +1 -1
- infrahub/core/validators/attribute/enum.py +1 -1
- infrahub/core/validators/attribute/kind.py +1 -1
- infrahub/core/validators/attribute/length.py +1 -1
- infrahub/core/validators/attribute/optional.py +1 -1
- infrahub/core/validators/attribute/regex.py +1 -1
- infrahub/core/validators/attribute/unique.py +1 -1
- infrahub/core/validators/checks_runner.py +37 -0
- infrahub/core/validators/node/generate_profile.py +1 -1
- infrahub/core/validators/node/hierarchy.py +1 -1
- infrahub/core/validators/query.py +1 -1
- infrahub/core/validators/relationship/count.py +1 -1
- infrahub/core/validators/relationship/optional.py +1 -1
- infrahub/core/validators/relationship/peer.py +1 -1
- infrahub/core/validators/tasks.py +8 -6
- infrahub/core/validators/uniqueness/query.py +20 -17
- infrahub/database/__init__.py +15 -2
- infrahub/database/memgraph.py +1 -1
- infrahub/dependencies/builder/constraint/grouped/node_runner.py +0 -2
- infrahub/dependencies/builder/diff/combiner.py +1 -1
- infrahub/dependencies/builder/diff/conflicts_enricher.py +1 -1
- infrahub/dependencies/builder/diff/coordinator.py +0 -2
- infrahub/dependencies/builder/diff/deserializer.py +1 -1
- infrahub/dependencies/builder/diff/enricher/summary_counts.py +1 -1
- infrahub/events/branch_action.py +47 -21
- infrahub/events/group_action.py +73 -0
- infrahub/events/models.py +159 -51
- infrahub/events/node_action.py +74 -8
- infrahub/events/repository_action.py +8 -8
- infrahub/events/schema_action.py +21 -8
- infrahub/generators/tasks.py +12 -13
- infrahub/git/base.py +3 -5
- infrahub/git/constants.py +0 -1
- infrahub/git/integrator.py +36 -35
- infrahub/git/repository.py +7 -8
- infrahub/git/tasks.py +43 -107
- infrahub/git_credential/helper.py +2 -3
- infrahub/graphql/analyzer.py +572 -11
- infrahub/graphql/app.py +34 -26
- infrahub/graphql/auth/query_permission_checker/anonymous_checker.py +5 -5
- infrahub/graphql/auth/query_permission_checker/default_branch_checker.py +4 -4
- infrahub/graphql/auth/query_permission_checker/merge_operation_checker.py +4 -4
- infrahub/graphql/auth/query_permission_checker/object_permission_checker.py +28 -35
- infrahub/graphql/auth/query_permission_checker/super_admin_checker.py +5 -5
- infrahub/graphql/enums.py +1 -1
- infrahub/graphql/initialization.py +5 -1
- infrahub/graphql/loaders/node.py +2 -2
- infrahub/graphql/manager.py +59 -54
- infrahub/graphql/mutations/account.py +20 -13
- infrahub/graphql/mutations/artifact_definition.py +16 -12
- infrahub/graphql/mutations/branch.py +61 -40
- infrahub/graphql/mutations/computed_attribute.py +19 -13
- infrahub/graphql/mutations/diff.py +37 -9
- infrahub/graphql/mutations/diff_conflict.py +9 -8
- infrahub/graphql/mutations/graphql_query.py +19 -11
- infrahub/graphql/mutations/ipam.py +21 -19
- infrahub/graphql/mutations/main.py +197 -44
- infrahub/graphql/mutations/menu.py +8 -8
- infrahub/graphql/mutations/proposed_change.py +36 -28
- infrahub/graphql/mutations/relationship.py +302 -105
- infrahub/graphql/mutations/repository.py +41 -35
- infrahub/graphql/mutations/resource_manager.py +26 -26
- infrahub/graphql/mutations/schema.py +51 -33
- infrahub/graphql/mutations/tasks.py +16 -10
- infrahub/graphql/parser.py +1 -1
- infrahub/graphql/permissions.py +6 -4
- infrahub/graphql/queries/account.py +22 -18
- infrahub/graphql/queries/branch.py +6 -4
- infrahub/graphql/queries/diff/tree.py +48 -42
- infrahub/graphql/queries/event.py +112 -0
- infrahub/graphql/queries/internal.py +3 -3
- infrahub/graphql/queries/ipam.py +23 -18
- infrahub/graphql/queries/relationship.py +11 -10
- infrahub/graphql/queries/resource_manager.py +43 -27
- infrahub/graphql/queries/search.py +9 -8
- infrahub/graphql/queries/status.py +12 -9
- infrahub/graphql/queries/task.py +11 -9
- infrahub/graphql/resolvers/resolver.py +69 -43
- infrahub/graphql/resolvers/single_relationship.py +16 -10
- infrahub/graphql/schema.py +2 -0
- infrahub/graphql/subscription/__init__.py +1 -1
- infrahub/graphql/subscription/events.py +1 -1
- infrahub/graphql/subscription/graphql_query.py +8 -8
- infrahub/graphql/types/branch.py +2 -2
- infrahub/graphql/types/common.py +6 -1
- infrahub/graphql/types/enums.py +2 -0
- infrahub/graphql/types/event.py +100 -0
- infrahub/graphql/types/interface.py +2 -2
- infrahub/graphql/types/node.py +3 -3
- infrahub/graphql/types/permission.py +2 -2
- infrahub/graphql/types/relationship.py +3 -3
- infrahub/graphql/types/standard_node.py +9 -11
- infrahub/graphql/utils.py +28 -182
- infrahub/groups/tasks.py +2 -3
- infrahub/lock.py +1 -1
- infrahub/menu/constants.py +1 -0
- infrahub/menu/generator.py +14 -3
- infrahub/menu/menu.py +116 -127
- infrahub/menu/models.py +4 -4
- infrahub/message_bus/messages/__init__.py +0 -4
- infrahub/message_bus/messages/event_branch_merge.py +3 -0
- infrahub/message_bus/messages/request_proposedchange_pipeline.py +2 -0
- infrahub/message_bus/operations/__init__.py +3 -5
- infrahub/message_bus/operations/check/__init__.py +2 -2
- infrahub/message_bus/operations/check/generator.py +1 -3
- infrahub/message_bus/operations/check/repository.py +1 -1
- infrahub/message_bus/operations/event/branch.py +7 -3
- infrahub/message_bus/operations/event/schema.py +1 -1
- infrahub/message_bus/operations/finalize/validator.py +1 -1
- infrahub/message_bus/operations/git/file.py +2 -2
- infrahub/message_bus/operations/git/repository.py +1 -1
- infrahub/message_bus/operations/requests/__init__.py +0 -2
- infrahub/message_bus/operations/requests/generator_definition.py +1 -1
- infrahub/message_bus/operations/requests/proposed_change.py +26 -11
- infrahub/message_bus/operations/requests/repository.py +2 -2
- infrahub/message_bus/operations/send/echo.py +1 -1
- infrahub/message_bus/types.py +1 -1
- infrahub/permissions/__init__.py +2 -1
- infrahub/permissions/types.py +26 -0
- infrahub/pools/prefix.py +29 -165
- infrahub/prefect_server/__init__.py +0 -0
- infrahub/prefect_server/app.py +18 -0
- infrahub/prefect_server/database.py +20 -0
- infrahub/prefect_server/events.py +28 -0
- infrahub/prefect_server/models.py +46 -0
- infrahub/proposed_change/models.py +15 -1
- infrahub/proposed_change/tasks.py +173 -35
- infrahub/pytest_plugin.py +4 -4
- infrahub/server.py +12 -11
- infrahub/services/__init__.py +147 -62
- infrahub/services/adapters/cache/__init__.py +7 -5
- infrahub/services/adapters/cache/nats.py +40 -22
- infrahub/services/adapters/cache/redis.py +0 -4
- infrahub/services/adapters/event/__init__.py +10 -18
- infrahub/services/adapters/http/__init__.py +0 -5
- infrahub/services/adapters/http/httpx.py +22 -15
- infrahub/services/adapters/message_bus/__init__.py +23 -6
- infrahub/services/adapters/message_bus/local.py +8 -6
- infrahub/services/adapters/message_bus/nats.py +12 -6
- infrahub/services/adapters/message_bus/rabbitmq.py +22 -9
- infrahub/services/adapters/workflow/__init__.py +11 -8
- infrahub/services/adapters/workflow/local.py +28 -7
- infrahub/services/adapters/workflow/worker.py +23 -7
- infrahub/services/component.py +38 -35
- infrahub/services/scheduler.py +32 -29
- infrahub/storage.py +2 -4
- infrahub/task_manager/constants.py +1 -1
- infrahub/task_manager/event.py +182 -0
- infrahub/task_manager/models.py +125 -1
- infrahub/task_manager/task.py +1 -1
- infrahub/tasks/artifact.py +14 -16
- infrahub/tasks/registry.py +1 -1
- infrahub/tasks/telemetry.py +13 -14
- infrahub/transformations/tasks.py +3 -5
- infrahub/trigger/__init__.py +0 -0
- infrahub/trigger/catalogue.py +15 -0
- infrahub/trigger/constants.py +9 -0
- infrahub/trigger/models.py +69 -0
- infrahub/trigger/tasks.py +85 -0
- infrahub/types.py +1 -1
- infrahub/utils.py +1 -1
- infrahub/webhook/constants.py +0 -2
- infrahub/webhook/models.py +8 -2
- infrahub/webhook/tasks.py +20 -73
- infrahub/webhook/triggers.py +20 -0
- infrahub/workers/infrahub_async.py +36 -25
- infrahub/workers/utils.py +63 -0
- infrahub/workflows/catalogue.py +13 -37
- infrahub/workflows/initialization.py +6 -8
- infrahub/workflows/models.py +3 -5
- infrahub/workflows/utils.py +1 -1
- infrahub_sdk/ctl/check.py +3 -3
- infrahub_sdk/ctl/cli_commands.py +11 -10
- infrahub_sdk/ctl/exceptions.py +0 -6
- infrahub_sdk/ctl/exporter.py +1 -1
- infrahub_sdk/ctl/generator.py +5 -5
- infrahub_sdk/ctl/importer.py +3 -2
- infrahub_sdk/ctl/menu.py +1 -1
- infrahub_sdk/ctl/object.py +1 -1
- infrahub_sdk/ctl/repository.py +23 -15
- infrahub_sdk/ctl/schema.py +2 -2
- infrahub_sdk/ctl/utils.py +4 -3
- infrahub_sdk/ctl/validate.py +2 -1
- infrahub_sdk/exceptions.py +6 -0
- infrahub_sdk/generator.py +3 -0
- infrahub_sdk/node.py +2 -2
- infrahub_sdk/schema/__init__.py +14 -2
- infrahub_sdk/schema/main.py +7 -0
- infrahub_sdk/utils.py +11 -1
- infrahub_sdk/yaml.py +2 -3
- {infrahub_server-1.1.6.dist-info → infrahub_server-1.2.0rc0.dist-info}/METADATA +46 -12
- {infrahub_server-1.1.6.dist-info → infrahub_server-1.2.0rc0.dist-info}/RECORD +338 -321
- infrahub_testcontainers/container.py +14 -6
- infrahub_testcontainers/docker-compose.test.yml +24 -5
- infrahub_testcontainers/haproxy.cfg +43 -0
- infrahub_testcontainers/helpers.py +85 -1
- infrahub/core/branch/constants.py +0 -2
- infrahub/graphql/query.py +0 -52
- infrahub/message_bus/messages/request_artifactdefinition_check.py +0 -17
- infrahub/message_bus/operations/requests/artifact_definition.py +0 -148
- infrahub/schema/constants.py +0 -1
- infrahub/schema/tasks.py +0 -76
- infrahub/services/adapters/database/__init__.py +0 -9
- infrahub_sdk/ctl/_file.py +0 -13
- /infrahub/{schema → artifacts}/__init__.py +0 -0
- {infrahub_server-1.1.6.dist-info → infrahub_server-1.2.0rc0.dist-info}/LICENSE.txt +0 -0
- {infrahub_server-1.1.6.dist-info → infrahub_server-1.2.0rc0.dist-info}/WHEEL +0 -0
- {infrahub_server-1.1.6.dist-info → infrahub_server-1.2.0rc0.dist-info}/entry_points.txt +0 -0
infrahub/graphql/app.py
CHANGED
|
@@ -76,8 +76,6 @@ if TYPE_CHECKING:
|
|
|
76
76
|
|
|
77
77
|
from .auth.query_permission_checker.checker import GraphQLQueryPermissionChecker
|
|
78
78
|
|
|
79
|
-
# pylint: disable=unused-argument,raise-missing-from
|
|
80
|
-
|
|
81
79
|
|
|
82
80
|
GQL_CONNECTION_ACK = "connection_ack"
|
|
83
81
|
GQL_CONNECTION_ERROR = "connection_error"
|
|
@@ -208,13 +206,32 @@ class InfrahubGraphQLApp:
|
|
|
208
206
|
graphql_params = await prepare_graphql_params(
|
|
209
207
|
db=db, branch=branch, at=at, account_session=account_session, request=request
|
|
210
208
|
)
|
|
209
|
+
schema_branch = db.schema.get_schema_branch(name=branch.name)
|
|
210
|
+
|
|
211
211
|
analyzed_query = InfrahubGraphQLQueryAnalyzer(
|
|
212
212
|
query=query,
|
|
213
|
+
schema_branch=schema_branch,
|
|
213
214
|
query_variables=variable_values,
|
|
214
215
|
schema=graphql_params.schema,
|
|
215
216
|
operation_name=operation_name,
|
|
216
217
|
branch=branch,
|
|
217
218
|
)
|
|
219
|
+
|
|
220
|
+
# if the query contains some mutation, it's not currently supported to set AT manually
|
|
221
|
+
if analyzed_query.contains_mutation:
|
|
222
|
+
graphql_params.context.at = Timestamp()
|
|
223
|
+
elif at and branch.schema_changed_at and Timestamp(branch.schema_changed_at) > Timestamp(at):
|
|
224
|
+
schema_branch = await registry.schema.load_schema_from_db(db=db, branch=branch, at=Timestamp(at))
|
|
225
|
+
db.add_schema(name=branch.name, schema=schema_branch)
|
|
226
|
+
analyzed_query = InfrahubGraphQLQueryAnalyzer(
|
|
227
|
+
query=query,
|
|
228
|
+
schema_branch=schema_branch,
|
|
229
|
+
query_variables=variable_values,
|
|
230
|
+
schema=graphql_params.schema,
|
|
231
|
+
operation_name=operation_name,
|
|
232
|
+
branch=branch,
|
|
233
|
+
)
|
|
234
|
+
|
|
218
235
|
await self._evaluate_permissions(
|
|
219
236
|
db=db,
|
|
220
237
|
request=request,
|
|
@@ -224,13 +241,6 @@ class InfrahubGraphQLApp:
|
|
|
224
241
|
branch=branch,
|
|
225
242
|
)
|
|
226
243
|
|
|
227
|
-
# if the query contains some mutation, it's not currently supported to set AT manually
|
|
228
|
-
if analyzed_query.contains_mutation:
|
|
229
|
-
graphql_params.context.at = Timestamp()
|
|
230
|
-
elif at and branch.schema_changed_at and Timestamp(branch.schema_changed_at) > Timestamp(at):
|
|
231
|
-
schema_branch = await registry.schema.load_schema_from_db(db=db, branch=branch, at=Timestamp(at))
|
|
232
|
-
db.add_schema(name=branch.name, schema=schema_branch)
|
|
233
|
-
|
|
234
244
|
if operation_name == "IntrospectionQuery":
|
|
235
245
|
nbr_object_in_schema = len(graphql_params.schema.type_map)
|
|
236
246
|
self.logger.debug(
|
|
@@ -272,17 +282,15 @@ class InfrahubGraphQLApp:
|
|
|
272
282
|
GRAPHQL_QUERY_HEIGHT_METRICS.labels(**labels).observe(await analyzed_query.calculate_height())
|
|
273
283
|
# GRAPHQL_QUERY_VARS_METRICS.labels(**labels).observe(len(analyzed_query.variables))
|
|
274
284
|
GRAPHQL_TOP_LEVEL_QUERIES_METRICS.labels(**labels).observe(analyzed_query.nbr_queries)
|
|
275
|
-
GRAPHQL_QUERY_OBJECTS_METRICS.labels(**labels).observe(
|
|
276
|
-
len(await analyzed_query.get_models_in_use(types=graphql_params.context.types))
|
|
277
|
-
)
|
|
285
|
+
GRAPHQL_QUERY_OBJECTS_METRICS.labels(**labels).observe(len(analyzed_query.query_report.impacted_models))
|
|
278
286
|
|
|
279
|
-
|
|
280
|
-
if
|
|
287
|
+
_, errors = analyzed_query.is_valid
|
|
288
|
+
if errors:
|
|
281
289
|
GRAPHQL_QUERY_ERRORS_METRICS.labels(**labels).observe(len(errors))
|
|
282
290
|
|
|
283
291
|
return json_response
|
|
284
292
|
|
|
285
|
-
def _set_labels(self, request: Request, branch: Branch, query: InfrahubGraphQLQueryAnalyzer) -> dict[str, Any]:
|
|
293
|
+
def _set_labels(self, request: Request, branch: Branch, query: InfrahubGraphQLQueryAnalyzer) -> dict[str, Any]: # noqa: ARG002
|
|
286
294
|
return {
|
|
287
295
|
"type": "mutation" if query.contains_mutation else "query",
|
|
288
296
|
"branch": branch.name,
|
|
@@ -293,7 +301,7 @@ class InfrahubGraphQLApp:
|
|
|
293
301
|
|
|
294
302
|
async def _evaluate_permissions(
|
|
295
303
|
self,
|
|
296
|
-
request: Request,
|
|
304
|
+
request: Request, # noqa: ARG002
|
|
297
305
|
db: InfrahubDatabase,
|
|
298
306
|
query: InfrahubGraphQLQueryAnalyzer,
|
|
299
307
|
query_parameters: GraphqlParams,
|
|
@@ -450,7 +458,7 @@ class InfrahubGraphQLApp:
|
|
|
450
458
|
async for result in asyncgen:
|
|
451
459
|
payload = {"data": result.data}
|
|
452
460
|
await websocket.send_json({"type": GQL_DATA, "id": operation_id, "payload": payload})
|
|
453
|
-
except Exception as error:
|
|
461
|
+
except Exception as error:
|
|
454
462
|
if not isinstance(error, GraphQLError):
|
|
455
463
|
self.logger.error("An exception occurred in resolvers", exc_info=error)
|
|
456
464
|
error = GraphQLError(str(error), original_error=error)
|
|
@@ -471,8 +479,8 @@ async def _get_operation_from_request(request: Request) -> Union[dict[str, Any],
|
|
|
471
479
|
if content_type == "application/json":
|
|
472
480
|
try:
|
|
473
481
|
return cast(Union[dict[str, Any], list[Any]], await request.json())
|
|
474
|
-
except (TypeError, ValueError):
|
|
475
|
-
raise ValueError("Request body is not a valid JSON")
|
|
482
|
+
except (TypeError, ValueError) as err:
|
|
483
|
+
raise ValueError("Request body is not a valid JSON") from err
|
|
476
484
|
elif content_type == "multipart/form-data":
|
|
477
485
|
return await _get_operation_from_multipart(request)
|
|
478
486
|
else:
|
|
@@ -482,24 +490,24 @@ async def _get_operation_from_request(request: Request) -> Union[dict[str, Any],
|
|
|
482
490
|
async def _get_operation_from_multipart(request: Request) -> Union[dict[str, Any], list[Any]]:
|
|
483
491
|
try:
|
|
484
492
|
request_body = await request.form()
|
|
485
|
-
except Exception:
|
|
486
|
-
raise ValueError("Request body is not a valid multipart/form-data")
|
|
493
|
+
except Exception as err:
|
|
494
|
+
raise ValueError("Request body is not a valid multipart/form-data") from err
|
|
487
495
|
|
|
488
496
|
try:
|
|
489
497
|
operations_value = request_body.get("operations")
|
|
490
498
|
operations_data = operations_value if isinstance(operations_value, str) else ""
|
|
491
499
|
operations = ujson.loads(operations_data)
|
|
492
|
-
except (TypeError, ValueError):
|
|
493
|
-
raise ValueError("'operations' must be a valid JSON")
|
|
494
|
-
if not isinstance(operations,
|
|
500
|
+
except (TypeError, ValueError) as err:
|
|
501
|
+
raise ValueError("'operations' must be a valid JSON") from err
|
|
502
|
+
if not isinstance(operations, dict | list):
|
|
495
503
|
raise ValueError("'operations' field must be an Object or an Array")
|
|
496
504
|
|
|
497
505
|
try:
|
|
498
506
|
map_value = request_body.get("map")
|
|
499
507
|
map_data = map_value if isinstance(map_value, str) else ""
|
|
500
508
|
name_path_map = ujson.loads(map_data)
|
|
501
|
-
except (TypeError, ValueError):
|
|
502
|
-
raise ValueError("'map' field must be a valid JSON")
|
|
509
|
+
except (TypeError, ValueError) as err:
|
|
510
|
+
raise ValueError("'map' field must be a valid JSON") from err
|
|
503
511
|
if not isinstance(name_path_map, dict):
|
|
504
512
|
raise ValueError("'map' field must be an Object")
|
|
505
513
|
|
|
@@ -14,16 +14,16 @@ class AnonymousGraphQLPermissionChecker(GraphQLQueryPermissionCheckerInterface):
|
|
|
14
14
|
def __init__(self, anonymous_access_allowed_func: Callable[[], bool]) -> None:
|
|
15
15
|
self.anonymous_access_allowed_func = anonymous_access_allowed_func
|
|
16
16
|
|
|
17
|
-
async def supports(self, db: InfrahubDatabase, account_session: AccountSession, branch: Branch) -> bool:
|
|
17
|
+
async def supports(self, db: InfrahubDatabase, account_session: AccountSession, branch: Branch) -> bool: # noqa: ARG002
|
|
18
18
|
return not account_session.authenticated
|
|
19
19
|
|
|
20
20
|
async def check(
|
|
21
21
|
self,
|
|
22
|
-
db: InfrahubDatabase,
|
|
23
|
-
account_session: AccountSession,
|
|
22
|
+
db: InfrahubDatabase, # noqa: ARG002
|
|
23
|
+
account_session: AccountSession, # noqa: ARG002
|
|
24
24
|
analyzed_query: InfrahubGraphQLQueryAnalyzer,
|
|
25
|
-
query_parameters: GraphqlParams,
|
|
26
|
-
branch: Branch,
|
|
25
|
+
query_parameters: GraphqlParams, # noqa: ARG002
|
|
26
|
+
branch: Branch, # noqa: ARG002
|
|
27
27
|
) -> CheckerResolution:
|
|
28
28
|
if not self.anonymous_access_allowed_func() or analyzed_query.contains_mutation:
|
|
29
29
|
raise AuthorizationError("Authentication is required to perform this operation")
|
|
@@ -25,16 +25,16 @@ class DefaultBranchPermissionChecker(GraphQLQueryPermissionCheckerInterface):
|
|
|
25
25
|
"InfrahubAccountTokenDelete",
|
|
26
26
|
]
|
|
27
27
|
|
|
28
|
-
async def supports(self, db: InfrahubDatabase, account_session: AccountSession, branch: Branch) -> bool:
|
|
28
|
+
async def supports(self, db: InfrahubDatabase, account_session: AccountSession, branch: Branch) -> bool: # noqa: ARG002
|
|
29
29
|
return config.SETTINGS.main.allow_anonymous_access or account_session.authenticated
|
|
30
30
|
|
|
31
31
|
async def check(
|
|
32
32
|
self,
|
|
33
|
-
db: InfrahubDatabase,
|
|
34
|
-
account_session: AccountSession,
|
|
33
|
+
db: InfrahubDatabase, # noqa: ARG002
|
|
34
|
+
account_session: AccountSession, # noqa: ARG002
|
|
35
35
|
analyzed_query: InfrahubGraphQLQueryAnalyzer,
|
|
36
36
|
query_parameters: GraphqlParams,
|
|
37
|
-
branch: Branch,
|
|
37
|
+
branch: Branch, # noqa: ARG002
|
|
38
38
|
) -> CheckerResolution:
|
|
39
39
|
operates_on_default_branch = analyzed_query.branch is None or analyzed_query.branch.name in (
|
|
40
40
|
GLOBAL_BRANCH_NAME,
|
|
@@ -17,16 +17,16 @@ class MergeBranchPermissionChecker(GraphQLQueryPermissionCheckerInterface):
|
|
|
17
17
|
action=GlobalPermissions.MERGE_BRANCH.value, decision=PermissionDecision.ALLOW_ALL.value
|
|
18
18
|
)
|
|
19
19
|
|
|
20
|
-
async def supports(self, db: InfrahubDatabase, account_session: AccountSession, branch: Branch) -> bool:
|
|
20
|
+
async def supports(self, db: InfrahubDatabase, account_session: AccountSession, branch: Branch) -> bool: # noqa: ARG002
|
|
21
21
|
return config.SETTINGS.main.allow_anonymous_access or account_session.authenticated
|
|
22
22
|
|
|
23
23
|
async def check(
|
|
24
24
|
self,
|
|
25
|
-
db: InfrahubDatabase,
|
|
26
|
-
account_session: AccountSession,
|
|
25
|
+
db: InfrahubDatabase, # noqa: ARG002
|
|
26
|
+
account_session: AccountSession, # noqa: ARG002
|
|
27
27
|
analyzed_query: InfrahubGraphQLQueryAnalyzer,
|
|
28
28
|
query_parameters: GraphqlParams,
|
|
29
|
-
branch: Branch,
|
|
29
|
+
branch: Branch, # noqa: ARG002
|
|
30
30
|
) -> CheckerResolution:
|
|
31
31
|
if "BranchMerge" in [operation.name for operation in analyzed_query.operations]:
|
|
32
32
|
query_parameters.context.active_permissions.raise_for_permission(permission=self.permission_required)
|
|
@@ -18,16 +18,16 @@ from .interface import CheckerResolution, GraphQLQueryPermissionCheckerInterface
|
|
|
18
18
|
class ObjectPermissionChecker(GraphQLQueryPermissionCheckerInterface):
|
|
19
19
|
"""Checker that makes sure a user account can perform some action on some kind of objects."""
|
|
20
20
|
|
|
21
|
-
async def supports(self, db: InfrahubDatabase, account_session: AccountSession, branch: Branch) -> bool:
|
|
21
|
+
async def supports(self, db: InfrahubDatabase, account_session: AccountSession, branch: Branch) -> bool: # noqa: ARG002
|
|
22
22
|
return config.SETTINGS.main.allow_anonymous_access or account_session.authenticated
|
|
23
23
|
|
|
24
24
|
async def check(
|
|
25
25
|
self,
|
|
26
|
-
db: InfrahubDatabase,
|
|
27
|
-
account_session: AccountSession,
|
|
26
|
+
db: InfrahubDatabase, # noqa: ARG002
|
|
27
|
+
account_session: AccountSession, # noqa: ARG002
|
|
28
28
|
analyzed_query: InfrahubGraphQLQueryAnalyzer,
|
|
29
29
|
query_parameters: GraphqlParams,
|
|
30
|
-
branch: Branch,
|
|
30
|
+
branch: Branch, # noqa: ARG002
|
|
31
31
|
) -> CheckerResolution:
|
|
32
32
|
required_decision = (
|
|
33
33
|
PermissionDecisionFlag.ALLOW_DEFAULT
|
|
@@ -36,34 +36,27 @@ class ObjectPermissionChecker(GraphQLQueryPermissionCheckerInterface):
|
|
|
36
36
|
else PermissionDecisionFlag.ALLOW_OTHER
|
|
37
37
|
)
|
|
38
38
|
|
|
39
|
-
kinds = await analyzed_query.get_models_in_use(types=query_parameters.context.types)
|
|
40
|
-
|
|
41
|
-
# Identify which operations are performed. As we don't have a mapping between kinds and the
|
|
42
|
-
# operation we currently require permissions all defined permissions for all objects
|
|
43
|
-
# within the GraphQL query / mutation
|
|
44
|
-
actions: set[str] = set()
|
|
45
|
-
for operation in analyzed_query.operations:
|
|
46
|
-
for kind in kinds:
|
|
47
|
-
if operation.name and operation.name.startswith(kind):
|
|
48
|
-
# An empty string after prefix removal means a query to "view"
|
|
49
|
-
query_action = operation.name[len(kind) :].lower() or "view"
|
|
50
|
-
if query_action == "upsert":
|
|
51
|
-
# Require both create and update for Upsert mutations
|
|
52
|
-
actions.add("create")
|
|
53
|
-
actions.add("update")
|
|
54
|
-
else:
|
|
55
|
-
actions.add(query_action)
|
|
56
|
-
|
|
57
|
-
# Infer required permissions from the kind/operation map
|
|
58
39
|
permissions: list[ObjectPermission] = []
|
|
59
|
-
for
|
|
60
|
-
|
|
40
|
+
for kind, object_access in analyzed_query.query_report.requested_read.items():
|
|
41
|
+
if object_access.attributes or object_access.relationships:
|
|
42
|
+
extracted_words = extract_camelcase_words(kind)
|
|
43
|
+
permissions.append(
|
|
44
|
+
ObjectPermission(
|
|
45
|
+
namespace=extracted_words[0],
|
|
46
|
+
name="".join(extracted_words[1:]),
|
|
47
|
+
action="view",
|
|
48
|
+
decision=required_decision,
|
|
49
|
+
)
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
for kind, requested_permissions in analyzed_query.query_report.kind_action_map.items():
|
|
53
|
+
for requested_permission in requested_permissions:
|
|
61
54
|
extracted_words = extract_camelcase_words(kind)
|
|
62
55
|
permissions.append(
|
|
63
56
|
ObjectPermission(
|
|
64
57
|
namespace=extracted_words[0],
|
|
65
58
|
name="".join(extracted_words[1:]),
|
|
66
|
-
action=
|
|
59
|
+
action=requested_permission.value,
|
|
67
60
|
decision=required_decision,
|
|
68
61
|
)
|
|
69
62
|
)
|
|
@@ -83,19 +76,19 @@ class AccountManagerPermissionChecker(GraphQLQueryPermissionCheckerInterface):
|
|
|
83
76
|
action=GlobalPermissions.MANAGE_ACCOUNTS.value, decision=PermissionDecision.ALLOW_ALL.value
|
|
84
77
|
)
|
|
85
78
|
|
|
86
|
-
async def supports(self, db: InfrahubDatabase, account_session: AccountSession, branch: Branch) -> bool:
|
|
79
|
+
async def supports(self, db: InfrahubDatabase, account_session: AccountSession, branch: Branch) -> bool: # noqa: ARG002
|
|
87
80
|
return config.SETTINGS.main.allow_anonymous_access or account_session.authenticated
|
|
88
81
|
|
|
89
82
|
async def check(
|
|
90
83
|
self,
|
|
91
84
|
db: InfrahubDatabase,
|
|
92
|
-
account_session: AccountSession,
|
|
85
|
+
account_session: AccountSession, # noqa: ARG002
|
|
93
86
|
analyzed_query: InfrahubGraphQLQueryAnalyzer,
|
|
94
87
|
query_parameters: GraphqlParams,
|
|
95
88
|
branch: Branch,
|
|
96
89
|
) -> CheckerResolution:
|
|
97
90
|
is_account_operation = False
|
|
98
|
-
kinds =
|
|
91
|
+
kinds = analyzed_query.query_report.impacted_models
|
|
99
92
|
operation_names = [operation.name for operation in analyzed_query.operations]
|
|
100
93
|
|
|
101
94
|
for kind in kinds:
|
|
@@ -127,19 +120,19 @@ class PermissionManagerPermissionChecker(GraphQLQueryPermissionCheckerInterface)
|
|
|
127
120
|
action=GlobalPermissions.MANAGE_PERMISSIONS.value, decision=PermissionDecision.ALLOW_ALL.value
|
|
128
121
|
)
|
|
129
122
|
|
|
130
|
-
async def supports(self, db: InfrahubDatabase, account_session: AccountSession, branch: Branch) -> bool:
|
|
123
|
+
async def supports(self, db: InfrahubDatabase, account_session: AccountSession, branch: Branch) -> bool: # noqa: ARG002
|
|
131
124
|
return config.SETTINGS.main.allow_anonymous_access or account_session.authenticated
|
|
132
125
|
|
|
133
126
|
async def check(
|
|
134
127
|
self,
|
|
135
128
|
db: InfrahubDatabase,
|
|
136
|
-
account_session: AccountSession,
|
|
129
|
+
account_session: AccountSession, # noqa: ARG002
|
|
137
130
|
analyzed_query: InfrahubGraphQLQueryAnalyzer,
|
|
138
131
|
query_parameters: GraphqlParams,
|
|
139
132
|
branch: Branch,
|
|
140
133
|
) -> CheckerResolution:
|
|
141
134
|
is_permission_operation = False
|
|
142
|
-
kinds =
|
|
135
|
+
kinds = analyzed_query.query_report.impacted_models
|
|
143
136
|
|
|
144
137
|
for kind in kinds:
|
|
145
138
|
schema = get_schema(db=db, branch=branch, node_schema=kind)
|
|
@@ -168,19 +161,19 @@ class RepositoryManagerPermissionChecker(GraphQLQueryPermissionCheckerInterface)
|
|
|
168
161
|
action=GlobalPermissions.MANAGE_REPOSITORIES.value, decision=PermissionDecision.ALLOW_ALL.value
|
|
169
162
|
)
|
|
170
163
|
|
|
171
|
-
async def supports(self, db: InfrahubDatabase, account_session: AccountSession, branch: Branch) -> bool:
|
|
164
|
+
async def supports(self, db: InfrahubDatabase, account_session: AccountSession, branch: Branch) -> bool: # noqa: ARG002
|
|
172
165
|
return config.SETTINGS.main.allow_anonymous_access or account_session.authenticated
|
|
173
166
|
|
|
174
167
|
async def check(
|
|
175
168
|
self,
|
|
176
169
|
db: InfrahubDatabase,
|
|
177
|
-
account_session: AccountSession,
|
|
170
|
+
account_session: AccountSession, # noqa: ARG002
|
|
178
171
|
analyzed_query: InfrahubGraphQLQueryAnalyzer,
|
|
179
172
|
query_parameters: GraphqlParams,
|
|
180
173
|
branch: Branch,
|
|
181
174
|
) -> CheckerResolution:
|
|
182
175
|
is_repository_operation = False
|
|
183
|
-
kinds =
|
|
176
|
+
kinds = analyzed_query.query_report.impacted_models
|
|
184
177
|
|
|
185
178
|
for kind in kinds:
|
|
186
179
|
schema = get_schema(db=db, branch=branch, node_schema=kind)
|
|
@@ -17,16 +17,16 @@ class SuperAdminPermissionChecker(GraphQLQueryPermissionCheckerInterface):
|
|
|
17
17
|
action=GlobalPermissions.SUPER_ADMIN.value, decision=PermissionDecision.ALLOW_ALL.value
|
|
18
18
|
)
|
|
19
19
|
|
|
20
|
-
async def supports(self, db: InfrahubDatabase, account_session: AccountSession, branch: Branch) -> bool:
|
|
20
|
+
async def supports(self, db: InfrahubDatabase, account_session: AccountSession, branch: Branch) -> bool: # noqa: ARG002
|
|
21
21
|
return config.SETTINGS.main.allow_anonymous_access or account_session.authenticated
|
|
22
22
|
|
|
23
23
|
async def check(
|
|
24
24
|
self,
|
|
25
|
-
db: InfrahubDatabase,
|
|
26
|
-
account_session: AccountSession,
|
|
27
|
-
analyzed_query: InfrahubGraphQLQueryAnalyzer,
|
|
25
|
+
db: InfrahubDatabase, # noqa: ARG002
|
|
26
|
+
account_session: AccountSession, # noqa: ARG002
|
|
27
|
+
analyzed_query: InfrahubGraphQLQueryAnalyzer, # noqa: ARG002
|
|
28
28
|
query_parameters: GraphqlParams,
|
|
29
|
-
branch: Branch,
|
|
29
|
+
branch: Branch, # noqa: ARG002
|
|
30
30
|
) -> CheckerResolution:
|
|
31
31
|
return (
|
|
32
32
|
CheckerResolution.TERMINATE
|
infrahub/graphql/enums.py
CHANGED
|
@@ -6,7 +6,7 @@ import graphene
|
|
|
6
6
|
from infrahub.core.enums import generate_python_enum
|
|
7
7
|
from infrahub.core.schema import AttributeSchema, MainSchemaTypes
|
|
8
8
|
|
|
9
|
-
ENUM_NAME_REGEX = re.compile("[_a-zA-Z0-9]+")
|
|
9
|
+
ENUM_NAME_REGEX = re.compile(r"[_a-zA-Z0-9]+")
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
def get_enum_attribute_type_name(node_schema: MainSchemaTypes, attr_schema: AttributeSchema) -> str:
|
|
@@ -5,6 +5,7 @@ from typing import TYPE_CHECKING
|
|
|
5
5
|
|
|
6
6
|
from starlette.background import BackgroundTasks
|
|
7
7
|
|
|
8
|
+
from infrahub.context import InfrahubContext
|
|
8
9
|
from infrahub.core import registry
|
|
9
10
|
from infrahub.core.timestamp import Timestamp
|
|
10
11
|
from infrahub.exceptions import InitializationError
|
|
@@ -35,9 +36,9 @@ class GraphqlContext:
|
|
|
35
36
|
branch: Branch
|
|
36
37
|
types: dict
|
|
37
38
|
single_relationship_resolver: SingleRelationshipResolver
|
|
39
|
+
service: InfrahubServices | None = None
|
|
38
40
|
at: Timestamp | None = None
|
|
39
41
|
related_node_ids: set | None = None
|
|
40
|
-
service: InfrahubServices | None = None
|
|
41
42
|
account_session: AccountSession | None = None
|
|
42
43
|
permissions: PermissionManager | None = None
|
|
43
44
|
background: BackgroundTasks | None = None
|
|
@@ -70,6 +71,9 @@ class GraphqlContext:
|
|
|
70
71
|
return self.service
|
|
71
72
|
raise InitializationError("GraphQLContext doesn't contain a service")
|
|
72
73
|
|
|
74
|
+
def get_context(self) -> InfrahubContext:
|
|
75
|
+
return InfrahubContext.init(branch=self.branch, account=self.active_account_session)
|
|
76
|
+
|
|
73
77
|
|
|
74
78
|
async def prepare_graphql_params(
|
|
75
79
|
db: InfrahubDatabase,
|
infrahub/graphql/loaders/node.py
CHANGED
|
@@ -50,7 +50,7 @@ class NodeDataLoader(DataLoader[str, Node | None]):
|
|
|
50
50
|
self.query_params = query_params
|
|
51
51
|
self.db = db
|
|
52
52
|
|
|
53
|
-
async def batch_load_fn(self, keys: list[Any]) -> list[Node | None]:
|
|
53
|
+
async def batch_load_fn(self, keys: list[Any]) -> list[Node | None]:
|
|
54
54
|
async with self.db.start_session() as db:
|
|
55
55
|
nodes_by_id = await NodeManager.get_many(
|
|
56
56
|
db=db,
|
|
@@ -75,7 +75,7 @@ def to_frozen_set(to_freeze: dict[str, Any]) -> frozenset:
|
|
|
75
75
|
for k, v in to_freeze.items():
|
|
76
76
|
if isinstance(v, dict):
|
|
77
77
|
freezing_dict[k] = to_frozen_set(v)
|
|
78
|
-
elif isinstance(v,
|
|
78
|
+
elif isinstance(v, list | set):
|
|
79
79
|
freezing_dict[k] = frozenset(v)
|
|
80
80
|
else:
|
|
81
81
|
freezing_dict[k] = v
|