aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio_22/Tango.Portal.Chat.Web/Services/KqlGuard.cs
diff options
context:
space:
mode:
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.cs45
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);
+ }
+}