Resolve Server-007..014 code-review findings

Server-007: GalaxyHierarchyProjector re-filtered the whole hierarchy per
page (O(total) paging). It now memoizes the filtered list per cache-entry +
filter signature so subsequent pages are an O(pageSize) slice.

Server-008: WatchDeployEvents re-resolved browse subtrees and rebuilt globs
per streamed event. ResolveBrowseSubtrees is hoisted out of the loop and
GalaxyGlobMatcher caches compiled Regex instances per pattern.

Server-009: auth-store connections used no busy timeout or WAL. A new
OpenConnectionAsync applies journal_mode=WAL and a busy_timeout; all auth
call sites use it. docs/Authentication.md updated.

Server-010: the dashboard rendered Rotate/Revoke for revoked keys, where
Rotate silently reactivates them. ApiKeysPage now shows actions only for
Active keys. docs/Authentication.md updated.

Server-011: WorkerAlarmRpcDispatcher converted to a primary constructor and
brought in line with module conventions.

Server-012: CLAUDE.md corrected to the canonical *:* scope strings.

Server-013 (partly re-triaged): three named coverage gaps were already
closed; the genuine gap (WorkerExecutableValidator) is now covered.

Server-014: rewrote stale "alarm path not yet wired" comments in
MxAccessGatewayService to describe the production WorkerAlarmRpcDispatcher.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Joseph Doherty
2026-05-18 22:42:06 -04:00
parent a02faa6ade
commit fe9044115b
18 changed files with 552 additions and 139 deletions
@@ -10,7 +10,17 @@ namespace MxGateway.Server.Security.Authentication;
public sealed class AuthSqliteConnectionFactory(IOptions<GatewayOptions> options)
{
/// <summary>
/// Creates and configures a SQLite connection to the auth database.
/// Busy timeout applied to every auth-store connection. SQLite retries a busy
/// database for this long before surfacing <c>SQLITE_BUSY</c>, so the concurrent
/// <c>MarkKeyUsedAsync</c> / audit-append writers degrade gracefully under load
/// instead of failing the request path.
/// </summary>
private static readonly TimeSpan BusyTimeout = TimeSpan.FromSeconds(5);
/// <summary>
/// Creates an unopened SQLite connection to the auth database. Prefer
/// <see cref="OpenConnectionAsync"/>, which also applies WAL journaling and the
/// busy timeout.
/// </summary>
public SqliteConnection CreateConnection()
{
@@ -25,9 +35,44 @@ public sealed class AuthSqliteConnectionFactory(IOptions<GatewayOptions> options
SqliteConnectionStringBuilder builder = new()
{
DataSource = sqlitePath,
Mode = SqliteOpenMode.ReadWriteCreate
Mode = SqliteOpenMode.ReadWriteCreate,
Pooling = true,
DefaultTimeout = (int)BusyTimeout.TotalSeconds,
};
return new SqliteConnection(builder.ToString());
}
/// <summary>
/// Creates a SQLite connection, opens it, and configures WAL journaling and a
/// non-zero busy timeout so concurrent readers and writers degrade gracefully
/// rather than surfacing <c>SQLITE_BUSY</c> as a hard failure.
/// </summary>
public async Task<SqliteConnection> OpenConnectionAsync(CancellationToken cancellationToken)
{
SqliteConnection connection = CreateConnection();
try
{
await connection.OpenAsync(cancellationToken).ConfigureAwait(false);
await ConfigureConnectionAsync(connection, cancellationToken).ConfigureAwait(false);
return connection;
}
catch
{
await connection.DisposeAsync().ConfigureAwait(false);
throw;
}
}
private static async Task ConfigureConnectionAsync(
SqliteConnection connection,
CancellationToken cancellationToken)
{
// WAL is a persistent, database-level setting; re-applying it per connection
// is cheap and a no-op once set. busy_timeout is per-connection state.
await using SqliteCommand command = connection.CreateCommand();
command.CommandText =
$"PRAGMA journal_mode=WAL; PRAGMA busy_timeout={(int)BusyTimeout.TotalMilliseconds};";
await command.ExecuteNonQueryAsync(cancellationToken).ConfigureAwait(false);
}
}
@@ -10,8 +10,7 @@ public sealed class SqliteApiKeyAdminStore(AuthSqliteConnectionFactory connectio
/// <inheritdoc />
public async Task CreateAsync(ApiKeyCreateRequest request, CancellationToken cancellationToken)
{
await using SqliteConnection connection = connectionFactory.CreateConnection();
await connection.OpenAsync(cancellationToken).ConfigureAwait(false);
await using SqliteConnection connection = await connectionFactory.OpenConnectionAsync(cancellationToken).ConfigureAwait(false);
await using SqliteCommand command = connection.CreateCommand();
command.CommandText = """
@@ -44,8 +43,7 @@ public sealed class SqliteApiKeyAdminStore(AuthSqliteConnectionFactory connectio
/// <inheritdoc />
public async Task<IReadOnlyList<ApiKeyRecord>> ListAsync(CancellationToken cancellationToken)
{
await using SqliteConnection connection = connectionFactory.CreateConnection();
await connection.OpenAsync(cancellationToken).ConfigureAwait(false);
await using SqliteConnection connection = await connectionFactory.OpenConnectionAsync(cancellationToken).ConfigureAwait(false);
await using SqliteCommand command = connection.CreateCommand();
command.CommandText = """
@@ -70,8 +68,7 @@ public sealed class SqliteApiKeyAdminStore(AuthSqliteConnectionFactory connectio
/// <inheritdoc />
public async Task<bool> RevokeAsync(string keyId, DateTimeOffset revokedUtc, CancellationToken cancellationToken)
{
await using SqliteConnection connection = connectionFactory.CreateConnection();
await connection.OpenAsync(cancellationToken).ConfigureAwait(false);
await using SqliteConnection connection = await connectionFactory.OpenConnectionAsync(cancellationToken).ConfigureAwait(false);
await using SqliteCommand command = connection.CreateCommand();
command.CommandText = """
@@ -94,8 +91,7 @@ public sealed class SqliteApiKeyAdminStore(AuthSqliteConnectionFactory connectio
DateTimeOffset rotatedUtc,
CancellationToken cancellationToken)
{
await using SqliteConnection connection = connectionFactory.CreateConnection();
await connection.OpenAsync(cancellationToken).ConfigureAwait(false);
await using SqliteConnection connection = await connectionFactory.OpenConnectionAsync(cancellationToken).ConfigureAwait(false);
await using SqliteCommand command = connection.CreateCommand();
command.CommandText = """
@@ -7,8 +7,7 @@ public sealed class SqliteApiKeyAuditStore(AuthSqliteConnectionFactory connectio
/// <inheritdoc />
public async Task AppendAsync(ApiKeyAuditEntry entry, CancellationToken cancellationToken)
{
await using SqliteConnection connection = connectionFactory.CreateConnection();
await connection.OpenAsync(cancellationToken).ConfigureAwait(false);
await using SqliteConnection connection = await connectionFactory.OpenConnectionAsync(cancellationToken).ConfigureAwait(false);
await using SqliteCommand command = connection.CreateCommand();
command.CommandText = """
@@ -32,8 +31,7 @@ public sealed class SqliteApiKeyAuditStore(AuthSqliteConnectionFactory connectio
return [];
}
await using SqliteConnection connection = connectionFactory.CreateConnection();
await connection.OpenAsync(cancellationToken).ConfigureAwait(false);
await using SqliteConnection connection = await connectionFactory.OpenConnectionAsync(cancellationToken).ConfigureAwait(false);
await using SqliteCommand command = connection.CreateCommand();
command.CommandText = """
@@ -20,8 +20,7 @@ public sealed class SqliteApiKeyStore(AuthSqliteConnectionFactory connectionFact
/// <inheritdoc />
public async Task MarkKeyUsedAsync(string keyId, DateTimeOffset usedUtc, CancellationToken cancellationToken)
{
await using SqliteConnection connection = connectionFactory.CreateConnection();
await connection.OpenAsync(cancellationToken).ConfigureAwait(false);
await using SqliteConnection connection = await connectionFactory.OpenConnectionAsync(cancellationToken).ConfigureAwait(false);
await using SqliteCommand command = connection.CreateCommand();
command.CommandText = """
@@ -40,8 +39,7 @@ public sealed class SqliteApiKeyStore(AuthSqliteConnectionFactory connectionFact
bool requireActive,
CancellationToken cancellationToken)
{
await using SqliteConnection connection = connectionFactory.CreateConnection();
await connection.OpenAsync(cancellationToken).ConfigureAwait(false);
await using SqliteConnection connection = await connectionFactory.OpenConnectionAsync(cancellationToken).ConfigureAwait(false);
await using SqliteCommand command = connection.CreateCommand();
command.CommandText = requireActive
@@ -8,8 +8,7 @@ public sealed class SqliteAuthStoreMigrator(AuthSqliteConnectionFactory connecti
/// <param name="cancellationToken">Cancellation token.</param>
public async Task MigrateAsync(CancellationToken cancellationToken)
{
await using SqliteConnection connection = connectionFactory.CreateConnection();
await connection.OpenAsync(cancellationToken).ConfigureAwait(false);
await using SqliteConnection connection = await connectionFactory.OpenConnectionAsync(cancellationToken).ConfigureAwait(false);
await using SqliteTransaction transaction =
(SqliteTransaction)await connection.BeginTransactionAsync(cancellationToken).ConfigureAwait(false);