Files
mxaccessgw/docs/audit/fragments/06-config.md
T

21 KiB
Raw Blame History

Cluster 06 — Config

Docs audited: docs/GatewayConfiguration.md, docs/Diagnostics.md, docs/Metrics.md

Code verified against:

  • src/ZB.MOM.WW.MxGateway.Server/Configuration/ (GatewayOptions, GatewayOptionsValidator, and all sub-options)
  • src/ZB.MOM.WW.MxGateway.Server/Diagnostics/
  • src/ZB.MOM.WW.MxGateway.Server/Metrics/
  • src/ZB.MOM.WW.MxGateway.Server/Galaxy/GalaxyRepositoryOptions.cs
  • src/ZB.MOM.WW.MxGateway.Server/Dashboard/DashboardRoles.cs, DashboardAuthenticationDefaults.cs
  • src/ZB.MOM.WW.MxGateway.Server/appsettings.json

DOC / GatewayConfiguration.md / LINES / 5556 CLAIM / Config shape example shows GroupToRole values as "Admin" and "Viewer" CLAIM_TYPE / config-key VERDICT / wrong EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/Dashboard/DashboardRoles.cs:14 — public const string Admin = "Administrator";; src/ZB.MOM.WW.MxGateway.Server/Configuration/GatewayOptionsValidator.cs:212216 — validator compares against DashboardRoles.Admin and DashboardRoles.Viewer; src/ZB.MOM.WW.MxGateway.Server/appsettings.json:63 — canonical example uses "Administrator" CODE_AREA / config.Dashboard.GroupToRole SEVERITY / high PROPOSED_FIX / Change "Admin" to "Administrator" in the config shape example JSON (line 55). The Viewer value is correct.


DOC / GatewayConfiguration.md / LINES / 156 CLAIM / Description says 'Values must be Admin (read/write, API-key CRUD) or Viewer (read-only)' CLAIM_TYPE / config-key VERDICT / wrong EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/Dashboard/DashboardRoles.cs:14 — public const string Admin = "Administrator";; GatewayOptionsValidator.cs:216 — error message embeds DashboardRoles.Admin which resolves to "Administrator" CODE_AREA / config.Dashboard.GroupToRole SEVERITY / high PROPOSED_FIX / Replace `Admin` with `Administrator` in the table description. The note in the Authorization policies subsection (lines 169, 174) says "Admin or Viewer" as role labels, not config values — those are fine as label prose.


DOC / Diagnostics.md / LINES / 165166 CLAIM / Code snippet shows CreateLogger("ZB.MOM.WW.MxGateway.Request") as the logger category CLAIM_TYPE / term VERDICT / wrong EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/Diagnostics/GatewayRequestLoggingMiddlewareExtensions.cs:30 — .CreateLogger("MxGateway.Request") CODE_AREA / diag.GatewayRequestLoggingMiddleware SEVERITY / medium PROPOSED_FIX / Change the code snippet and the surrounding sentence ("The logger category is ZB.MOM.WW.MxGateway.Request") to use MxGateway.Request.


DOC / GatewayConfiguration.md / LINES / 1419 CLAIM / The MxGateway:Ldap configuration section (11 keys, validated by GatewayOptionsValidator) is not documented in this file CLAIM_TYPE / config-key VERDICT / gap EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/Configuration/LdapOptions.cs:3171 — 11 properties (Enabled, Server, Port, Transport, AllowInsecure, SearchBase, ServiceAccountDn, ServiceAccountPassword, UserNameAttribute, DisplayNameAttribute, GroupAttribute); GatewayOptionsValidator.cs:5590 — ValidateLdap() validates all required fields; appsettings.json:2233 — Ldap section present in default config; GatewayOptions.cs:13 — public LdapOptions Ldap { get; init; } = new(); CODE_AREA / config.Ldap SEVERITY / medium PROPOSED_FIX / Add a ## Ldap Options table covering the 11 keys with their defaults and the validation rules (Server/SearchBase/ServiceAccountDn/ServiceAccountPassword/UserNameAttribute/DisplayNameAttribute/GroupAttribute required when Enabled; Port must be valid; Transport=None requires AllowInsecure=true).


