| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869 |
- using System.Globalization;
- using System.Threading;
- using Microsoft.Extensions.Logging;
- using SqlSugar;
- namespace Admin.NET.Plugin.AiDOP.Service.S8.Rules;
- /// <summary>
- /// S8-SQL-EVALUATOR-GUARD-P2-1:S8 三类 SQL evaluator 公共防护工具。
- /// 承载:
- /// 1) AIDOP_S8_EVALUATOR_COMMAND_TIMEOUT_SECONDS / AIDOP_S8_EVALUATOR_MAX_ROWS env 解析(含默认值与下限保护,解析失败单次 warn);
- /// 2) ApplyCommandTimeout:在 evaluator 独立 SqlSugarScope 上显式设置 Ado.CommandTimeOut;
- /// 3) EnsureRowCountWithinLimit:检查返回行数,超限抛 S8RuleEvaluatorException(result_too_many_rows)。
- /// 不承载业务规则判断;不访问数据库;不修改 rule;不写业务数据明细;不读取 rule.Expression / dataSource.Endpoint / rule.ParamsJson。
- /// </summary>
- internal static class S8EvaluatorGuard
- {
- public const int DefaultCommandTimeoutSeconds = 60;
- public const int MinCommandTimeoutSeconds = 5;
- public const int DefaultMaxRows = 1000;
- public const int MinMaxRows = 1;
- public const string EnvCommandTimeoutSeconds = "AIDOP_S8_EVALUATOR_COMMAND_TIMEOUT_SECONDS";
- public const string EnvMaxRows = "AIDOP_S8_EVALUATOR_MAX_ROWS";
- // 单进程内 AIDOP_S8_EVALUATOR_* 解析失败 warn 仅输出一次,避免日志刷屏。
- // 与 S8WatchSchedulerJob._firstParseFailLogged 同形(Interlocked.Exchange 单次锚点)。
- private static int _firstParseFailLogged;
- public static int ResolveCommandTimeoutSeconds(ILogger? logger = null) =>
- ResolveIntFromEnv(EnvCommandTimeoutSeconds, DefaultCommandTimeoutSeconds, MinCommandTimeoutSeconds, logger);
- public static int ResolveMaxRows(ILogger? logger = null) =>
- ResolveIntFromEnv(EnvMaxRows, DefaultMaxRows, MinMaxRows, logger);
- public static void ApplyCommandTimeout(SqlSugarScope scope, int seconds)
- {
- scope.Ado.CommandTimeOut = seconds;
- }
- /// <summary>
- /// 检查 evaluator SQL 返回行数;超限抛 S8RuleEvaluatorException(result_too_many_rows)。
- /// 异常 message 仅含 ruleType / ruleCode / 实际行数 / 上限值,禁止携带 SQL 全文、连接串、ParamsJson、返回行内容。
- /// </summary>
- public static void EnsureRowCountWithinLimit(int actualRows, int maxRows, string ruleType, string ruleCode)
- {
- if (actualRows > maxRows)
- {
- throw new S8RuleEvaluatorException(
- "result_too_many_rows",
- $"{ruleType} 规则 {ruleCode} 返回 {actualRows} 行,超过安全上限 {maxRows},请缩小规则条件或拆分规则");
- }
- }
- private static int ResolveIntFromEnv(string envName, int defaultValue, int minValue, ILogger? logger)
- {
- var raw = Environment.GetEnvironmentVariable(envName);
- if (string.IsNullOrWhiteSpace(raw)) return defaultValue;
- if (int.TryParse(raw.Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out var v) && v >= minValue)
- return v;
- if (Interlocked.Exchange(ref _firstParseFailLogged, 1) == 0 && logger != null)
- {
- logger.LogWarning(
- "s8_evaluator_guard_env_invalid env={Env} fallback={Fallback}",
- envName, defaultValue);
- }
- return defaultValue;
- }
- }
|