@@ -1121,6 +1121,24 @@ func makeHttpRequest(ctx context.Context, url string, headers map[string]string,
11211121}
11221122
11231123// AuditMiddleware 拦截工作台odc请求进行加工
1124+ //
1125+ // 设计原则(issue #850, bug 修复):
1126+ //
1127+ // 本中间件提供的是「在 streamExecute 反代到 ODC 前叠加 SQLE 审核」的增强能力,
1128+ // 不是业务流的必经环节。当:
1129+ // - SQL/数据源 ID 解析失败;
1130+ // - 缓存 / 用户上下文缺失;
1131+ // - 该 DBService 未开启 SQL 审核;
1132+ // - SQLE 服务自身调用失败;
1133+ //
1134+ // 均应**透传放行**(fail-open,return next(c))让 ODC 继续执行用户的 SQL,
1135+ // 而不是把请求 400 掉、让用户连查询都跑不通。只有审核**明确返回需要拦截**
1136+ // 的结果(如规则违反需审批)才走 buildAuditResponseWithoutExecution 路径。
1137+ //
1138+ // 修复前:未启用审核 / 缓存缺失 / 用户解析失败 等辅助路径异常均直接
1139+ // `return errors.New(...)`,被 dms 的 HTTPErrorHandler 统一映射成 400,
1140+ // 导致 case-pg-mysql-baseline-001 等用例在 SQL Console 上完全无法运行(见
1141+ // docs/dev/fix-task-004-odc-streamExecute-400.md)。
11241142func (sqlWorkbenchService * SqlWorkbenchService ) AuditMiddleware () echo.MiddlewareFunc {
11251143 return func (next echo.HandlerFunc ) echo.HandlerFunc {
11261144 return func (c echo.Context ) error {
@@ -1132,7 +1150,8 @@ func (sqlWorkbenchService *SqlWorkbenchService) AuditMiddleware() echo.Middlewar
11321150 // 读取请求体
11331151 bodyBytes , err := io .ReadAll (c .Request ().Body )
11341152 if err != nil {
1135- sqlWorkbenchService .log .Errorf ("failed to read request body: %v" , err )
1153+ // body 读不出来无法叠加审核,但也无法继续构造反代请求;保留 fail-closed。
1154+ sqlWorkbenchService .log .Errorf ("failed to read streamExecute request body: %v" , err )
11361155 return errors .New (locale .Bundle .LocalizeMsgByCtx (c .Request ().Context (), locale .SqlWorkbenchAuditReadReqBodyErr ))
11371156 }
11381157 // 恢复请求体,供后续处理使用
@@ -1141,7 +1160,6 @@ func (sqlWorkbenchService *SqlWorkbenchService) AuditMiddleware() echo.Middlewar
11411160 // 解析请求体获取 SQL 和 datasource ID
11421161 // 注意:解析仅服务于审核辅助路径,解析失败不应直接阻塞用户的 SQL 执行;
11431162 // 否则一旦中间件辅助能力出错(如 sid 解码失败),用户连查询都跑不了。
1144- // 真正的「未启用审核 / 审核失败」等强策略仍由后续分支按既有 fail-closed 处理。
11451163 sql , sidInfo , err := sqlWorkbenchService .parseStreamExecuteRequest (bodyBytes )
11461164 if err != nil {
11471165 sqlWorkbenchService .log .Warnf ("failed to parse streamExecute request, skipping audit: %v" , err )
@@ -1157,32 +1175,37 @@ func (sqlWorkbenchService *SqlWorkbenchService) AuditMiddleware() echo.Middlewar
11571175 // 获取当前用户 ID
11581176 dmsUserId , err := sqlWorkbenchService .getDMSUserIdFromRequest (c )
11591177 if err != nil {
1160- sqlWorkbenchService .log .Errorf ("failed to get DMS user ID: %v" , err )
1161- return errors .New (locale .Bundle .LocalizeMsgByCtx (c .Request ().Context (), locale .SqlWorkbenchAuditGetDMSUserErr ))
1178+ // 审计需要用户上下文,缺失时跳过审计而非阻塞执行(鉴权由前置 Login() 已经把关)。
1179+ sqlWorkbenchService .log .Warnf ("failed to get DMS user ID, skipping audit: %v" , err )
1180+ return next (c )
11621181 }
11631182
11641183 // 从缓存表获取 dms_db_service_id
11651184 dmsDBServiceID , err := sqlWorkbenchService .getDMSDBServiceIDFromCache (c .Request ().Context (), datasourceID , dmsUserId )
11661185 if err != nil {
1167- sqlWorkbenchService .log .Errorf ("failed to get dms_db_service_id from cache: %v" , err )
1168- return errors .New (locale .Bundle .LocalizeMsgByCtx (c .Request ().Context (), locale .SqlWorkbenchAuditGetDBServiceMappingErr ))
1186+ // 缓存查询失败属于辅助路径异常,不应阻塞 SQL 执行。
1187+ sqlWorkbenchService .log .Warnf ("failed to get dms_db_service_id from cache, skipping audit: %v" , err )
1188+ return next (c )
11691189 }
11701190
11711191 if dmsDBServiceID == "" {
1172- sqlWorkbenchService .log .Debugf ("dms_db_service_id not found in cache for datasource: %s" , datasourceID )
1173- return errors .New (locale .Bundle .LocalizeMsgByCtx (c .Request ().Context (), locale .SqlWorkbenchAuditDBServiceMappingNotFoundErr ))
1192+ // 用户首次在工作台使用该数据源 / 数据源未走"通过 DMS 加载"路径时缓存为空,应放行。
1193+ sqlWorkbenchService .log .Warnf ("dms_db_service_id not found in cache for datasource=%s, skipping audit" , datasourceID )
1194+ return next (c )
11741195 }
11751196
11761197 // 获取 DBService 信息
11771198 dbService , err := sqlWorkbenchService .dbServiceUsecase .GetDBService (c .Request ().Context (), dmsDBServiceID )
11781199 if err != nil {
1179- sqlWorkbenchService .log .Errorf ("failed to get DBService: %v" , err )
1180- return errors .New (locale .Bundle .LocalizeMsgByCtx (c .Request ().Context (), locale .SqlWorkbenchAuditGetDBServiceErr ))
1200+ // DBService 元数据查询失败属于辅助路径异常,不应阻塞 SQL 执行。
1201+ sqlWorkbenchService .log .Warnf ("failed to get DBService %s, skipping audit: %v" , dmsDBServiceID , err )
1202+ return next (c )
11811203 }
11821204
11831205 // 未开启 SQL 审核时直接放行,由 ODC 执行 SQL
11841206 if ! sqlWorkbenchService .isEnableSQLAudit (dbService ) {
1185- sqlWorkbenchService .log .Debugf ("SQL audit is not enabled for DBService: %s" , dmsDBServiceID )
1207+ // 未启用审核 = 该数据源没要求审核加强,按裸 ODC 反代行为放行。
1208+ sqlWorkbenchService .log .Debugf ("SQL audit is not enabled for DBService %s, skipping audit" , dmsDBServiceID )
11861209 return next (c )
11871210 }
11881211
@@ -1199,8 +1222,9 @@ func (sqlWorkbenchService *SqlWorkbenchService) AuditMiddleware() echo.Middlewar
11991222 // 调用 SQLE 审核接口
12001223 auditResult , err := sqlWorkbenchService .callSQLEAudit (c .Request ().Context (), sql , dbService , schemaName )
12011224 if err != nil {
1202- sqlWorkbenchService .log .Errorf ("call SQLE audit failed: %v" , err )
1203- return errors .New (locale .Bundle .LocalizeMsgByCtx (c .Request ().Context (), locale .SqlWorkbenchAuditCallSQLEErr ))
1225+ // SQLE 服务自身故障(连不上、超时等)不应让用户的 SQL 执行链路一起挂;放行并打 Warn 便于排障。
1226+ sqlWorkbenchService .log .Warnf ("call SQLE audit failed, skipping audit: %v" , err )
1227+ return next (c )
12041228 }
12051229
12061230 // 拦截响应并添加审核结果
0 commit comments