Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
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
41 changes: 38 additions & 3 deletions backend/global_settings/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from ciso_assistant.settings import CISO_ASSISTANT_URL
from rest_framework.decorators import action

from core.serializers import SerializerFactory
from iam.sso.models import SSOSettings
from integrations.models import IntegrationProvider

Expand All @@ -12,8 +13,25 @@
GeneralSettingsSerializer,
FeatureFlagsSerializer,
)

from django.conf import settings
from .models import GlobalSettings
import structlog

logger = structlog.get_logger(__name__)


class GlobalSettingsSerializerFactory(SerializerFactory):
"""Factory to get a serializer class from a list of modules.
Attributes:
modules (list): List of module names to search for the serializer.
"""

def __init__(self, *modules: str):
# Reverse to prioritize later modules
self.modules = list(reversed(modules))

def get_serializer(self, base_name: str, action: str = "default"):
return self._get_serializer_class(f"{base_name}Serializer")


class GlobalSettingsViewSet(viewsets.ModelViewSet):
Expand Down Expand Up @@ -43,15 +61,32 @@ class FeatureFlagsViewSet(viewsets.ModelViewSet):
model = GlobalSettings
serializer_class = FeatureFlagsSerializer
queryset = GlobalSettings.objects.filter(name="feature-flags")
serializers_module = "global_settings.serializers"

def get_serializer_class(self, **kwargs):
serializer_factory = GlobalSettingsSerializerFactory(
self.serializers_module, settings.MODULE_PATHS.get("serializers", [])
)
serializer_class = serializer_factory.get_serializer(
"FeatureFlags", kwargs.get("action", "default")
)
logger.debug(
"Serializer class",
serializer_class=serializer_class,
action=kwargs.get("action", self.action),
viewset=self,
module_paths=settings.MODULE_PATHS,
)
return serializer_class

def retrieve(self, request, *args, **kwargs):
instance = self.get_object()
serializer = self.get_serializer(instance)
serializer = self.get_serializer_class()(instance)
return Response(serializer.data)

def update(self, request, *args, **kwargs):
instance = self.get_object()
serializer = self.get_serializer(instance, data=request.data)
serializer = self.get_serializer_class()(instance, data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data)
Expand Down
47 changes: 47 additions & 0 deletions enterprise/backend/enterprise_core/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
from core.serializer_fields import FieldsRelatedField
from iam.models import Folder, User, Role

from global_settings.models import GlobalSettings
from global_settings.serializers import (
FeatureFlagsSerializer as CommunityFeatureFlagSerializer,
)

from .models import ClientSettings, LogEntryAction
from auditlog.models import LogEntry

Expand Down Expand Up @@ -129,6 +134,48 @@ class Meta:
exclude = ["is_published", "folder"]


class FeatureFlagsSerializer(CommunityFeatureFlagSerializer):
"""
Serializer for managing Feature Flags stored within the 'value' JSON field
of a GlobalSettings instance. Each flag is represented as an explicit
BooleanField, mapping directly to keys within the 'value' dictionary.
"""

campaigns = serializers.BooleanField(
source="value.campaigns", required=False, default=True
)

class Meta:
model = GlobalSettings
fields = [
"xrays",
"incidents",
"tasks",
"risk_acceptances",
"exceptions",
"follow_up",
"ebiosrm",
"scoring_assistant",
"vulnerabilities",
"compliance",
"tprm",
"privacy",
"experimental",
"inherent_risk",
"organisation_objectives",
"organisation_issues",
"quantitative_risk_studies",
"terminologies",
"bia",
"project_management",
"contracts",
"reports",
"validation_flows",
"campaigns",
]
read_only_fields = ["name"]


class LogEntrySerializer(serializers.ModelSerializer):
"""
Serializer for the LogEntry model.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import { m } from '$paraglide/messages';
import Checkbox from '$lib/components/Forms/Checkbox.svelte';

import { page } from '$app/state';

interface Props {
form: SuperValidated<any>;
}
Expand All @@ -21,6 +23,7 @@
{ field: 'scoring_assistant', label: m.scoringAssistant() },
{ field: 'vulnerabilities', label: m.vulnerabilities() },
{ field: 'compliance', label: m.compliance() },
{ field: 'campaigns', label: m.campaigns() },
{ field: 'tprm', label: m.thirdParty() },
{ field: 'privacy', label: m.privacy() },
{ field: 'experimental', label: m.experimental() },
Expand All @@ -34,7 +37,7 @@
{ field: 'contracts', label: m.contracts() },
{ field: 'reports', label: m.reports() },
{ field: 'validation_flows', label: m.validationFlows() }
];
].filter(({ field }) => field in page.data.featureFlagSettings);
</script>

<div
Expand Down
1 change: 1 addition & 0 deletions frontend/src/lib/feature-flags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export function loadFeatureFlags() {
scoringAssistant: {},
vulnerabilities: {},
compliance: {},
campaigns: {},
tprm: {},
privacy: {},
experimental: {},
Expand Down
1 change: 1 addition & 0 deletions frontend/src/lib/utils/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,7 @@ export const FeatureFlagsSchema = z.object({
scoring_assistant: z.boolean().optional(),
vulnerabilities: z.boolean().optional(),
compliance: z.boolean().optional(),
campaigns: z.boolean().optional(),
tprm: z.boolean().optional(),
ebiosrm: z.boolean().optional(),
privacy: z.boolean().optional(),
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/lib/utils/sidebar-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ type SidebarBackendKeys = {
scoring_assistant: boolean;
vulnerabilities: boolean;
compliance: boolean;
campaigns: boolean;
tprm: boolean;
privacy: boolean;
experimental: boolean;
Expand All @@ -34,6 +35,7 @@ type SidebarFrontendKeys = {
scoringAssistant: boolean;
vulnerabilities: boolean;
compliance: boolean;
campaigns: boolean;
thirdPartyCategory: boolean;
privacy: boolean;
experimental: boolean;
Expand Down Expand Up @@ -62,6 +64,7 @@ export function getSidebarVisibleItems(
scoringAssistant: featureFlags?.scoring_assistant ?? false,
vulnerabilities: featureFlags?.vulnerabilities ?? false,
compliance: featureFlags?.compliance ?? false,
campaigns: featureFlags?.campaigns ?? false,
thirdPartyCategory: featureFlags?.tprm ?? false,
privacy: featureFlags?.privacy ?? false,
experimental: featureFlags?.experimental ?? false,
Expand Down