Skip to main content
Glama

powerbi-tabular-mcp

SecurityTests.cs6.53 kB
using pbi_local_mcp.Configuration; using pbi_local_mcp.Core; namespace pbi_local_mcp.Tests; /// <summary> /// Security tests for SQL injection vulnerabilities and input validation /// </summary> public class SecurityTests { [Theory] [InlineData("ValidTableName")] [InlineData("Table_With_Underscores")] [InlineData("Table With Spaces")] [InlineData("Table123")] [InlineData("Profit Margin %")] [InlineData("Table's Name")] [InlineData("O'Connor")] [InlineData("Table--comment")] [InlineData("Table;")] [InlineData("Table\n")] [InlineData("Table\r")] [InlineData("Table\t")] public void DaxSecurityUtils_IsValidIdentifier_ValidIdentifiers_ReturnsTrue(string identifier) { // Act var result = DaxSecurityUtils.IsValidIdentifier(identifier); // Assert Assert.True(result); } [Theory] [InlineData(null)] [InlineData("")] [InlineData(" ")] [InlineData("Table\0")] // Only null characters are rejected public void DaxSecurityUtils_IsValidIdentifier_InvalidIdentifiers_ReturnsFalse(string identifier) { // Act var result = DaxSecurityUtils.IsValidIdentifier(identifier); // Assert Assert.False(result); } [Fact] public void DaxSecurityUtils_IsValidIdentifier_TooLongIdentifier_ReturnsFalse() { // Arrange var longIdentifier = new string('a', 129); // Over 128 character limit // Act var result = DaxSecurityUtils.IsValidIdentifier(longIdentifier); // Assert Assert.False(result); } [Theory] [InlineData("TableName", "'TableName'")] [InlineData("Table's Name", "'Table''s Name'")] [InlineData("O'Connor", "'O''Connor'")] [InlineData("Profit Margin %", "'Profit Margin %'")] [InlineData("Table--comment", "'Table--comment'")] public void DaxSecurityUtils_EscapeDaxIdentifier_ValidIdentifiers_EscapesCorrectly(string input, string expected) { // Act var result = DaxSecurityUtils.EscapeDaxIdentifier(input); // Assert Assert.Equal(expected, result); } [Theory] [InlineData(null)] [InlineData("")] [InlineData(" ")] [InlineData("Table\0")] public void DaxSecurityUtils_EscapeDaxIdentifier_InvalidIdentifiers_ThrowsArgumentException(string identifier) { // Act & Assert Assert.Throws<ArgumentException>(() => DaxSecurityUtils.EscapeDaxIdentifier(identifier)); } [Theory] [InlineData("[Name] = 'Value'")] [InlineData("[ID] > 100")] [InlineData("[Status] = 'Active' AND [Type] = 'User'")] public void FilterExpressionValidator_ValidateFilterExpression_ValidExpressions_DoesNotThrow(string filterExpr) { // Act & Assert - Should not throw FilterExpressionValidator.ValidateFilterExpression(filterExpr); } [Theory] [InlineData("[Name] = 'Value'; DROP TABLE Users; --")] [InlineData("[Name] = 'Value'--comment")] [InlineData("[Name] = 'Value'/*comment*/")] [InlineData("xp_cmdshell('dir')")] [InlineData("EXEC sp_executesql")] [InlineData("DROP TABLE Users")] [InlineData("INSERT INTO Users")] [InlineData("UPDATE Users SET")] [InlineData("CREATE TABLE Test")] [InlineData("ALTER TABLE Users")] [InlineData("UNION SELECT * FROM")] [InlineData("javascript:alert('xss')")] [InlineData("eval('malicious code')")] public void FilterExpressionValidator_ValidateFilterExpression_MaliciousExpressions_ThrowsArgumentException(string filterExpr) { // Act & Assert Assert.Throws<ArgumentException>(() => FilterExpressionValidator.ValidateFilterExpression(filterExpr)); } [Theory] [InlineData("[Name] = 'Value' <script>")] [InlineData("[Name] = 'Value' $ illegal")] public void FilterExpressionValidator_ValidateFilterExpression_InvalidCharacters_ThrowsArgumentException(string filterExpr) { // Act & Assert Assert.Throws<ArgumentException>(() => FilterExpressionValidator.ValidateFilterExpression(filterExpr)); } [Theory] [InlineData(null)] [InlineData("")] [InlineData(" ")] public void FilterExpressionValidator_ValidateFilterExpression_NullOrEmptyExpressions_DoesNotThrow(string filterExpr) { // Act & Assert - Should not throw for null/empty expressions FilterExpressionValidator.ValidateFilterExpression(filterExpr); } } /// <summary> /// Configuration validation security tests /// </summary> public class PowerBiConfigSecurityTests { [Theory] [InlineData("8080")] [InlineData("1433")] [InlineData("65535")] [InlineData("1")] public void PowerBiConfig_Port_ValidPorts_DoesNotThrow(string port) { // Arrange var config = new PowerBiConfig(); // Act & Assert - Should not throw config.Port = port; Assert.Equal(port, config.Port); } [Theory] [InlineData(null)] [InlineData("")] [InlineData(" ")] [InlineData("0")] [InlineData("-1")] [InlineData("65536")] [InlineData("99999")] [InlineData("abc")] [InlineData("80.5")] [InlineData("8080; DROP TABLE Users; --")] public void PowerBiConfig_Port_InvalidPorts_ThrowsArgumentException(string port) { // Arrange var config = new PowerBiConfig(); // Act & Assert Assert.Throws<ArgumentException>(() => config.Port = port); } [Theory] [InlineData("ValidDatabaseId")] [InlineData("Database_123")] [InlineData("db-with-hyphens")] public void PowerBiConfig_DbId_ValidDbIds_DoesNotThrow(string dbId) { // Arrange var config = new PowerBiConfig(); // Act & Assert - Should not throw config.DbId = dbId; Assert.Equal(dbId, config.DbId); } [Theory] [InlineData(null)] [InlineData("")] [InlineData(" ")] public void PowerBiConfig_DbId_NullOrEmptyDbIds_ThrowsArgumentException(string dbId) { // Arrange var config = new PowerBiConfig(); // Act & Assert Assert.Throws<ArgumentException>(() => config.DbId = dbId); } [Fact] public void PowerBiConfig_DbId_TooLongDbId_ThrowsArgumentException() { // Arrange var config = new PowerBiConfig(); var longDbId = new string('a', 101); // Over 100 character limit // Act & Assert Assert.Throws<ArgumentException>(() => config.DbId = longDbId); } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/jonaolden/tabular-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server