fix(site-event-logging): resolve SiteEventLogging-012..014 — fault dropped-event tasks, escape LIKE wildcards, re-triage startup-purge finding (Won't Fix)
This commit is contained in:
@@ -30,6 +30,19 @@ public class EventLogQueryService : IEventLogQueryService
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Escapes the SQL <c>LIKE</c> metacharacters (<c>\</c>, <c>%</c>, <c>_</c>) in a
|
||||
/// user-supplied keyword so it is matched as a literal substring. Used together
|
||||
/// with a <c>LIKE ... ESCAPE '\'</c> clause.
|
||||
/// </summary>
|
||||
private static string EscapeLikePattern(string input)
|
||||
{
|
||||
return input
|
||||
.Replace("\\", "\\\\")
|
||||
.Replace("%", "\\%")
|
||||
.Replace("_", "\\_");
|
||||
}
|
||||
|
||||
public EventLogQueryResponse ExecuteQuery(EventLogQueryRequest request)
|
||||
{
|
||||
try
|
||||
@@ -78,8 +91,14 @@ public class EventLogQueryService : IEventLogQueryService
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(request.KeywordFilter))
|
||||
{
|
||||
whereClauses.Add("(message LIKE $keyword OR source LIKE $keyword)");
|
||||
parameters.Add(new SqliteParameter("$keyword", $"%{request.KeywordFilter}%"));
|
||||
// Keyword search is a literal substring match. The LIKE
|
||||
// metacharacters % and _ (and the escape char itself) must be
|
||||
// escaped so identifiers such as "store_and_forward" or a literal
|
||||
// "%" are not misinterpreted as wildcards (SiteEventLogging-013).
|
||||
var escaped = EscapeLikePattern(request.KeywordFilter);
|
||||
whereClauses.Add(
|
||||
"(message LIKE $keyword ESCAPE '\\' OR source LIKE $keyword ESCAPE '\\')");
|
||||
parameters.Add(new SqliteParameter("$keyword", $"%{escaped}%"));
|
||||
}
|
||||
|
||||
var whereClause = whereClauses.Count > 0
|
||||
|
||||
@@ -160,9 +160,13 @@ public class SiteEventLogger : ISiteEventLogger, IDisposable
|
||||
if (!_writeQueue.Writer.TryWrite(pending))
|
||||
{
|
||||
// The channel is unbounded, so the only way TryWrite fails is that the
|
||||
// writer has been completed (logger disposed). Drop silently — there is
|
||||
// nowhere to persist the event.
|
||||
pending.Completion.TrySetResult();
|
||||
// writer has been completed (logger disposed). The event cannot be
|
||||
// persisted — fault the Task (SiteEventLogging-012) rather than
|
||||
// reporting false success, so a caller that awaits a critical audit
|
||||
// event can tell it was dropped.
|
||||
pending.Completion.TrySetException(
|
||||
new ObjectDisposedException(nameof(SiteEventLogger),
|
||||
"Event could not be recorded: the event logger has been disposed."));
|
||||
}
|
||||
|
||||
return pending.Completion.Task;
|
||||
@@ -191,9 +195,20 @@ public class SiteEventLogger : ISiteEventLogger, IDisposable
|
||||
cmd.ExecuteNonQuery();
|
||||
});
|
||||
|
||||
// WithConnection returns false only when the logger has been
|
||||
// disposed; the event simply cannot be persisted in that case.
|
||||
pending.Completion.TrySetResult();
|
||||
if (written)
|
||||
{
|
||||
pending.Completion.TrySetResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
// WithConnection returns false only when the logger has been
|
||||
// disposed mid-drain; the event was not persisted. Fault the
|
||||
// Task (SiteEventLogging-012) instead of reporting false
|
||||
// success for a dropped audit event.
|
||||
pending.Completion.TrySetException(
|
||||
new ObjectDisposedException(nameof(SiteEventLogger),
|
||||
"Event could not be recorded: the event logger was disposed before the write completed."));
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user