diff options
Diffstat (limited to 'Software/Visual_Studio_22/Tango.Portal.Chat.Web/Services/KqlGuard.cs')
| -rw-r--r-- | Software/Visual_Studio_22/Tango.Portal.Chat.Web/Services/KqlGuard.cs | 45 |
1 files changed, 45 insertions, 0 deletions
diff --git a/Software/Visual_Studio_22/Tango.Portal.Chat.Web/Services/KqlGuard.cs b/Software/Visual_Studio_22/Tango.Portal.Chat.Web/Services/KqlGuard.cs new file mode 100644 index 000000000..6ce4e44c9 --- /dev/null +++ b/Software/Visual_Studio_22/Tango.Portal.Chat.Web/Services/KqlGuard.cs @@ -0,0 +1,45 @@ +using System.Text.RegularExpressions; + +namespace ChatADX.Web.Services +{ + public sealed class KqlGuard + { + private static readonly string[] Banned = new[] { + "externaldata", "evaluate", "cluster(", "database(", "ingest", "print", "datatable", "delete", "drop", "truncate", "update", "set", "declare", "let", "materializedview", "mv-merge", "alter", "create", "append", "ingestiontime()", ".show", ".set", ".clear", ".drop", ".alter" + }; + + public KqlValidationResult Validate(string kql) + { + var text = kql.ToLowerInvariant(); + + foreach (var token in Banned) + if (text.Contains(token)) + return KqlValidationResult.Fail($"Query uses banned token: {token}"); + + // Ensure only allowed tables are referenced (quick heuristic) + //var tableNames = new HashSet<string>(allowTables.Select(t => t.ToLowerInvariant())); + //var tableRefs = Regex.Matches(text, @"\b([A-Za-z_][A-Za-z0-9_]*)\bTable").Cast<Match>().Select(m => m.Value.ToLowerInvariant().Replace("table", "")); + + //foreach (var tr in tableRefs) + // if (!tableNames.Contains(tr)) + // return KqlValidationResult.Fail($"Query references non-allowlisted table: {tr}"); + + // Encourage summarize/top/take to avoid huge result sets + //if (!(text.Contains("summarize") || text.Contains("| take ") || text.Contains("| top "))) + // return KqlValidationResult.Fail("Query must include summarize/top/take to limit results."); + + return KqlValidationResult.Ok(); + } + } + + public readonly struct KqlValidationResult + { + public bool IsOk { get; } + public string? Error { get; } + + private KqlValidationResult(bool ok, string? error) { IsOk = ok; Error = error; } + + public static KqlValidationResult Ok() => new(true, null); + public static KqlValidationResult Fail(string error) => new(false, error); + } +} |