DOC / Diagnostics.md / LINES / 1222 CLAIM / GatewayLogRedactorSeam (in Diagnostics/ folder) is not mentioned CLAIM_TYPE / term VERDICT / gap EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/Diagnostics/GatewayLogRedactorSeam.cs:127 — implements ILogRedactor; adapts GatewayLogRedactor for the Serilog RedactionEnricher so every log event masks API-key/credential material in ClientIdentity, authorization, and Authorization properties CODE_AREA / diag.GatewayLogRedactorSeam SEVERITY / low PROPOSED_FIX / Add a short note under the Consumers section describing GatewayLogRedactorSeam as the ILogRedactor adapter that wires GatewayLogRedactor into the Serilog telemetry enrichment pipeline, covering the three property keys it redacts.


DOC / Diagnostics.md / LINES / 1222 CLAIM / AuthStoreHealthCheck (in Diagnostics/ folder, an ASP.NET Core health check) is not mentioned CLAIM_TYPE / term VERDICT / gap EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/Diagnostics/AuthStoreHealthCheck.cs:130 — readiness probe verifying the SQLite auth store; GatewayApplication.cs:7172 — .AddTypeActivatedCheck<AuthStoreHealthCheck>(...) CODE_AREA / diag.AuthStoreHealthCheck SEVERITY / low PROPOSED_FIX / Add a brief section describing the AuthStoreHealthCheck readiness probe (executes SELECT 1 against the SQLite auth store, exposed via the /health/ready and /healthz endpoints).


DOC / GatewayConfiguration.md / LINES / 1477 (config shape JSON) CLAIM / Config shape JSON example omits the MxGateway:Ldap section entirely CLAIM_TYPE / config-key VERDICT / gap EVIDENCE / appsettings.json:2233 — Ldap section is present; GatewayOptions.cs:13 — Ldap is a first-class sub-section of GatewayOptions CODE_AREA / config.Ldap SEVERITY / medium PROPOSED_FIX / Add the "Ldap": { ... } block to the configuration shape example, showing the keys and their defaults from LdapOptions.


DOC / GatewayConfiguration.md / LINES / 1519 CLAIM / Authentication options: Mode=ApiKey, SqlitePath, PepperSecretName, RunMigrationsOnStartup all have documented defaults matching code CLAIM_TYPE / config-key VERDICT / accurate EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/Configuration/AuthenticationOptions.cs:616 — Mode=ApiKey, SqlitePath=C:\ProgramData\MxGateway\gateway-auth.db, PepperSecretName=MxGateway:ApiKeyPepper, RunMigrationsOnStartup=true CODE_AREA / config.Authentication SEVERITY / low PROPOSED_FIX / flag only


DOC / GatewayConfiguration.md / LINES / 2133 CLAIM / Worker options: all 10 keys and their documented defaults match code CLAIM_TYPE / config-key VERDICT / accurate EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/Configuration/WorkerOptions.cs:538 — ExecutablePath, WorkingDirectory=null, RequiredArchitecture=X86, StartupTimeoutSeconds=30, StartupProbeRetryAttempts=3, StartupProbeRetryDelayMilliseconds=250, PipeConnectAttemptTimeoutMilliseconds=2000, ShutdownTimeoutSeconds=10, HeartbeatIntervalSeconds=5, HeartbeatGraceSeconds=15, MaxMessageBytes=16777216 CODE_AREA / config.Worker SEVERITY / low PROPOSED_FIX / flag only


DOC / GatewayConfiguration.md / LINES / 110 CLAIM / MaxMessageBytes validator range is 1024 through 268435456 CLAIM_TYPE / config-key VERDICT / accurate EVIDENCE / GatewayOptionsValidator.cs:910 — MinimumMaxMessageBytes = 1024, MaximumMaxMessageBytes = 256 * 1024 * 1024 (= 268435456) CODE_AREA / config.Worker.MaxMessageBytes SEVERITY / low PROPOSED_FIX / flag only


