diff --git a/src/WebJobs.Script.WebHost/Diagnostics/Sanitizer.cs b/src/WebJobs.Script.WebHost/Diagnostics/Sanitizer.cs index 93d3a95180..8ed931b721 100644 --- a/src/WebJobs.Script.WebHost/Diagnostics/Sanitizer.cs +++ b/src/WebJobs.Script.WebHost/Diagnostics/Sanitizer.cs @@ -13,7 +13,7 @@ internal static class Sanitizer { private const string SecretReplacement = "[Hidden Credential]"; private static readonly char[] ValueTerminators = new char[] { '<', '"' }; - private static readonly string[] CredentialTokens = new string[] { "Token=", "DefaultEndpointsProtocol=http", "AccountKey=", "Data Source=", "Server=", "Password=", "pwd=", "&sig=" }; + private static readonly string[] CredentialTokens = new string[] { "Token=", "DefaultEndpointsProtocol=http", "AccountKey=", "Data Source=", "Server=", "Password=", "pwd=", "&sig=", "SharedAccessKey=" }; /// /// Removes well-known credential strings from strings. diff --git a/test/WebJobs.Script.Tests/ScriptHostTests.cs b/test/WebJobs.Script.Tests/ScriptHostTests.cs index e16c3917ef..6361dd8ad5 100644 --- a/test/WebJobs.Script.Tests/ScriptHostTests.cs +++ b/test/WebJobs.Script.Tests/ScriptHostTests.cs @@ -1051,6 +1051,80 @@ public void Initialize_AppliesLoggerConfig() } } + [Fact] + public void Initialize_Sanitizes_HostJsonLog() + { + TestTraceWriter traceWriter = new TestTraceWriter(TraceLevel.Info); + TestLoggerProvider loggerProvider = null; + var loggerFactoryHookMock = new Mock(MockBehavior.Strict); + loggerFactoryHookMock + .Setup(m => m.AddLoggerProviders(It.IsAny(), It.IsAny(), It.IsAny())) + .Callback((factory, scriptConfig, settings) => + { + loggerProvider = new TestLoggerProvider(scriptConfig.LogFilter.Filter); + factory.AddProvider(loggerProvider); + }); + + string rootPath = Path.Combine(Environment.CurrentDirectory, "ScriptHostTests"); + if (!Directory.Exists(rootPath)) + { + Directory.CreateDirectory(rootPath); + } + + // Turn off all logging. We shouldn't see any output. + string hostJsonContent = @" + { + 'functionTimeout': '00:05:00', + 'functions': [ 'FunctionA', 'FunctionB' ], + 'logger': { + 'categoryFilter': { + 'defaultLevel': 'Information' + } + }, + 'Values': { + 'MyCustomValue': 'abc' + } + }"; + + File.WriteAllText(Path.Combine(rootPath, "host.json"), hostJsonContent); + + ScriptHostConfiguration config = new ScriptHostConfiguration() + { + RootScriptPath = rootPath, + TraceWriter = traceWriter + }; + + config.LoggerFactoryBuilder = loggerFactoryHookMock.Object; + + config.HostConfig.HostId = ID; + var environment = new Mock(); + var eventManager = new Mock(); + + ScriptHost.Create(environment.Object, eventManager.Object, config, _settingsManager); + + string hostJsonSanitized = @" + { + 'functionTimeout': '00:05:00', + 'functions': [ 'FunctionA', 'FunctionB' ], + 'logger': { + 'categoryFilter': { + 'defaultLevel': 'Information' + } + } + }"; + + // for formatting + var hostJson = JObject.Parse(hostJsonSanitized); + string expectedMessgae = $"Host configuration file read:{Environment.NewLine}{hostJson}"; + + var logger = loggerProvider.CreatedLoggers.Single(l => l.Category == LogCategories.Startup); + var logMessage = logger.LogMessages.Single(l => l.FormattedMessage.StartsWith("Host configuration ")).FormattedMessage; + Assert.Equal(expectedMessgae, logMessage); + + var traceMessage = traceWriter.Traces.Single(t => t.Message.StartsWith("Host configuration ")).Message; + Assert.Equal(expectedMessgae, traceMessage); + } + [Fact] public void Initialize_LogsException_IfParseError() {