- Add RemovePassFromTrace, RemoveAuthTokenFromTrace, RemoveSecretsFromTrace static methods to ServerLogging (mirrors removeSecretsFromTrace/redact in server/client.go); uses same regex patterns as Go source to redact only the first match's value with [REDACTED]. - Update ClientConnection.RemoveSecretsFromTrace stub to delegate to ServerLogging.RemoveSecretsFromTrace. - Add 2 unit tests to SignalHandlerTests (T:2919 invalid command, T:2920 invalid PID); mark 14 process-injection/subprocess tests as deferred ([Fact(Skip=…)]). - Create ServerLoggerTests with 3 test methods (T:2020, T:2021, T:2022) covering NoPasswordsFromConnectTrace, RemovePassFromTrace (8 theory cases), RemoveAuthTokenFromTrace (8 theory cases). - DB: 3 log tests → complete, 2 signal tests → complete, 14 signal tests → deferred. - All 663 unit tests pass (was 645), 14 deferred skipped.
139 lines
6.5 KiB
C#
139 lines
6.5 KiB
C#
// Copyright 2012-2025 The NATS Authors
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
using Shouldly;
|
|
using ZB.MOM.NatsNet.Server.Internal;
|
|
|
|
namespace ZB.MOM.NatsNet.Server.Tests.Internal;
|
|
|
|
/// <summary>
|
|
/// Tests for server logging trace sanitization (RemovePassFromTrace, RemoveAuthTokenFromTrace).
|
|
/// Mirrors server/log_test.go — TestNoPasswordsFromConnectTrace, TestRemovePassFromTrace,
|
|
/// TestRemoveAuthTokenFromTrace.
|
|
/// </summary>
|
|
public class ServerLoggerTests
|
|
{
|
|
// ---------------------------------------------------------------------------
|
|
// T:2020 — TestNoPasswordsFromConnectTrace
|
|
// ---------------------------------------------------------------------------
|
|
|
|
/// <summary>
|
|
/// Mirrors TestNoPasswordsFromConnectTrace.
|
|
/// Verifies that a CONNECT trace with a password or auth_token does not
|
|
/// expose the secret value after sanitization.
|
|
/// </summary>
|
|
[Fact] // T:2020
|
|
public void NoPasswordsFromConnectTrace_ShouldSucceed()
|
|
{
|
|
const string connectWithPass =
|
|
"""CONNECT {"verbose":false,"pedantic":false,"user":"derek","pass":"s3cr3t","tls_required":false}""";
|
|
const string connectWithToken =
|
|
"""CONNECT {"verbose":false,"auth_token":"secret-token","tls_required":false}""";
|
|
|
|
ServerLogging.RemovePassFromTrace(connectWithPass).ShouldNotContain("s3cr3t");
|
|
ServerLogging.RemoveAuthTokenFromTrace(connectWithToken).ShouldNotContain("secret-token");
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// T:2021 — TestRemovePassFromTrace
|
|
// ---------------------------------------------------------------------------
|
|
|
|
/// <summary>
|
|
/// Mirrors TestRemovePassFromTrace — covers all test vectors from log_test.go.
|
|
/// Each case verifies that RemovePassFromTrace redacts the first pass/password value
|
|
/// with [REDACTED] while leaving other fields intact.
|
|
/// </summary>
|
|
[Theory] // T:2021
|
|
[InlineData(
|
|
"user and pass",
|
|
"CONNECT {\"user\":\"derek\",\"pass\":\"s3cr3t\"}\r\n",
|
|
"CONNECT {\"user\":\"derek\",\"pass\":\"[REDACTED]\"}\r\n")]
|
|
[InlineData(
|
|
"user and pass extra space",
|
|
"CONNECT {\"user\":\"derek\",\"pass\": \"s3cr3t\"}\r\n",
|
|
"CONNECT {\"user\":\"derek\",\"pass\": \"[REDACTED]\"}\r\n")]
|
|
[InlineData(
|
|
"user and pass is empty",
|
|
"CONNECT {\"user\":\"derek\",\"pass\":\"\"}\r\n",
|
|
"CONNECT {\"user\":\"derek\",\"pass\":\"[REDACTED]\"}\r\n")]
|
|
[InlineData(
|
|
"user and pass is empty whitespace",
|
|
"CONNECT {\"user\":\"derek\",\"pass\":\" \"}\r\n",
|
|
"CONNECT {\"user\":\"derek\",\"pass\":\"[REDACTED]\"}\r\n")]
|
|
[InlineData(
|
|
"only pass",
|
|
"CONNECT {\"pass\":\"s3cr3t\",}\r\n",
|
|
"CONNECT {\"pass\":\"[REDACTED]\",}\r\n")]
|
|
[InlineData(
|
|
"complete connect",
|
|
"CONNECT {\"echo\":true,\"verbose\":false,\"pedantic\":false,\"user\":\"foo\",\"pass\":\"s3cr3t\",\"tls_required\":false,\"name\":\"APM7JU94z77YzP6WTBEiuw\"}\r\n",
|
|
"CONNECT {\"echo\":true,\"verbose\":false,\"pedantic\":false,\"user\":\"foo\",\"pass\":\"[REDACTED]\",\"tls_required\":false,\"name\":\"APM7JU94z77YzP6WTBEiuw\"}\r\n")]
|
|
[InlineData(
|
|
"user and pass are filtered",
|
|
"CONNECT {\"user\":\"s3cr3t\",\"pass\":\"s3cr3t\"}\r\n",
|
|
"CONNECT {\"user\":\"s3cr3t\",\"pass\":\"[REDACTED]\"}\r\n")]
|
|
[InlineData(
|
|
"single long password",
|
|
"CONNECT {\"pass\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"}\r\n",
|
|
"CONNECT {\"pass\":\"[REDACTED]\"}\r\n")]
|
|
public void RemovePassFromTrace_ShouldSucceed(string name, string input, string expected)
|
|
{
|
|
_ = name; // used for test display only
|
|
ServerLogging.RemovePassFromTrace(input).ShouldBe(expected);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// T:2022 — TestRemoveAuthTokenFromTrace
|
|
// ---------------------------------------------------------------------------
|
|
|
|
/// <summary>
|
|
/// Mirrors TestRemoveAuthTokenFromTrace — covers representative test vectors
|
|
/// from log_test.go. Each case verifies that RemoveAuthTokenFromTrace redacts
|
|
/// the first auth_token value with [REDACTED].
|
|
/// </summary>
|
|
[Theory] // T:2022
|
|
[InlineData(
|
|
"user and auth_token",
|
|
"CONNECT {\"user\":\"derek\",\"auth_token\":\"s3cr3t\"}\r\n",
|
|
"CONNECT {\"user\":\"derek\",\"auth_token\":\"[REDACTED]\"}\r\n")]
|
|
[InlineData(
|
|
"user and auth_token extra space",
|
|
"CONNECT {\"user\":\"derek\",\"auth_token\": \"s3cr3t\"}\r\n",
|
|
"CONNECT {\"user\":\"derek\",\"auth_token\": \"[REDACTED]\"}\r\n")]
|
|
[InlineData(
|
|
"user and auth_token is empty",
|
|
"CONNECT {\"user\":\"derek\",\"auth_token\":\"\"}\r\n",
|
|
"CONNECT {\"user\":\"derek\",\"auth_token\":\"[REDACTED]\"}\r\n")]
|
|
[InlineData(
|
|
"only auth_token",
|
|
"CONNECT {\"auth_token\":\"s3cr3t\",}\r\n",
|
|
"CONNECT {\"auth_token\":\"[REDACTED]\",}\r\n")]
|
|
[InlineData(
|
|
"complete connect",
|
|
"CONNECT {\"echo\":true,\"verbose\":false,\"pedantic\":false,\"auth_token\":\"s3cr3t\",\"tls_required\":false,\"name\":\"APM7JU94z77YzP6WTBEiuw\"}\r\n",
|
|
"CONNECT {\"echo\":true,\"verbose\":false,\"pedantic\":false,\"auth_token\":\"[REDACTED]\",\"tls_required\":false,\"name\":\"APM7JU94z77YzP6WTBEiuw\"}\r\n")]
|
|
[InlineData(
|
|
"user and token are filtered",
|
|
"CONNECT {\"user\":\"s3cr3t\",\"auth_token\":\"s3cr3t\"}\r\n",
|
|
"CONNECT {\"user\":\"s3cr3t\",\"auth_token\":\"[REDACTED]\"}\r\n")]
|
|
[InlineData(
|
|
"single long token",
|
|
"CONNECT {\"auth_token\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"}\r\n",
|
|
"CONNECT {\"auth_token\":\"[REDACTED]\"}\r\n")]
|
|
public void RemoveAuthTokenFromTrace_ShouldSucceed(string name, string input, string expected)
|
|
{
|
|
_ = name; // used for test display only
|
|
ServerLogging.RemoveAuthTokenFromTrace(input).ShouldBe(expected);
|
|
}
|
|
}
|