@@ -1043,6 +1043,24 @@ func makeHttpRequest(ctx context.Context, url string, headers map[string]string,
10431043}
10441044
10451045// AuditMiddleware 拦截工作台odc请求进行加工
1046+ //
1047+ // 设计原则(issue #850, bug 修复):
1048+ //
1049+ // 本中间件提供的是「在 streamExecute 反代到 ODC 前叠加 SQLE 审核」的增强能力,
1050+ // 不是业务流的必经环节。当:
1051+ // - SQL/数据源 ID 解析失败;
1052+ // - 缓存 / 用户上下文缺失;
1053+ // - 该 DBService 未开启 SQL 审核;
1054+ // - SQLE 服务自身调用失败;
1055+ //
1056+ // 均应**透传放行**(fail-open,return next(c))让 ODC 继续执行用户的 SQL,
1057+ // 而不是把请求 400 掉、让用户连查询都跑不通。只有审核**明确返回需要拦截**
1058+ // 的结果(如规则违反需审批)才走 buildAuditResponseWithoutExecution 路径。
1059+ //
1060+ // 修复前:未启用审核 / 缓存缺失 / 用户解析失败 等辅助路径异常均直接
1061+ // `return errors.New(...)`,被 dms 的 HTTPErrorHandler 统一映射成 400,
1062+ // 导致 case-pg-mysql-baseline-001 等用例在 SQL Console 上完全无法运行(见
1063+ // docs/dev/fix-task-004-odc-streamExecute-400.md)。
10461064func (sqlWorkbenchService * SqlWorkbenchService ) AuditMiddleware () echo.MiddlewareFunc {
10471065 return func (next echo.HandlerFunc ) echo.HandlerFunc {
10481066 return func (c echo.Context ) error {
@@ -1054,7 +1072,8 @@ func (sqlWorkbenchService *SqlWorkbenchService) AuditMiddleware() echo.Middlewar
10541072 // 读取请求体
10551073 bodyBytes , err := io .ReadAll (c .Request ().Body )
10561074 if err != nil {
1057- sqlWorkbenchService .log .Errorf ("failed to read request body: %v" , err )
1075+ // body 读不出来无法叠加审核,但也无法继续构造反代请求;保留 fail-closed。
1076+ sqlWorkbenchService .log .Errorf ("failed to read streamExecute request body: %v" , err )
10581077 return errors .New (locale .Bundle .LocalizeMsgByCtx (c .Request ().Context (), locale .SqlWorkbenchAuditReadReqBodyErr ))
10591078 }
10601079 // 恢复请求体,供后续处理使用
@@ -1063,7 +1082,6 @@ func (sqlWorkbenchService *SqlWorkbenchService) AuditMiddleware() echo.Middlewar
10631082 // 解析请求体获取 SQL 和 datasource ID
10641083 // 注意:解析仅服务于审核辅助路径,解析失败不应直接阻塞用户的 SQL 执行;
10651084 // 否则一旦中间件辅助能力出错(如 sid 解码失败),用户连查询都跑不了。
1066- // 真正的「未启用审核 / 审核失败」等强策略仍由后续分支按既有 fail-closed 处理。
10671085 sql , sidInfo , err := sqlWorkbenchService .parseStreamExecuteRequest (bodyBytes )
10681086 if err != nil {
10691087 sqlWorkbenchService .log .Warnf ("failed to parse streamExecute request, skipping audit: %v" , err )
@@ -1079,32 +1097,37 @@ func (sqlWorkbenchService *SqlWorkbenchService) AuditMiddleware() echo.Middlewar
10791097 // 获取当前用户 ID
10801098 dmsUserId , err := sqlWorkbenchService .getDMSUserIdFromRequest (c )
10811099 if err != nil {
1082- sqlWorkbenchService .log .Errorf ("failed to get DMS user ID: %v" , err )
1083- return errors .New (locale .Bundle .LocalizeMsgByCtx (c .Request ().Context (), locale .SqlWorkbenchAuditGetDMSUserErr ))
1100+ // 审计需要用户上下文,缺失时跳过审计而非阻塞执行(鉴权由前置 Login() 已经把关)。
1101+ sqlWorkbenchService .log .Warnf ("failed to get DMS user ID, skipping audit: %v" , err )
1102+ return next (c )
10841103 }
10851104
10861105 // 从缓存表获取 dms_db_service_id
10871106 dmsDBServiceID , err := sqlWorkbenchService .getDMSDBServiceIDFromCache (c .Request ().Context (), datasourceID , dmsUserId )
10881107 if err != nil {
1089- sqlWorkbenchService .log .Errorf ("failed to get dms_db_service_id from cache: %v" , err )
1090- return errors .New (locale .Bundle .LocalizeMsgByCtx (c .Request ().Context (), locale .SqlWorkbenchAuditGetDBServiceMappingErr ))
1108+ // 缓存查询失败属于辅助路径异常,不应阻塞 SQL 执行。
1109+ sqlWorkbenchService .log .Warnf ("failed to get dms_db_service_id from cache, skipping audit: %v" , err )
1110+ return next (c )
10911111 }
10921112
10931113 if dmsDBServiceID == "" {
1094- sqlWorkbenchService .log .Debugf ("dms_db_service_id not found in cache for datasource: %s" , datasourceID )
1095- return errors .New (locale .Bundle .LocalizeMsgByCtx (c .Request ().Context (), locale .SqlWorkbenchAuditDBServiceMappingNotFoundErr ))
1114+ // 用户首次在工作台使用该数据源 / 数据源未走"通过 DMS 加载"路径时缓存为空,应放行。
1115+ sqlWorkbenchService .log .Warnf ("dms_db_service_id not found in cache for datasource=%s, skipping audit" , datasourceID )
1116+ return next (c )
10961117 }
10971118
10981119 // 获取 DBService 信息
10991120 dbService , err := sqlWorkbenchService .dbServiceUsecase .GetDBService (c .Request ().Context (), dmsDBServiceID )
11001121 if err != nil {
1101- sqlWorkbenchService .log .Errorf ("failed to get DBService: %v" , err )
1102- return errors .New (locale .Bundle .LocalizeMsgByCtx (c .Request ().Context (), locale .SqlWorkbenchAuditGetDBServiceErr ))
1122+ // DBService 元数据查询失败属于辅助路径异常,不应阻塞 SQL 执行。
1123+ sqlWorkbenchService .log .Warnf ("failed to get DBService %s, skipping audit: %v" , dmsDBServiceID , err )
1124+ return next (c )
11031125 }
11041126
11051127 // 未开启 SQL 审核时直接放行,由 ODC 执行 SQL
11061128 if ! sqlWorkbenchService .isEnableSQLAudit (dbService ) {
1107- sqlWorkbenchService .log .Debugf ("SQL audit is not enabled for DBService: %s" , dmsDBServiceID )
1129+ // 未启用审核 = 该数据源没要求审核加强,按裸 ODC 反代行为放行。
1130+ sqlWorkbenchService .log .Debugf ("SQL audit is not enabled for DBService %s, skipping audit" , dmsDBServiceID )
11081131 return next (c )
11091132 }
11101133
@@ -1121,8 +1144,9 @@ func (sqlWorkbenchService *SqlWorkbenchService) AuditMiddleware() echo.Middlewar
11211144 // 调用 SQLE 审核接口
11221145 auditResult , err := sqlWorkbenchService .callSQLEAudit (c .Request ().Context (), sql , dbService , schemaName )
11231146 if err != nil {
1124- sqlWorkbenchService .log .Errorf ("call SQLE audit failed: %v" , err )
1125- return errors .New (locale .Bundle .LocalizeMsgByCtx (c .Request ().Context (), locale .SqlWorkbenchAuditCallSQLEErr ))
1147+ // SQLE 服务自身故障(连不上、超时等)不应让用户的 SQL 执行链路一起挂;放行并打 Warn 便于排障。
1148+ sqlWorkbenchService .log .Warnf ("call SQLE audit failed, skipping audit: %v" , err )
1149+ return next (c )
11261150 }
11271151
11281152 // 拦截响应并添加审核结果
0 commit comments