From 768d24ea96f8a8e04b5bbe602a31f633282fa22b Mon Sep 17 00:00:00 2001 From: actiontech-zihan Date: Wed, 23 Sep 2026 13:15:36 +0800 Subject: [PATCH 1/5] feat(ui): add schema and object_name match condition controls Expose the new exception dimensions on the manage form with enums and i18n labels. Co-authored-by: Cursor --- .../lib/api/sqle/service/common.enum.ts | 6 ++++- .../Form/index.tsx | 26 +++++++++++++++++++ .../index.data.ts | 14 ++++++++-- .../sqle/src/locale/en-US/ruleException.ts | 3 +++ .../sqle/src/locale/zh-CN/ruleException.ts | 3 +++ .../sqle/src/page/RuleException/index.type.ts | 1 - 6 files changed, 49 insertions(+), 4 deletions(-) diff --git a/packages/shared/lib/api/sqle/service/common.enum.ts b/packages/shared/lib/api/sqle/service/common.enum.ts index c86fd54c0..b7a0f0f00 100644 --- a/packages/shared/lib/api/sqle/service/common.enum.ts +++ b/packages/shared/lib/api/sqle/service/common.enum.ts @@ -297,7 +297,11 @@ export enum MatchConditionReqV1TypeEnum { db_type = 'db_type', - sql_source = 'sql_source' + sql_source = 'sql_source', + + schema = 'schema', + + object_name = 'object_name' } export enum OperationRecordListStatusEnum { diff --git a/packages/sqle/src/components/RuleExceptionMatchConditions/Form/index.tsx b/packages/sqle/src/components/RuleExceptionMatchConditions/Form/index.tsx index cd17af5c5..7fc5328a0 100644 --- a/packages/sqle/src/components/RuleExceptionMatchConditions/Form/index.tsx +++ b/packages/sqle/src/components/RuleExceptionMatchConditions/Form/index.tsx @@ -268,6 +268,32 @@ const MatchRowContentField: React.FC = ({ ); } + if ( + type === MatchConditionReqV1TypeEnum.schema || + type === MatchConditionReqV1TypeEnum.object_name + ) { + return ( + + + + + + + + + ); + } + return ( = { sql: t('ruleException.matchType.sql'), @@ -31,6 +33,10 @@ export const AuditWhitelistMatchTypeDirection: Record< [MatchConditionReqV1TypeEnum.db_type]: t('ruleException.matchType.db_type'), [MatchConditionReqV1TypeEnum.sql_source]: t( 'ruleException.matchType.sql_source' + ), + [MatchConditionReqV1TypeEnum.schema]: t('ruleException.matchType.schema'), + [MatchConditionReqV1TypeEnum.object_name]: t( + 'ruleException.matchType.object_name' ) }; @@ -74,6 +80,8 @@ export const AuditWhitelistExtendedMatchTypeOptions = [ MatchConditionReqV1TypeEnum.audit_task_id, MatchConditionReqV1TypeEnum.db_type, MatchConditionReqV1TypeEnum.sql_source, + MatchConditionReqV1TypeEnum.schema, + MatchConditionReqV1TypeEnum.object_name, MatchConditionReqV1TypeEnum.fp_sql, MatchConditionReqV1TypeEnum.sql ].map((value) => ({ @@ -87,7 +95,9 @@ export const AuditWhitelistAllMatchTypeOptions = [ MatchConditionReqV1TypeEnum.audit_task_type, MatchConditionReqV1TypeEnum.audit_task_id, MatchConditionReqV1TypeEnum.db_type, - MatchConditionReqV1TypeEnum.sql_source + MatchConditionReqV1TypeEnum.sql_source, + MatchConditionReqV1TypeEnum.schema, + MatchConditionReqV1TypeEnum.object_name ].map((value) => ({ label: AuditWhitelistMatchTypeDirection[ diff --git a/packages/sqle/src/locale/en-US/ruleException.ts b/packages/sqle/src/locale/en-US/ruleException.ts index 2f272d103..837fd7f4e 100644 --- a/packages/sqle/src/locale/en-US/ruleException.ts +++ b/packages/sqle/src/locale/en-US/ruleException.ts @@ -41,6 +41,9 @@ export default { audit_task_type: 'Scan task type', audit_task_id: 'Scan task', sql_source: 'Source', + schema: 'Schema', + object_name: 'Object name', + objectNameTip: 'Includes tables and views', sqlSource: { sql_audit_record: 'Quick audit', audit_plan: 'Scan task' diff --git a/packages/sqle/src/locale/zh-CN/ruleException.ts b/packages/sqle/src/locale/zh-CN/ruleException.ts index 45b80e9cf..eb5fcadec 100644 --- a/packages/sqle/src/locale/zh-CN/ruleException.ts +++ b/packages/sqle/src/locale/zh-CN/ruleException.ts @@ -41,6 +41,9 @@ export default { audit_task_type: '扫描任务类型', audit_task_id: '扫描任务', sql_source: '来源', + schema: '库名', + object_name: '对象名', + objectNameTip: '含表与视图', sqlSource: { sql_audit_record: '快捷审核', audit_plan: '扫描任务' diff --git a/packages/sqle/src/page/RuleException/index.type.ts b/packages/sqle/src/page/RuleException/index.type.ts index 06d94c866..fff7af7b5 100644 --- a/packages/sqle/src/page/RuleException/index.type.ts +++ b/packages/sqle/src/page/RuleException/index.type.ts @@ -1,5 +1,4 @@ import { - IAuditResult, IAuditWhitelistResV1, ISkippedByRuleExceptionItem } from '@actiontech/shared/lib/api/sqle/service/common'; From b2d358dd4c602782720f24151b808dbd3f8f7af1 Mon Sep 17 00:00:00 2001 From: actiontech-zihan Date: Wed, 23 Sep 2026 13:15:36 +0800 Subject: [PATCH 2/5] feat(ui): prefer schema/object prefill from scan detail entries Isolate scan-task add-exception flows to prefill library/object instead of create-table fingerprint. Co-authored-by: Cursor --- .../AuditResultExemptionPanel/index.tsx | 5 +-- .../sqle/src/page/RuleException/prefill.ts | 33 ++++++++++++++++++- .../Detail/ScanTypeSqlCollection/index.tsx | 20 +++++++++-- 3 files changed, 51 insertions(+), 7 deletions(-) diff --git a/packages/sqle/src/components/RuleException/AuditResultExemptionPanel/index.tsx b/packages/sqle/src/components/RuleException/AuditResultExemptionPanel/index.tsx index 25d10a6b6..0b91df258 100644 --- a/packages/sqle/src/components/RuleException/AuditResultExemptionPanel/index.tsx +++ b/packages/sqle/src/components/RuleException/AuditResultExemptionPanel/index.tsx @@ -21,10 +21,7 @@ import ExemptedAuditResultWithActions from '../ExemptedAuditResultWithActions'; import CollapsibleExemptedSection from './CollapsibleExemptedSection'; import FullSqlExemptedResultItem from '../FullSqlExemptedResultItem'; import { AuditResultExemptionPanelStyleWrapper } from './style'; -import { - AuditResultExemptionPanelLayout, - AuditResultExemptionPanelProps -} from './types'; +import { AuditResultExemptionPanelProps } from './types'; import { IAuditResultItem } from '../../ReportDrawer/index.type'; export type { AuditResultExemptionPanelLayout } from './types'; diff --git a/packages/sqle/src/page/RuleException/prefill.ts b/packages/sqle/src/page/RuleException/prefill.ts index de1e0ecdd..4e13245f4 100644 --- a/packages/sqle/src/page/RuleException/prefill.ts +++ b/packages/sqle/src/page/RuleException/prefill.ts @@ -37,6 +37,10 @@ export type SqlManageRuleExceptionRecord = { instance_name?: string; audit_plan_db_type?: string; db_type?: string; + /** Scan-task schema_name; used when preferSchemaObjectMatch */ + schema_name?: string; + /** Scan-task schema_meta_name (table/view); used when preferSchemaObjectMatch */ + schema_meta_name?: string; source?: ISqlManageRuleExceptionContext['source']; audit_result?: IAuditResult[] | null; }; @@ -71,6 +75,8 @@ export type ScanTaskRuleExceptionRecordInput = { fingerprint?: string; sql?: string; instance_id?: string; + schema_name?: string; + schema_meta_name?: string; audit_result?: IAuditResult[] | null; }; @@ -111,6 +117,8 @@ export const toScanTaskRuleExceptionRecord = ( sql, instance_id: record.instance_id?.trim() || sourceContext?.instanceId, db_type: sourceContext?.instanceType, + schema_name: record.schema_name?.trim() || undefined, + schema_meta_name: record.schema_meta_name?.trim() || undefined, source: { sql_source_type: sourceContext?.auditPlanType, sql_source_ids: sourceContext?.auditPlanId @@ -126,6 +134,12 @@ export type BuildBlacklistPrefillFromSqlManageOptions = { ruleName?: string; /** Row action entry: specific scope without pre-selecting rules */ specificRuleScopeWithoutPreselect?: boolean; + /** + * Scan-task detail A/B only. When object name is present, prefill + * schema + object_name and skip fp_sql/sql fingerprint conditions. + * Must not be set for SQL管控 / workflow / SqlAnalyze callers (AC-001b). + */ + preferSchemaObjectMatch?: boolean; }; const AUDIT_TASK_MATCH_PREFILL_SKIP_SOURCE_TYPES = new Set([ @@ -271,7 +285,24 @@ export const buildBlacklistPrefillFromSqlManage = ( const match_conditions: IMatchConditionReqV1[] = []; - if (context.sql_fingerprint) { + const objectName = record?.schema_meta_name?.trim(); + const schemaName = record?.schema_name?.trim(); + + if (options?.preferSchemaObjectMatch && objectName) { + if (schemaName) { + match_conditions.push({ + type: MatchConditionReqV1TypeEnum.schema, + content: schemaName + }); + } + match_conditions.push({ + type: MatchConditionReqV1TypeEnum.object_name, + content: objectName + }); + } else if (!options?.preferSchemaObjectMatch && context.sql_fingerprint) { + // Default fingerprint path (SQL管控 / 其它入口). When scan-task + // preferSchemaObjectMatch is on but object name is missing, do not + // fall back to full DDL as fp_sql (S1 §5.4). match_conditions.push({ type: MatchConditionReqV1TypeEnum.fp_sql, content: context.sql_fingerprint diff --git a/packages/sqle/src/page/SqlManagementConf/Detail/ScanTypeSqlCollection/index.tsx b/packages/sqle/src/page/SqlManagementConf/Detail/ScanTypeSqlCollection/index.tsx index ef056a99c..a5458245c 100644 --- a/packages/sqle/src/page/SqlManagementConf/Detail/ScanTypeSqlCollection/index.tsx +++ b/packages/sqle/src/page/SqlManagementConf/Detail/ScanTypeSqlCollection/index.tsx @@ -183,6 +183,14 @@ const ScanTypeSqlCollection: React.FC = ({ fingerprint: record['fingerprint'], sql: record['sql'], instance_id: record['instance_id'], + schema_name: + typeof record['schema_name'] === 'string' + ? record['schema_name'] + : undefined, + schema_meta_name: + typeof record['schema_meta_name'] === 'string' + ? record['schema_meta_name'] + : undefined, audit_result: active }, scanTaskSourceContext @@ -212,9 +220,13 @@ const ScanTypeSqlCollection: React.FC = ({ (params: OpenCreateAuditWhitelistExceptionParams) => { closeRemediationDrawer(); setRemediationDrawerRecord(undefined); + // 扫描详情 A/B 共用:preferSchemaObjectMatch 入口隔离(勿传给 SQL管控等) openAuditWhitelistCreateWithPrefill( toScanTaskRecord(remediationDrawerRecord), - { ruleName: params.auditResult?.rule_name } + { + ruleName: params.auditResult?.rule_name, + preferSchemaObjectMatch: true + } ); }, [ @@ -228,9 +240,13 @@ const ScanTypeSqlCollection: React.FC = ({ const handleOpenCreateExceptionFromReport = useCallback( (params: OpenCreateAuditWhitelistExceptionParams) => { closeReportDrawer(); + // 扫描详情 A/B 共用:preferSchemaObjectMatch 入口隔离(勿传给 SQL管控等) openAuditWhitelistCreateWithPrefill( toScanTaskRecord(currentAuditResultRecord), - { ruleName: params.auditResult?.rule_name } + { + ruleName: params.auditResult?.rule_name, + preferSchemaObjectMatch: true + } ); }, [ From 23bd2bf0f797d65debd47b39ac22609fdb4683c0 Mon Sep 17 00:00:00 2001 From: actiontech-zihan Date: Wed, 23 Sep 2026 13:15:37 +0800 Subject: [PATCH 3/5] test(ui): cover preferSchemaObjectMatch prefill helpers Lock the scan-detail vs SQL-manage prefill branching for the new dimensions. Co-authored-by: Cursor --- .../RuleException/__tests__/utils.test.ts | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/packages/sqle/src/page/RuleException/__tests__/utils.test.ts b/packages/sqle/src/page/RuleException/__tests__/utils.test.ts index dc2d32b24..f0b73d186 100644 --- a/packages/sqle/src/page/RuleException/__tests__/utils.test.ts +++ b/packages/sqle/src/page/RuleException/__tests__/utils.test.ts @@ -87,6 +87,97 @@ describe('sqle/page/RuleException/utils', () => { }); }); + it('buildBlacklistPrefillFromSqlManage prefers schema+object_name when preferSchemaObjectMatch', () => { + expect( + buildBlacklistPrefillFromSqlManage( + { + sql_fingerprint: 'CREATE TABLE `v_exc_target` (`id` int)', + instance_id: '123', + db_type: 'MySQL', + schema_name: 'sqle', + schema_meta_name: 'v_exc_target', + source: { + sql_source_type: 'mysql_schema_meta', + sql_source_ids: ['1'] + } + }, + { preferSchemaObjectMatch: true } + ) + ).toEqual({ + match_conditions: [ + { + type: MatchConditionReqV1TypeEnum.schema, + content: 'sqle' + }, + { + type: MatchConditionReqV1TypeEnum.object_name, + content: 'v_exc_target' + }, + { + type: MatchConditionReqV1TypeEnum.instance, + content: '123' + }, + { + type: MatchConditionReqV1TypeEnum.audit_task_type, + content: 'mysql_schema_meta' + }, + { + type: MatchConditionReqV1TypeEnum.audit_task_id, + content: '1' + }, + { + type: MatchConditionReqV1TypeEnum.sql_source, + content: 'audit_plan' + }, + { + type: MatchConditionReqV1TypeEnum.db_type, + content: 'MySQL' + } + ] + }); + }); + + it('buildBlacklistPrefillFromSqlManage does not fall back to fp_sql when preferSchemaObjectMatch lacks object', () => { + expect( + buildBlacklistPrefillFromSqlManage( + { + sql_fingerprint: 'CREATE TABLE `t` (`id` int)', + instance_id: '123', + db_type: 'MySQL', + schema_name: 'sqle', + source: { + sql_source_type: 'mysql_schema_meta', + sql_source_ids: ['1'] + } + }, + { preferSchemaObjectMatch: true } + ) + ).toEqual({ + match_conditions: [ + { + type: MatchConditionReqV1TypeEnum.instance, + content: '123' + }, + { + type: MatchConditionReqV1TypeEnum.audit_task_type, + content: 'mysql_schema_meta' + }, + { + type: MatchConditionReqV1TypeEnum.audit_task_id, + content: '1' + }, + { + type: MatchConditionReqV1TypeEnum.sql_source, + content: 'audit_plan' + }, + { + type: MatchConditionReqV1TypeEnum.db_type, + content: 'MySQL' + } + ] + }); + }); + it('buildBlacklistPrefillFromSqlManage skips audit task match for quick audit source', () => { expect( buildBlacklistPrefillFromSqlManage({ From 1290429d289eacb81303478e3963590004e8b3a5 Mon Sep 17 00:00:00 2001 From: actiontech-zihan Date: Wed, 23 Sep 2026 17:20:10 +0800 Subject: [PATCH 4/5] feat(ui): hang schema/object prefill on SQL manage; revoke scan detail MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit preferSchemaObjectMatch only on SQL管控 list/drawer entries; require both schema and object name else fingerprint fallback (AC-001/AC-001b). Scan detail drawers drop the flag (AC-001a); read info.schema_meta_name (AC-011). Co-authored-by: Cursor --- .../sqle/src/page/RuleException/prefill.ts | 54 +++++++++++++------ .../Modal/RemediationDetailDrawer/index.tsx | 6 ++- .../SQLEEIndex/Modal/StatusDrawer/index.tsx | 6 ++- .../component/SQLEEIndex/index.tsx | 6 ++- .../Detail/ScanTypeSqlCollection/index.tsx | 10 ++-- 5 files changed, 57 insertions(+), 25 deletions(-) diff --git a/packages/sqle/src/page/RuleException/prefill.ts b/packages/sqle/src/page/RuleException/prefill.ts index 4e13245f4..f5eb05a94 100644 --- a/packages/sqle/src/page/RuleException/prefill.ts +++ b/packages/sqle/src/page/RuleException/prefill.ts @@ -37,9 +37,9 @@ export type SqlManageRuleExceptionRecord = { instance_name?: string; audit_plan_db_type?: string; db_type?: string; - /** Scan-task schema_name; used when preferSchemaObjectMatch */ + /** SQL管控行 schema_name;仅 preferSchemaObjectMatch 入口消费 */ schema_name?: string; - /** Scan-task schema_meta_name (table/view); used when preferSchemaObjectMatch */ + /** SQL管控行 info.schema_meta_name(表/视图);仅 preferSchemaObjectMatch 入口消费 */ schema_meta_name?: string; source?: ISqlManageRuleExceptionContext['source']; audit_result?: IAuditResult[] | null; @@ -49,6 +49,25 @@ type ISqlManageWithInstanceId = ISqlManage & { instance_id?: string; db_type?: string; audit_plan_db_type?: string; + /** AC-011 list透出;三种缺省(缺键/空串/省略 info)均视为无对象名 */ + info?: { schema_meta_name?: string } | null; +}; + +export const resolveSchemaMetaNameFromSqlManageInfo = ( + info?: { schema_meta_name?: string } | null +): string | undefined => { + if (!info || typeof info !== 'object') { + return undefined; + } + if (!Object.prototype.hasOwnProperty.call(info, 'schema_meta_name')) { + return undefined; + } + const raw = info.schema_meta_name; + if (typeof raw !== 'string') { + return undefined; + } + const trimmed = raw.trim(); + return trimmed || undefined; }; export const toSqlManageRuleExceptionRecord = ( @@ -65,6 +84,10 @@ export const toSqlManageRuleExceptionRecord = ( instance_name: record.instance_name, audit_plan_db_type: recordWithExtra.audit_plan_db_type, db_type: recordWithExtra.db_type, + schema_name: record.schema_name?.trim() || undefined, + schema_meta_name: resolveSchemaMetaNameFromSqlManageInfo( + recordWithExtra.info + ), source: record.source, audit_result: record.audit_result }; @@ -135,9 +158,10 @@ export type BuildBlacklistPrefillFromSqlManageOptions = { /** Row action entry: specific scope without pre-selecting rules */ specificRuleScopeWithoutPreselect?: boolean; /** - * Scan-task detail A/B only. When object name is present, prefill - * schema + object_name and skip fp_sql/sql fingerprint conditions. - * Must not be set for SQL管控 / workflow / SqlAnalyze callers (AC-001b). + * SQL管控页「添加为审核SQL例外」专用(S1 §5.4)。 + * 库名+对象名均有值 → 预填 schema + object_name,跳过 fp_sql; + * 缺任一侧 → 指纹回退(AC-001b)。 + * 禁止传给扫描详情抽屉 / 快捷审核 / 工单 / SqlAnalyze(AC-001a / AC-012)。 */ preferSchemaObjectMatch?: boolean; }; @@ -287,22 +311,20 @@ export const buildBlacklistPrefillFromSqlManage = ( const objectName = record?.schema_meta_name?.trim(); const schemaName = record?.schema_name?.trim(); + // AC-001:须库名与对象名均非空才走对象预填;缺一则 AC-001b 指纹回退 + const useSchemaObjectMatch = + !!options?.preferSchemaObjectMatch && !!schemaName && !!objectName; - if (options?.preferSchemaObjectMatch && objectName) { - if (schemaName) { - match_conditions.push({ - type: MatchConditionReqV1TypeEnum.schema, - content: schemaName - }); - } + if (useSchemaObjectMatch) { + match_conditions.push({ + type: MatchConditionReqV1TypeEnum.schema, + content: schemaName + }); match_conditions.push({ type: MatchConditionReqV1TypeEnum.object_name, content: objectName }); - } else if (!options?.preferSchemaObjectMatch && context.sql_fingerprint) { - // Default fingerprint path (SQL管控 / 其它入口). When scan-task - // preferSchemaObjectMatch is on but object name is missing, do not - // fall back to full DDL as fp_sql (S1 §5.4). + } else if (context.sql_fingerprint) { match_conditions.push({ type: MatchConditionReqV1TypeEnum.fp_sql, content: context.sql_fingerprint diff --git a/packages/sqle/src/page/SqlManagement/component/SQLEEIndex/Modal/RemediationDetailDrawer/index.tsx b/packages/sqle/src/page/SqlManagement/component/SQLEEIndex/Modal/RemediationDetailDrawer/index.tsx index a54806f58..80adfc7ab 100644 --- a/packages/sqle/src/page/SqlManagement/component/SQLEEIndex/Modal/RemediationDetailDrawer/index.tsx +++ b/packages/sqle/src/page/SqlManagement/component/SQLEEIndex/Modal/RemediationDetailDrawer/index.tsx @@ -32,9 +32,13 @@ const RemediationDetailDrawerModal = () => { const handleOpenCreateException = useCallback( (params: OpenCreateAuditWhitelistExceptionParams) => { + // SQL管控抽屉加号:与列表同入口族,挂对象预填(S1 §5.4) openAuditWhitelistCreateWithPrefill( toSqlManageRuleExceptionRecord(selectedData ?? undefined), - { ruleName: params.auditResult?.rule_name } + { + ruleName: params.auditResult?.rule_name, + preferSchemaObjectMatch: true + } ); }, [openAuditWhitelistCreateWithPrefill, selectedData] diff --git a/packages/sqle/src/page/SqlManagement/component/SQLEEIndex/Modal/StatusDrawer/index.tsx b/packages/sqle/src/page/SqlManagement/component/SQLEEIndex/Modal/StatusDrawer/index.tsx index 6a53ec5dd..ff55f0123 100644 --- a/packages/sqle/src/page/SqlManagement/component/SQLEEIndex/Modal/StatusDrawer/index.tsx +++ b/packages/sqle/src/page/SqlManagement/component/SQLEEIndex/Modal/StatusDrawer/index.tsx @@ -104,9 +104,13 @@ const StatusDrawer = () => { const handleOpenCreateException = useCallback( (params: OpenCreateAuditWhitelistExceptionParams) => { + // SQL管控抽屉加号:与列表同入口族,挂对象预填(S1 §5.4) openAuditWhitelistCreateWithPrefill( toSqlManageRuleExceptionRecord(selectedData ?? undefined), - { ruleName: params.auditResult?.rule_name } + { + ruleName: params.auditResult?.rule_name, + preferSchemaObjectMatch: true + } ); }, [openAuditWhitelistCreateWithPrefill, selectedData] diff --git a/packages/sqle/src/page/SqlManagement/component/SQLEEIndex/index.tsx b/packages/sqle/src/page/SqlManagement/component/SQLEEIndex/index.tsx index 0f5b98910..a320ab682 100644 --- a/packages/sqle/src/page/SqlManagement/component/SQLEEIndex/index.tsx +++ b/packages/sqle/src/page/SqlManagement/component/SQLEEIndex/index.tsx @@ -320,9 +320,13 @@ const SQLEEIndex = () => { const onCreateWhitelist = useCallback( (record?: ISqlManage) => { + // SQL管控主路径:preferSchemaObjectMatch 仅本入口族(S1 §5.4) openAuditWhitelistCreateWithPrefill( toSqlManageRuleExceptionRecord(record), - { specificRuleScopeWithoutPreselect: true } + { + specificRuleScopeWithoutPreselect: true, + preferSchemaObjectMatch: true + } ); }, [openAuditWhitelistCreateWithPrefill] diff --git a/packages/sqle/src/page/SqlManagementConf/Detail/ScanTypeSqlCollection/index.tsx b/packages/sqle/src/page/SqlManagementConf/Detail/ScanTypeSqlCollection/index.tsx index a5458245c..171cc50af 100644 --- a/packages/sqle/src/page/SqlManagementConf/Detail/ScanTypeSqlCollection/index.tsx +++ b/packages/sqle/src/page/SqlManagementConf/Detail/ScanTypeSqlCollection/index.tsx @@ -220,12 +220,11 @@ const ScanTypeSqlCollection: React.FC = ({ (params: OpenCreateAuditWhitelistExceptionParams) => { closeRemediationDrawer(); setRemediationDrawerRecord(undefined); - // 扫描详情 A/B 共用:preferSchemaObjectMatch 入口隔离(勿传给 SQL管控等) + // AC-001a:扫描详情撤回库表对象预填,恢复改前指纹路径(勿传 preferSchemaObjectMatch) openAuditWhitelistCreateWithPrefill( toScanTaskRecord(remediationDrawerRecord), { - ruleName: params.auditResult?.rule_name, - preferSchemaObjectMatch: true + ruleName: params.auditResult?.rule_name } ); }, @@ -240,12 +239,11 @@ const ScanTypeSqlCollection: React.FC = ({ const handleOpenCreateExceptionFromReport = useCallback( (params: OpenCreateAuditWhitelistExceptionParams) => { closeReportDrawer(); - // 扫描详情 A/B 共用:preferSchemaObjectMatch 入口隔离(勿传给 SQL管控等) + // AC-001a:扫描详情撤回库表对象预填,恢复改前指纹路径(勿传 preferSchemaObjectMatch) openAuditWhitelistCreateWithPrefill( toScanTaskRecord(currentAuditResultRecord), { - ruleName: params.auditResult?.rule_name, - preferSchemaObjectMatch: true + ruleName: params.auditResult?.rule_name } ); }, From 6b632ae1a57ac1f7c487330dcc4e17affa427838 Mon Sep 17 00:00:00 2001 From: actiontech-zihan Date: Wed, 23 Sep 2026 17:20:10 +0800 Subject: [PATCH 5/5] test(ui): cover SQL manage object prefill fallback and info consume Add AC-001b missing-schema/object fingerprint fallback cases and toSqlManageRuleExceptionRecord info.schema_meta_name defaults (AC-011). Co-authored-by: Cursor --- .../RuleException/__tests__/utils.test.ts | 87 ++++++++++++++++++- 1 file changed, 86 insertions(+), 1 deletion(-) diff --git a/packages/sqle/src/page/RuleException/__tests__/utils.test.ts b/packages/sqle/src/page/RuleException/__tests__/utils.test.ts index f0b73d186..947c239c6 100644 --- a/packages/sqle/src/page/RuleException/__tests__/utils.test.ts +++ b/packages/sqle/src/page/RuleException/__tests__/utils.test.ts @@ -11,6 +11,7 @@ import { normalizeMatchRowsOrder, rowsToAuditWhitelistBody, rowsToBlacklistBody, + toSqlManageRuleExceptionRecord, validateAuditWhitelistMatchRows, validateMatchRows } from '../utils'; @@ -137,7 +138,7 @@ describe('sqle/page/RuleException/utils', () => { }); }); - it('buildBlacklistPrefillFromSqlManage does not fall back to fp_sql when preferSchemaObjectMatch lacks object', () => { + it('buildBlacklistPrefillFromSqlManage falls back to fp_sql when preferSchemaObjectMatch lacks object (AC-001b)', () => { expect( buildBlacklistPrefillFromSqlManage( { @@ -154,6 +155,55 @@ describe('sqle/page/RuleException/utils', () => { ) ).toEqual({ match_conditions: [ + { + type: MatchConditionReqV1TypeEnum.fp_sql, + content: 'CREATE TABLE `t` (`id` int)' + }, + { + type: MatchConditionReqV1TypeEnum.instance, + content: '123' + }, + { + type: MatchConditionReqV1TypeEnum.audit_task_type, + content: 'mysql_schema_meta' + }, + { + type: MatchConditionReqV1TypeEnum.audit_task_id, + content: '1' + }, + { + type: MatchConditionReqV1TypeEnum.sql_source, + content: 'audit_plan' + }, + { + type: MatchConditionReqV1TypeEnum.db_type, + content: 'MySQL' + } + ] + }); + }); + + it('buildBlacklistPrefillFromSqlManage falls back to fp_sql when preferSchemaObjectMatch lacks schema (AC-001b)', () => { + expect( + buildBlacklistPrefillFromSqlManage( + { + sql_fingerprint: 'CREATE TABLE `t` (`id` int)', + instance_id: '123', + db_type: 'MySQL', + schema_meta_name: 't', + source: { + sql_source_type: 'mysql_schema_meta', + sql_source_ids: ['1'] + } + }, + { preferSchemaObjectMatch: true } + ) + ).toEqual({ + match_conditions: [ + { + type: MatchConditionReqV1TypeEnum.fp_sql, + content: 'CREATE TABLE `t` (`id` int)' + }, { type: MatchConditionReqV1TypeEnum.instance, content: '123' @@ -178,6 +228,41 @@ describe('sqle/page/RuleException/utils', () => { }); }); + it('toSqlManageRuleExceptionRecord reads schema_name and info.schema_meta_name (AC-011 consume)', () => { + const withObject = { + sql_fingerprint: 'CREATE TABLE `v` (`id` int)', + schema_name: 'sqle', + info: { schema_meta_name: 'v_exc_target' } + }; + expect(toSqlManageRuleExceptionRecord(withObject)).toMatchObject({ + schema_name: 'sqle', + schema_meta_name: 'v_exc_target' + }); + + const emptyObjectName = { + sql_fingerprint: 'select 1', + schema_name: 'sqle', + info: { schema_meta_name: '' } + }; + expect( + toSqlManageRuleExceptionRecord(emptyObjectName)?.schema_meta_name + ).toBeUndefined(); + + const missingKey = { + sql_fingerprint: 'select 1', + info: {} + }; + expect( + toSqlManageRuleExceptionRecord(missingKey)?.schema_meta_name + ).toBeUndefined(); + + expect( + toSqlManageRuleExceptionRecord({ + sql_fingerprint: 'select 1' + })?.schema_meta_name + ).toBeUndefined(); + }); + it('buildBlacklistPrefillFromSqlManage skips audit task match for quick audit source', () => { expect( buildBlacklistPrefillFromSqlManage({