From ab7314943266cbed57f9f68df74c67583f9f0fb5 Mon Sep 17 00:00:00 2001 From: actiontech-zihan Date: Wed, 6 May 2026 04:25:44 +0000 Subject: [PATCH 1/2] =?UTF-8?q?feat(data=5Fmasking):=20=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E8=87=AA=E5=AE=9A=E4=B9=89=E8=84=B1=E6=95=8F=E8=A7=84=E5=88=99?= =?UTF-8?q?=20-=20CE=20API=E7=B1=BB=E5=9E=8B=E4=B8=8EMock=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=20#800?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增自定义脱敏规则相关前端API client函数和Mock数据: - 扩展Masking API service支持规则CRUD、敏感类型管理等接口 - 新增对应的TypeScript类型定义 - 新增测试Mock数据和Mock API --- .../lib/api/base/service/Masking/index.d.ts | 317 ++++++++++++++ .../lib/api/base/service/Masking/index.ts | 238 +++++++++- .../lib/testUtil/mockApi/base/masking/data.ts | 407 ++++++++++++++++++ .../testUtil/mockApi/base/masking/index.ts | 237 ++++++++++ 4 files changed, 1198 insertions(+), 1 deletion(-) create mode 100644 packages/shared/lib/testUtil/mockApi/base/masking/data.ts create mode 100644 packages/shared/lib/testUtil/mockApi/base/masking/index.ts diff --git a/packages/shared/lib/api/base/service/Masking/index.d.ts b/packages/shared/lib/api/base/service/Masking/index.d.ts index f75855f95..bf6ac0de4 100644 --- a/packages/shared/lib/api/base/service/Masking/index.d.ts +++ b/packages/shared/lib/api/base/service/Masking/index.d.ts @@ -189,3 +189,320 @@ export interface IDeleteMaskingTemplateParams { export interface IDeleteMaskingTemplateReturn extends IDeleteMaskingTemplateReply {} + +export interface IListMaskingRulesV2Params { + project_uid: string; + + source?: string; + + keywords?: string; + + page_size?: number; + + page_index?: number; +} + +export interface IListMaskingRulesV2Data { + id?: number; + + name?: string; + + source?: string; + + sensitive_type_name?: string; + + sensitive_type_info?: string; + + is_custom_type?: boolean; + + algorithm_type?: string; + + description?: string; + + effect?: string; + + effect_example_before?: string; + + effect_example_after?: string; +} + +export interface IListMaskingRulesV2Return { + code?: number; + + message?: string; + + data?: IListMaskingRulesV2Data[]; + + total_nums?: number; +} + +export interface ICustomRuleMaskingAlgorithm { + masking_algorithm_name: string; + + mask_type: string; + + value?: string; + + offset?: number; + + padding?: number; + + length?: number; + + reverse?: boolean; + + ignore_char_set?: string; +} + +export interface IAddCustomMaskingRuleParams { + project_uid: string; + + rule: { + name: string; + description?: string; + sensitive_data_type_uid: string; + masking_algorithm_config: ICustomRuleMaskingAlgorithm; + }; +} + +export interface IAddCustomMaskingRuleReturn { + code?: number; + + message?: string; + + data?: { + rule_id?: number; + }; +} + +export interface IUpdateCustomMaskingRuleParams { + project_uid: string; + + rule_id: number; + + rule: { + name: string; + description?: string; + masking_algorithm_config?: ICustomRuleMaskingAlgorithm; + }; +} + +export interface IUpdateCustomMaskingRuleReturn { + code?: number; + + message?: string; +} + +export interface IDeleteCustomMaskingRuleParams { + project_uid: string; + + rule_id: number; +} + +export interface IDeleteCustomMaskingRuleReturn { + code?: number; + + message?: string; +} + +export interface IListSensitiveTypesParams { + project_uid: string; +} + +export interface ISensitiveTypeData { + id?: number; + + sensitive_data_type_source?: string; + + en_identifier?: string; + + cn_name?: string; + + field_keywords?: string[]; + + sample_data_regex_list?: string[]; + + sample_data_list?: string[]; + + rule_count?: number; +} + +export interface IListSensitiveTypesReturn { + code?: number; + + message?: string; + + data?: ISensitiveTypeData[]; +} + +export interface IPreviewMaskingEffectParams { + project_uid: string; + + sample_input_list: string[]; + + masking_algorithm_config: ICustomRuleMaskingAlgorithm; +} + +export interface IPreviewMaskingEffectReturn { + code?: number; + + message?: string; + + data?: { + masked_output_list?: string[]; + }; +} + +export interface IGetMaskingRuleDetailParams { + project_uid: string; + + rule_id: number; +} + +export interface IGetMaskingRuleDetailData { + rule_id?: number; + + name?: string; + + description?: string; + + sensitive_data_type?: ISensitiveTypeData; + + masking_algorithm_config?: ICustomRuleMaskingAlgorithm; +} + +export interface IGetMaskingRuleDetailReturn { + code?: number; + + message?: string; + + data?: IGetMaskingRuleDetailData; +} + +export interface INewCustomSensitiveType { + cn_name: string; + + en_identifier: string; + + field_keywords?: string[]; + + sample_data_regex_list?: string[]; + + sample_data_list?: string[]; +} + +export interface IAddSensitiveDataTypeParams { + project_uid: string; + + type: INewCustomSensitiveType; +} + +export interface IAddSensitiveDataTypeReturn { + code?: number; + + message?: string; + + data?: { + sensitive_data_type_id?: number; + }; +} + +export interface IUpdateSensitiveDataTypeData { + field_keywords?: string[]; + + sample_data_regex_list?: string[]; + + sample_data_list?: string[]; +} + +export interface IUpdateSensitiveDataTypeParams { + project_uid: string; + + sensitive_data_type_id: number; + + type: IUpdateSensitiveDataTypeData; +} + +export interface IUpdateSensitiveDataTypeReturn { + code?: number; + + message?: string; +} + +export interface IDeleteSensitiveDataTypeParams { + project_uid: string; + + sensitive_data_type_id: number; +} + +export interface IDeleteSensitiveDataTypeReturn { + code?: number; + + message?: string; +} + +export interface ITestSensitiveDataTypeMatchParams { + project_uid: string; + + sensitive_data_type_id?: number; + + field_keywords?: string[]; + + sample_data_regex_list?: string[]; + + sample_values: string[]; +} + +export interface ISensitiveDataTypeMatchResult { + value?: string; + + matched?: boolean; +} + +export interface ITestSensitiveDataTypeMatchReturn { + code?: number; + + message?: string; + + data?: { + results?: ISensitiveDataTypeMatchResult[]; + }; +} + +export interface IListDBServiceSchemasForMaskingTaskParams { + project_uid: string; + + db_service_uid: string; +} + +export interface IDBServiceSchemaData { + name?: string; +} + +export interface IListDBServiceSchemasForMaskingTaskReturn { + code?: number; + + message?: string; + + data?: IDBServiceSchemaData[]; +} + +export interface IListDBServiceTablesForMaskingTaskParams { + project_uid: string; + + db_service_uid: string; + + schema_name: string; +} + +export interface IDBServiceTableData { + name?: string; +} + +export interface IListDBServiceTablesForMaskingTaskReturn { + code?: number; + + message?: string; + + data?: IDBServiceTableData[]; +} diff --git a/packages/shared/lib/api/base/service/Masking/index.ts b/packages/shared/lib/api/base/service/Masking/index.ts index a0ae6c052..f3e66a1c6 100644 --- a/packages/shared/lib/api/base/service/Masking/index.ts +++ b/packages/shared/lib/api/base/service/Masking/index.ts @@ -39,7 +39,33 @@ import { IUpdateMaskingTemplateParams, IUpdateMaskingTemplateReturn, IDeleteMaskingTemplateParams, - IDeleteMaskingTemplateReturn + IDeleteMaskingTemplateReturn, + IListMaskingRulesV2Params, + IListMaskingRulesV2Return, + IAddCustomMaskingRuleParams, + IAddCustomMaskingRuleReturn, + IUpdateCustomMaskingRuleParams, + IUpdateCustomMaskingRuleReturn, + IDeleteCustomMaskingRuleParams, + IDeleteCustomMaskingRuleReturn, + IListSensitiveTypesParams, + IListSensitiveTypesReturn, + IPreviewMaskingEffectParams, + IPreviewMaskingEffectReturn, + IGetMaskingRuleDetailParams, + IGetMaskingRuleDetailReturn, + IAddSensitiveDataTypeParams, + IAddSensitiveDataTypeReturn, + IUpdateSensitiveDataTypeParams, + IUpdateSensitiveDataTypeReturn, + IDeleteSensitiveDataTypeParams, + IDeleteSensitiveDataTypeReturn, + ITestSensitiveDataTypeMatchParams, + ITestSensitiveDataTypeMatchReturn, + IListDBServiceSchemasForMaskingTaskParams, + IListDBServiceSchemasForMaskingTaskReturn, + IListDBServiceTablesForMaskingTaskParams, + IListDBServiceTablesForMaskingTaskReturn } from './index.d'; class MaskingService extends ServiceBase { @@ -314,6 +340,216 @@ class MaskingService extends ServiceBase { options ); } + + public ListMaskingRulesV2( + params: IListMaskingRulesV2Params, + options?: AxiosRequestConfig + ) { + const paramsData = this.cloneDeep(params); + const project_uid = paramsData.project_uid; + delete paramsData.project_uid; + + return this.get( + `/v1/dms/projects/${project_uid}/masking/rules`, + paramsData, + options + ); + } + + public AddCustomMaskingRule( + params: IAddCustomMaskingRuleParams, + options?: AxiosRequestConfig + ) { + const paramsData = this.cloneDeep(params); + const project_uid = paramsData.project_uid; + delete paramsData.project_uid; + + return this.post( + `/v1/dms/projects/${project_uid}/masking/rules`, + paramsData, + options + ); + } + + public UpdateCustomMaskingRule( + params: IUpdateCustomMaskingRuleParams, + options?: AxiosRequestConfig + ) { + const paramsData = this.cloneDeep(params); + const project_uid = paramsData.project_uid; + delete paramsData.project_uid; + + const rule_id = paramsData.rule_id; + delete paramsData.rule_id; + + return this.put( + `/v1/dms/projects/${project_uid}/masking/rules/${rule_id}`, + paramsData, + options + ); + } + + public DeleteCustomMaskingRule( + params: IDeleteCustomMaskingRuleParams, + options?: AxiosRequestConfig + ) { + const paramsData = this.cloneDeep(params); + const project_uid = paramsData.project_uid; + delete paramsData.project_uid; + + const rule_id = paramsData.rule_id; + delete paramsData.rule_id; + + return this.delete( + `/v1/dms/projects/${project_uid}/masking/rules/${rule_id}`, + paramsData, + options + ); + } + + public ListSensitiveTypes( + params: IListSensitiveTypesParams, + options?: AxiosRequestConfig + ) { + const paramsData = this.cloneDeep(params); + const project_uid = paramsData.project_uid; + delete paramsData.project_uid; + + return this.get( + `/v1/dms/projects/${project_uid}/masking/sensitive-types`, + paramsData, + options + ); + } + + public PreviewMaskingEffect( + params: IPreviewMaskingEffectParams, + options?: AxiosRequestConfig + ) { + const paramsData = this.cloneDeep(params); + const project_uid = paramsData.project_uid; + delete paramsData.project_uid; + + return this.post( + `/v1/dms/projects/${project_uid}/masking/preview`, + paramsData, + options + ); + } + + public GetMaskingRuleDetail( + params: IGetMaskingRuleDetailParams, + options?: AxiosRequestConfig + ) { + const paramsData = this.cloneDeep(params); + const project_uid = paramsData.project_uid; + delete paramsData.project_uid; + + const rule_id = paramsData.rule_id; + delete paramsData.rule_id; + + return this.get( + `/v1/dms/projects/${project_uid}/masking/rules/${rule_id}`, + paramsData, + options + ); + } + + public AddSensitiveDataType( + params: IAddSensitiveDataTypeParams, + options?: AxiosRequestConfig + ) { + const paramsData = this.cloneDeep(params); + const project_uid = paramsData.project_uid; + delete paramsData.project_uid; + + return this.post( + `/v1/dms/projects/${project_uid}/masking/sensitive-types`, + paramsData, + options + ); + } + + public UpdateSensitiveDataType( + params: IUpdateSensitiveDataTypeParams, + options?: AxiosRequestConfig + ) { + const paramsData = this.cloneDeep(params); + const project_uid = paramsData.project_uid; + delete paramsData.project_uid; + + const sensitive_data_type_id = paramsData.sensitive_data_type_id; + delete paramsData.sensitive_data_type_id; + + return this.put( + `/v1/dms/projects/${project_uid}/masking/sensitive-types/${sensitive_data_type_id}`, + paramsData, + options + ); + } + + public DeleteSensitiveDataType( + params: IDeleteSensitiveDataTypeParams, + options?: AxiosRequestConfig + ) { + const paramsData = this.cloneDeep(params); + const project_uid = paramsData.project_uid; + delete paramsData.project_uid; + + const sensitive_data_type_id = paramsData.sensitive_data_type_id; + delete paramsData.sensitive_data_type_id; + + return this.delete( + `/v1/dms/projects/${project_uid}/masking/sensitive-types/${sensitive_data_type_id}`, + paramsData, + options + ); + } + + public TestSensitiveDataTypeMatch( + params: ITestSensitiveDataTypeMatchParams, + options?: AxiosRequestConfig + ) { + const paramsData = this.cloneDeep(params); + const project_uid = paramsData.project_uid; + delete paramsData.project_uid; + + return this.post( + `/v1/dms/projects/${project_uid}/masking/sensitive-types/match-test`, + paramsData, + options + ); + } + + public ListDBServiceSchemasForMaskingTask( + params: IListDBServiceSchemasForMaskingTaskParams, + options?: AxiosRequestConfig + ) { + const paramsData = this.cloneDeep(params); + const project_uid = paramsData.project_uid; + delete paramsData.project_uid; + + return this.get( + `/v1/dms/projects/${project_uid}/masking/sensitive-data-discovery-tasks/db-service-schemas`, + paramsData, + options + ); + } + + public ListDBServiceTablesForMaskingTask( + params: IListDBServiceTablesForMaskingTaskParams, + options?: AxiosRequestConfig + ) { + const paramsData = this.cloneDeep(params); + const project_uid = paramsData.project_uid; + delete paramsData.project_uid; + + return this.get( + `/v1/dms/projects/${project_uid}/masking/sensitive-data-discovery-tasks/db-service-tables`, + paramsData, + options + ); + } } export default new MaskingService(); diff --git a/packages/shared/lib/testUtil/mockApi/base/masking/data.ts b/packages/shared/lib/testUtil/mockApi/base/masking/data.ts new file mode 100644 index 000000000..77526a982 --- /dev/null +++ b/packages/shared/lib/testUtil/mockApi/base/masking/data.ts @@ -0,0 +1,407 @@ +import { + IGetMaskingOverviewTreeData, + IListCreatableDBServicesForMaskingTaskData, + IListMaskingRulesData, + IListMaskingTemplatesData, + IListSensitiveDataDiscoveryTasksData, + IListSensitiveDataDiscoveryTaskHistoriesData, + ISuspectedSensitiveFieldsTree, + ITableColumnMaskingDetail +} from '../../../../api/base/service/common'; +import { + IListMaskingRulesV2Data, + ISensitiveTypeData, + IGetMaskingRuleDetailData +} from '../../../../api/base/service/Masking/index.d'; +import { + ListSensitiveDataDiscoveryTaskHistoriesDataStatusEnum, + ListSensitiveDataDiscoveryTasksDataExecutionPlanEnum, + ListSensitiveDataDiscoveryTasksDataIdentificationMethodEnum, + ListSensitiveDataDiscoveryTasksDataStatusEnum, + ListSensitiveDataDiscoveryTasksDataTaskTypeEnum, + TableColumnMaskingDetailStatusEnum +} from '../../../../api/base/service/common.enum'; + +export const creatableDBServicesForMaskingTaskData: IListCreatableDBServicesForMaskingTaskData[] = + [ + { + db_service_uid: 'db-uid-1', + db_service_name: 'test-mysql', + db_service_host: '10.0.0.1', + db_service_port: '3306', + db_type: 'mysql' + }, + { + db_service_uid: 'db-uid-minimal', + db_service_name: 'minimal-svc', + db_type: 'mysql' + }, + { + db_service_uid: '', + db_service_name: 'skip-empty-uid', + db_type: 'mysql' + }, + { + db_service_uid: 'db-uid-no-label', + db_type: 'mysql' + } + ]; + +export const maskingTemplatesData: IListMaskingTemplatesData[] = [ + { + id: 1, + name: '默认模板', + rule_count: 2, + rule_names: ['全量脱敏', '部分脱敏', '全量', '部分', '脱敏', '脱敏2'] + }, + { + id: 2, + name: '邮箱模板', + rule_count: 1, + rule_names: ['部分脱敏'] + }, + { + id: 3, + name: '空模板', + rule_count: 0, + rule_names: [] + } +]; + +export const maskingRulesData: IListMaskingRulesData[] = [ + { + id: 1, + masking_type: 'full_mask', + description: '全量脱敏', + effect: 'replace', + effect_example_before: '13800138000', + effect_example_after: '***********' + }, + { + id: 2, + masking_type: 'partial_mask', + description: '部分脱敏', + effect: 'partial_replace', + effect_example_before: 'test@example.com', + effect_example_after: 'te**@example.com' + }, + { + id: 3, + masking_type: 'type_only_no_desc', + effect: 'replace', + effect_example_before: '', + effect_example_after: '' + } +]; + +export const maskingRulesV2Data: IListMaskingRulesV2Data[] = [ + { + id: 1, + name: 'full_mask', + source: 'builtin', + sensitive_type_name: '手机号码', + sensitive_type_info: '字段名关键词: phone, mobile', + is_custom_type: false, + algorithm_type: 'CHAR', + description: '全量脱敏', + effect: 'replace', + effect_example_before: '13800138000', + effect_example_after: '***********' + }, + { + id: 2, + name: 'partial_mask', + source: 'builtin', + sensitive_type_name: '邮箱', + sensitive_type_info: '字段名关键词: email', + is_custom_type: false, + algorithm_type: 'CHAR', + description: '部分脱敏', + effect: 'partial_replace', + effect_example_before: 'test@example.com', + effect_example_after: 'te**@example.com' + }, + { + id: 3, + name: 'type_only_no_desc', + source: 'builtin', + is_custom_type: false, + algorithm_type: 'REPLACE', + effect: 'replace', + effect_example_before: '', + effect_example_after: '' + } +]; + +export const suspectedSensitiveFieldsTreeData: ISuspectedSensitiveFieldsTree = { + databases: { + demo_schema: { + tables: { + user_table: { + fields: { + email_col: { + scan_info: '命中邮箱规则', + confidence: 'HIGH', + recommended_masking_rule_id: 1, + recommended_masking_rule_name: '推荐全量' + }, + phone_plain: { + confidence: 'MEDIUM', + recommended_masking_rule_id: 2, + recommended_masking_rule_name: '推荐部分' + }, + loose: { + scan_info: '仅描述', + confidence: 'LOW' + }, + custom_conf: { + confidence: 'CUSTOM' + } + } + } + } + } + } +}; + +export const sensitiveDataDiscoveryTaskHistoriesData: IListSensitiveDataDiscoveryTaskHistoriesData[] = + [ + { + executed_at: '2026-03-30 10:30:00', + status: ListSensitiveDataDiscoveryTaskHistoriesDataStatusEnum.COMPLETED, + new_sensitive_field_count: 2, + remark: 'ok' + }, + { + executed_at: '2026-03-29 09:00:00', + status: + ListSensitiveDataDiscoveryTaskHistoriesDataStatusEnum.PENDING_CONFIRM, + new_sensitive_field_count: 5, + remark: '待确认' + }, + { + executed_at: '2026-03-28 08:30:00', + status: ListSensitiveDataDiscoveryTaskHistoriesDataStatusEnum.NORMAL, + new_sensitive_field_count: 1, + remark: '无新增敏感字段' + }, + { + executed_at: '2026-03-27 07:15:00', + status: ListSensitiveDataDiscoveryTaskHistoriesDataStatusEnum.RUNNING, + new_sensitive_field_count: 0, + remark: '执行中' + }, + { + executed_at: '2026-03-26 06:45:00', + status: ListSensitiveDataDiscoveryTaskHistoriesDataStatusEnum.FAILED, + new_sensitive_field_count: 0, + remark: '连接失败' + }, + { + executed_at: '2026-03-25 06:00:00', + status: ListSensitiveDataDiscoveryTaskHistoriesDataStatusEnum.STOPPED, + new_sensitive_field_count: 3, + remark: '手动停止' + } + ]; + +export const sensitiveDataDiscoveryTasksData: IListSensitiveDataDiscoveryTasksData[] = + [ + { + id: 11, + db_service_uid: 'db-uid-1', + db_service_name: 'mysql-periodic', + db_service_host: '10.0.0.1', + db_service_port: '3306', + task_type: ListSensitiveDataDiscoveryTasksDataTaskTypeEnum.PERIODIC, + execution_plan: + ListSensitiveDataDiscoveryTasksDataExecutionPlanEnum.PERIODIC, + identification_method: + ListSensitiveDataDiscoveryTasksDataIdentificationMethodEnum.BY_FIELD_NAME, + masking_template_id: 1, + masking_template_name: '默认模板', + next_execution_at: '2026-03-31 10:00:00', + status: ListSensitiveDataDiscoveryTasksDataStatusEnum.NORMAL + }, + { + id: 12, + db_service_uid: 'db-uid-2', + db_service_name: 'mysql-stopped', + db_service_host: '10.0.0.2', + db_service_port: '3307', + task_type: ListSensitiveDataDiscoveryTasksDataTaskTypeEnum.PERIODIC, + execution_plan: + ListSensitiveDataDiscoveryTasksDataExecutionPlanEnum.PERIODIC, + identification_method: + ListSensitiveDataDiscoveryTasksDataIdentificationMethodEnum.BY_FIELD_NAME, + masking_template_id: 1, + masking_template_name: '默认模板', + next_execution_at: '2026-03-31 11:00:00', + status: ListSensitiveDataDiscoveryTasksDataStatusEnum.STOPPED + }, + { + id: 13, + db_service_uid: 'db-uid-3', + db_service_name: 'mysql-running-once', + db_service_host: '10.0.0.3', + db_service_port: '3308', + task_type: ListSensitiveDataDiscoveryTasksDataTaskTypeEnum.ONE_TIME, + execution_plan: + ListSensitiveDataDiscoveryTasksDataExecutionPlanEnum.ONE_TIME, + identification_method: + ListSensitiveDataDiscoveryTasksDataIdentificationMethodEnum.BY_SAMPLE_DATA, + masking_template_id: 2, + masking_template_name: '邮箱模板', + next_execution_at: '2026-03-31 12:30:00', + status: ListSensitiveDataDiscoveryTasksDataStatusEnum.RUNNING + }, + { + id: 14, + db_service_uid: 'db-uid-4', + db_service_name: 'mysql-pending-default', + db_service_host: '10.0.0.4', + db_service_port: '3309', + task_type: ListSensitiveDataDiscoveryTasksDataTaskTypeEnum.PERIODIC, + execution_plan: + ListSensitiveDataDiscoveryTasksDataExecutionPlanEnum.PERIODIC, + identification_method: + ListSensitiveDataDiscoveryTasksDataIdentificationMethodEnum.BY_SAMPLE_DATA, + masking_template_id: 2, + masking_template_name: '邮箱模板', + next_execution_at: '2026-03-31 13:00:00', + status: ListSensitiveDataDiscoveryTasksDataStatusEnum.PENDING_CONFIRM + }, + { + id: 15, + db_service_uid: 'db-uid-5', + db_service_name: 'mysql-failed-once', + db_service_host: '10.0.0.5', + db_service_port: '3310', + task_type: ListSensitiveDataDiscoveryTasksDataTaskTypeEnum.ONE_TIME, + execution_plan: + ListSensitiveDataDiscoveryTasksDataExecutionPlanEnum.ONE_TIME, + identification_method: + ListSensitiveDataDiscoveryTasksDataIdentificationMethodEnum.BY_FIELD_NAME, + status: ListSensitiveDataDiscoveryTasksDataStatusEnum.FAILED + }, + { + id: 16, + db_service_uid: 'db-uid-6', + db_service_name: 'mysql-completed-periodic', + db_service_host: '10.0.0.6', + db_service_port: '3311', + task_type: ListSensitiveDataDiscoveryTasksDataTaskTypeEnum.PERIODIC, + execution_plan: + ListSensitiveDataDiscoveryTasksDataExecutionPlanEnum.PERIODIC, + identification_method: + ListSensitiveDataDiscoveryTasksDataIdentificationMethodEnum.BY_FIELD_NAME, + masking_template_id: 3, + masking_template_name: '空模板', + next_execution_at: '2026-03-31 13:30:00', + status: ListSensitiveDataDiscoveryTasksDataStatusEnum.COMPLETED + }, + { + id: 17, + db_service_uid: 'db-uid-8', + db_service_name: 'mysql-periodic-123', + db_service_host: '10.0.0.9', + db_service_port: '3309', + task_type: ListSensitiveDataDiscoveryTasksDataTaskTypeEnum.PERIODIC, + execution_plan: + ListSensitiveDataDiscoveryTasksDataExecutionPlanEnum.PERIODIC, + identification_method: + ListSensitiveDataDiscoveryTasksDataIdentificationMethodEnum.BY_FIELD_NAME, + masking_template_id: 3, + masking_template_name: '模板', + next_execution_at: '2026-03-31 13:32:00' + } + ]; + +export const maskingOverviewTreeData: IGetMaskingOverviewTreeData = { + dashboard: { + total_sensitive_tables: 2, + configured_masking_columns: 5, + pending_confirm_masking_columns: 3 + }, + databases: { + test_schema: { + tables: { + user_info: { + table_id: 1001, + configured_masking_columns: 2, + pending_confirm_masking_columns: 1 + }, + employee: { + table_id: 1002, + configured_masking_columns: 3, + pending_confirm_masking_columns: 2 + } + } + } + } +}; + +/** 与 overview 树中 test_schema.user_info(table_id: 1001)配套的字段详情列表 */ +export const tableColumnMaskingDetailsData: ITableColumnMaskingDetail[] = [ + { + column_name: 'email_col', + masking_rule_name: '全量脱敏', + status: TableColumnMaskingDetailStatusEnum.CONFIGURED + }, + { + column_name: 'phone_plain', + masking_rule_name: '部分脱敏', + status: TableColumnMaskingDetailStatusEnum.PENDING_CONFIRM + }, + { + column_name: 'plain', + masking_rule_name: '部分', + status: TableColumnMaskingDetailStatusEnum.SYSTEM_CONFIRMED + } +]; + +export const sensitiveTypesData: ISensitiveTypeData[] = [ + { + id: 1, + sensitive_data_type_source: 'builtin', + en_identifier: 'phone', + cn_name: '手机号码', + field_keywords: ['phone', 'mobile'], + sample_data_regex_list: ['^1[3-9]\\d{9}$'] + }, + { + id: 2, + sensitive_data_type_source: 'builtin', + en_identifier: 'email', + cn_name: '邮箱', + field_keywords: ['email', 'mail'], + sample_data_regex_list: ['^\\S+@\\S+\\.\\S+$'] + }, + { + id: 100, + sensitive_data_type_source: 'custom', + en_identifier: 'custom_phone', + cn_name: '自定义手机号', + field_keywords: ['phone'], + sample_data_regex_list: [] + } +]; + +export const maskingRuleDetailData: IGetMaskingRuleDetailData = { + rule_id: 1, + name: 'full_mask', + description: '全量脱敏', + sensitive_data_type: { + id: 1, + sensitive_data_type_source: 'builtin', + en_identifier: 'phone', + cn_name: '手机号码', + field_keywords: ['phone', 'mobile'], + sample_data_regex_list: ['^1[3-9]\\d{9}$'] + }, + masking_algorithm_config: { + masking_algorithm_name: 'FULL_MASK', + mask_type: 'CHAR', + value: '*' + } +}; diff --git a/packages/shared/lib/testUtil/mockApi/base/masking/index.ts b/packages/shared/lib/testUtil/mockApi/base/masking/index.ts new file mode 100644 index 000000000..5c219bcf1 --- /dev/null +++ b/packages/shared/lib/testUtil/mockApi/base/masking/index.ts @@ -0,0 +1,237 @@ +import { MockSpyApy, createSpySuccessResponse } from '../../common'; +import Masking from '../../../../api/base/service/Masking'; +import { + creatableDBServicesForMaskingTaskData, + maskingOverviewTreeData, + maskingRulesData, + maskingRulesV2Data, + maskingRuleDetailData, + maskingTemplatesData, + sensitiveDataDiscoveryTasksData, + sensitiveDataDiscoveryTaskHistoriesData, + sensitiveTypesData, + suspectedSensitiveFieldsTreeData, + tableColumnMaskingDetailsData +} from './data'; + +class MockMaskingApi implements MockSpyApy { + public mockAllApi(): void { + this.ListMaskingRules(); + this.ListMaskingRulesV2(); + this.ListSensitiveDataDiscoveryTasks(); + this.GetMaskingOverviewTree(); + this.GetTableColumnMaskingDetails(); + this.ListCreatableDBServicesForMaskingTask(); + this.ListMaskingTemplates(); + this.AddSensitiveDataDiscoveryTask(); + this.UpdateSensitiveDataDiscoveryTask(); + this.DeleteSensitiveDataDiscoveryTask(); + this.ConfigureMaskingRules(); + this.AddMaskingTemplate(); + this.UpdateMaskingTemplate(); + this.DeleteMaskingTemplate(); + this.ListSensitiveDataDiscoveryTaskHistories(); + this.ListSensitiveTypes(); + this.AddCustomMaskingRule(); + this.UpdateCustomMaskingRule(); + this.DeleteCustomMaskingRule(); + this.GetMaskingRuleDetail(); + this.AddSensitiveDataType(); + this.PreviewMaskingEffect(); + } + + public ListSensitiveDataDiscoveryTasks() { + const spy = jest.spyOn(Masking, 'ListSensitiveDataDiscoveryTasks'); + spy.mockImplementation(() => + createSpySuccessResponse({ + total_nums: sensitiveDataDiscoveryTasksData.length, + data: sensitiveDataDiscoveryTasksData + }) + ); + return spy; + } + + public GetMaskingOverviewTree() { + const spy = jest.spyOn(Masking, 'GetMaskingOverviewTree'); + spy.mockImplementation(() => + createSpySuccessResponse({ + data: maskingOverviewTreeData + }) + ); + return spy; + } + + public GetTableColumnMaskingDetails() { + const spy = jest.spyOn(Masking, 'GetTableColumnMaskingDetails'); + spy.mockImplementation(() => + createSpySuccessResponse({ + data: tableColumnMaskingDetailsData + }) + ); + return spy; + } + + public ListMaskingRules() { + const spy = jest.spyOn(Masking, 'ListMaskingRules'); + spy.mockImplementation(() => + createSpySuccessResponse({ + data: maskingRulesData + }) + ); + return spy; + } + + public ListMaskingRulesV2() { + const spy = jest.spyOn(Masking, 'ListMaskingRulesV2'); + spy.mockImplementation(() => + createSpySuccessResponse({ + data: maskingRulesV2Data, + total_nums: maskingRulesV2Data.length + }) + ); + return spy; + } + + public ListCreatableDBServicesForMaskingTask() { + const spy = jest.spyOn(Masking, 'ListCreatableDBServicesForMaskingTask'); + spy.mockImplementation(() => + createSpySuccessResponse({ + data: creatableDBServicesForMaskingTaskData + }) + ); + return spy; + } + + public ListMaskingTemplates() { + const spy = jest.spyOn(Masking, 'ListMaskingTemplates'); + spy.mockImplementation(() => + createSpySuccessResponse({ + data: maskingTemplatesData + }) + ); + return spy; + } + + public AddSensitiveDataDiscoveryTask() { + const spy = jest.spyOn(Masking, 'AddSensitiveDataDiscoveryTask'); + spy.mockImplementation(() => + createSpySuccessResponse({ + data: { + suspected_sensitive_fields_tree: suspectedSensitiveFieldsTreeData + } + }) + ); + return spy; + } + + public UpdateSensitiveDataDiscoveryTask() { + const spy = jest.spyOn(Masking, 'UpdateSensitiveDataDiscoveryTask'); + spy.mockImplementation(() => createSpySuccessResponse({})); + return spy; + } + + public DeleteSensitiveDataDiscoveryTask() { + const spy = jest.spyOn(Masking, 'DeleteSensitiveDataDiscoveryTask'); + spy.mockImplementation(() => createSpySuccessResponse({})); + return spy; + } + + public ConfigureMaskingRules() { + const spy = jest.spyOn(Masking, 'ConfigureMaskingRules'); + spy.mockImplementation(() => createSpySuccessResponse({})); + return spy; + } + + public AddMaskingTemplate() { + const spy = jest.spyOn(Masking, 'AddMaskingTemplate'); + spy.mockImplementation(() => createSpySuccessResponse({})); + return spy; + } + + public UpdateMaskingTemplate() { + const spy = jest.spyOn(Masking, 'UpdateMaskingTemplate'); + spy.mockImplementation(() => createSpySuccessResponse({})); + return spy; + } + + public DeleteMaskingTemplate() { + const spy = jest.spyOn(Masking, 'DeleteMaskingTemplate'); + spy.mockImplementation(() => createSpySuccessResponse({})); + return spy; + } + + public ListSensitiveDataDiscoveryTaskHistories() { + const spy = jest.spyOn(Masking, 'ListSensitiveDataDiscoveryTaskHistories'); + spy.mockImplementation(() => + createSpySuccessResponse({ + total_nums: sensitiveDataDiscoveryTaskHistoriesData.length, + data: sensitiveDataDiscoveryTaskHistoriesData + }) + ); + return spy; + } + + public ListSensitiveTypes() { + const spy = jest.spyOn(Masking, 'ListSensitiveTypes'); + spy.mockImplementation(() => + createSpySuccessResponse({ + data: sensitiveTypesData + }) + ); + return spy; + } + + public AddCustomMaskingRule() { + const spy = jest.spyOn(Masking, 'AddCustomMaskingRule'); + spy.mockImplementation(() => + createSpySuccessResponse({ + data: { rule_id: 100 } + }) + ); + return spy; + } + + public UpdateCustomMaskingRule() { + const spy = jest.spyOn(Masking, 'UpdateCustomMaskingRule'); + spy.mockImplementation(() => createSpySuccessResponse({})); + return spy; + } + + public DeleteCustomMaskingRule() { + const spy = jest.spyOn(Masking, 'DeleteCustomMaskingRule'); + spy.mockImplementation(() => createSpySuccessResponse({})); + return spy; + } + + public GetMaskingRuleDetail() { + const spy = jest.spyOn(Masking, 'GetMaskingRuleDetail'); + spy.mockImplementation(() => + createSpySuccessResponse({ + data: maskingRuleDetailData + }) + ); + return spy; + } + + public AddSensitiveDataType() { + const spy = jest.spyOn(Masking, 'AddSensitiveDataType'); + spy.mockImplementation(() => + createSpySuccessResponse({ + data: { sensitive_data_type_id: 200 } + }) + ); + return spy; + } + + public PreviewMaskingEffect() { + const spy = jest.spyOn(Masking, 'PreviewMaskingEffect'); + spy.mockImplementation(() => + createSpySuccessResponse({ + data: { masked_output_list: ['***'] } + }) + ); + return spy; + } +} + +export default new MockMaskingApi(); From f9068a8f065553c78506ee85bf563acadb8ced6d Mon Sep 17 00:00:00 2001 From: actiontech-zihan Date: Wed, 6 May 2026 04:26:09 +0000 Subject: [PATCH 2/2] =?UTF-8?q?feat(data=5Fmasking):=20=E6=9B=B4=E6=96=B0M?= =?UTF-8?q?asking=20API=E7=B1=BB=E5=9E=8B=E5=AE=9A=E4=B9=89=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E8=87=AA=E5=AE=9A=E4=B9=89=E8=A7=84=E5=88=99=20#800?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增rule_refs字段支持规则来源(内置/自定义)区分 - 新增schema_names/table_names支持按库/表粒度扫描 - 新增masking_rule_source/is_masking_enabled等字段 --- .../shared/lib/api/base/service/common.d.ts | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/packages/shared/lib/api/base/service/common.d.ts b/packages/shared/lib/api/base/service/common.d.ts index 6d4a5091c..be2a5a4f7 100644 --- a/packages/shared/lib/api/base/service/common.d.ts +++ b/packages/shared/lib/api/base/service/common.d.ts @@ -134,7 +134,9 @@ export interface IAddGatewayReq { export interface IAddMaskingTemplate { name: string; - rule_ids: number[]; + rule_refs?: Array<{ rule_id: number; rule_source: string }>; + + rule_ids?: number[]; } export interface IAddMaskingTemplateReply { @@ -239,6 +241,10 @@ export interface IAddSensitiveDataDiscoveryTask { is_periodic_scan_enabled?: boolean; masking_template_id: number; + + schema_names?: string[]; + + table_names?: string[]; } export interface IAddSensitiveDataDiscoveryTaskData { @@ -1525,6 +1531,8 @@ export interface IListCreatableDBServicesForMaskingTaskData { db_service_uid?: string; db_type?: string; + + has_task?: boolean; } export interface IListCreatableDBServicesForMaskingTaskReply { @@ -2226,6 +2234,10 @@ export interface IListSensitiveDataDiscoveryTasksData { next_execution_at?: string; + schema_names?: string[]; + + table_names?: string[]; + status?: ListSensitiveDataDiscoveryTasksDataStatusEnum; task_type?: ListSensitiveDataDiscoveryTasksDataTaskTypeEnum; @@ -2360,6 +2372,8 @@ export interface IMaskingRuleConfig { masking_rule_id: number; + masking_rule_source?: string; + schema_name: string; table_name: string; @@ -2872,6 +2886,8 @@ export interface ISensitiveFieldScanResult { recommended_masking_rule_name?: string; + recommended_masking_rule_source?: string; + scan_info?: string; } @@ -2916,10 +2932,14 @@ export interface ITableColumnMaskingDetail { confidence?: TableColumnMaskingDetailConfidenceEnum; + is_masking_enabled?: boolean; + masking_rule_id?: number; masking_rule_name?: string; + masking_rule_source?: string; + status?: TableColumnMaskingDetailStatusEnum; } @@ -3214,7 +3234,9 @@ export interface IUpdateLoginConfigurationReq { } export interface IUpdateMaskingTemplate { - rule_ids: number[]; + rule_refs?: Array<{ rule_id: number; rule_source: string }>; + + rule_ids?: number[]; } export interface IUpdateMaskingTemplateReply { @@ -3317,6 +3339,10 @@ export interface IUpdateSensitiveDataDiscoveryTask { identification_method?: UpdateSensitiveDataDiscoveryTaskIdentificationMethodEnum; masking_template_id?: number; + + schema_names?: string[]; + + table_names?: string[]; } export interface IUpdateSensitiveDataDiscoveryTaskData {