|
|
@@ -0,0 +1,148 @@
|
|
|
+using Admin.NET.Plugin.AiDOP.DataPlatform;
|
|
|
+using Admin.NET.Plugin.AiDOP.Job;
|
|
|
+using Microsoft.Extensions.Logging;
|
|
|
+using Xunit;
|
|
|
+
|
|
|
+namespace Admin.NET.Plugin.AiDOP.Tests.DataPlatform;
|
|
|
+
|
|
|
+public class MdpSourcePasswordResolverTests
|
|
|
+{
|
|
|
+ private const string SourceCode = "UNIT_TEST_SRC";
|
|
|
+ private const string Secret = "unit-test-secret-value";
|
|
|
+
|
|
|
+ [Fact]
|
|
|
+ public void Env_wins_over_stored_secret()
|
|
|
+ {
|
|
|
+ var env = MdpSourcePasswordResolver.EnvironmentVariableName(SourceCode);
|
|
|
+ var previous = Environment.GetEnvironmentVariable(env);
|
|
|
+ try
|
|
|
+ {
|
|
|
+ Environment.SetEnvironmentVariable(env, Secret);
|
|
|
+ var logger = new ListLogger();
|
|
|
+ var value = new MdpSourcePasswordResolver(logger).Resolve(SourceCode, "stored-cipher");
|
|
|
+ Assert.Equal(Secret, value);
|
|
|
+ Assert.DoesNotContain(Secret, logger.Text);
|
|
|
+ }
|
|
|
+ finally
|
|
|
+ {
|
|
|
+ Environment.SetEnvironmentVariable(env, previous);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ [Fact]
|
|
|
+ public void Missing_env_uses_successful_decrypt_without_logging_it()
|
|
|
+ {
|
|
|
+ var env = MdpSourcePasswordResolver.EnvironmentVariableName(SourceCode);
|
|
|
+ var previous = Environment.GetEnvironmentVariable(env);
|
|
|
+ try
|
|
|
+ {
|
|
|
+ Environment.SetEnvironmentVariable(env, null);
|
|
|
+ var logger = new ListLogger();
|
|
|
+ var value = MdpSourcePasswordResolver.ResolveCore(
|
|
|
+ SourceCode, "cipher-blob", _ => "opened-secret", logger);
|
|
|
+ Assert.Equal("opened-secret", value);
|
|
|
+ Assert.DoesNotContain("cipher-blob", logger.Text);
|
|
|
+ Assert.DoesNotContain("opened-secret", logger.Text);
|
|
|
+ Assert.DoesNotContain(Secret, logger.Text);
|
|
|
+ }
|
|
|
+ finally
|
|
|
+ {
|
|
|
+ Environment.SetEnvironmentVariable(env, previous);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ [Fact]
|
|
|
+ public void Missing_env_uses_legacy_plaintext_without_logging_it()
|
|
|
+ {
|
|
|
+ var env = MdpSourcePasswordResolver.EnvironmentVariableName(SourceCode);
|
|
|
+ var previous = Environment.GetEnvironmentVariable(env);
|
|
|
+ try
|
|
|
+ {
|
|
|
+ Environment.SetEnvironmentVariable(env, null);
|
|
|
+ var logger = new ListLogger();
|
|
|
+ var value = new MdpSourcePasswordResolver(logger).Resolve(SourceCode, Secret);
|
|
|
+ Assert.Equal(Secret, value);
|
|
|
+ Assert.Contains("legacy plaintext", logger.Text);
|
|
|
+ Assert.DoesNotContain(Secret, logger.Text);
|
|
|
+ }
|
|
|
+ finally
|
|
|
+ {
|
|
|
+ Environment.SetEnvironmentVariable(env, previous);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ [Fact]
|
|
|
+ public void Missing_env_and_stored_secret_throws_SECRET_MISSING()
|
|
|
+ {
|
|
|
+ var env = MdpSourcePasswordResolver.EnvironmentVariableName(SourceCode);
|
|
|
+ var previous = Environment.GetEnvironmentVariable(env);
|
|
|
+ try
|
|
|
+ {
|
|
|
+ Environment.SetEnvironmentVariable(env, null);
|
|
|
+ var ex = Assert.Throws<MdpSourceSecretException>(() =>
|
|
|
+ new MdpSourcePasswordResolver().Resolve(SourceCode, null));
|
|
|
+ Assert.Equal("SECRET_MISSING", ex.Code);
|
|
|
+ Assert.Contains(env, ex.Message);
|
|
|
+ Assert.DoesNotContain(Secret, ex.Message);
|
|
|
+ }
|
|
|
+ finally
|
|
|
+ {
|
|
|
+ Environment.SetEnvironmentVariable(env, previous);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ [Fact]
|
|
|
+ public void Health_classifier_does_not_keep_connection_text()
|
|
|
+ {
|
|
|
+ Assert.Equal("SECRET_MISSING", MdpSourceHealthCheckJob.ClassifyHealthFailure(
|
|
|
+ new MdpSourceSecretException("SECRET_MISSING", "set the env")));
|
|
|
+ Assert.Equal("AUTH_FAILED", MdpSourceHealthCheckJob.ClassifyHealthFailure(
|
|
|
+ new InvalidOperationException("Login failed for user 'dopsa'")));
|
|
|
+ Assert.Equal("NETWORK_FAILED", MdpSourceHealthCheckJob.ClassifyHealthFailure(
|
|
|
+ new TimeoutException("Unable to connect to the server")));
|
|
|
+ Assert.Equal("连接失败,详情见运行日志", MdpSourceHealthCheckJob.SafeHealthMessage(
|
|
|
+ "Password=unit-test-secret-value;Server=example"));
|
|
|
+ Assert.DoesNotContain(Secret, MdpSourceHealthCheckJob.SafeHealthMessage(
|
|
|
+ "Password=unit-test-secret-value;Server=example"));
|
|
|
+ }
|
|
|
+
|
|
|
+ [Fact]
|
|
|
+ public void Database_json_no_longer_contains_t8_v5()
|
|
|
+ {
|
|
|
+ var dir = new DirectoryInfo(AppContext.BaseDirectory);
|
|
|
+ string? path = null;
|
|
|
+ while (dir != null)
|
|
|
+ {
|
|
|
+ var candidate = Path.Combine(dir.FullName, "server", "Admin.NET.Application", "Configuration", "Database.json");
|
|
|
+ if (File.Exists(candidate))
|
|
|
+ {
|
|
|
+ path = candidate;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ dir = dir.Parent;
|
|
|
+ }
|
|
|
+ Assert.False(string.IsNullOrEmpty(path), "Database.json not found from " + AppContext.BaseDirectory);
|
|
|
+ var text = File.ReadAllText(path);
|
|
|
+ Assert.DoesNotContain("t8_v5", text, StringComparison.OrdinalIgnoreCase);
|
|
|
+ }
|
|
|
+
|
|
|
+ private sealed class ListLogger : ILogger<MdpSourcePasswordResolver>
|
|
|
+ {
|
|
|
+ public string Text { get; private set; } = "";
|
|
|
+
|
|
|
+ public IDisposable BeginScope<TState>(TState state) where TState : notnull => NullScope.Instance;
|
|
|
+
|
|
|
+ public bool IsEnabled(LogLevel logLevel) => true;
|
|
|
+
|
|
|
+ public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
|
|
|
+ {
|
|
|
+ Text += formatter(state, exception);
|
|
|
+ }
|
|
|
+
|
|
|
+ private sealed class NullScope : IDisposable
|
|
|
+ {
|
|
|
+ public static readonly NullScope Instance = new();
|
|
|
+ public void Dispose() { }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|