MarketAlly.AIPlugin.Extensions/MarketAlly.AIPlugin.Learnin.../Services/SecurityServiceTests.cs

319 lines
9.8 KiB
C#
Executable File

using MarketAlly.AIPlugin.Learning.Configuration;
using MarketAlly.AIPlugin.Learning.Services;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace MarketAlly.AIPlugin.Learning.Tests.Services
{
[TestClass]
public class SecurityServiceTests
{
private SecurityService _securityService;
private Mock<ILogger<SecurityService>> _mockLogger;
private LearningConfiguration _config;
[TestInitialize]
public void Setup()
{
_mockLogger = new Mock<ILogger<SecurityService>>();
_config = new LearningConfiguration
{
Security = new SecurityConfiguration
{
ForbiddenDirectories = new[] { "bin", "obj", ".git", "node_modules" },
AllowedFileExtensions = new[] { ".cs", ".csproj", ".sln", ".json" },
MaxFileSizeBytes = 10 * 1024 * 1024, // 10MB
EnablePathValidation = true,
EnableInputSanitization = true
}
};
var options = Options.Create(_config);
_securityService = new SecurityService(options, _mockLogger.Object, @"C:\Users\logik\source\repos\MarketAlly.AIPlugin");
}
[TestMethod]
public void IsPathSafe_ValidPath_ReturnsTrue()
{
// Arrange
var validPath = @"C:\Users\logik\source\repos\MarketAlly.AIPlugin\Services\UserService.cs";
// Act
var result = _securityService.IsPathSafe(validPath);
// Assert
Assert.IsTrue(result);
}
[TestMethod]
public void IsPathSafe_PathWithDoubleDots_ReturnsFalse()
{
// Arrange
var maliciousPath = @"C:\Users\logik\source\repos\MarketAlly.AIPlugin\..\..\..\Windows\System32\notepad.exe";
// Act
var result = _securityService.IsPathSafe(maliciousPath);
// Assert
Assert.IsFalse(result);
}
[TestMethod]
public void IsPathSafe_PathOutsideWorkingDirectory_ReturnsFalse()
{
// Arrange
var outsidePath = @"C:\SomeOtherProject\file.cs";
// Act
var result = _securityService.IsPathSafe(outsidePath);
// Assert
Assert.IsFalse(result);
}
[TestMethod]
public void IsPathSafe_ForbiddenDirectory_ReturnsFalse()
{
// Arrange
var forbiddenPath = @"C:\Users\logik\source\repos\MarketAlly.AIPlugin\bin\Debug\app.exe";
// Act
var result = _securityService.IsPathSafe(forbiddenPath);
// Assert
Assert.IsFalse(result);
}
[TestMethod]
public void IsFileAllowed_AllowedExtension_ReturnsTrue()
{
// Arrange
var allowedFile = @"C:\Users\logik\source\repos\MarketAlly.AIPlugin\Services\UserService.cs";
// Act
var result = _securityService.IsFileAllowed(allowedFile);
// Assert
Assert.IsTrue(result);
}
[TestMethod]
public void IsFileAllowed_DisallowedExtension_ReturnsFalse()
{
// Arrange
var disallowedFile = @"C:\Users\logik\source\repos\MarketAlly.AIPlugin\malicious.exe";
// Act
var result = _securityService.IsFileAllowed(disallowedFile);
// Assert
Assert.IsFalse(result);
}
[TestMethod]
public void SanitizeInput_InputWithUnsafeCharacters_RemovesUnsafeCharacters()
{
// Arrange
var unsafeInput = "SELECT * FROM Users WHERE Name = '<script>alert('xss')</script>'";
// Act
var result = _securityService.SanitizeInput(unsafeInput);
// Assert
Assert.IsFalse(result.Contains("<script>"));
Assert.IsFalse(result.Contains("</script>"));
}
[TestMethod]
public void SanitizeInput_NullInput_ReturnsEmptyString()
{
// Arrange
string? nullInput = null;
// Act
var result = _securityService.SanitizeInput(nullInput);
// Assert
Assert.AreEqual(string.Empty, result);
}
[TestMethod]
public void SanitizeInput_EmptyInput_ReturnsEmptyString()
{
// Arrange
var emptyInput = string.Empty;
// Act
var result = _securityService.SanitizeInput(emptyInput);
// Assert
Assert.AreEqual(string.Empty, result);
}
[TestMethod]
public void SanitizeInput_ValidInput_ReturnsUnchanged()
{
// Arrange
var validInput = "This is a normal query about refactoring UserService class";
// Act
var result = _securityService.SanitizeInput(validInput);
// Assert
Assert.AreEqual(validInput, result);
}
[TestMethod]
public void ValidateConfiguration_ValidConfig_ReturnsValid()
{
// Arrange
var validConfig = new LearningConfiguration
{
Git = new GitConfiguration
{
BranchPrefix = "ai-refactoring",
CommitterName = "AI Learning System",
CommitterEmail = "ai@learning.system"
},
Security = new SecurityConfiguration
{
ForbiddenDirectories = new[] { "bin", "obj" },
AllowedFileExtensions = new[] { ".cs", ".csproj" },
MaxFileSizeBytes = 1024 * 1024,
EnablePathValidation = true,
EnableInputSanitization = true
},
AI = new AIConfiguration(),
Performance = new PerformanceConfiguration(),
LearningModes = new LearningModeConfiguration()
};
// Act
var result = _securityService.ValidateConfiguration(validConfig);
// Assert
Assert.IsTrue(result.IsValid);
Assert.IsFalse(result.Errors.Any());
}
[TestMethod]
public void ValidateConfiguration_InvalidEmail_ReturnsInvalid()
{
// Arrange
var invalidConfig = new LearningConfiguration
{
Git = new GitConfiguration
{
BranchPrefix = "ai-refactoring",
CommitterName = "AI Learning System",
CommitterEmail = "invalid-email" // Invalid email format
},
Security = new SecurityConfiguration(),
AI = new AIConfiguration(),
Performance = new PerformanceConfiguration(),
LearningModes = new LearningModeConfiguration()
};
// Act
var result = _securityService.ValidateConfiguration(invalidConfig);
// Assert
Assert.IsFalse(result.IsValid);
Assert.IsTrue(result.Errors.Any(e => e.Contains("email")));
}
[TestMethod]
public void GenerateSecureSessionId_MultipleInvocations_ReturnsDifferentIds()
{
// Act
var id1 = _securityService.GenerateSecureSessionId();
var id2 = _securityService.GenerateSecureSessionId();
// Assert
Assert.AreNotEqual(id1, id2);
Assert.IsTrue(id1.Length >= 8);
Assert.IsTrue(id2.Length >= 8);
}
[TestMethod]
public void GenerateSecureSessionId_GeneratedId_IsValidFormat()
{
// Act
var sessionId = _securityService.GenerateSecureSessionId();
// Assert
Assert.IsNotNull(sessionId);
Assert.IsTrue(sessionId.Length >= 8);
Assert.IsTrue(sessionId.All(c => char.IsLetterOrDigit(c) || c == '-' || c == '_'));
}
[TestMethod]
public void IsDirectoryWithinBounds_ValidDirectory_ReturnsTrue()
{
// Arrange
var validDirectory = @"C:\Users\logik\source\repos\MarketAlly.AIPlugin\Services";
// Act
var result = _securityService.IsDirectoryWithinBounds(validDirectory);
// Assert
Assert.IsTrue(result);
}
[TestMethod]
public void IsDirectoryWithinBounds_DirectoryOutsideBounds_ReturnsFalse()
{
// Arrange
var outsideDirectory = @"C:\SomeOtherProject";
// Act
var result = _securityService.IsDirectoryWithinBounds(outsideDirectory);
// Assert
Assert.IsFalse(result);
}
[TestMethod]
public void IsOperationAllowed_AllowedOperation_ReturnsTrue()
{
// Arrange
var operation = "read";
var context = new SessionContext { SessionId = "test-session" };
// Act
var result = _securityService.IsOperationAllowed(operation, context);
// Assert
Assert.IsTrue(result);
}
[TestMethod]
public void IsOperationAllowed_NullContext_ReturnsFalse()
{
// Arrange
var operation = "read";
SessionContext? context = null;
// Act
var result = _securityService.IsOperationAllowed(operation, context);
// Assert
Assert.IsFalse(result);
}
[TestMethod]
public void IsOperationAllowed_DangerousOperation_ReturnsFalse()
{
// Arrange
var operation = "execute";
var context = new SessionContext { SessionId = "test-session" };
// Act
var result = _securityService.IsOperationAllowed(operation, context);
// Assert
Assert.IsFalse(result);
}
}
}