docs(src): add missing XML docs and strip tracking-ID comments
Sweep of 203 source files resolving CommentChecker findings: add <summary>/<param>/<returns>/<inheritdoc> where missing, and remove resolved task/issue tracking markers (Tests-NNN, Worker-NNN, Server-NNN, Task N) from code comments. Comment/doc-only — no logic changes. Server+Tests build clean under TreatWarningsAsErrors.
This commit is contained in:
@@ -19,7 +19,13 @@ public sealed class CanonicalAuditWriter(
|
||||
SqliteCanonicalAuditStore store,
|
||||
ILogger<CanonicalAuditWriter> logger) : IAuditWriter
|
||||
{
|
||||
/// <inheritdoc />
|
||||
/// <summary>
|
||||
/// Persists a canonical audit event to the underlying <see cref="SqliteCanonicalAuditStore"/>.
|
||||
/// Any failure is caught, logged, and swallowed rather than propagated to the caller.
|
||||
/// </summary>
|
||||
/// <param name="auditEvent">The canonical audit event to persist.</param>
|
||||
/// <param name="cancellationToken">Token to cancel the underlying store write.</param>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
public async Task WriteAsync(AuditEvent auditEvent, CancellationToken cancellationToken = default)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(auditEvent);
|
||||
|
||||
+8
-2
@@ -43,7 +43,10 @@ public sealed class CanonicalForwardingApiKeyAuditStore(
|
||||
/// <summary>The library's keyless schema-init event type.</summary>
|
||||
private const string InitDbEventType = "init-db";
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>Canonicalizes a library-emitted API-key audit entry onto <see cref="AuditEvent"/> and writes it via <see cref="IAuditWriter"/>.</summary>
|
||||
/// <param name="entry">The library's API-key audit entry to forward.</param>
|
||||
/// <param name="ct">Token to observe for cancellation.</param>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
public async Task AppendAsync(ApiKeyAuditEntry entry, CancellationToken ct)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(entry);
|
||||
@@ -71,7 +74,10 @@ public sealed class CanonicalForwardingApiKeyAuditStore(
|
||||
await auditWriter.WriteAsync(auditEvent, ct).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>Reads back the most recent entries from the canonical audit store and maps each one to an <see cref="ApiKeyAuditEntry"/>.</summary>
|
||||
/// <param name="limit">The maximum number of entries to return.</param>
|
||||
/// <param name="ct">Token to observe for cancellation.</param>
|
||||
/// <returns>Up to <paramref name="limit"/> recent API-key audit entries.</returns>
|
||||
public async Task<IReadOnlyList<ApiKeyAuditEntry>> ListRecentAsync(int limit, CancellationToken ct)
|
||||
{
|
||||
IReadOnlyList<AuditEvent> events = await store.ListRecentAsync(limit, ct).ConfigureAwait(false);
|
||||
|
||||
@@ -43,6 +43,7 @@ public sealed class SqliteCanonicalAuditStore(AuthSqliteConnectionFactory connec
|
||||
/// <summary>Inserts a canonical audit event into the <c>audit_event</c> table.</summary>
|
||||
/// <param name="auditEvent">The canonical event to persist.</param>
|
||||
/// <param name="cancellationToken">Token to observe for cancellation.</param>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
public async Task InsertAsync(AuditEvent auditEvent, CancellationToken cancellationToken)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(auditEvent);
|
||||
@@ -79,6 +80,7 @@ public sealed class SqliteCanonicalAuditStore(AuthSqliteConnectionFactory connec
|
||||
/// <summary>Returns the most recent canonical audit events, newest first.</summary>
|
||||
/// <param name="limit">Maximum number of events to return.</param>
|
||||
/// <param name="cancellationToken">Token to observe for cancellation.</param>
|
||||
/// <returns>The most recent audit events, up to <paramref name="limit"/>, newest first.</returns>
|
||||
public async Task<IReadOnlyList<AuditEvent>> ListRecentAsync(int limit, CancellationToken cancellationToken)
|
||||
{
|
||||
if (limit <= 0)
|
||||
|
||||
@@ -26,6 +26,7 @@ public sealed class ApiKeyAdminCliRunner(ApiKeyAdminCommands commands)
|
||||
/// <param name="command">API key administration command to execute.</param>
|
||||
/// <param name="output">Text writer for command output.</param>
|
||||
/// <param name="cancellationToken">Token to cancel the asynchronous operation.</param>
|
||||
/// <returns>The process exit code for the executed command.</returns>
|
||||
public async Task<int> RunAsync(
|
||||
ApiKeyAdminCommand command,
|
||||
TextWriter output,
|
||||
|
||||
@@ -6,6 +6,7 @@ public sealed record ApiKeyAdminParseResult(
|
||||
string? Error)
|
||||
{
|
||||
/// <summary>Returns a result indicating the input was not an API key command.</summary>
|
||||
/// <returns>A result with <see cref="IsApiKeyCommand"/> set to <see langword="false"/>.</returns>
|
||||
public static ApiKeyAdminParseResult NotApiKeyCommand()
|
||||
{
|
||||
return new ApiKeyAdminParseResult(false, null, null);
|
||||
@@ -13,6 +14,7 @@ public sealed record ApiKeyAdminParseResult(
|
||||
|
||||
/// <summary>Returns a successful parse result with the parsed API key command.</summary>
|
||||
/// <param name="command">Parsed API key administration command.</param>
|
||||
/// <returns>A successful <see cref="ApiKeyAdminParseResult"/> wrapping <paramref name="command"/>.</returns>
|
||||
public static ApiKeyAdminParseResult Success(ApiKeyAdminCommand command)
|
||||
{
|
||||
return new ApiKeyAdminParseResult(true, command, null);
|
||||
@@ -20,6 +22,7 @@ public sealed record ApiKeyAdminParseResult(
|
||||
|
||||
/// <summary>Returns a parse result with the specified error message.</summary>
|
||||
/// <param name="error">Error message describing the parse failure.</param>
|
||||
/// <returns>A failed <see cref="ApiKeyAdminParseResult"/> carrying <paramref name="error"/>.</returns>
|
||||
public static ApiKeyAdminParseResult Fail(string error)
|
||||
{
|
||||
return new ApiKeyAdminParseResult(true, null, error);
|
||||
|
||||
@@ -12,6 +12,7 @@ public static class ApiKeyConstraintSerializer
|
||||
|
||||
/// <summary>Serializes API key constraints to JSON, or returns null if the constraints are empty.</summary>
|
||||
/// <param name="constraints">The constraints to serialize.</param>
|
||||
/// <returns>The serialized JSON, or <see langword="null"/> when the constraints are empty.</returns>
|
||||
public static string? Serialize(ApiKeyConstraints constraints)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(constraints);
|
||||
@@ -20,6 +21,7 @@ public static class ApiKeyConstraintSerializer
|
||||
|
||||
/// <summary>Deserializes API key constraints from JSON, or returns empty constraints if JSON is null or whitespace.</summary>
|
||||
/// <param name="json">The JSON string to deserialize.</param>
|
||||
/// <returns>The deserialized constraints, or <see cref="ApiKeyConstraints.Empty"/> when <paramref name="json"/> is null/whitespace.</returns>
|
||||
public static ApiKeyConstraints Deserialize(string? json)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(json))
|
||||
|
||||
-4
@@ -66,10 +66,6 @@ public static class AuthStoreServiceCollectionExtensions
|
||||
// migrator and the migration hosted service.
|
||||
services.AddZbApiKeyAuth(effectiveConfig, AuthenticationSectionPath);
|
||||
|
||||
// Canonical audit (Task 2.3 — DEEP adopt ZB.MOM.WW.Audit). All MxGateway audit flows as a
|
||||
// canonical AuditEvent through the library IAuditWriter, persisted in a NEW gateway-owned
|
||||
// audit_event table that lives in the SAME SQLite DB file as the api-key stores (it reuses
|
||||
// the library's AuthSqliteConnectionFactory, registered by AddZbApiKeyAuth above).
|
||||
services.AddSingleton(sp =>
|
||||
new SqliteCanonicalAuditStore(sp.GetRequiredService<AuthSqliteConnectionFactory>()));
|
||||
// Resolve the logger defensively: the production host always registers ILogger<T>, but the
|
||||
|
||||
@@ -16,10 +16,7 @@ public sealed class ConstraintEnforcer(
|
||||
IGalaxyHierarchyCache cache,
|
||||
IAuditWriter auditWriter) : IConstraintEnforcer
|
||||
{
|
||||
/// <summary>Checks read constraints on a tag address.</summary>
|
||||
/// <param name="identity">The API key identity to check constraints for.</param>
|
||||
/// <param name="tagAddress">Tag address to validate.</param>
|
||||
/// <param name="cancellationToken">Token to observe for cancellation.</param>
|
||||
/// <inheritdoc />
|
||||
public Task<ConstraintFailure?> CheckReadTagAsync(
|
||||
ApiKeyIdentity? identity,
|
||||
string tagAddress,
|
||||
@@ -34,12 +31,7 @@ public sealed class ConstraintEnforcer(
|
||||
return Task.FromResult(CheckReadTarget(constraints, tagAddress));
|
||||
}
|
||||
|
||||
/// <summary>Checks read constraints on a server and item handle.</summary>
|
||||
/// <param name="identity">The API key identity to check constraints for.</param>
|
||||
/// <param name="session">The gateway session containing handle registrations.</param>
|
||||
/// <param name="serverHandle">The MXAccess server handle.</param>
|
||||
/// <param name="itemHandle">The MXAccess item handle.</param>
|
||||
/// <param name="cancellationToken">Token to observe for cancellation.</param>
|
||||
/// <inheritdoc />
|
||||
public Task<ConstraintFailure?> CheckReadHandleAsync(
|
||||
ApiKeyIdentity? identity,
|
||||
GatewaySession session,
|
||||
@@ -61,12 +53,7 @@ public sealed class ConstraintEnforcer(
|
||||
return Task.FromResult(CheckReadTarget(constraints, registration.TagAddress));
|
||||
}
|
||||
|
||||
/// <summary>Checks write constraints on a server and item handle.</summary>
|
||||
/// <param name="identity">The API key identity to check constraints for.</param>
|
||||
/// <param name="session">The gateway session containing handle registrations.</param>
|
||||
/// <param name="serverHandle">The MXAccess server handle.</param>
|
||||
/// <param name="itemHandle">The MXAccess item handle.</param>
|
||||
/// <param name="cancellationToken">Token to observe for cancellation.</param>
|
||||
/// <inheritdoc />
|
||||
public Task<ConstraintFailure?> CheckWriteHandleAsync(
|
||||
ApiKeyIdentity? identity,
|
||||
GatewaySession session,
|
||||
@@ -115,18 +102,7 @@ public sealed class ConstraintEnforcer(
|
||||
return Task.FromResult<ConstraintFailure?>(null);
|
||||
}
|
||||
|
||||
/// <summary>Records a constraint denial audit entry.</summary>
|
||||
/// <param name="identity">The API key identity that was denied.</param>
|
||||
/// <param name="commandKind">The command type (e.g., read, write).</param>
|
||||
/// <param name="target">The target being accessed (tag address or handle).</param>
|
||||
/// <param name="failure">The constraint failure details.</param>
|
||||
/// <param name="correlationId">
|
||||
/// The per-request client correlation id, if any. Persisted as the audit record's typed
|
||||
/// <c>CorrelationId</c> when it parses as a GUID; a non-GUID value leaves that column null.
|
||||
/// The raw string is always preserved in <c>DetailsJson["clientCorrelationId"]</c> so a
|
||||
/// non-GUID id (e.g. from Rust/Python/Java clients) is never silently lost.
|
||||
/// </param>
|
||||
/// <param name="cancellationToken">Token to observe for cancellation.</param>
|
||||
/// <inheritdoc />
|
||||
public async Task RecordDenialAsync(
|
||||
ApiKeyIdentity? identity,
|
||||
string commandKind,
|
||||
@@ -135,8 +111,8 @@ public sealed class ConstraintEnforcer(
|
||||
string? correlationId,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
// Emit a canonical Denied AuditEvent directly through the best-effort IAuditWriter
|
||||
// (Task 2.3 #6): structured Target ("<commandKind>:<target>") and a richer DetailsJson
|
||||
// Emit a canonical Denied AuditEvent directly through the best-effort IAuditWriter:
|
||||
// structured Target ("<commandKind>:<target>") and a richer DetailsJson
|
||||
// envelope carrying constraint/message/commandKind/target.
|
||||
AuditEvent auditEvent = new()
|
||||
{
|
||||
|
||||
@@ -8,7 +8,9 @@ namespace ZB.MOM.WW.MxGateway.Server.Security.Authorization;
|
||||
public sealed class GatewayBrowseScopeProvider(IGatewayRequestIdentityAccessor identityAccessor)
|
||||
: IGalaxyBrowseScopeProvider
|
||||
{
|
||||
/// <inheritdoc />
|
||||
/// <summary>Resolves the Galaxy browse subtrees the calling API key is scoped to, from the ambient request identity.</summary>
|
||||
/// <param name="context">The gRPC server call context for the in-flight browse request.</param>
|
||||
/// <returns>The caller's configured browse subtrees, or <see langword="null"/>/empty when the caller is unscoped (full hierarchy).</returns>
|
||||
public IReadOnlyList<string>? ResolveBrowseSubtrees(ServerCallContext context)
|
||||
{
|
||||
// Invariant: the caller identity is the ambient one pushed by
|
||||
|
||||
+2
-4
@@ -6,12 +6,10 @@ public sealed class GatewayRequestIdentityAccessor : IGatewayRequestIdentityAcce
|
||||
{
|
||||
private readonly AsyncLocal<ApiKeyIdentity?> currentIdentity = new();
|
||||
|
||||
/// <summary>Gets the current request identity.</summary>
|
||||
/// <inheritdoc />
|
||||
public ApiKeyIdentity? Current => currentIdentity.Value;
|
||||
|
||||
/// <summary>Sets the current identity and returns a scope that restores the previous identity.</summary>
|
||||
/// <param name="identity">The identity to push.</param>
|
||||
/// <returns>Disposable scope.</returns>
|
||||
/// <inheritdoc />
|
||||
public IDisposable Push(ApiKeyIdentity identity)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(identity);
|
||||
|
||||
+1
@@ -13,6 +13,7 @@ public static class GrpcAuthorizationServiceCollectionExtensions
|
||||
/// Registers gRPC authorization middleware and scope resolver.
|
||||
/// </summary>
|
||||
/// <param name="services">Service collection to register dependencies into.</param>
|
||||
/// <returns>The same service collection, for chaining.</returns>
|
||||
public static IServiceCollection AddGatewayGrpcAuthorization(this IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton<GatewayGrpcScopeResolver>();
|
||||
|
||||
@@ -9,6 +9,7 @@ public interface IConstraintEnforcer
|
||||
/// <param name="identity">The API key identity.</param>
|
||||
/// <param name="tagAddress">Tag address to check.</param>
|
||||
/// <param name="cancellationToken">Token to observe for cancellation.</param>
|
||||
/// <returns>The constraint failure details if denied; otherwise null.</returns>
|
||||
Task<ConstraintFailure?> CheckReadTagAsync(
|
||||
ApiKeyIdentity? identity,
|
||||
string tagAddress,
|
||||
@@ -20,6 +21,7 @@ public interface IConstraintEnforcer
|
||||
/// <param name="serverHandle">The MXAccess server handle.</param>
|
||||
/// <param name="itemHandle">The MXAccess item handle.</param>
|
||||
/// <param name="cancellationToken">Token to observe for cancellation.</param>
|
||||
/// <returns>The constraint failure details if denied; otherwise null.</returns>
|
||||
Task<ConstraintFailure?> CheckReadHandleAsync(
|
||||
ApiKeyIdentity? identity,
|
||||
GatewaySession session,
|
||||
@@ -33,6 +35,7 @@ public interface IConstraintEnforcer
|
||||
/// <param name="serverHandle">The MXAccess server handle.</param>
|
||||
/// <param name="itemHandle">The MXAccess item handle.</param>
|
||||
/// <param name="cancellationToken">Token to observe for cancellation.</param>
|
||||
/// <returns>The constraint failure details if denied; otherwise null.</returns>
|
||||
Task<ConstraintFailure?> CheckWriteHandleAsync(
|
||||
ApiKeyIdentity? identity,
|
||||
GatewaySession session,
|
||||
@@ -50,6 +53,7 @@ public interface IConstraintEnforcer
|
||||
/// <c>CorrelationId</c> when it parses as a GUID; otherwise left null.
|
||||
/// </param>
|
||||
/// <param name="cancellationToken">Token to observe for cancellation.</param>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
Task RecordDenialAsync(
|
||||
ApiKeyIdentity? identity,
|
||||
string commandKind,
|
||||
|
||||
+1
@@ -10,5 +10,6 @@ public interface IGatewayRequestIdentityAccessor
|
||||
|
||||
/// <summary>Temporarily pushes an identity onto the scope stack, returning a handle to restore the previous state.</summary>
|
||||
/// <param name="identity">API key identity to push.</param>
|
||||
/// <returns>A disposable handle that restores the previous identity when disposed.</returns>
|
||||
IDisposable Push(ApiKeyIdentity identity);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@ public static class KestrelTlsInspector
|
||||
/// <c>Certificate:Thumbprint</c>), meaning the gateway must supply a
|
||||
/// generated fallback certificate.
|
||||
/// </summary>
|
||||
/// <param name="configuration">The application configuration to inspect for Kestrel certificate settings.</param>
|
||||
/// <returns><see langword="true"/> if the gateway must supply a generated fallback certificate; otherwise <see langword="false"/>.</returns>
|
||||
public static bool RequiresGeneratedCertificate(IConfiguration configuration)
|
||||
{
|
||||
// A Kestrel default certificate applies to every endpoint that lacks its own.
|
||||
|
||||
@@ -20,6 +20,10 @@ public sealed class SelfSignedCertificateProvider
|
||||
private readonly ILogger<SelfSignedCertificateProvider> _logger;
|
||||
private readonly TimeProvider _timeProvider;
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="SelfSignedCertificateProvider"/> class.</summary>
|
||||
/// <param name="options">TLS options controlling certificate generation and persistence.</param>
|
||||
/// <param name="logger">Logger for certificate generation and load diagnostics.</param>
|
||||
/// <param name="timeProvider">Time provider used for certificate validity and expiration checks.</param>
|
||||
public SelfSignedCertificateProvider(
|
||||
TlsOptions options,
|
||||
ILogger<SelfSignedCertificateProvider> logger,
|
||||
@@ -31,6 +35,7 @@ public sealed class SelfSignedCertificateProvider
|
||||
}
|
||||
|
||||
/// <summary>Creates a fresh in-memory ECDSA P-256 self-signed certificate.</summary>
|
||||
/// <returns>The generated self-signed certificate.</returns>
|
||||
public X509Certificate2 GenerateCertificate()
|
||||
{
|
||||
using ECDsa key = ECDsa.Create(ECCurve.NamedCurves.nistP256);
|
||||
@@ -89,6 +94,7 @@ public sealed class SelfSignedCertificateProvider
|
||||
|
||||
/// <summary>Loads the persisted certificate, regenerating when missing,
|
||||
/// expired (and allowed), or unreadable.</summary>
|
||||
/// <returns>The loaded or newly generated and persisted certificate.</returns>
|
||||
public X509Certificate2 LoadOrCreate()
|
||||
{
|
||||
string path = _options.SelfSignedCertPath;
|
||||
|
||||
Reference in New Issue
Block a user