319 lines
9.8 KiB
C#
Executable File
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);
|
|
}
|
|
}
|
|
} |