docs: complete XML-doc coverage and strip internal tracking IDs from code comments
Resolve all CommentChecker findings across the gateway server, worker, tests, and .NET client (314 -> 0 real issues): add missing <returns>/<summary>/<param> on public and test members, convert Stream/interface overrides to <inheritdoc/>, and remove internal task/issue tracking IDs (SEC-*, IPC-*, WRK-*, GWC-*, TST-*, Client.Dotnet-*) from shipped code documentation while preserving the design rationale prose. Shipped comments should not carry internal bookkeeping, and complete XML docs keep the analyzer/TreatWarningsAsErrors gate and generated API docs clean. The 6 remaining flags are heuristic false positives (MD5, UTC-4, capacity-1, near-1601) left intact so real documentation is not corrupted. Claude-Session: https://claude.ai/code/session_01DMXXvNuPekkkrTEyPNxEkW
This commit is contained in:
@@ -14,7 +14,7 @@ public sealed class GatewayOptionsTests
|
||||
GatewayOptions options = BindOptions(new Dictionary<string, string?>());
|
||||
|
||||
Assert.Equal(AuthenticationMode.ApiKey, options.Authentication.Mode);
|
||||
// SEC-01: the default is derived from CommonApplicationData (C:\ProgramData on Windows,
|
||||
// The default is derived from CommonApplicationData (C:\ProgramData on Windows,
|
||||
// /usr/share on Unix) rather than a Windows literal, so assert against the same derivation
|
||||
// to stay platform-correct.
|
||||
Assert.Equal(
|
||||
@@ -35,7 +35,7 @@ public sealed class GatewayOptionsTests
|
||||
Assert.Equal(10, options.Worker.ShutdownTimeoutSeconds);
|
||||
Assert.Equal(5, options.Worker.HeartbeatIntervalSeconds);
|
||||
Assert.Equal(15, options.Worker.HeartbeatGraceSeconds);
|
||||
// 16 MiB public gRPC cap plus the 64 KiB worker-frame envelope reserve (IPC-03 headroom).
|
||||
// 16 MiB public gRPC cap plus the 64 KiB worker-frame envelope reserve for headroom.
|
||||
Assert.Equal((16 * 1024 * 1024) + (64 * 1024), options.Worker.MaxMessageBytes);
|
||||
|
||||
Assert.Equal(30, options.Sessions.DefaultCommandTimeoutSeconds);
|
||||
|
||||
@@ -550,10 +550,6 @@ public sealed class GatewayOptionsValidatorTests
|
||||
Assert.True(result.Succeeded);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// SEC-01: security-sensitive paths must be rooted (absolute)
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
private static GatewayOptions CloneWithAuthentication(GatewayOptions source, AuthenticationOptions authentication)
|
||||
=> new()
|
||||
{
|
||||
@@ -606,10 +602,6 @@ public sealed class GatewayOptionsValidatorTests
|
||||
f => f.Contains("MxGateway:Tls:SelfSignedCertPath") && f.Contains("rooted"));
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// SEC-04: DisableLogin production guard
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
private static GatewayOptions CloneWithDashboard(GatewayOptions source, DashboardOptions dashboard)
|
||||
=> new()
|
||||
{
|
||||
@@ -649,10 +641,6 @@ public sealed class GatewayOptionsValidatorTests
|
||||
Assert.True(result.Succeeded);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// SEC-06: LDAP plaintext transport production guard
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/// <summary>Verifies plaintext LDAP transport (None) aborts startup in Production.</summary>
|
||||
[Fact]
|
||||
public void Validate_Fails_WhenLdapTransportNoneInProduction()
|
||||
@@ -684,8 +672,6 @@ public sealed class GatewayOptionsValidatorTests
|
||||
Assert.True(result.Succeeded);
|
||||
}
|
||||
|
||||
// ---- SEC-11: MxGateway:Security validation ----
|
||||
|
||||
private static GatewayOptions WithSecurity(SecurityOptions security) => new() { Security = security };
|
||||
|
||||
/// <summary>Verifies the default security options pass validation.</summary>
|
||||
@@ -791,7 +777,7 @@ public sealed class GatewayOptionsValidatorTests
|
||||
|
||||
/// <summary>
|
||||
/// Verifies the default worker-frame maximum keeps the required envelope-overhead reserve above
|
||||
/// the default public gRPC cap, so a stock configuration passes the IPC-03 headroom check.
|
||||
/// the default public gRPC cap, so a stock configuration passes the headroom check.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void Validate_Succeeds_WhenWorkerFrameMaxHasEnvelopeHeadroom()
|
||||
@@ -803,7 +789,7 @@ public sealed class GatewayOptionsValidatorTests
|
||||
/// <summary>
|
||||
/// Verifies that a worker-frame maximum equal to the gRPC cap (zero headroom) fails validation:
|
||||
/// a maximally-sized accepted gRPC payload would not fit one worker frame once wrapped in a
|
||||
/// WorkerEnvelope, faulting the whole session on the outbound write (IPC-03).
|
||||
/// WorkerEnvelope, faulting the whole session on the outbound write.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void Validate_Fails_WhenWorkerFrameMaxEqualsGrpcMaxWithoutHeadroom()
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace ZB.MOM.WW.MxGateway.Tests.Contracts;
|
||||
public sealed class ClientProtoInputTests
|
||||
{
|
||||
/// <summary>
|
||||
/// Guards the published client descriptor set against silent staleness (IPC-01). Every message
|
||||
/// Guards the published client descriptor set against silent staleness. Every message
|
||||
/// and field compiled into the in-process contract (which the build regenerates from the current
|
||||
/// <c>.proto</c> sources) must appear in the committed protoset. A missing symbol means the
|
||||
/// descriptor was not regenerated after a proto change; run
|
||||
|
||||
@@ -7,7 +7,7 @@ using ZB.MOM.WW.MxGateway.Server.Dashboard;
|
||||
namespace ZB.MOM.WW.MxGateway.Tests.Gateway.Dashboard;
|
||||
|
||||
/// <summary>
|
||||
/// SEC-11: the <c>POST /auth/login</c> fixed-window per-IP rate limiter. Exercised through the same
|
||||
/// Tests the <c>POST /auth/login</c> fixed-window per-IP rate limiter. Exercised through the same
|
||||
/// partition factory the production policy registers, so the test pins the real permit limit and
|
||||
/// per-IP partitioning without standing up an HTTP server.
|
||||
/// </summary>
|
||||
|
||||
+7
-4
@@ -203,7 +203,7 @@ public sealed class DashboardSessionAdminServiceTests
|
||||
/// <summary>
|
||||
/// Verifies that a successful close writes a canonical <c>dashboard-close-session</c>
|
||||
/// <see cref="AuditEvent"/> — actor, session-id target, and Success outcome — to the
|
||||
/// audit store, not only the operational log (SEC-12).
|
||||
/// audit store, not only the operational log.
|
||||
/// </summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
@@ -229,7 +229,7 @@ public sealed class DashboardSessionAdminServiceTests
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that a successful kill writes a canonical <c>dashboard-kill-worker</c>
|
||||
/// <see cref="AuditEvent"/> to the audit store (SEC-12).
|
||||
/// <see cref="AuditEvent"/> to the audit store.
|
||||
/// </summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
@@ -253,7 +253,7 @@ public sealed class DashboardSessionAdminServiceTests
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that an unauthorized (viewer) close attempt still writes a <c>Denied</c>
|
||||
/// audit row, so rejected destructive attempts are durably recorded (SEC-12).
|
||||
/// audit row, so rejected destructive attempts are durably recorded.
|
||||
/// </summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
@@ -305,7 +305,10 @@ public sealed class DashboardSessionAdminServiceTests
|
||||
/// <summary>Gets the audit events written through this writer, in order.</summary>
|
||||
public IReadOnlyList<AuditEvent> Events => _events.ToArray();
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>Records the given audit event for later inspection by the test.</summary>
|
||||
/// <param name="evt">The audit event to record.</param>
|
||||
/// <param name="ct">Token to cancel the asynchronous operation.</param>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
public Task WriteAsync(AuditEvent evt, CancellationToken ct = default)
|
||||
{
|
||||
_events.Enqueue(evt);
|
||||
|
||||
@@ -145,7 +145,7 @@ public sealed class HubTokenServiceTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The default token lifetime is the short (5-minute) window mandated by SEC-05, not the
|
||||
/// The default token lifetime is the short (5-minute) window, not the
|
||||
/// former 30-minute window. Pins the value so a regression that widens the exposure window
|
||||
/// of an irrevocable, query-string-carried token is caught in CI.
|
||||
/// </summary>
|
||||
|
||||
@@ -39,7 +39,7 @@ public sealed class EventStreamServiceTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// TST-02 (owner-scoped attach): the API key that opened a session may attach its event
|
||||
/// Owner-scoped attach: the API key that opened a session may attach its event
|
||||
/// stream — the caller key equals the session owner, so streaming proceeds normally.
|
||||
/// </summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
@@ -64,7 +64,7 @@ public sealed class EventStreamServiceTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// TST-02 (owner-scoped attach, security control): a caller whose API key differs from
|
||||
/// Owner-scoped attach, security control: a caller whose API key differs from
|
||||
/// the key that opened the session is rejected with a <see cref="SessionManagerErrorCode.PermissionDenied"/>
|
||||
/// fault before any events are streamed — closing the reconnect/fan-out trust-boundary hole.
|
||||
/// </summary>
|
||||
|
||||
@@ -18,8 +18,9 @@ public sealed class MxAccessGrpcRequestValidatorTests
|
||||
|
||||
/// <summary>
|
||||
/// Verifies a DrainEvents request within the per-request ceiling passes validation, including the
|
||||
/// <c>max_events = 0</c> "worker default cap" sentinel (IPC-04).
|
||||
/// <c>max_events = 0</c> "worker default cap" sentinel.
|
||||
/// </summary>
|
||||
/// <param name="maxEvents">The requested drain-events ceiling to validate.</param>
|
||||
[Theory]
|
||||
[InlineData(0u)]
|
||||
[InlineData(1u)]
|
||||
@@ -32,7 +33,7 @@ public sealed class MxAccessGrpcRequestValidatorTests
|
||||
|
||||
/// <summary>
|
||||
/// Verifies a DrainEvents request above the per-request ceiling is rejected with InvalidArgument
|
||||
/// so one accepted request cannot pack an unbounded reply frame (IPC-04).
|
||||
/// so one accepted request cannot pack an unbounded reply frame.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void ValidateInvoke_RejectsDrainEvents_AboveCeiling()
|
||||
|
||||
+1
-1
@@ -108,7 +108,7 @@ public sealed class GatewaySessionDashboardMirrorTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GWC-01 regression: with the internal dashboard mirror active, a second internal
|
||||
/// With the internal dashboard mirror active, a second internal
|
||||
/// subscriber (the alarm monitor's feed, attached via
|
||||
/// <see cref="GatewaySession.AttachInternalEventSubscriber"/>) receives EVERY event —
|
||||
/// including the alarm <c>Acknowledge</c> transition — rather than the two consumers
|
||||
|
||||
@@ -59,7 +59,7 @@ public sealed class WorkerClientTests
|
||||
/// <summary>
|
||||
/// Verifies that a command whose serialized envelope exceeds the negotiated worker-frame maximum
|
||||
/// fails only that command with <see cref="WorkerClientErrorCode.CommandTooLarge"/> at the enqueue
|
||||
/// boundary, leaving the client ready for subsequent commands (IPC-03). Without the pre-check the
|
||||
/// boundary, leaving the client ready for subsequent commands. Without the pre-check the
|
||||
/// oversized frame would reach the write loop and fault the whole session.
|
||||
/// </summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
@@ -170,7 +170,7 @@ public sealed class WorkerClientTests
|
||||
|
||||
/// <summary>
|
||||
/// The worker event channel is single-reader: a second <see cref="WorkerClient.ReadEventsAsync"/>
|
||||
/// enumerator must throw rather than silently split events between two consumers (GWC-01).
|
||||
/// enumerator must throw rather than silently split events between two consumers.
|
||||
/// </summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
@@ -221,7 +221,7 @@ public sealed class WorkerClientTests
|
||||
/// <summary>
|
||||
/// Verifies that a command reply arriving on the pipe after events is dispatched promptly even
|
||||
/// when the event channel is full and has no consumer — event enqueue is decoupled from the read
|
||||
/// loop, so a blocked event writer cannot delay a reply (GWC-04). The event full-mode timeout is
|
||||
/// loop, so a blocked event writer cannot delay a reply. The event full-mode timeout is
|
||||
/// set far above the command timeout: without the decoupling the read loop would block behind the
|
||||
/// full event channel and the in-flight InvokeAsync would hit CommandTimeout.
|
||||
/// </summary>
|
||||
|
||||
@@ -161,7 +161,7 @@ public sealed class GatewayMetricsTests
|
||||
/// Verifies that <see cref="GatewayMetrics.HeartbeatFailed"/> increments
|
||||
/// <c>mxgateway.heartbeats.failed</c> without emitting a <c>session_id</c> tag: the tag is
|
||||
/// unbounded cardinality (every session mints a new exporter time series), so per-session
|
||||
/// attribution is deliberately kept out of the exported counter (SEC-20).
|
||||
/// attribution is deliberately kept out of the exported counter.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void HeartbeatFailed_IncrementsCounterWithoutSessionIdTag()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
namespace ZB.MOM.WW.MxGateway.Tests.ProjectStructure;
|
||||
|
||||
/// <summary>
|
||||
/// Repo-hygiene guards over the source tree. See SEC-01: a Windows-absolute default path that
|
||||
/// Repo-hygiene guards over the source tree. A Windows-absolute default path that
|
||||
/// resolves relative to the launch working directory silently materializes a SQLite credential
|
||||
/// store inside the tree. This test fails if any such <c>*.db</c> file appears under <c>src/</c>.
|
||||
/// </summary>
|
||||
|
||||
@@ -54,7 +54,7 @@ public sealed class ApiKeyAdminCliRunnerTests : IDisposable
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that a key created with an already-past <c>--expires</c> is rejected by the verifier
|
||||
/// — the CLI expiry wiring reaches the store and the library enforces it end-to-end (SEC-10).
|
||||
/// — the CLI expiry wiring reaches the store and the library enforces it end-to-end.
|
||||
/// </summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
|
||||
+4
-4
@@ -52,7 +52,7 @@ public sealed class ApiKeyAdminCommandLineParserTests
|
||||
Assert.Contains("events:read", result.Command.Scopes);
|
||||
}
|
||||
|
||||
/// <summary>A create-key command without --expires leaves the key non-expiring (opt-in, SEC-10).</summary>
|
||||
/// <summary>A create-key command without --expires leaves the key non-expiring (opt-in).</summary>
|
||||
[Fact]
|
||||
public void Parse_CreateKeyCommand_WithoutExpires_HasNoExpiry()
|
||||
{
|
||||
@@ -63,7 +63,7 @@ public sealed class ApiKeyAdminCommandLineParserTests
|
||||
Assert.Null(result.Command.ExpiresUtc);
|
||||
}
|
||||
|
||||
/// <summary>An absolute ISO-8601 --expires value is parsed to that exact UTC instant (SEC-10).</summary>
|
||||
/// <summary>An absolute ISO-8601 --expires value is parsed to that exact UTC instant.</summary>
|
||||
[Fact]
|
||||
public void Parse_CreateKeyCommand_WithAbsoluteExpires_ParsesInstant()
|
||||
{
|
||||
@@ -77,7 +77,7 @@ public sealed class ApiKeyAdminCommandLineParserTests
|
||||
result.Command.ExpiresUtc);
|
||||
}
|
||||
|
||||
/// <summary>A relative "<N>d" --expires value resolves to a future UTC instant (SEC-10).</summary>
|
||||
/// <summary>A relative "<N>d" --expires value resolves to a future UTC instant.</summary>
|
||||
[Fact]
|
||||
public void Parse_CreateKeyCommand_WithRelativeExpires_ResolvesToFuture()
|
||||
{
|
||||
@@ -94,7 +94,7 @@ public sealed class ApiKeyAdminCommandLineParserTests
|
||||
DateTimeOffset.UtcNow + TimeSpan.FromDays(30) + TimeSpan.FromMinutes(1));
|
||||
}
|
||||
|
||||
/// <summary>An unparseable --expires value fails at parse time (SEC-10).</summary>
|
||||
/// <summary>An unparseable --expires value fails at parse time.</summary>
|
||||
[Fact]
|
||||
public void Parse_CreateKeyCommand_WithInvalidExpires_Fails()
|
||||
{
|
||||
|
||||
+29
-1
@@ -8,7 +8,7 @@ using LibApiKeyIdentity = ZB.MOM.WW.Auth.Abstractions.ApiKeys.ApiKeyIdentity;
|
||||
namespace ZB.MOM.WW.MxGateway.Tests.Security.Authentication;
|
||||
|
||||
/// <summary>
|
||||
/// SEC-08 hot-path decorators. Covers both mechanisms: <see cref="CachingApiKeyVerifier"/>
|
||||
/// Hot-path decorators. Covers both mechanisms: <see cref="CachingApiKeyVerifier"/>
|
||||
/// (read/verification coalescing plus revoke/rotate invalidation) and
|
||||
/// <see cref="CoalescingMarkApiKeyStore"/> (the <c>last_used</c> write coalescing that keeps the
|
||||
/// per-RPC database write off the throughput ceiling).
|
||||
@@ -18,6 +18,7 @@ public sealed class CachingApiKeyVerifierTests
|
||||
private const string Header = "Bearer mxgw_operator01_super-secret";
|
||||
|
||||
/// <summary>A cache hit within the TTL returns the cached result and never calls the inner verifier.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task VerifyAsync_RepeatedWithinTtl_CallsInnerOnce()
|
||||
{
|
||||
@@ -34,6 +35,7 @@ public sealed class CachingApiKeyVerifierTests
|
||||
}
|
||||
|
||||
/// <summary>Different presented secrets are cached under distinct keys (no cross-secret aliasing).</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task VerifyAsync_DifferentTokens_NotAliased()
|
||||
{
|
||||
@@ -48,6 +50,7 @@ public sealed class CachingApiKeyVerifierTests
|
||||
}
|
||||
|
||||
/// <summary>Failed verifications are never cached; every attempt reaches the inner verifier.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task VerifyAsync_FailedVerification_NotCached()
|
||||
{
|
||||
@@ -62,6 +65,7 @@ public sealed class CachingApiKeyVerifierTests
|
||||
}
|
||||
|
||||
/// <summary>A TTL of zero disables caching: the inner verifier is called on every request.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task VerifyAsync_ZeroTtl_DisablesCache()
|
||||
{
|
||||
@@ -76,6 +80,7 @@ public sealed class CachingApiKeyVerifierTests
|
||||
}
|
||||
|
||||
/// <summary>Invalidating a key id (revoke/rotate) drops its cached verification, forcing a re-verify.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task Invalidate_DropsCachedEntry_ForcesReverify()
|
||||
{
|
||||
@@ -96,6 +101,7 @@ public sealed class CachingApiKeyVerifierTests
|
||||
/// The store decorator coalesces repeated <c>MarkUsed</c> writes for the same key inside the
|
||||
/// window down to a single forwarded write — the ≤1/min guarantee for <c>last_used_utc</c>.
|
||||
/// </summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task CoalescingStore_RepeatedMarksWithinWindow_ForwardsOnce()
|
||||
{
|
||||
@@ -114,6 +120,7 @@ public sealed class CachingApiKeyVerifierTests
|
||||
}
|
||||
|
||||
/// <summary>After the window elapses the next mark is forwarded again (staleness is bounded, not frozen).</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task CoalescingStore_AfterWindow_ForwardsAgain()
|
||||
{
|
||||
@@ -129,6 +136,7 @@ public sealed class CachingApiKeyVerifierTests
|
||||
}
|
||||
|
||||
/// <summary>Distinct keys are coalesced independently.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task CoalescingStore_DistinctKeys_TrackedSeparately()
|
||||
{
|
||||
@@ -144,6 +152,7 @@ public sealed class CachingApiKeyVerifierTests
|
||||
}
|
||||
|
||||
/// <summary>A zero window disables coalescing: every mark is forwarded.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task CoalescingStore_ZeroWindow_ForwardsEveryMark()
|
||||
{
|
||||
@@ -173,8 +182,13 @@ public sealed class CachingApiKeyVerifierTests
|
||||
|
||||
private sealed class FakeVerifier(ApiKeyVerification result) : IApiKeyVerifier
|
||||
{
|
||||
/// <summary>Gets the number of times <see cref="VerifyAsync"/> has been called.</summary>
|
||||
public int CallCount { get; private set; }
|
||||
|
||||
/// <summary>Records the call and returns the fixed <paramref name="result"/> supplied at construction.</summary>
|
||||
/// <param name="authorizationHeader">The authorization header presented by the caller.</param>
|
||||
/// <param name="ct">A token to observe for cancellation.</param>
|
||||
/// <returns>The fixed verification result.</returns>
|
||||
public Task<ApiKeyVerification> VerifyAsync(string authorizationHeader, CancellationToken ct)
|
||||
{
|
||||
CallCount++;
|
||||
@@ -184,14 +198,28 @@ public sealed class CachingApiKeyVerifierTests
|
||||
|
||||
private sealed class FakeStore : IApiKeyStore
|
||||
{
|
||||
/// <summary>Gets the number of times <see cref="MarkUsedAsync"/> has been called.</summary>
|
||||
public int MarkUsedCount { get; private set; }
|
||||
|
||||
/// <summary>Always returns <see langword="null"/>; not exercised by these tests.</summary>
|
||||
/// <param name="keyId">The key id to look up.</param>
|
||||
/// <param name="ct">A token to observe for cancellation.</param>
|
||||
/// <returns><see langword="null"/>.</returns>
|
||||
public Task<ApiKeyRecord?> FindByKeyIdAsync(string keyId, CancellationToken ct)
|
||||
=> Task.FromResult<ApiKeyRecord?>(null);
|
||||
|
||||
/// <summary>Always returns <see langword="null"/>; not exercised by these tests.</summary>
|
||||
/// <param name="keyId">The key id to look up.</param>
|
||||
/// <param name="ct">A token to observe for cancellation.</param>
|
||||
/// <returns><see langword="null"/>.</returns>
|
||||
public Task<ApiKeyRecord?> FindActiveByKeyIdAsync(string keyId, CancellationToken ct)
|
||||
=> Task.FromResult<ApiKeyRecord?>(null);
|
||||
|
||||
/// <summary>Records the call by incrementing <see cref="MarkUsedCount"/>.</summary>
|
||||
/// <param name="keyId">The key id that was used.</param>
|
||||
/// <param name="whenUtc">The UTC timestamp of use.</param>
|
||||
/// <param name="ct">A token to observe for cancellation.</param>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
public Task MarkUsedAsync(string keyId, DateTimeOffset whenUtc, CancellationToken ct)
|
||||
{
|
||||
MarkUsedCount++;
|
||||
|
||||
+2
-2
@@ -359,7 +359,7 @@ public sealed class GatewayGrpcAuthorizationInterceptorTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SEC-11: once a peer has exceeded the failure limit, the interceptor short-circuits with
|
||||
/// Once a peer has exceeded the failure limit, the interceptor short-circuits with
|
||||
/// <see cref="StatusCode.ResourceExhausted"/> BEFORE calling the verifier, so an online guessing
|
||||
/// loop stops spending a store read per attempt. A verifier that always fails is used; after the
|
||||
/// limit is reached the verifier is no longer invoked.
|
||||
@@ -404,7 +404,7 @@ public sealed class GatewayGrpcAuthorizationInterceptorTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SEC-11: a successful verification resets the peer's failure counter, so accumulated failures
|
||||
/// A successful verification resets the peer's failure counter, so accumulated failures
|
||||
/// from a fat-fingered secret do not lock out a client that subsequently authenticates.
|
||||
/// </summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace ZB.MOM.WW.MxGateway.Tests.TestSupport;
|
||||
/// <remarks>
|
||||
/// Many tests build the full gateway host through <c>GatewayApplication.Build</c> against the dev
|
||||
/// <c>appsettings.json</c> (which ships <c>Ldap:Transport=None</c> and other dev-only defaults).
|
||||
/// An unset environment resolves to Production, where the SEC-04/06 production guards fail startup
|
||||
/// An unset environment resolves to Production, where the production guards fail startup
|
||||
/// by design — so those host-building tests would trip the guards. Setting the environment to
|
||||
/// Development once, before any test runs, keeps that suite exercising app wiring rather than
|
||||
/// production-config validation. Tests that specifically assert production behavior construct
|
||||
@@ -28,6 +28,10 @@ namespace ZB.MOM.WW.MxGateway.Tests.TestSupport;
|
||||
/// </remarks>
|
||||
internal static class TestHostEnvironmentInitializer
|
||||
{
|
||||
/// <summary>
|
||||
/// Applies the Development environment and isolated self-signed-cert path defaults described
|
||||
/// on this type, run once by the runtime before any test in the assembly executes.
|
||||
/// </summary>
|
||||
[ModuleInitializer]
|
||||
internal static void SetDevelopmentEnvironmentDefault()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user