From f1129b969daadb792d23af65721b4a9176dad1f8 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Mon, 1 Jun 2026 15:49:32 -0400 Subject: [PATCH] feat(mxgateway): expose GatewayLogRedactor via shared ILogRedactor seam --- .../Diagnostics/GatewayLogRedactorSeam.cs | 28 +++++++++++++++++++ .../GatewayApplication.cs | 1 + .../GatewayLogRedactorSeamTests.cs | 15 ++++++++++ 3 files changed, 44 insertions(+) create mode 100644 src/ZB.MOM.WW.MxGateway.Server/Diagnostics/GatewayLogRedactorSeam.cs create mode 100644 src/ZB.MOM.WW.MxGateway.Tests/Diagnostics/GatewayLogRedactorSeamTests.cs diff --git a/src/ZB.MOM.WW.MxGateway.Server/Diagnostics/GatewayLogRedactorSeam.cs b/src/ZB.MOM.WW.MxGateway.Server/Diagnostics/GatewayLogRedactorSeam.cs new file mode 100644 index 0000000..0beab89 --- /dev/null +++ b/src/ZB.MOM.WW.MxGateway.Server/Diagnostics/GatewayLogRedactorSeam.cs @@ -0,0 +1,28 @@ +using ZB.MOM.WW.Telemetry.Serilog; + +namespace ZB.MOM.WW.MxGateway.Server.Diagnostics; + +/// +/// Adapts the static to the shared seam +/// so the telemetry RedactionEnricher masks API-key/credential material on every log event. +/// +public sealed class GatewayLogRedactorSeam : ILogRedactor +{ + private static readonly string[] IdentityKeys = ["ClientIdentity", "authorization", "Authorization"]; + + /// + /// Masks API-key/credential material in known identity-bearing log properties. + /// + /// The log event property dictionary to redact in place. + public void Redact(IDictionary properties) + { + ArgumentNullException.ThrowIfNull(properties); + foreach (var key in IdentityKeys) + { + if (properties.TryGetValue(key, out var value) && value is string s) + { + properties[key] = GatewayLogRedactor.RedactClientIdentity(s); + } + } + } +} diff --git a/src/ZB.MOM.WW.MxGateway.Server/GatewayApplication.cs b/src/ZB.MOM.WW.MxGateway.Server/GatewayApplication.cs index 4ff780f..621e630 100644 --- a/src/ZB.MOM.WW.MxGateway.Server/GatewayApplication.cs +++ b/src/ZB.MOM.WW.MxGateway.Server/GatewayApplication.cs @@ -73,6 +73,7 @@ public static class GatewayApplication failureStatus: null, tags: new[] { ZbHealthTags.Ready }); builder.Services.AddSingleton(); + builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); diff --git a/src/ZB.MOM.WW.MxGateway.Tests/Diagnostics/GatewayLogRedactorSeamTests.cs b/src/ZB.MOM.WW.MxGateway.Tests/Diagnostics/GatewayLogRedactorSeamTests.cs new file mode 100644 index 0000000..494808e --- /dev/null +++ b/src/ZB.MOM.WW.MxGateway.Tests/Diagnostics/GatewayLogRedactorSeamTests.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; +using ZB.MOM.WW.MxGateway.Server.Diagnostics; +using Xunit; + +public class GatewayLogRedactorSeamTests +{ + [Fact] + public void Redact_MasksApiKeyInClientIdentity() + { + var redactor = new GatewayLogRedactorSeam(); + var props = new Dictionary { ["ClientIdentity"] = "Bearer mxgw_operator01_super-secret" }; + redactor.Redact(props); + Assert.Equal("Bearer mxgw_operator01_[redacted]", props["ClientIdentity"]); + } +}