diff --git a/authentik/blueprints/tests/fixtures/tags.yaml b/authentik/blueprints/tests/fixtures/tags.yaml index e7c6d4071..9f7c91b71 100644 --- a/authentik/blueprints/tests/fixtures/tags.yaml +++ b/authentik/blueprints/tests/fixtures/tags.yaml @@ -4,7 +4,8 @@ context: policy_property: name policy_property_value: foo-bar-baz-qux entries: - - model: authentik_sources_oauth.oauthsource + - model: !Format ["%s", authentik_sources_oauth.oauthsource] + state: !Format ["%s", present] identifiers: slug: test attrs: diff --git a/authentik/blueprints/v1/common.py b/authentik/blueprints/v1/common.py index 1a585b2c8..0f02a6e09 100644 --- a/authentik/blueprints/v1/common.py +++ b/authentik/blueprints/v1/common.py @@ -5,7 +5,7 @@ from enum import Enum from functools import reduce from operator import ixor from os import getenv -from typing import Any, Literal, Optional +from typing import Any, Literal, Optional, Union from uuid import UUID from django.apps import apps @@ -56,8 +56,10 @@ class BlueprintEntryDesiredState(Enum): class BlueprintEntry: """Single entry of a blueprint""" - model: str - state: BlueprintEntryDesiredState = field(default=BlueprintEntryDesiredState.PRESENT) + model: Union[str, "YAMLTag"] + state: Union[BlueprintEntryDesiredState, "YAMLTag"] = field( + default=BlueprintEntryDesiredState.PRESENT + ) conditions: list[Any] = field(default_factory=list) identifiers: dict[str, Any] = field(default_factory=dict) attrs: Optional[dict[str, Any]] = field(default_factory=dict) @@ -103,6 +105,14 @@ class BlueprintEntry: """Get attributes of this entry, with all yaml tags resolved""" return self.tag_resolver(self.identifiers, blueprint) + def get_state(self, blueprint: "Blueprint") -> BlueprintEntryDesiredState: + """Get the blueprint state, with yaml tags resolved if present""" + return BlueprintEntryDesiredState(self.tag_resolver(self.state, blueprint)) + + def get_model(self, blueprint: "Blueprint") -> str: + """Get the blueprint model, with yaml tags resolved if present""" + return str(self.tag_resolver(self.model, blueprint)) + def check_all_conditions_match(self, blueprint: "Blueprint") -> bool: """Check all conditions of this entry match (evaluate to True)""" return all(self.tag_resolver(self.conditions, blueprint)) diff --git a/authentik/blueprints/v1/importer.py b/authentik/blueprints/v1/importer.py index 705e103de..6a59431cc 100644 --- a/authentik/blueprints/v1/importer.py +++ b/authentik/blueprints/v1/importer.py @@ -148,7 +148,7 @@ class Importer: self.logger.debug("One or more conditions of this entry are not fulfilled, skipping") return None - model_app_label, model_name = entry.model.split(".") + model_app_label, model_name = entry.get_model(self.__import).split(".") model: type[SerializerModel] = registry.get_model(model_app_label, model_name) # Don't use isinstance since we don't want to check for inheritance if not is_model_allowed(model): @@ -184,7 +184,7 @@ class Importer: serializer_kwargs = {} model_instance = existing_models.first() if not isinstance(model(), BaseMetaModel) and model_instance: - if entry.state == BlueprintEntryDesiredState.CREATED: + if entry.get_state(self.__import) == BlueprintEntryDesiredState.CREATED: self.logger.debug("instance exists, skipping") return None self.logger.debug( @@ -237,7 +237,7 @@ class Importer: """Apply (create/update) models yaml""" self.__pk_map = {} for entry in self.__import.entries: - model_app_label, model_name = entry.model.split(".") + model_app_label, model_name = entry.get_model(self.__import).split(".") try: model: type[SerializerModel] = registry.get_model(model_app_label, model_name) except LookupError: @@ -254,7 +254,8 @@ class Importer: if not serializer: continue - if entry.state in [ + state = entry.get_state(self.__import) + if state in [ BlueprintEntryDesiredState.PRESENT, BlueprintEntryDesiredState.CREATED, ]: @@ -263,7 +264,7 @@ class Importer: self.__pk_map[entry.identifiers["pk"]] = model.pk entry._state = BlueprintEntryState(model) self.logger.debug("updated model", model=model) - elif entry.state == BlueprintEntryDesiredState.ABSENT: + elif state == BlueprintEntryDesiredState.ABSENT: instance: Optional[Model] = serializer.instance if instance: instance.delete()