From 96548ed66be4d7f58c5dab5e22cabee90e0172bd Mon Sep 17 00:00:00 2001 From: jinweijie Date: Fri, 4 Sep 2026 10:20:40 +0800 Subject: [PATCH 1/5] ``` feat(settings): add fallback mechanism for missing conf.env module - Wrap conf.env import in try-except block to handle ModuleNotFoundError - Add comprehensive fallback configuration with default SQLite settings - Include detailed warning log message guiding users to create env config - Set default database, Redis, and application settings for development use - Configure default allowed hosts and column exclude apps ``` --- application/settings.py | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/application/settings.py b/application/settings.py index 76540fe..c7bbf31 100644 --- a/application/settings.py +++ b/application/settings.py @@ -28,7 +28,31 @@ # ******************** Dynamic Config ******************** # # ================================================= # -from conf.env import * +try: + from conf.env import * +except ModuleNotFoundError: + import logging as _lg + _lg.getLogger(__name__).warning( + "conf.env module not found, using default settings (SQLite). " + "Copy conf/env.example.py to conf/env.py and customize it for production use." + ) + DATABASE_ENGINE = "django.db.backends.sqlite3" + DATABASE_NAME = os.path.join(BASE_DIR, "db.sqlite3") + DATABASE_USER = "" + DATABASE_PASSWORD = "" + DATABASE_HOST = "" + DATABASE_PORT = "" + TABLE_PREFIX = "" + REDIS_DB = 0 + CELERY_BROKER_DB = 1 + REDIS_PASSWORD = "" + REDIS_HOST = "127.0.0.1" + REDIS_URL = f'redis://:{REDIS_PASSWORD or ""}@{REDIS_HOST}:6379' + DEBUG = True + ENABLE_LOGIN_ANALYSIS_LOG = True + LOGIN_NO_CAPTCHA_AUTH = True + ALLOWED_HOSTS = ["*"] + COLUMN_EXCLUDE_APPS = [] # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/ From f09133bbd2548cd384efd8dbd961cdb455cf43f7 Mon Sep 17 00:00:00 2001 From: jinweijie Date: Fri, 4 Sep 2026 10:36:46 +0800 Subject: [PATCH 2/5] ``` refactor(serializers): remove unused workflow approval models and add EE import check Remove obsolete workflow approval related models including WorkflowApprove, WorkflowApprovalRule, WorkflowApprovalNode, WorkflowApprovalInstance, WorkflowApprovalNodeExecution, and other unused models like HostLog, ManagedProgram, ProgramInstallTemplate, ProgramHostBinding, etc. Add conditional import logic for enterprise edition serializers with proper fallback handling to prevent AttributeError when EE module is missing. The thin wrapper serializers now only load when _EE_SUPERVISOR_PROGRAM_OK flag is True, otherwise fallback serializers are used. Fix DRF field info error in ProgramCommandViewSet when EE module is not available. ``` --- taurus/serializers.py | 51 ++++++++++++++++++++++--------------------- taurus/views.py | 14 +----------- 2 files changed, 27 insertions(+), 38 deletions(-) diff --git a/taurus/serializers.py b/taurus/serializers.py index cd12e2e..01f2485 100644 --- a/taurus/serializers.py +++ b/taurus/serializers.py @@ -6,19 +6,11 @@ from dvadmin.utils.validator import CustomUniqueValidator from .models import ( Workflow, WorkflowCategory, WorkflowStep, WorkflowExecution, WorkflowStepExecution, - WorkflowApprove, - WorkflowApprovalRule, WorkflowApprovalNode, WorkflowApprovalInstance, WorkflowApprovalNodeExecution, Host, Schedule, ScheduleExecution, RegistrationToken, HostHeartbeat, HeartbeatServer, ProgramInstallConfig, ProgramInstallPolicy, ProgramCommand, - HostLog, ManagedProgram, ProgramInstallTemplate, ProgramHostBinding, - LogCommand, OpsExecution, OpsExecutionApproval, - ScriptCategory, Script, ScriptVersion, ScriptPermission, ScriptTask, + ManagedProgram, ProgramInstallTemplate, ProgramHostBinding, + OpsExecution, ScriptCategory, Script, ScriptVersion, ScriptPermission, ScriptTask, ScriptTaskExecution, - ScriptAudit, ScriptApprove, - ScriptApprovalRule, ScriptApprovalNode, ScriptApprovalInstance, ScriptApprovalNodeExecution, - ScriptCheckRule, - SharePermissionDef, ScriptSharePermission, WorkflowSharePermission, - ShareLink, ShareLinkAccessLog, ) @@ -1269,6 +1261,12 @@ class Meta: # [M2.4 Thin Wrapper] Supervisor 程序管理高级 Serializers(F_PROGRAM_INSTALL_TEMPLATE / # F_PROGRAM_HOST_BINDING / F_PROGRAM_INSTALL_CONFIG / F_PROGRAM_COMMAND_BATCH / # F_PROGRAM_INSTALL_POLICY — EE 专属。原类名保留不动,thin pass 继承 taurus_ee.*。 +# +# 注意:这些 Serializer 均已在上方定义了 CE 基础版本(含正确的 Meta.model)。 +# Thin Wrapper 仅在 EE 成功导入时才重新定义(继承 EE 扩展);若 EE 缺失, +# 必须保留原 CE 版本不变,否则继承 _EEFallbackSerializer (model=None) 会导致 +# DRF 在 get_field_info 阶段抛出 AttributeError: 'NoneType' object has no attribute '_meta' +# (尤其是 ProgramCommandViewSet,其基础 CRUD 不走 EE Gate)。 # ============================================================================ try: from taurus_ee.serializers.supervisor_program import ( @@ -1288,7 +1286,9 @@ class Meta: _EEProgramInstallPolicyCreateSerializer as _EE_PIP_CreateSer, _EEProgramInstallPolicyUpdateSerializer as _EE_PIP_UpdateSer, ) + _EE_SUPERVISOR_PROGRAM_OK = True except ImportError: + _EE_SUPERVISOR_PROGRAM_OK = False from taurus.ee_fallback import _EEFallbackSerializer as _FBSer class _EE_PC_CreateSer(_FBSer): pass class _EE_PC_Ser(_FBSer): pass @@ -1307,21 +1307,22 @@ class _EE_PIT_Ser(_FBSer): pass class _EE_PIT_UpdateSer(_FBSer): pass -class ProgramInstallTemplateSerializer(_EE_PIT_Ser): pass # noqa: E701 Thin Wrapper -class ProgramInstallTemplateCreateSerializer(_EE_PIT_CreateSer): pass # noqa: E701 -class ProgramInstallTemplateUpdateSerializer(_EE_PIT_UpdateSer): pass # noqa: E701 -class ProgramHostBindingSerializer(_EE_PHB_Ser): pass # noqa: E701 -class ProgramHostBindingCreateSerializer(_EE_PHB_CreateSer): pass # noqa: E701 -class ProgramHostBindingUpdateSerializer(_EE_PHB_UpdateSer): pass # noqa: E701 -class ProgramInstallConfigSerializer(_EE_PIC_Ser): pass # noqa: E701 -class ProgramInstallConfigCreateSerializer(_EE_PIC_CreateSer): pass # noqa: E701 -class ProgramInstallConfigUpdateSerializer(_EE_PIC_UpdateSer): pass # noqa: E701 -class ProgramCommandSerializer(_EE_PC_Ser): pass # noqa: E701 -class ProgramCommandCreateSerializer(_EE_PC_CreateSer): pass # noqa: E701 -class ProgramCommandUpdateSerializer(_EE_PC_UpdateSer): pass # noqa: E701 -class ProgramInstallPolicySerializer(_EE_PIP_Ser): pass # noqa: E701 -class ProgramInstallPolicyCreateSerializer(_EE_PIP_CreateSer): pass # noqa: E701 -class ProgramInstallPolicyUpdateSerializer(_EE_PIP_UpdateSer): pass # noqa: E701 +if _EE_SUPERVISOR_PROGRAM_OK: + class ProgramInstallTemplateSerializer(_EE_PIT_Ser): pass # noqa: E701 Thin Wrapper + class ProgramInstallTemplateCreateSerializer(_EE_PIT_CreateSer): pass # noqa: E701 + class ProgramInstallTemplateUpdateSerializer(_EE_PIT_UpdateSer): pass # noqa: E701 + class ProgramHostBindingSerializer(_EE_PHB_Ser): pass # noqa: E701 + class ProgramHostBindingCreateSerializer(_EE_PHB_CreateSer): pass # noqa: E701 + class ProgramHostBindingUpdateSerializer(_EE_PHB_UpdateSer): pass # noqa: E701 + class ProgramInstallConfigSerializer(_EE_PIC_Ser): pass # noqa: E701 + class ProgramInstallConfigCreateSerializer(_EE_PIC_CreateSer): pass # noqa: E701 + class ProgramInstallConfigUpdateSerializer(_EE_PIC_UpdateSer): pass # noqa: E701 + class ProgramCommandSerializer(_EE_PC_Ser): pass # noqa: E701 + class ProgramCommandCreateSerializer(_EE_PC_CreateSer): pass # noqa: E701 + class ProgramCommandUpdateSerializer(_EE_PC_UpdateSer): pass # noqa: E701 + class ProgramInstallPolicySerializer(_EE_PIP_Ser): pass # noqa: E701 + class ProgramInstallPolicyCreateSerializer(_EE_PIP_CreateSer): pass # noqa: E701 + class ProgramInstallPolicyUpdateSerializer(_EE_PIP_UpdateSer): pass # noqa: E701 # ------------------ [M2.5 Thin Wrapper] HostLog & LogCommand (log center EE) ------------------ diff --git a/taurus/views.py b/taurus/views.py index 9552a1b..68e86cb 100644 --- a/taurus/views.py +++ b/taurus/views.py @@ -15,21 +15,16 @@ from taurus.models import ( Workflow, WorkflowCategory, WorkflowStep, WorkflowExecution, WorkflowStepExecution, - WorkflowApprove, Host, Schedule, ScheduleExecution, RegistrationToken, HostHeartbeat, HeartbeatServer, ProgramInstallConfig, ProgramInstallPolicy, ProgramCommand, ManagedProgram, HostLog, ProgramInstallTemplate, ProgramHostBinding, LogCommand, OpsExecution, OpsExecutionApproval, ScriptCategory, Script, ScriptVersion, ScriptPermission, ScriptTask, ScriptTaskExecution, ScriptAudit, ScriptApprove, - ScriptApprovalRule, ScriptApprovalNode, ScriptApprovalInstance, ScriptApprovalNodeExecution, SharePermissionDef, ScriptSharePermission, WorkflowSharePermission, - ShareLink, ShareLinkAccessLog, ) from taurus.serializers import ( WorkflowSerializer, WorkflowListSerializer, WorkflowExportSerializer, WorkflowStepSerializer, WorkflowCategorySerializer, WorkflowCategoryCreateSerializer, WorkflowCategoryUpdateSerializer, - WorkflowApproveSerializer, WorkflowApproveCreateSerializer, - WorkflowApproveApproveSerializer, WorkflowApproveRejectSerializer, WorkflowExecutionSerializer, ScheduleSerializer, ScheduleListSerializer, ScheduleExecutionSerializer, HostSerializer, ExecutorRegisterSerializer, RegistrationTokenSerializer, SupervisorHeartbeatSerializer, HostHeartbeatSerializer, HeartbeatServerSerializer, @@ -50,18 +45,12 @@ ScriptVersionSerializer, ScriptPermissionSerializer, ScriptTaskSerializer, ScriptTaskCreateSerializer, ScriptTaskUpdateSerializer, ScriptTaskExecutionSerializer, - ScriptAuditSerializer, ScriptApproveSerializer, - ScriptApprovalRuleSerializer, ScriptApprovalNodeSerializer, - ScriptApprovalInstanceSerializer, ScriptApprovalNodeExecutionSerializer, SharePermissionDefSerializer, ScriptSharePermissionSerializer, WorkflowSharePermissionSerializer, - SharePermissionBatchCreateSerializer, ShareLinkSerializer, - ShareLinkActivateSerializer, ShareLinkAccessLogSerializer, - TaskCenterItemSerializer, + SharePermissionBatchCreateSerializer, TaskCenterItemSerializer, ) from taurus.utils.share_permission import ( SharePermissionChecker, - ShareLinkService, ShareVisibleQS, require_share_perm, ) @@ -75,7 +64,6 @@ from rest_framework.decorators import api_view, permission_classes from rest_framework.response import Response from rest_framework import status as drf_status -from rest_framework.permissions import AllowAny logger = logging.getLogger(__name__) From 24e31913ba7d2d4c3904a01907d56e1cdd99e637 Mon Sep 17 00:00:00 2001 From: jinweijie Date: Fri, 4 Sep 2026 10:39:24 +0800 Subject: [PATCH 3/5] ``` chore(serializers): add audit script to check Meta.model=None bug in Thin Wrapper Serializers Add audit script to identify serializers with Meta.model=None issues when EE is absent. The script checks various serializer classes including WorkflowDAGVersionSerializer, ProgramInstallTemplateSerializers, HostLogSerializers, OpsExecutionApprovalSerializers, Script approval serializers, SharePermission serializers, Workflow approval serializers, Scheduler HA serializers, and Extension center placeholders. The audit identifies problematic serializers by attempting to instantiate them and accessing their fields property which triggers DRF get_field_info and reveals ModelSerializer subclasses with Meta.model=None configuration that could cause HTTP 400/500 errors when ViewSet has no EE gate. ``` --- _audit_serializers.py | 127 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 _audit_serializers.py diff --git a/_audit_serializers.py b/_audit_serializers.py new file mode 100644 index 0000000..f10f993 --- /dev/null +++ b/_audit_serializers.py @@ -0,0 +1,127 @@ +"""Audit all Thin Wrapper Serializers for Meta.model=None bug when EE is absent.""" +import os, sys, traceback +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'application.settings') +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) + +import django +django.setup() + +from taurus import serializers as ser_module +import inspect + +# Grep: all classes defined in taurus.serializers that have a Meta inner class +# We will check Meta.model and flag those with None (or missing) + +SERIALIZERS_TO_CHECK = [ + # M2.2 Workflow DAG + 'WorkflowDAGVersionSerializer', + # M2.4 Supervisor program (already fixed — verify) + 'ProgramInstallTemplateSerializer', + 'ProgramInstallTemplateCreateSerializer', + 'ProgramInstallTemplateUpdateSerializer', + 'ProgramHostBindingSerializer', + 'ProgramHostBindingCreateSerializer', + 'ProgramHostBindingUpdateSerializer', + 'ProgramInstallConfigSerializer', + 'ProgramInstallConfigCreateSerializer', + 'ProgramInstallConfigUpdateSerializer', + 'ProgramCommandSerializer', + 'ProgramCommandCreateSerializer', + 'ProgramCommandUpdateSerializer', + 'ProgramInstallPolicySerializer', + 'ProgramInstallPolicyCreateSerializer', + 'ProgramInstallPolicyUpdateSerializer', + # M2.5 HostLog / LogCommand + 'HostLogSerializer', + 'HostLogReceiveSerializer', + 'LogCommandSerializer', + 'LogCommandCreateSerializer', + 'LogCommandUpdateSerializer', + # Ops approval + 'OpsExecutionApprovalSerializer', + 'OpsExecutionApprovalListSerializer', + 'OpsExecutionApprovalCreateSerializer', + 'OpsExecutionApprovalActionSerializer', + # Script library EE + 'ScriptAuditSerializer', + 'ScriptApproveSerializer', + 'ScriptApprovalRuleSerializer', + 'ScriptApprovalNodeSerializer', + 'ScriptApprovalInstanceSerializer', + 'ScriptApprovalNodeExecutionSerializer', + 'ScriptCheckRuleSerializer', + # Share permission + 'SharePermissionDefSerializer', + 'ScriptSharePermissionSerializer', + 'WorkflowSharePermissionSerializer', + 'SharePermissionBatchCreateSerializer', + 'ShareLinkSerializer', + 'ShareLinkActivateSerializer', + 'ShareLinkAccessLogSerializer', + # Workflow approval + 'WorkflowApproveSerializer', + 'WorkflowApproveCreateSerializer', + 'WorkflowApproveApproveSerializer', + 'WorkflowApproveRejectSerializer', + 'WorkflowApproveCompatSerializer', + 'WorkflowApprovalRuleSerializer', + 'WorkflowApprovalNodeSerializer', + 'WorkflowApprovalInstanceSerializer', + 'WorkflowApprovalNodeExecutionSerializer', + # Scheduler HA + 'ScheduleExecutionHASerializer', + 'ScriptTaskExecutionUnifiedSerializer', + 'SchedulerAlertRuleSerializer', + 'UnifiedScheduleListRequestSerializer', + 'UnifiedScheduleStatsSerializer', + 'SchedulerAlertEventSerializer', + # Extension center placeholders + 'ContactLeadSerializer', + 'TaskCenterItemSerializer', + 'KnowledgeBasePlaceholderSerializer', + 'InspectionCenterPlaceholderSerializer', + 'ToolsCenterPlaceholderSerializer', + 'BackupRestoreCenterPlaceholderSerializer', + 'DownloadCenterPlaceholderSerializer', +] + +problems = [] +oks = [] +for name in SERIALIZERS_TO_CHECK: + cls = getattr(ser_module, name, None) + if cls is None: + problems.append((name, 'CLASS NOT FOUND', None)) + continue + meta = getattr(cls, 'Meta', None) + model = getattr(meta, 'model', None) if meta else None + # Test if serializer instantiation + .fields access works (this triggers DRF get_field_info) + try: + inst = cls() + _ = inst.fields # This is the crash site path + fields_ok = True + except Exception as e: + fields_ok = False + problems.append((name, f'fields lookup ERROR: {type(e).__name__}: {e}', model)) + continue + if model is None: + # Check if this is intentional (non-model serializer, e.g. serializers.Serializer base) + from rest_framework import serializers as drf_ser + is_non_model_serializer = issubclass(cls, drf_ser.Serializer) and not issubclass(cls, drf_ser.ModelSerializer) + if is_non_model_serializer: + oks.append((name, f'OK (non-model Serializer)', model)) + else: + problems.append((name, 'Meta.model = None (but ModelSerializer subclass)', model)) + else: + oks.append((name, f'OK model={model.__name__}', model)) + +print('='*90) +print(f'CHECKED {len(SERIALIZERS_TO_CHECK)} SERIALIZERS — {len(problems)} PROBLEMS, {len(oks)} OK') +print('='*90) +if problems: + print('\n[PROBLEMS — likely cause HTTP 400/500 when ViewSet has no EE gate]:') + for p in problems: + print(f' ⚠️ {p[0]:<55s} | {p[1]} | model={p[2]}') +print() +print('[OK]:') +for o in oks: + print(f' ✅ {o[0]:<55s} | {o[1]}') \ No newline at end of file From 248f4474b9f759a8d0cf033e0eb7ea3503b595f3 Mon Sep 17 00:00:00 2001 From: jinweijie Date: Fri, 4 Sep 2026 11:12:43 +0800 Subject: [PATCH 4/5] ``` feat(serializers): add conditional EE serializer definitions with import guards Add defensive import guards for all EE serializers to prevent AttributeError when EE modules are not available. Introduce *_OK flags to conditionally define serializer classes only when EE imports succeed. This fixes an issue where CE functionality would fail when accessing WorkflowDAGVersionSerializer during workflow publishing due to missing Meta.model attribute when EE is not installed. Also adds CE base implementation for WorkflowDAGVersionSerializer to ensure core functionality remains available without EE dependencies. ``` --- taurus/serializers.py | 256 +++++++++++++++++++++++++----------------- 1 file changed, 156 insertions(+), 100 deletions(-) diff --git a/taurus/serializers.py b/taurus/serializers.py index 01f2485..02ef748 100644 --- a/taurus/serializers.py +++ b/taurus/serializers.py @@ -834,18 +834,34 @@ class WorkflowExecuteSerializer(serializers.Serializer): # [M2.2 Thin Wrapper] WorkflowDAGVersionSerializer → EE 实现 +# +# 先提供 CE 基础版本(真实 Meta.model),否则 EE 缺失时 WorkflowViewSet.publish +# (CE 功能,无 EE Gate)在成功返回时会访问 WorkflowDAGVersionSerializer(dag_ver).data +# 触发 DRF get_field_info → AttributeError: 'NoneType' object has no attribute '_meta'。 +from taurus.workflow.models import WorkflowDAGVersion as _WorkflowDAGVersionModel # noqa: E402 (circular import guard) +class WorkflowDAGVersionSerializer(CustomModelSerializer): + """Workflow DAG published version serializer (CE base — EE overrides via Thin Wrapper below).""" + class Meta: + model = _WorkflowDAGVersionModel + fields = '__all__' + read_only_fields = ['id', 'create_datetime', 'update_datetime', 'creator'] + + try: from taurus_ee.serializers.workflow_dag import ( WorkflowDAGVersionSerializer as _EEWorkflowDAGVersionSerializer, ) + _EE_WORKFLOW_DAG_SER_OK = True except ImportError: + _EE_WORKFLOW_DAG_SER_OK = False from taurus.ee_fallback import _EEFallbackSerializer as _FBSer class _EEWorkflowDAGVersionSerializer(_FBSer): pass -class WorkflowDAGVersionSerializer(_EEWorkflowDAGVersionSerializer): - """Thin wrapper — EE implementation in taurus_ee.serializers.workflow_dag""" - pass +if _EE_WORKFLOW_DAG_SER_OK: + class WorkflowDAGVersionSerializer(_EEWorkflowDAGVersionSerializer): # noqa: F811 + """Thin wrapper — EE implementation in taurus_ee.serializers.workflow_dag""" + pass class WorkflowNodeExecutionSerializer(CustomModelSerializer): @@ -1326,6 +1342,9 @@ class ProgramInstallPolicyUpdateSerializer(_EE_PIP_UpdateSer): pass # noqa: E70 # ------------------ [M2.5 Thin Wrapper] HostLog & LogCommand (log center EE) ------------------ +# 这些 Serializer 是 EE 专属功能(HostLogViewSet / LogCommandViewSet / TaskCenterViewSet +# 等均带 dispatch EE Gate),但仍然加 _EE_OK 守卫,避免未来有人绕过 gate 直接使用 +# 时踩到 _EEFallbackSerializer 的 Meta.model=None 问题。 try: from taurus_ee.serializers.log_ext_center import ( _EEHostLogSerializer, @@ -1341,7 +1360,9 @@ class ProgramInstallPolicyUpdateSerializer(_EE_PIP_UpdateSer): pass # noqa: E70 _EEBackupRestoreCenterPlaceholderSerializer, _EEDownloadCenterPlaceholderSerializer, ) + _EE_LOG_EXT_OK = True except ImportError: + _EE_LOG_EXT_OK = False from taurus.ee_fallback import _EEFallbackSerializer as _FBSer class _EEBackupRestoreCenterPlaceholderSerializer(_FBSer): pass class _EEContactLeadSerializer(_FBSer): pass @@ -1357,14 +1378,15 @@ class _EETaskCenterItemSerializer(_FBSer): pass class _EEToolsCenterPlaceholderSerializer(_FBSer): pass -class HostLogSerializer(_EEHostLogSerializer): - """Thin Wrapper — EE impl: taurus_ee.serializers.log_ext_center._EEHostLogSerializer""" - pass +if _EE_LOG_EXT_OK: + class HostLogSerializer(_EEHostLogSerializer): + """Thin Wrapper — EE impl: taurus_ee.serializers.log_ext_center._EEHostLogSerializer""" + pass -class HostLogReceiveSerializer(_EEHostLogReceiveSerializer): - """Thin Wrapper — EE impl: taurus_ee.serializers.log_ext_center._EEHostLogReceiveSerializer""" - pass + class HostLogReceiveSerializer(_EEHostLogReceiveSerializer): + """Thin Wrapper — EE impl: taurus_ee.serializers.log_ext_center._EEHostLogReceiveSerializer""" + pass class ManagedProgramSerializer(CustomModelSerializer): @@ -1382,19 +1404,20 @@ class Meta: -class LogCommandSerializer(_EELogCommandSerializer): - """Thin Wrapper — EE impl: taurus_ee.serializers.log_ext_center._EELogCommandSerializer""" - pass +if _EE_LOG_EXT_OK: + class LogCommandSerializer(_EELogCommandSerializer): + """Thin Wrapper — EE impl: taurus_ee.serializers.log_ext_center._EELogCommandSerializer""" + pass -class LogCommandCreateSerializer(_EELogCommandCreateSerializer): - """Thin Wrapper — EE impl: taurus_ee.serializers.log_ext_center._EELogCommandCreateSerializer""" - pass + class LogCommandCreateSerializer(_EELogCommandCreateSerializer): + """Thin Wrapper — EE impl: taurus_ee.serializers.log_ext_center._EELogCommandCreateSerializer""" + pass -class LogCommandUpdateSerializer(_EELogCommandUpdateSerializer): - """Thin Wrapper (NEW M2.5) — EE impl: taurus_ee.serializers.log_ext_center._EELogCommandUpdateSerializer""" - pass + class LogCommandUpdateSerializer(_EELogCommandUpdateSerializer): + """Thin Wrapper (NEW M2.5) — EE impl: taurus_ee.serializers.log_ext_center._EELogCommandUpdateSerializer""" + pass @@ -1661,7 +1684,9 @@ def get_duration(self, obj): _EEOpsExecutionApprovalCreateSerializer, _EEOpsExecutionApprovalActionSerializer, ) + _EE_OPS_APPROVAL_OK = True except ImportError: + _EE_OPS_APPROVAL_OK = False from taurus.ee_fallback import _EEFallbackSerializer as _FBSer class _EEOpsExecutionApprovalActionSerializer(_FBSer): pass class _EEOpsExecutionApprovalCreateSerializer(_FBSer): pass @@ -1669,10 +1694,11 @@ class _EEOpsExecutionApprovalListSerializer(_FBSer): pass class _EEOpsExecutionApprovalSerializer(_FBSer): pass -class OpsExecutionApprovalSerializer(_EEOpsExecutionApprovalSerializer): pass -class OpsExecutionApprovalListSerializer(_EEOpsExecutionApprovalListSerializer): pass -class OpsExecutionApprovalCreateSerializer(_EEOpsExecutionApprovalCreateSerializer): pass -class OpsExecutionApprovalActionSerializer(_EEOpsExecutionApprovalActionSerializer): pass +if _EE_OPS_APPROVAL_OK: + class OpsExecutionApprovalSerializer(_EEOpsExecutionApprovalSerializer): pass + class OpsExecutionApprovalListSerializer(_EEOpsExecutionApprovalListSerializer): pass + class OpsExecutionApprovalCreateSerializer(_EEOpsExecutionApprovalCreateSerializer): pass + class OpsExecutionApprovalActionSerializer(_EEOpsExecutionApprovalActionSerializer): pass # ========================== ScriptlibrarySerializationserver ========================== @@ -2134,10 +2160,16 @@ def get_host_summary(self, obj) -> dict: # Script* EE 系列 Thin Wrapper(实现在 taurus_ee.serializers.*) # 保留原名:taurus/urls.py + views.py 中 `from taurus.serializers import X` # 所有旧引用保持 0 改动。 +# +# 防御性修复:所有 try/except 均引入 _*_OK 标志位,仅在 EE 导入成功时才重新定义类。 +# 否则不产生 class 重新定义(这些 Serializer 本就只能在 EE-gated 路径下实例化; +# 若强行实例化会报 NameError,但这比 Meta.model=None 静默抛 AttributeError 好诊断)。 # ================================================================ try: from taurus_ee.serializers.script_audit import ScriptAuditSerializer as _EEScriptAuditSerializer + _EE_SCRIPT_AUDIT_OK = True except ImportError: + _EE_SCRIPT_AUDIT_OK = False from taurus.ee_fallback import _EEFallbackSerializer as _FBSer class _EEScriptAuditSerializer(_FBSer): pass @@ -2149,7 +2181,9 @@ class _EEScriptAuditSerializer(_FBSer): pass ScriptApprovalInstanceSerializer as _EEScriptApprovalInstanceSerializer, ScriptApprovalNodeExecutionSerializer as _EEScriptApprovalNodeExecutionSerializer, ) + _EE_SCRIPT_APPROVAL_OK = True except ImportError: + _EE_SCRIPT_APPROVAL_OK = False from taurus.ee_fallback import _EEFallbackSerializer as _FBSer class _EEScriptApprovalInstanceSerializer(_FBSer): pass class _EEScriptApprovalNodeExecutionSerializer(_FBSer): pass @@ -2159,7 +2193,9 @@ class _EEScriptApproveSerializer(_FBSer): pass try: from taurus_ee.serializers.script_check import ScriptCheckRuleSerializer as _EEScriptCheckRuleSerializer + _EE_SCRIPT_CHECK_OK = True except ImportError: + _EE_SCRIPT_CHECK_OK = False from taurus.ee_fallback import _EEFallbackSerializer as _FBSer class _EEScriptCheckRuleSerializer(_FBSer): pass @@ -2173,7 +2209,9 @@ class _EEScriptCheckRuleSerializer(_FBSer): pass ShareLinkActivateSerializer as _EEShareLinkActivateSerializer, ShareLinkAccessLogSerializer as _EEShareLinkAccessLogSerializer, ) + _EE_SHARE_PERM_OK = True except ImportError: + _EE_SHARE_PERM_OK = False from taurus.ee_fallback import _EEFallbackSerializer as _FBSer class _EEScriptSharePermissionSerializer(_FBSer): pass class _EEShareLinkAccessLogSerializer(_FBSer): pass @@ -2184,63 +2222,67 @@ class _EESharePermissionDefSerializer(_FBSer): pass class _EEWorkflowSharePermissionSerializer(_FBSer): pass -class ScriptAuditSerializer(_EEScriptAuditSerializer): - """Thin Wrapper → taurus_ee.serializers.script_audit.ScriptAuditSerializer""" - pass +if _EE_SCRIPT_AUDIT_OK: + class ScriptAuditSerializer(_EEScriptAuditSerializer): + """Thin Wrapper → taurus_ee.serializers.script_audit.ScriptAuditSerializer""" + pass -class ScriptApproveSerializer(_EEScriptApproveSerializer): - """Thin Wrapper.""" - pass +if _EE_SCRIPT_APPROVAL_OK: + class ScriptApproveSerializer(_EEScriptApproveSerializer): + """Thin Wrapper.""" + pass -class ScriptApprovalRuleSerializer(_EEScriptApprovalRuleSerializer): - pass + class ScriptApprovalRuleSerializer(_EEScriptApprovalRuleSerializer): + pass -class ScriptApprovalNodeSerializer(_EEScriptApprovalNodeSerializer): - pass + class ScriptApprovalNodeSerializer(_EEScriptApprovalNodeSerializer): + pass -class ScriptApprovalInstanceSerializer(_EEScriptApprovalInstanceSerializer): - pass + class ScriptApprovalInstanceSerializer(_EEScriptApprovalInstanceSerializer): + pass -class ScriptApprovalNodeExecutionSerializer(_EEScriptApprovalNodeExecutionSerializer): - pass + class ScriptApprovalNodeExecutionSerializer(_EEScriptApprovalNodeExecutionSerializer): + pass -class ScriptCheckRuleSerializer(_EEScriptCheckRuleSerializer): - pass +if _EE_SCRIPT_CHECK_OK: + class ScriptCheckRuleSerializer(_EEScriptCheckRuleSerializer): + pass # ---------------- share permission Thin Wrappers ---------------- -class SharePermissionDefSerializer(_EESharePermissionDefSerializer): - pass +if _EE_SHARE_PERM_OK: + class SharePermissionDefSerializer(_EESharePermissionDefSerializer): + pass -class ScriptSharePermissionSerializer(_EEScriptSharePermissionSerializer): - pass + class ScriptSharePermissionSerializer(_EEScriptSharePermissionSerializer): + pass -class WorkflowSharePermissionSerializer(_EEWorkflowSharePermissionSerializer): - pass + class WorkflowSharePermissionSerializer(_EEWorkflowSharePermissionSerializer): + pass -class SharePermissionBatchCreateSerializer(_EESharePermissionBatchCreateSerializer): - pass + class SharePermissionBatchCreateSerializer(_EESharePermissionBatchCreateSerializer): + pass -class ShareLinkSerializer(_EEShareLinkSerializer): - pass + class ShareLinkSerializer(_EEShareLinkSerializer): + pass -class ShareLinkActivateSerializer(_EEShareLinkActivateSerializer): - pass + class ShareLinkActivateSerializer(_EEShareLinkActivateSerializer): + pass -class ShareLinkAccessLogSerializer(_EEShareLinkAccessLogSerializer): - pass + class ShareLinkAccessLogSerializer(_EEShareLinkAccessLogSerializer): + pass # ================================================================ @@ -2248,8 +2290,9 @@ class ShareLinkAccessLogSerializer(_EEShareLinkAccessLogSerializer): # Thin Wrapper 提前覆盖,此处不再保留,避免与继承 EE 的版本双定义。 # 原 class ScriptApproveSerializer -> model = ScriptApprove 由 EE Meta 继承保证。 # ================================================================ -class ScriptApproveSerializer(_EEScriptApproveSerializer): # noqa: F811 - """(Double re-declare 仅兼容,与上方 Thin Wrapper 等价。)""" +if _EE_SCRIPT_APPROVAL_OK: + class ScriptApproveSerializer(_EEScriptApproveSerializer): # noqa: F811 + """(Double re-declare 仅兼容,与上方 Thin Wrapper 等价。)""" # 保留 Meta 注释以展示老代码模型 # model = ScriptApprove (已在 EE 版 Meta 中定义) pass @@ -2292,7 +2335,9 @@ class _LegacyMetaAnchor_ScriptApprove: # Never used WorkflowApprovalInstanceSerializer as _EEWorkflowApprovalInstanceSerializer, WorkflowApprovalNodeExecutionSerializer as _EEWorkflowApprovalNodeExecutionSerializer, ) + _EE_WF_APPROVAL_OK = True except ImportError: + _EE_WF_APPROVAL_OK = False from taurus.ee_fallback import _EEFallbackSerializer as _FBSer class _EEWorkflowApprovalInstanceSerializer(_FBSer): pass class _EEWorkflowApprovalNodeExecutionSerializer(_FBSer): pass @@ -2305,15 +2350,16 @@ class _EEWorkflowApproveRejectSerializer(_FBSer): pass class _EEWorkflowApproveSerializer(_FBSer): pass -class WorkflowApproveSerializer(_EEWorkflowApproveSerializer): pass -class WorkflowApproveCreateSerializer(_EEWorkflowApproveCreateSerializer): pass -class WorkflowApproveApproveSerializer(_EEWorkflowApproveApproveSerializer): pass -class WorkflowApproveRejectSerializer(_EEWorkflowApproveRejectSerializer): pass -class WorkflowApproveCompatSerializer(_EEWorkflowApproveCompatSerializer): pass -class WorkflowApprovalRuleSerializer(_EEWorkflowApprovalRuleSerializer): pass -class WorkflowApprovalNodeSerializer(_EEWorkflowApprovalNodeSerializer): pass -class WorkflowApprovalInstanceSerializer(_EEWorkflowApprovalInstanceSerializer): pass -class WorkflowApprovalNodeExecutionSerializer(_EEWorkflowApprovalNodeExecutionSerializer): pass +if _EE_WF_APPROVAL_OK: + class WorkflowApproveSerializer(_EEWorkflowApproveSerializer): pass + class WorkflowApproveCreateSerializer(_EEWorkflowApproveCreateSerializer): pass + class WorkflowApproveApproveSerializer(_EEWorkflowApproveApproveSerializer): pass + class WorkflowApproveRejectSerializer(_EEWorkflowApproveRejectSerializer): pass + class WorkflowApproveCompatSerializer(_EEWorkflowApproveCompatSerializer): pass + class WorkflowApprovalRuleSerializer(_EEWorkflowApprovalRuleSerializer): pass + class WorkflowApprovalNodeSerializer(_EEWorkflowApprovalNodeSerializer): pass + class WorkflowApprovalInstanceSerializer(_EEWorkflowApprovalInstanceSerializer): pass + class WorkflowApprovalNodeExecutionSerializer(_EEWorkflowApprovalNodeExecutionSerializer): pass # ============================================================ @@ -2343,7 +2389,9 @@ class TaskCenterItemSerializer(_EETaskCenterItemSerializer): UnifiedScheduleStatsSerializer as _EEUnifiedScheduleStatsSerializer, SchedulerAlertEventSerializer as _EESchedulerAlertEventSerializer, ) + _EE_SCHEDULER_HA_OK = True except ImportError: + _EE_SCHEDULER_HA_OK = False from taurus.ee_fallback import _EEFallbackSerializer as _FBSer class _EEScheduleExecutionHASerializer(_FBSer): pass class _EESchedulerAlertEventSerializer(_FBSer): pass @@ -2353,62 +2401,70 @@ class _EEUnifiedScheduleListRequestSerializer(_FBSer): pass class _EEUnifiedScheduleStatsSerializer(_FBSer): pass -class ScheduleExecutionHASerializer(_EEScheduleExecutionHASerializer): - """Thin Wrapper — EE 实现: taurus_ee.serializers.scheduler_ha""" - pass +if _EE_SCHEDULER_HA_OK: + class ScheduleExecutionHASerializer(_EEScheduleExecutionHASerializer): + """Thin Wrapper — EE 实现: taurus_ee.serializers.scheduler_ha""" + pass -class ScriptTaskExecutionUnifiedSerializer(_EEScriptTaskExecutionUnifiedSerializer): - """Thin Wrapper — EE 实现: taurus_ee.serializers.scheduler_ha""" - pass + class ScriptTaskExecutionUnifiedSerializer(_EEScriptTaskExecutionUnifiedSerializer): + """Thin Wrapper — EE 实现: taurus_ee.serializers.scheduler_ha""" + pass -class SchedulerAlertRuleSerializer(_EESchedulerAlertRuleSerializer): - """Thin Wrapper — EE 实现: taurus_ee.serializers.scheduler_ha""" - pass + class SchedulerAlertRuleSerializer(_EESchedulerAlertRuleSerializer): + """Thin Wrapper — EE 实现: taurus_ee.serializers.scheduler_ha""" + pass -class UnifiedScheduleListRequestSerializer(_EEUnifiedScheduleListRequestSerializer): - """Thin Wrapper — EE 实现: taurus_ee.serializers.scheduler_ha""" - pass + class UnifiedScheduleListRequestSerializer(_EEUnifiedScheduleListRequestSerializer): + """Thin Wrapper — EE 实现: taurus_ee.serializers.scheduler_ha""" + pass -class UnifiedScheduleStatsSerializer(_EEUnifiedScheduleStatsSerializer): - """Thin Wrapper — EE 实现: taurus_ee.serializers.scheduler_ha""" - pass + class UnifiedScheduleStatsSerializer(_EEUnifiedScheduleStatsSerializer): + """Thin Wrapper — EE 实现: taurus_ee.serializers.scheduler_ha""" + pass -class SchedulerAlertEventSerializer(_EESchedulerAlertEventSerializer): - """Thin Wrapper — EE 实现: taurus_ee.serializers.scheduler_ha""" - pass + class SchedulerAlertEventSerializer(_EESchedulerAlertEventSerializer): + """Thin Wrapper — EE 实现: taurus_ee.serializers.scheduler_ha""" + pass -class ContactLeadSerializer(_EEContactLeadSerializer): - """Thin Wrapper — EE impl: taurus_ee.serializers.log_ext_center._EEContactLeadSerializer""" - pass +# ContactLead & 6 Placeholder 与 M2.5 log_ext_center 同组导入,共用 _EE_LOG_EXT_OK +if _EE_LOG_EXT_OK: + class TaskCenterItemSerializer(_EETaskCenterItemSerializer): + """Thin Wrapper — EE impl: taurus_ee.serializers.log_ext_center._EETaskCenterItemSerializer""" + pass -# -------- 6 extension center placeholder Ser (M2.5 EE 空壳) -------- -class KnowledgeBasePlaceholderSerializer(_EEKnowledgeBasePlaceholderSerializer): - """Thin Wrapper — 知识库占位(M2.5 EE 空壳)""" - pass + class ContactLeadSerializer(_EEContactLeadSerializer): + """Thin Wrapper — EE impl: taurus_ee.serializers.log_ext_center._EEContactLeadSerializer""" + pass -class InspectionCenterPlaceholderSerializer(_EEInspectionCenterPlaceholderSerializer): - """Thin Wrapper — 巡检中心占位(M2.5 EE 空壳)""" - pass + # -------- 6 extension center placeholder Ser (M2.5 EE 空壳) -------- + class KnowledgeBasePlaceholderSerializer(_EEKnowledgeBasePlaceholderSerializer): + """Thin Wrapper — 知识库占位(M2.5 EE 空壳)""" + pass -class ToolsCenterPlaceholderSerializer(_EEToolsCenterPlaceholderSerializer): - """Thin Wrapper — 工具中心占位(M2.5 EE 空壳)""" - pass + class InspectionCenterPlaceholderSerializer(_EEInspectionCenterPlaceholderSerializer): + """Thin Wrapper — 巡检中心占位(M2.5 EE 空壳)""" + pass -class BackupRestoreCenterPlaceholderSerializer(_EEBackupRestoreCenterPlaceholderSerializer): - """Thin Wrapper — 备份恢复中心占位(M2.5 EE 空壳)""" - pass + class ToolsCenterPlaceholderSerializer(_EEToolsCenterPlaceholderSerializer): + """Thin Wrapper — 工具中心占位(M2.5 EE 空壳)""" + pass + + + class BackupRestoreCenterPlaceholderSerializer(_EEBackupRestoreCenterPlaceholderSerializer): + """Thin Wrapper — 备份恢复中心占位(M2.5 EE 空壳)""" + pass -class DownloadCenterPlaceholderSerializer(_EEDownloadCenterPlaceholderSerializer): - """Thin Wrapper — 客户端打包下载中心占位(M2.5 EE 空壳)""" - pass \ No newline at end of file + class DownloadCenterPlaceholderSerializer(_EEDownloadCenterPlaceholderSerializer): + """Thin Wrapper — 客户端打包下载中心占位(M2.5 EE 空壳)""" + pass \ No newline at end of file From 7afe6a1b155038648da5ab1f203b4bfe89d0b5e1 Mon Sep 17 00:00:00 2001 From: jinweijie Date: Fri, 4 Sep 2026 15:32:48 +0800 Subject: [PATCH 5/5] ``` refactor(serializers): remove conditional guards from EE serializer wrappers Remove _EE_*_OK conditional guards from enterprise edition serializer wrappers in taurus/serializers.py. All thin wrapper classes are now unconditionally defined since they are protected by dispatch-level EE gates that prevent instantiation when EE is not available. The changes ensure consistent behavior across all EE serializers and reduce complexity by removing the need to check import success flags. Classes that were previously conditionally defined are now always defined as thin wrappers extending their EE implementations or fallback serializers when EE imports fail. This affects multiple serializer groups including log center, operations approval, script audit/approval/check, share permissions, workflow approvals, and scheduler HA components. ``` --- taurus/serializers.py | 249 +++++++++++++++++++----------------------- 1 file changed, 113 insertions(+), 136 deletions(-) diff --git a/taurus/serializers.py b/taurus/serializers.py index 02ef748..e848fb8 100644 --- a/taurus/serializers.py +++ b/taurus/serializers.py @@ -1342,9 +1342,11 @@ class ProgramInstallPolicyUpdateSerializer(_EE_PIP_UpdateSer): pass # noqa: E70 # ------------------ [M2.5 Thin Wrapper] HostLog & LogCommand (log center EE) ------------------ -# 这些 Serializer 是 EE 专属功能(HostLogViewSet / LogCommandViewSet / TaskCenterViewSet -# 等均带 dispatch EE Gate),但仍然加 _EE_OK 守卫,避免未来有人绕过 gate 直接使用 -# 时踩到 _EEFallbackSerializer 的 Meta.model=None 问题。 +# 注意:这些 Serializer 均被 taurus/views.py 顶层 `from taurus.serializers import X` 导入, +# 因此 class 名称必须始终存在(否则 ImportError)。好在 HostLogViewSet / LogCommandViewSet / +# TaskCenterViewSet 等都带 dispatch 级 EE Gate(403 拦截),即使 EE 缺失时 Thin Wrapper +# 继承 Meta.model=None 的 _EEFallbackSerializer 也不会真正走到 Serializer 实例化。 +# 因此这里不使用 if-guard 做 class 重定义覆盖,直接无条件 Thin Wrapper 即可。 try: from taurus_ee.serializers.log_ext_center import ( _EEHostLogSerializer, @@ -1360,9 +1362,7 @@ class ProgramInstallPolicyUpdateSerializer(_EE_PIP_UpdateSer): pass # noqa: E70 _EEBackupRestoreCenterPlaceholderSerializer, _EEDownloadCenterPlaceholderSerializer, ) - _EE_LOG_EXT_OK = True except ImportError: - _EE_LOG_EXT_OK = False from taurus.ee_fallback import _EEFallbackSerializer as _FBSer class _EEBackupRestoreCenterPlaceholderSerializer(_FBSer): pass class _EEContactLeadSerializer(_FBSer): pass @@ -1378,15 +1378,14 @@ class _EETaskCenterItemSerializer(_FBSer): pass class _EEToolsCenterPlaceholderSerializer(_FBSer): pass -if _EE_LOG_EXT_OK: - class HostLogSerializer(_EEHostLogSerializer): - """Thin Wrapper — EE impl: taurus_ee.serializers.log_ext_center._EEHostLogSerializer""" - pass +class HostLogSerializer(_EEHostLogSerializer): + """Thin Wrapper — EE impl: taurus_ee.serializers.log_ext_center._EEHostLogSerializer""" + pass - class HostLogReceiveSerializer(_EEHostLogReceiveSerializer): - """Thin Wrapper — EE impl: taurus_ee.serializers.log_ext_center._EEHostLogReceiveSerializer""" - pass +class HostLogReceiveSerializer(_EEHostLogReceiveSerializer): + """Thin Wrapper — EE impl: taurus_ee.serializers.log_ext_center._EEHostLogReceiveSerializer""" + pass class ManagedProgramSerializer(CustomModelSerializer): @@ -1404,20 +1403,20 @@ class Meta: -if _EE_LOG_EXT_OK: - class LogCommandSerializer(_EELogCommandSerializer): - """Thin Wrapper — EE impl: taurus_ee.serializers.log_ext_center._EELogCommandSerializer""" - pass + +class LogCommandSerializer(_EELogCommandSerializer): + """Thin Wrapper — EE impl: taurus_ee.serializers.log_ext_center._EELogCommandSerializer""" + pass - class LogCommandCreateSerializer(_EELogCommandCreateSerializer): - """Thin Wrapper — EE impl: taurus_ee.serializers.log_ext_center._EELogCommandCreateSerializer""" - pass +class LogCommandCreateSerializer(_EELogCommandCreateSerializer): + """Thin Wrapper — EE impl: taurus_ee.serializers.log_ext_center._EELogCommandCreateSerializer""" + pass - class LogCommandUpdateSerializer(_EELogCommandUpdateSerializer): - """Thin Wrapper (NEW M2.5) — EE impl: taurus_ee.serializers.log_ext_center._EELogCommandUpdateSerializer""" - pass +class LogCommandUpdateSerializer(_EELogCommandUpdateSerializer): + """Thin Wrapper (NEW M2.5) — EE impl: taurus_ee.serializers.log_ext_center._EELogCommandUpdateSerializer""" + pass @@ -1677,6 +1676,9 @@ def get_duration(self, obj): # ========================== Execution Task Approval Serializers (Thin Wrapper, 真实实现迁 taurus_ee.serializers.ops_approval) ========================== +# 注意:OpsExecutionApproval 四个 Serializer 均被 taurus/views.py 顶层 `from taurus.serializers import X` +# 导入,因此 class 名称必须始终存在(否则 ImportError)。相关 ViewSet 均带 dispatch 级 EE Gate +# (403 拦截),EE 缺失时 Thin Wrapper 继承 Meta.model=None 的 fallback 也不会走到实例化。 try: from taurus_ee.serializers.ops_approval import ( _EEOpsExecutionApprovalSerializer, @@ -1684,9 +1686,7 @@ def get_duration(self, obj): _EEOpsExecutionApprovalCreateSerializer, _EEOpsExecutionApprovalActionSerializer, ) - _EE_OPS_APPROVAL_OK = True except ImportError: - _EE_OPS_APPROVAL_OK = False from taurus.ee_fallback import _EEFallbackSerializer as _FBSer class _EEOpsExecutionApprovalActionSerializer(_FBSer): pass class _EEOpsExecutionApprovalCreateSerializer(_FBSer): pass @@ -1694,11 +1694,10 @@ class _EEOpsExecutionApprovalListSerializer(_FBSer): pass class _EEOpsExecutionApprovalSerializer(_FBSer): pass -if _EE_OPS_APPROVAL_OK: - class OpsExecutionApprovalSerializer(_EEOpsExecutionApprovalSerializer): pass - class OpsExecutionApprovalListSerializer(_EEOpsExecutionApprovalListSerializer): pass - class OpsExecutionApprovalCreateSerializer(_EEOpsExecutionApprovalCreateSerializer): pass - class OpsExecutionApprovalActionSerializer(_EEOpsExecutionApprovalActionSerializer): pass +class OpsExecutionApprovalSerializer(_EEOpsExecutionApprovalSerializer): pass +class OpsExecutionApprovalListSerializer(_EEOpsExecutionApprovalListSerializer): pass +class OpsExecutionApprovalCreateSerializer(_EEOpsExecutionApprovalCreateSerializer): pass +class OpsExecutionApprovalActionSerializer(_EEOpsExecutionApprovalActionSerializer): pass # ========================== ScriptlibrarySerializationserver ========================== @@ -2161,15 +2160,17 @@ def get_host_summary(self, obj) -> dict: # 保留原名:taurus/urls.py + views.py 中 `from taurus.serializers import X` # 所有旧引用保持 0 改动。 # -# 防御性修复:所有 try/except 均引入 _*_OK 标志位,仅在 EE 导入成功时才重新定义类。 -# 否则不产生 class 重新定义(这些 Serializer 本就只能在 EE-gated 路径下实例化; -# 若强行实例化会报 NameError,但这比 Meta.model=None 静默抛 AttributeError 好诊断)。 +# 策略:这些 Serializer 绝大多数为 EE 专属、由 dispatch 级 EE Gate 保护(403 拦截); +# 少数(SharePermissionDefSerializer 等 4 个 + TaskCenterItemSerializer)被 views.py +# 顶层 `from taurus.serializers import X` 导入,因此 class 名称必须始终存在(否则 ImportError)。 +# 为保持一致性与最小风险,本块所有 Thin Wrapper 一律无条件定义(移除 _EE_*_OK 守卫), +# EE 缺失时继承 Meta.model=None 的 fallback 类不会真正走到 Serializer 实例化。 +# 只有 M2.4(ProgramCommand 等已有 CE 基础类)与 WorkflowDAGVersion 保留守卫, +# 目的是"不要覆盖掉原本就存在的正确 CE 类定义(含真实 Meta.model)"。 # ================================================================ try: from taurus_ee.serializers.script_audit import ScriptAuditSerializer as _EEScriptAuditSerializer - _EE_SCRIPT_AUDIT_OK = True except ImportError: - _EE_SCRIPT_AUDIT_OK = False from taurus.ee_fallback import _EEFallbackSerializer as _FBSer class _EEScriptAuditSerializer(_FBSer): pass @@ -2181,9 +2182,7 @@ class _EEScriptAuditSerializer(_FBSer): pass ScriptApprovalInstanceSerializer as _EEScriptApprovalInstanceSerializer, ScriptApprovalNodeExecutionSerializer as _EEScriptApprovalNodeExecutionSerializer, ) - _EE_SCRIPT_APPROVAL_OK = True except ImportError: - _EE_SCRIPT_APPROVAL_OK = False from taurus.ee_fallback import _EEFallbackSerializer as _FBSer class _EEScriptApprovalInstanceSerializer(_FBSer): pass class _EEScriptApprovalNodeExecutionSerializer(_FBSer): pass @@ -2193,9 +2192,7 @@ class _EEScriptApproveSerializer(_FBSer): pass try: from taurus_ee.serializers.script_check import ScriptCheckRuleSerializer as _EEScriptCheckRuleSerializer - _EE_SCRIPT_CHECK_OK = True except ImportError: - _EE_SCRIPT_CHECK_OK = False from taurus.ee_fallback import _EEFallbackSerializer as _FBSer class _EEScriptCheckRuleSerializer(_FBSer): pass @@ -2209,9 +2206,7 @@ class _EEScriptCheckRuleSerializer(_FBSer): pass ShareLinkActivateSerializer as _EEShareLinkActivateSerializer, ShareLinkAccessLogSerializer as _EEShareLinkAccessLogSerializer, ) - _EE_SHARE_PERM_OK = True except ImportError: - _EE_SHARE_PERM_OK = False from taurus.ee_fallback import _EEFallbackSerializer as _FBSer class _EEScriptSharePermissionSerializer(_FBSer): pass class _EEShareLinkAccessLogSerializer(_FBSer): pass @@ -2222,67 +2217,63 @@ class _EESharePermissionDefSerializer(_FBSer): pass class _EEWorkflowSharePermissionSerializer(_FBSer): pass -if _EE_SCRIPT_AUDIT_OK: - class ScriptAuditSerializer(_EEScriptAuditSerializer): - """Thin Wrapper → taurus_ee.serializers.script_audit.ScriptAuditSerializer""" - pass +class ScriptAuditSerializer(_EEScriptAuditSerializer): + """Thin Wrapper → taurus_ee.serializers.script_audit.ScriptAuditSerializer""" + pass -if _EE_SCRIPT_APPROVAL_OK: - class ScriptApproveSerializer(_EEScriptApproveSerializer): - """Thin Wrapper.""" - pass +class ScriptApproveSerializer(_EEScriptApproveSerializer): + """Thin Wrapper.""" + pass - class ScriptApprovalRuleSerializer(_EEScriptApprovalRuleSerializer): - pass +class ScriptApprovalRuleSerializer(_EEScriptApprovalRuleSerializer): + pass - class ScriptApprovalNodeSerializer(_EEScriptApprovalNodeSerializer): - pass +class ScriptApprovalNodeSerializer(_EEScriptApprovalNodeSerializer): + pass - class ScriptApprovalInstanceSerializer(_EEScriptApprovalInstanceSerializer): - pass +class ScriptApprovalInstanceSerializer(_EEScriptApprovalInstanceSerializer): + pass - class ScriptApprovalNodeExecutionSerializer(_EEScriptApprovalNodeExecutionSerializer): - pass +class ScriptApprovalNodeExecutionSerializer(_EEScriptApprovalNodeExecutionSerializer): + pass -if _EE_SCRIPT_CHECK_OK: - class ScriptCheckRuleSerializer(_EEScriptCheckRuleSerializer): - pass +class ScriptCheckRuleSerializer(_EEScriptCheckRuleSerializer): + pass # ---------------- share permission Thin Wrappers ---------------- -if _EE_SHARE_PERM_OK: - class SharePermissionDefSerializer(_EESharePermissionDefSerializer): - pass +class SharePermissionDefSerializer(_EESharePermissionDefSerializer): + pass - class ScriptSharePermissionSerializer(_EEScriptSharePermissionSerializer): - pass +class ScriptSharePermissionSerializer(_EEScriptSharePermissionSerializer): + pass - class WorkflowSharePermissionSerializer(_EEWorkflowSharePermissionSerializer): - pass +class WorkflowSharePermissionSerializer(_EEWorkflowSharePermissionSerializer): + pass - class SharePermissionBatchCreateSerializer(_EESharePermissionBatchCreateSerializer): - pass +class SharePermissionBatchCreateSerializer(_EESharePermissionBatchCreateSerializer): + pass - class ShareLinkSerializer(_EEShareLinkSerializer): - pass +class ShareLinkSerializer(_EEShareLinkSerializer): + pass - class ShareLinkActivateSerializer(_EEShareLinkActivateSerializer): - pass +class ShareLinkActivateSerializer(_EEShareLinkActivateSerializer): + pass - class ShareLinkAccessLogSerializer(_EEShareLinkAccessLogSerializer): - pass +class ShareLinkAccessLogSerializer(_EEShareLinkAccessLogSerializer): + pass # ================================================================ @@ -2290,9 +2281,8 @@ class ShareLinkAccessLogSerializer(_EEShareLinkAccessLogSerializer): # Thin Wrapper 提前覆盖,此处不再保留,避免与继承 EE 的版本双定义。 # 原 class ScriptApproveSerializer -> model = ScriptApprove 由 EE Meta 继承保证。 # ================================================================ -if _EE_SCRIPT_APPROVAL_OK: - class ScriptApproveSerializer(_EEScriptApproveSerializer): # noqa: F811 - """(Double re-declare 仅兼容,与上方 Thin Wrapper 等价。)""" +class ScriptApproveSerializer(_EEScriptApproveSerializer): # noqa: F811 + """(Double re-declare 仅兼容,与上方 Thin Wrapper 等价。)""" # 保留 Meta 注释以展示老代码模型 # model = ScriptApprove (已在 EE 版 Meta 中定义) pass @@ -2335,9 +2325,7 @@ class _LegacyMetaAnchor_ScriptApprove: # Never used WorkflowApprovalInstanceSerializer as _EEWorkflowApprovalInstanceSerializer, WorkflowApprovalNodeExecutionSerializer as _EEWorkflowApprovalNodeExecutionSerializer, ) - _EE_WF_APPROVAL_OK = True except ImportError: - _EE_WF_APPROVAL_OK = False from taurus.ee_fallback import _EEFallbackSerializer as _FBSer class _EEWorkflowApprovalInstanceSerializer(_FBSer): pass class _EEWorkflowApprovalNodeExecutionSerializer(_FBSer): pass @@ -2350,16 +2338,15 @@ class _EEWorkflowApproveRejectSerializer(_FBSer): pass class _EEWorkflowApproveSerializer(_FBSer): pass -if _EE_WF_APPROVAL_OK: - class WorkflowApproveSerializer(_EEWorkflowApproveSerializer): pass - class WorkflowApproveCreateSerializer(_EEWorkflowApproveCreateSerializer): pass - class WorkflowApproveApproveSerializer(_EEWorkflowApproveApproveSerializer): pass - class WorkflowApproveRejectSerializer(_EEWorkflowApproveRejectSerializer): pass - class WorkflowApproveCompatSerializer(_EEWorkflowApproveCompatSerializer): pass - class WorkflowApprovalRuleSerializer(_EEWorkflowApprovalRuleSerializer): pass - class WorkflowApprovalNodeSerializer(_EEWorkflowApprovalNodeSerializer): pass - class WorkflowApprovalInstanceSerializer(_EEWorkflowApprovalInstanceSerializer): pass - class WorkflowApprovalNodeExecutionSerializer(_EEWorkflowApprovalNodeExecutionSerializer): pass +class WorkflowApproveSerializer(_EEWorkflowApproveSerializer): pass +class WorkflowApproveCreateSerializer(_EEWorkflowApproveCreateSerializer): pass +class WorkflowApproveApproveSerializer(_EEWorkflowApproveApproveSerializer): pass +class WorkflowApproveRejectSerializer(_EEWorkflowApproveRejectSerializer): pass +class WorkflowApproveCompatSerializer(_EEWorkflowApproveCompatSerializer): pass +class WorkflowApprovalRuleSerializer(_EEWorkflowApprovalRuleSerializer): pass +class WorkflowApprovalNodeSerializer(_EEWorkflowApprovalNodeSerializer): pass +class WorkflowApprovalInstanceSerializer(_EEWorkflowApprovalInstanceSerializer): pass +class WorkflowApprovalNodeExecutionSerializer(_EEWorkflowApprovalNodeExecutionSerializer): pass # ============================================================ @@ -2389,9 +2376,7 @@ class TaskCenterItemSerializer(_EETaskCenterItemSerializer): UnifiedScheduleStatsSerializer as _EEUnifiedScheduleStatsSerializer, SchedulerAlertEventSerializer as _EESchedulerAlertEventSerializer, ) - _EE_SCHEDULER_HA_OK = True except ImportError: - _EE_SCHEDULER_HA_OK = False from taurus.ee_fallback import _EEFallbackSerializer as _FBSer class _EEScheduleExecutionHASerializer(_FBSer): pass class _EESchedulerAlertEventSerializer(_FBSer): pass @@ -2401,70 +2386,62 @@ class _EEUnifiedScheduleListRequestSerializer(_FBSer): pass class _EEUnifiedScheduleStatsSerializer(_FBSer): pass -if _EE_SCHEDULER_HA_OK: - class ScheduleExecutionHASerializer(_EEScheduleExecutionHASerializer): - """Thin Wrapper — EE 实现: taurus_ee.serializers.scheduler_ha""" - pass - - - class ScriptTaskExecutionUnifiedSerializer(_EEScriptTaskExecutionUnifiedSerializer): - """Thin Wrapper — EE 实现: taurus_ee.serializers.scheduler_ha""" - pass +class ScheduleExecutionHASerializer(_EEScheduleExecutionHASerializer): + """Thin Wrapper — EE 实现: taurus_ee.serializers.scheduler_ha""" + pass - class SchedulerAlertRuleSerializer(_EESchedulerAlertRuleSerializer): - """Thin Wrapper — EE 实现: taurus_ee.serializers.scheduler_ha""" - pass +class ScriptTaskExecutionUnifiedSerializer(_EEScriptTaskExecutionUnifiedSerializer): + """Thin Wrapper — EE 实现: taurus_ee.serializers.scheduler_ha""" + pass - class UnifiedScheduleListRequestSerializer(_EEUnifiedScheduleListRequestSerializer): - """Thin Wrapper — EE 实现: taurus_ee.serializers.scheduler_ha""" - pass +class SchedulerAlertRuleSerializer(_EESchedulerAlertRuleSerializer): + """Thin Wrapper — EE 实现: taurus_ee.serializers.scheduler_ha""" + pass - class UnifiedScheduleStatsSerializer(_EEUnifiedScheduleStatsSerializer): - """Thin Wrapper — EE 实现: taurus_ee.serializers.scheduler_ha""" - pass +class UnifiedScheduleListRequestSerializer(_EEUnifiedScheduleListRequestSerializer): + """Thin Wrapper — EE 实现: taurus_ee.serializers.scheduler_ha""" + pass - class SchedulerAlertEventSerializer(_EESchedulerAlertEventSerializer): - """Thin Wrapper — EE 实现: taurus_ee.serializers.scheduler_ha""" - pass +class UnifiedScheduleStatsSerializer(_EEUnifiedScheduleStatsSerializer): + """Thin Wrapper — EE 实现: taurus_ee.serializers.scheduler_ha""" + pass -# ContactLead & 6 Placeholder 与 M2.5 log_ext_center 同组导入,共用 _EE_LOG_EXT_OK -if _EE_LOG_EXT_OK: - class TaskCenterItemSerializer(_EETaskCenterItemSerializer): - """Thin Wrapper — EE impl: taurus_ee.serializers.log_ext_center._EETaskCenterItemSerializer""" - pass +class SchedulerAlertEventSerializer(_EESchedulerAlertEventSerializer): + """Thin Wrapper — EE 实现: taurus_ee.serializers.scheduler_ha""" + pass - class ContactLeadSerializer(_EEContactLeadSerializer): - """Thin Wrapper — EE impl: taurus_ee.serializers.log_ext_center._EEContactLeadSerializer""" - pass +class ContactLeadSerializer(_EEContactLeadSerializer): + """Thin Wrapper — EE impl: taurus_ee.serializers.log_ext_center._EEContactLeadSerializer""" + pass - # -------- 6 extension center placeholder Ser (M2.5 EE 空壳) -------- - class KnowledgeBasePlaceholderSerializer(_EEKnowledgeBasePlaceholderSerializer): - """Thin Wrapper — 知识库占位(M2.5 EE 空壳)""" - pass +# -------- 6 extension center placeholder Ser (M2.5 EE 空壳) -------- +class KnowledgeBasePlaceholderSerializer(_EEKnowledgeBasePlaceholderSerializer): + """Thin Wrapper — 知识库占位(M2.5 EE 空壳)""" + pass - class InspectionCenterPlaceholderSerializer(_EEInspectionCenterPlaceholderSerializer): - """Thin Wrapper — 巡检中心占位(M2.5 EE 空壳)""" - pass +class InspectionCenterPlaceholderSerializer(_EEInspectionCenterPlaceholderSerializer): + """Thin Wrapper — 巡检中心占位(M2.5 EE 空壳)""" + pass - class ToolsCenterPlaceholderSerializer(_EEToolsCenterPlaceholderSerializer): - """Thin Wrapper — 工具中心占位(M2.5 EE 空壳)""" - pass +class ToolsCenterPlaceholderSerializer(_EEToolsCenterPlaceholderSerializer): + """Thin Wrapper — 工具中心占位(M2.5 EE 空壳)""" + pass - class BackupRestoreCenterPlaceholderSerializer(_EEBackupRestoreCenterPlaceholderSerializer): - """Thin Wrapper — 备份恢复中心占位(M2.5 EE 空壳)""" - pass +class BackupRestoreCenterPlaceholderSerializer(_EEBackupRestoreCenterPlaceholderSerializer): + """Thin Wrapper — 备份恢复中心占位(M2.5 EE 空壳)""" + pass - class DownloadCenterPlaceholderSerializer(_EEDownloadCenterPlaceholderSerializer): - """Thin Wrapper — 客户端打包下载中心占位(M2.5 EE 空壳)""" - pass \ No newline at end of file +class DownloadCenterPlaceholderSerializer(_EEDownloadCenterPlaceholderSerializer): + """Thin Wrapper — 客户端打包下载中心占位(M2.5 EE 空壳)""" + pass \ No newline at end of file