Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

55 changes: 49 additions & 6 deletions src/aap_eda/api/serializers/activation.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from typing import Optional

import yaml
from ansible_base.lib.serializers.mixins import CleanTextMixin
from django.conf import settings
from django.utils import timezone
from rest_framework import serializers
Expand Down Expand Up @@ -574,12 +575,17 @@ def to_representation(self, activation):


class ActivationCreateSerializer(
CleanTextMixin,
_K8sPodMetadataWriteFields,
OrganizationIdFieldMixin,
serializers.ModelSerializer,
):
"""Serializer for creating the Activation."""

# extra_var may legitimately contain Jinja2 template syntax
# (e.g. credential injectors), so it is excluded from free-text checks.
excluded_fields = frozenset({"extra_var"})

class Meta:
model = models.Activation
fields = [
Expand Down Expand Up @@ -665,7 +671,7 @@ def validate(self, data):
_validate_sources_with_event_streams(data=data)
_validate_persistence_credential(data=data)
_normalize_activation_k8s_pod_fields(data)
return data
return super().validate(data)

def create(self, validated_data):
rulebook_id = validated_data["rulebook_id"]
Expand Down Expand Up @@ -708,7 +714,26 @@ def create(self, validated_data):
return super().create(validated_data)


class ActivationCopySerializer(serializers.ModelSerializer):
class _ActivationCopyTextCheckSerializer(
CleanTextMixin, serializers.ModelSerializer
):
"""Internal-only: re-validate copied free-text fields as new content.

ActivationCopySerializer.is_valid() only ever validates "name",
since it's constructed with instance=<source activation>, which
would make CleanTextMixin grandfather "description" as unchanged.
This serializer is never exposed to clients; it's only used from
copy() to re-check the copied description with no instance to
grandfather against, the same way EdaCredentialCreateSerializer
re-validates a copied credential's description.
"""

class Meta:
model = models.Activation
fields = ["description", "k8s_service_name", "source_mappings"]


class ActivationCopySerializer(CleanTextMixin, serializers.ModelSerializer):
Comment thread
coderabbitai[bot] marked this conversation as resolved.
name = serializers.CharField(
required=True, validators=[validators.check_if_activation_name_used]
)
Expand All @@ -719,6 +744,19 @@ class Meta:

def copy(self) -> dict:
activation: models.Activation = self.instance

text_check = _ActivationCopyTextCheckSerializer(
data={
"description": activation.description,
"k8s_service_name": activation.k8s_service_name,
"source_mappings": activation.source_mappings,
}
)
text_check.is_valid(raise_exception=True)
description = text_check.validated_data["description"]
k8s_service_name = text_check.validated_data["k8s_service_name"]
source_mappings = text_check.validated_data["source_mappings"]

pod_metadata = _activation_k8s_pod_metadata_payload(activation)
_normalize_activation_k8s_pod_fields(pod_metadata)
validators.check_if_k8s_pod_service_account_name_valid(
Expand All @@ -740,7 +778,7 @@ def copy(self) -> dict:

copied_data = {
"name": self.validated_data["name"],
"description": activation.description,
"description": description,
"is_enabled": False,
"decision_environment": activation.decision_environment,
"rulebook": activation.rulebook,
Expand All @@ -751,8 +789,8 @@ def copy(self) -> dict:
"awx_token_id": activation.awx_token,
"log_level": activation.log_level,
"eda_credentials": activation.eda_credentials.all(),
"k8s_service_name": activation.k8s_service_name,
"source_mappings": activation.source_mappings,
"k8s_service_name": k8s_service_name,
"source_mappings": source_mappings,
"event_streams": activation.event_streams.all(),
"skip_audit_events": activation.skip_audit_events,
"rulebook_name": activation.rulebook.name,
Expand Down Expand Up @@ -782,12 +820,17 @@ def copy(self) -> dict:


class ActivationUpdateSerializer(
CleanTextMixin,
_K8sPodMetadataWriteFields,
OrganizationIdFieldMixin,
serializers.ModelSerializer,
):
"""Serializer for updating the Activation."""

# extra_var may legitimately contain Jinja2 template syntax
# (e.g. credential injectors), so it is excluded from free-text checks.
excluded_fields = frozenset({"extra_var"})

class Meta:
model = models.Activation
fields = [
Expand Down Expand Up @@ -897,7 +940,7 @@ def validate(self, data):
_validate_sources_with_event_streams(data=data)
_validate_persistence_credential(data=data)
_normalize_activation_k8s_pod_fields(data)
return data
return super().validate(data)

def prepare_update(self, activation: models.Activation):
rulebook_id = self.validated_data.get("rulebook_id")
Expand Down
21 changes: 17 additions & 4 deletions src/aap_eda/api/serializers/credential_input_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from ansible_base.lib.serializers.mixins import CleanTextMixin
from drf_spectacular.utils import extend_schema_field
from rest_framework import serializers

Expand Down Expand Up @@ -99,9 +100,15 @@ def to_representation(self, instance):
}


class CredentialInputSourceCreateSerializer(serializers.ModelSerializer):
class CredentialInputSourceCreateSerializer(
CleanTextMixin, serializers.ModelSerializer
):
"""Serializer used during the Create process of the instance."""

# metadata holds credential input values and is populated
# programmatically, so it is excluded from free-text checks.
excluded_fields = frozenset({"metadata"})

target_credential = serializers.PrimaryKeyRelatedField(
queryset=models.EdaCredential.objects.all(),
required=True,
Expand Down Expand Up @@ -149,7 +156,7 @@ def validate(self, attrs):
attrs.get("input_field_name"),
)

return attrs
return super().validate(attrs)

class Meta:
model = models.CredentialInputSource
Expand All @@ -163,9 +170,15 @@ class Meta:
]


class CredentialInputSourceUpdateSerializer(serializers.ModelSerializer):
class CredentialInputSourceUpdateSerializer(
CleanTextMixin, serializers.ModelSerializer
):
"""Serializer used during update of the instance."""

# metadata holds credential input values and is populated
# programmatically, so it is excluded from free-text checks.
excluded_fields = frozenset({"metadata"})

organization_id = serializers.IntegerField(
required=True,
allow_null=False,
Expand All @@ -185,7 +198,7 @@ def validate(self, attrs):
if bool(errors):
raise serializers.ValidationError(errors)

return attrs
return super().validate(attrs)

class Meta:
model = models.CredentialInputSource
Expand Down
11 changes: 9 additions & 2 deletions src/aap_eda/api/serializers/credential_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from ansible_base.lib.serializers.mixins import CleanTextMixin
from rest_framework import serializers

from aap_eda.core import models, validators
Expand All @@ -38,7 +39,13 @@ class Meta:
]


class CredentialTypeCreateSerializer(serializers.ModelSerializer):
class CredentialTypeCreateSerializer(
CleanTextMixin, serializers.ModelSerializer
):
# injectors commonly contain Jinja2 template syntax, so it is excluded
# from free-text checks.
excluded_fields = frozenset({"injectors"})

inputs = serializers.JSONField(
required=False,
default=dict,
Expand All @@ -63,7 +70,7 @@ def validate(self, data):
if bool(errors):
raise serializers.ValidationError(errors)

return data
return super().validate(data)

class Meta:
model = models.CredentialType
Expand Down
5 changes: 3 additions & 2 deletions src/aap_eda/api/serializers/decision_environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from ansible_base.lib.serializers.mixins import CleanTextMixin
from rest_framework import serializers

from aap_eda.api.serializers.eda_credential import EdaCredentialRefSerializer
Expand Down Expand Up @@ -58,7 +59,7 @@ def to_representation(self, decision_environment):


class DecisionEnvironmentCreateSerializer(
OrganizationIdFieldMixin, serializers.ModelSerializer
CleanTextMixin, OrganizationIdFieldMixin, serializers.ModelSerializer
):
"""Serializer for creating the DecisionEnvironment."""

Expand All @@ -75,7 +76,7 @@ def validate(self, data):
image_url = data.get("image_url") or self.instance.image_url
validators.check_if_de_valid(image_url, eda_credential_id)

return data
return super().validate(data)

class Meta:
model = models.DecisionEnvironment
Expand Down
23 changes: 17 additions & 6 deletions src/aap_eda/api/serializers/eda_credential.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
# limitations under the License.
import logging

from ansible_base.lib.serializers.mixins import CleanTextMixin
from django.db.models import Q
from django.urls import reverse
from drf_spectacular.utils import extend_schema_field
Expand Down Expand Up @@ -55,6 +56,8 @@ class EdaCredentialReferenceField(serializers.JSONField):


class EdaCredentialSerializer(serializers.ModelSerializer):
"""Serializer used during a GET."""

inputs = serializers.SerializerMethodField()
credential_type = CredentialTypeRefSerializer(
required=False, allow_null=True
Expand Down Expand Up @@ -120,7 +123,7 @@ def to_representation(self, eda_credential):
}


class EdaCredentialCopySerializer(serializers.ModelSerializer):
class EdaCredentialCopySerializer(CleanTextMixin, serializers.ModelSerializer):
name = serializers.CharField(
required=True,
validators=[validators.check_if_credential_name_used],
Expand All @@ -135,8 +138,12 @@ class Meta:


class EdaCredentialCreateSerializer(
OrganizationIdFieldMixin, serializers.ModelSerializer
CleanTextMixin, OrganizationIdFieldMixin, serializers.ModelSerializer
):
# inputs holds arbitrary secret credential values, so it is excluded
# from free-text checks.
excluded_fields = frozenset({"inputs"})

credential_type_id = serializers.IntegerField(
required=True,
allow_null=False,
Expand Down Expand Up @@ -181,7 +188,7 @@ def validate(self, data):
if bool(errors):
raise serializers.ValidationError(errors)

return data
return super().validate(data)

class Meta:
model = models.EdaCredential
Expand All @@ -195,8 +202,12 @@ class Meta:


class EdaCredentialUpdateSerializer(
OrganizationIdFieldMixin, serializers.ModelSerializer
CleanTextMixin, OrganizationIdFieldMixin, serializers.ModelSerializer
):
# inputs holds arbitrary secret credential values, so it is excluded
# from free-text checks.
excluded_fields = frozenset({"inputs"})

inputs = serializers.JSONField()

def validate(self, data):
Expand All @@ -212,7 +223,7 @@ def validate(self, data):
inputs = data.get("inputs", {})
# allow empty inputs during updating
if self.partial and not bool(inputs):
return data
return super().validate(data)

errors = validate_inputs(
credential_type,
Expand All @@ -224,7 +235,7 @@ def validate(self, data):
if bool(errors):
raise serializers.ValidationError(errors)

return data
return super().validate(data)

class Meta:
model = models.EdaCredential
Expand Down
7 changes: 5 additions & 2 deletions src/aap_eda/api/serializers/event_stream.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from urllib.parse import urljoin

import yaml
from ansible_base.lib.serializers.mixins import CleanTextMixin
from django.conf import settings
from django.urls import reverse
from rest_framework import serializers
Expand All @@ -27,7 +28,7 @@
from aap_eda.core import enums, models, validators


class EventStreamInSerializer(serializers.ModelSerializer):
class EventStreamInSerializer(CleanTextMixin, serializers.ModelSerializer):
organization_id = serializers.IntegerField(
required=True,
allow_null=False,
Expand Down Expand Up @@ -80,7 +81,7 @@ def validate(self, data):
if not event_stream_type:
data["event_stream_type"] = kind

return data
return super().validate(data)

class Meta:
model = models.EventStream
Expand All @@ -96,6 +97,8 @@ class Meta:


class EventStreamOutSerializer(serializers.ModelSerializer):
"""Serializer used during a GET."""

owner = serializers.SerializerMethodField()
organization = serializers.SerializerMethodField()
eda_credential = EdaCredentialRefSerializer(
Expand Down
Loading