DOC / GatewayConfiguration.md / LINES / 3441 CLAIM / Session options: all 6 keys and their documented defaults match code CLAIM_TYPE / config-key VERDICT / accurate EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/Configuration/SessionOptions.cs:430 — DefaultCommandTimeoutSeconds=30, MaxSessions=64, MaxPendingCommandsPerSession=128, DefaultLeaseSeconds=1800, LeaseSweepIntervalSeconds=30, AllowMultipleEventSubscribers=false (C# bool default) CODE_AREA / config.Sessions SEVERITY / low PROPOSED_FIX / flag only


DOC / GatewayConfiguration.md / LINES / 4345 CLAIM / Event options: QueueCapacity=10000, BackpressurePolicy=FailFast CLAIM_TYPE / config-key VERDICT / accurate EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/Configuration/EventOptions.cs:414 — QueueCapacity=10_000, BackpressurePolicy=FailFast CODE_AREA / config.Events SEVERITY / low PROPOSED_FIX / flag only


DOC / GatewayConfiguration.md / LINES / 4657 CLAIM / Dashboard options: Enabled=true, AllowAnonymousLocalhost=true, RequireHttpsCookie=true, CookieName default=MxGatewayDashboard, SnapshotIntervalMilliseconds=1000, RecentFaultLimit=100, RecentSessionLimit=200, ShowTagValues=false, GroupToRole empty by default CLAIM_TYPE / config-key VERDICT / accurate EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/Configuration/DashboardOptions.cs:653 — all defaults confirmed; src/ZB.MOM.WW.MxGateway.Server/Dashboard/DashboardAuthenticationDefaults.cs:38 — CookieName="MxGatewayDashboard" CODE_AREA / config.Dashboard SEVERITY / low PROPOSED_FIX / flag only


DOC / GatewayConfiguration.md / LINES / 5962 CLAIM / Protocol options: WorkerProtocolVersion=1, MaxGrpcMessageBytes=16777216; validator range 1024268435456 CLAIM_TYPE / config-key VERDICT / accurate EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/Configuration/ProtocolOptions.cs:1316; GatewayOptionsValidator.cs:291302 CODE_AREA / config.Protocol SEVERITY / low PROPOSED_FIX / flag only


DOC / GatewayConfiguration.md / LINES / 6369 CLAIM / Galaxy options: ConnectionString, CommandTimeoutSeconds=60, DashboardRefreshIntervalSeconds=30, PersistSnapshot=true, SnapshotCachePath defaults all match code CLAIM_TYPE / config-key VERDICT / accurate EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/Galaxy/GalaxyRepositoryOptions.cs:1646 — all defaults confirmed CODE_AREA / config.Galaxy SEVERITY / low PROPOSED_FIX / flag only


DOC / GatewayConfiguration.md / LINES / 7075 CLAIM / Alarm options: Enabled=false, SubscriptionExpression=empty, DefaultArea=empty, ReconcileIntervalSeconds=30 CLAIM_TYPE / config-key VERDICT / accurate EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/Configuration/AlarmsOptions.cs:2247 — Enabled default is C# bool default (false), SubscriptionExpression=string.Empty, DefaultArea=string.Empty, ReconcileIntervalSeconds=30 CODE_AREA / config.Alarms SEVERITY / low PROPOSED_FIX / flag only


DOC / GatewayConfiguration.md / LINES / 228 CLAIM / ReconcileIntervalSeconds is "Floored at 5 seconds" CLAIM_TYPE / behavior-rule VERDICT / accurate EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/Alarms/GatewayAlarmMonitor.cs:239 — int seconds = Math.Max(5, _options.ReconcileIntervalSeconds); CODE_AREA / config.Alarms.ReconcileIntervalSeconds SEVERITY / low PROPOSED_FIX / flag only


DOC / GatewayConfiguration.md / LINES / 346354 CLAIM / TLS options: SelfSignedCertPath, ValidityYears=10, AdditionalDnsNames=[], RegenerateIfExpired=true; ValidityYears validated 1100 CLAIM_TYPE / config-key VERDICT / accurate EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/Configuration/TlsOptions.cs:1122; GatewayOptionsValidator.cs:260261 — MinimumCertValidityYears = 1, MaximumCertValidityYears = 100 CODE_AREA / config.Tls SEVERITY / low PROPOSED_FIX / flag only


DOC / GatewayConfiguration.md / LINES / 164176 CLAIM / Three authorization policies named MxGateway.Dashboard.Viewer, MxGateway.Dashboard.Admin, MxGateway.Dashboard.HubClients; hub-token bearer scheme named MxGateway.Dashboard.HubToken CLAIM_TYPE / term VERDICT / accurate EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/Dashboard/DashboardAuthenticationDefaults.cs:20,27,34,14 CODE_AREA / config.Dashboard.AuthPolicies SEVERITY / low PROPOSED_FIX / flag only


DOC / GatewayConfiguration.md / LINES / 180195 CLAIM / SignalR hubs mapped at /hubs/snapshot, /hubs/alarms, /hubs/events; token endpoint at /hubs/token CLAIM_TYPE / path VERDICT / accurate EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/Dashboard/DashboardEndpointRouteBuilderExtensions.cs:6365,73 CODE_AREA / config.Dashboard.Hubs SEVERITY / low PROPOSED_FIX / flag only


DOC / GatewayConfiguration.md / LINES / 193 CLAIM / GET /hubs/token mints a 30-minute data-protected bearer token CLAIM_TYPE / behavior-rule VERDICT / accurate EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/Dashboard/HubTokenService.cs:29 — private static readonly TimeSpan TokenLifetime = TimeSpan.FromMinutes(30); CODE_AREA / config.Dashboard.HubToken SEVERITY / low PROPOSED_FIX / flag only


DOC / GatewayConfiguration.md / LINES / 197206 CLAIM / Pipeline ordering: UseGatewayRequestLoggingScope → UseStaticFiles → UseAuthentication → UseAuthorization → UseAntiforgery → MapGatewayEndpoints CLAIM_TYPE / behavior-rule VERDICT / accurate EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/GatewayApplication.cs:4045 CODE_AREA / diag.GatewayRequestLoggingMiddleware SEVERITY / low PROPOSED_FIX / flag only


DOC / Diagnostics.md / LINES / 1534 CLAIM / GatewayLogScope record signature (SessionId, WorkerProcessId, CorrelationId, CommandMethod, ClientIdentity) and ToDictionary behavior matches code CLAIM_TYPE / term VERDICT / accurate EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/Diagnostics/GatewayLogScope.cs:334 CODE_AREA / diag.GatewayLogScope SEVERITY / low PROPOSED_FIX / flag only


DOC / Diagnostics.md / LINES / 4457 CLAIM / GatewayLoggerExtensions.BeginGatewayScope signature and behavior match code CLAIM_TYPE / term VERDICT / accurate EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/Diagnostics/GatewayLoggerExtensions.cs:918 CODE_AREA / diag.GatewayLoggerExtensions SEVERITY / low PROPOSED_FIX / flag only


DOC / Diagnostics.md / LINES / 6880 CLAIM / SensitiveCommandMethods set contains AuthenticateUser, WriteSecured, WriteSecured2; IsCredentialBearingCommand logic is correct CLAIM_TYPE / behavior-rule VERDICT / accurate EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/Diagnostics/GatewayLogRedactor.cs:1126 CODE_AREA / diag.GatewayLogRedactor SEVERITY / low PROPOSED_FIX / flag only


DOC / Diagnostics.md / LINES / 86117 CLAIM / RedactApiKey implementation (bearer prefix, mxgw_ marker, split count=3, tokenParts[1] kept) matches code CLAIM_TYPE / behavior-rule VERDICT / accurate EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/Diagnostics/GatewayLogRedactor.cs:3259 CODE_AREA / diag.GatewayLogRedactor SEVERITY / low PROPOSED_FIX / flag only


DOC / Diagnostics.md / LINES / 127148 CLAIM / RedactCommandValue: when valueLoggingEnabled=false every value is redacted; credential-bearing commands always redact even with valueLoggingEnabled=true CLAIM_TYPE / behavior-rule VERDICT / accurate EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/Diagnostics/GatewayLogRedactor.cs:8399 CODE_AREA / diag.GatewayLogRedactor SEVERITY / low PROPOSED_FIX / flag only


DOC / Diagnostics.md / LINES / 181188 CLAIM / Request logging scope reads headers: x-session-id, x-worker-process-id, x-correlation-id, x-command-method, authorization CLAIM_TYPE / term VERDICT / accurate EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/Diagnostics/GatewayRequestLoggingMiddlewareExtensions.cs:916,3237 CODE_AREA / diag.GatewayRequestLoggingMiddleware SEVERITY / low PROPOSED_FIX / flag only


DOC / Metrics.md / LINES / 8 CLAIM / GatewayMetrics is a singleton registered in GatewayApplication.cs CLAIM_TYPE / term VERDICT / accurate EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/GatewayApplication.cs:76 — builder.Services.AddSingleton<GatewayMetrics>(); CODE_AREA / metrics.GatewayMetrics SEVERITY / low PROPOSED_FIX / flag only


DOC / Metrics.md / LINES / 14 CLAIM / Meter name constant is "ZB.MOM.WW.MxGateway" CLAIM_TYPE / term VERDICT / accurate EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/Metrics/GatewayMetrics.cs:8 — public const string MeterName = "ZB.MOM.WW.MxGateway"; CODE_AREA / metrics.GatewayMetrics.MeterName SEVERITY / low PROPOSED_FIX / flag only


DOC / Metrics.md / LINES / 3649 CLAIM / All 13 counter instrument names match code CLAIM_TYPE / term VERDICT / accurate EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/Metrics/GatewayMetrics.cs:5870 — mxgateway.sessions.opened, .sessions.closed, .commands.started, .commands.succeeded, .commands.failed, .events.received, .queues.overflows, .faults, .workers.killed, .workers.exited, .heartbeats.failed, .grpc.streams.disconnected, .retries.attempted all confirmed CODE_AREA / metrics.counters SEVERITY / low PROPOSED_FIX / flag only


DOC / Metrics.md / LINES / 5665 CLAIM / Three histograms: mxgateway.workers.startup.duration ("s"), mxgateway.commands.duration ("s"), mxgateway.events.stream_send.duration ("s") — names, units, tag shapes match code CLAIM_TYPE / term VERDICT / accurate EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/Metrics/GatewayMetrics.cs:7173 CODE_AREA / metrics.histograms SEVERITY / low PROPOSED_FIX / flag only


DOC / Metrics.md / LINES / 7377 CLAIM / Four observable gauges: mxgateway.sessions.open, mxgateway.workers.running, mxgateway.events.worker_queue.depth, mxgateway.events.grpc_stream_queue.depth match code CLAIM_TYPE / term VERDICT / accurate EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/Metrics/GatewayMetrics.cs:7578 CODE_AREA / metrics.gauges SEVERITY / low PROPOSED_FIX / flag only


DOC / Metrics.md / LINES / 82104 CLAIM / GatewayMetricsSnapshot record fields (21 parameters) match code exactly CLAIM_TYPE / term VERDICT / accurate EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/Metrics/GatewayMetricsSnapshot.cs:324 CODE_AREA / metrics.GatewayMetricsSnapshot SEVERITY / low PROPOSED_FIX / flag only


DOC / Metrics.md / LINES / 114 CLAIM / EventsReceived is read with Interlocked.Read(ref _eventsReceived) inside GetSnapshot CLAIM_TYPE / behavior-rule VERDICT / accurate EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/Metrics/GatewayMetrics.cs:397 — EventsReceived: Interlocked.Read(ref _eventsReceived), CODE_AREA / metrics.GatewayMetrics.GetSnapshot SEVERITY / low PROPOSED_FIX / flag only


DOC / Metrics.md / LINES / 138139 CLAIM / SessionRemoved decrements the open-session gauge without incrementing the closed counter CLAIM_TYPE / behavior-rule VERDICT / accurate EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/Metrics/GatewayMetrics.cs:126134 — SessionRemoved() decrements _openSessions but does not touch _sessionsClosed CODE_AREA / metrics.GatewayMetrics.SessionRemoved SEVERITY / low PROPOSED_FIX / flag only


DOC / Metrics.md / LINES / 169 CLAIM / SessionWorkerClientFactory records WorkerKilled("OpenSessionFailed") CLAIM_TYPE / behavior-rule VERDICT / accurate EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/Sessions/SessionWorkerClientFactory.cs:133 CODE_AREA / metrics.recording.SessionWorkerClientFactory SEVERITY / low PROPOSED_FIX / flag only


DOC / Metrics.md / LINES / 154162 CLAIM / WorkerProcessLauncher records WorkerKilled(reason) and RetryAttempted("worker_startup") CLAIM_TYPE / behavior-rule VERDICT / accurate EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/Workers/WorkerProcessLauncher.cs:260,282 CODE_AREA / metrics.recording.WorkerProcessLauncher SEVERITY / low PROPOSED_FIX / flag only


DOC / Metrics.md / LINES / 178192 CLAIM / EventStreamService records AdjustGrpcEventStreamQueueDepth, StreamDisconnected("Detached"), QueueOverflow("grpc-event-stream"), Fault(EventQueueOverflow), Fault(WorkerFaulted) CLAIM_TYPE / behavior-rule VERDICT / accurate EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/Grpc/EventStreamService.cs:58,67,96,99,146,150,179 CODE_AREA / metrics.recording.EventStreamService SEVERITY / low PROPOSED_FIX / flag only


Summary

Verdict Count
accurate 25
wrong 3
stale 0
unverifiable 0
gap 4
Total 32
Severity Count
high 2
medium 3
low 27

High-Severity Findings

  • GatewayConfiguration.md line 55 — GroupToRole config shape example uses "Admin" as a role value. The validator accepts only "Administrator" (DashboardRoles.Admin = "Administrator"). Any operator who copies this example verbatim will produce a validation failure at startup. Fix: change "GwAdmin": "Admin" to "GwAdmin": "Administrator" in the JSON block.

  • GatewayConfiguration.md line 156 — GroupToRole table description says values must be Admin or Viewer. The accepted value is "Administrator", not "Admin". This is the primary prose that operators read when configuring LDAP role mapping; the wrong string here will silently break authentication if an operator follows the docs. Fix: replace `Admin` with `Administrator` in the description column.

Medium-Severity Findings

  • Diagnostics.md line 165166 — Embedded code snippet and surrounding text state the logger category is ZB.MOM.WW.MxGateway.Request. The actual category used by GatewayRequestLoggingMiddlewareExtensions is MxGateway.Request. An operator filtering logs by the documented category will see no output. Fix: update snippet and prose to MxGateway.Request.

  • GatewayConfiguration.md — MxGateway:Ldap section (11 keys) is entirely absent from the config shape JSON example and has no option table. The section is validated at startup by GatewayOptionsValidator.ValidateLdap and appears in appsettings.json. Fix: add "Ldap" block to the JSON shape and a ## Ldap Options table.

  • GatewayConfiguration.md — Config shape JSON omits the Ldap section (duplicate of the above gap, listed separately because the shape and the prose table are independent defects).