diff --git a/Changelog.md b/Changelog.md index ece71d6f..c3bf10a6 100644 --- a/Changelog.md +++ b/Changelog.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.0.67] - 2025-10-22 +### Fix +Enabling suppressions for XML files (addressing bug [#588](https://github.com/microsoft/DevSkim/issues/588)) + ## [1.0.66] - 2025-09-04 ### Dependencies Update Dependencies for C# Projects diff --git a/DevSkim-DotNet/Microsoft.DevSkim.Tests/DevSkimRuleProcessorTests.cs b/DevSkim-DotNet/Microsoft.DevSkim.Tests/DevSkimRuleProcessorTests.cs new file mode 100644 index 00000000..e876a4fe --- /dev/null +++ b/DevSkim-DotNet/Microsoft.DevSkim.Tests/DevSkimRuleProcessorTests.cs @@ -0,0 +1,120 @@ +namespace Microsoft.DevSkim.Tests +{ + [TestClass] + public class DevSkimRuleProcessorTests + { + + [TestMethod] + [DataRow("csharp", "DS123456", "// DevSkim: ignore DS123456", DisplayName = "C# Basic Suppression")] + [DataRow("python", "DS123456", "# DevSkim: ignore DS123456", DisplayName = "Python Basic Suppression")] + [DataRow("sql", "DS123456", "-- DevSkim: ignore DS123456", DisplayName = "SQL Basic Suppression")] + [DataRow("vb", "DS123456", "' DevSkim: ignore DS123456", DisplayName = "VB Basic Suppression")] + [DataRow("csharp", "DS123456,DS789012", "// DevSkim: ignore DS123456,DS789012", DisplayName = "Multiple Rule IDs")] + [DataRow("csharp", "", "// DevSkim: ignore ", DisplayName = "Empty Rule ID")] + public void GenerateSuppressionByLanguageTest_BasicSuppressions(string language, string ruleId, string expected) + { + // Test basic suppression generation for various languages + string result = DevSkimRuleProcessor.GenerateSuppressionByLanguage(language, ruleId); + Assert.AreEqual(expected, result); + } + + [TestMethod] + [DataRow("csharp", "DS123456", 30, DisplayName = "C# with 30 days duration")] + [DataRow("python", "DS789012", 15, DisplayName = "Python with 15 days duration")] + [DataRow("sql", "DS111213", 60, DisplayName = "SQL with 60 days duration")] + [DataRow("vb", "DS141516", 7, DisplayName = "VB with 7 days duration")] + public void GenerateSuppressionByLanguageTest_WithDuration(string language, string ruleId, int duration) + { + // Test suppression with expiration date + DateTime testDate = DateTime.Now.AddDays(duration); + string expectedDate = testDate.ToString("yyyy-MM-dd"); + + string result = DevSkimRuleProcessor.GenerateSuppressionByLanguage(language, ruleId, duration: duration); + + Assert.IsTrue(result.Contains("until")); + Assert.IsTrue(result.Contains(expectedDate)); + Assert.IsTrue(result.Contains($"ignore {ruleId} until")); + } + + [TestMethod] + [DataRow("csharp", "DS123456", "JohnDoe", "// DevSkim: ignore DS123456 by JohnDoe", DisplayName = "C# with reviewer")] + [DataRow("python", "DS789012", "JaneSmith", "# DevSkim: ignore DS789012 by JaneSmith", DisplayName = "Python with reviewer")] + [DataRow("sql", "DS111213", "BobJones", "-- DevSkim: ignore DS111213 by BobJones", DisplayName = "SQL with reviewer")] + [DataRow("vb", "DS141516", "AliceWilliams", "' DevSkim: ignore DS141516 by AliceWilliams", DisplayName = "VB with reviewer")] + public void GenerateSuppressionByLanguageTest_WithReviewer(string language, string ruleId, string reviewerName, string expected) + { + // Test suppression with reviewer name + string result = DevSkimRuleProcessor.GenerateSuppressionByLanguage(language, ruleId, reviewerName: reviewerName); + + Assert.AreEqual(expected, result); + } + + [TestMethod] + [DataRow("csharp", "DS123456", 15, "JaneSmith", DisplayName = "C# with duration and reviewer")] + [DataRow("python", "DS789012", 30, "JohnDoe", DisplayName = "Python with duration and reviewer")] + [DataRow("sql", "DS111213", 7, "BobJones", DisplayName = "SQL with duration and reviewer")] + [DataRow("vb", "DS141516", 45, "AliceWilliams", DisplayName = "VB with duration and reviewer")] + public void GenerateSuppressionByLanguageTest_WithDurationAndReviewer(string language, string ruleId, int duration, string reviewerName) + { + // Test suppression with both duration and reviewer + DateTime testDate = DateTime.Now.AddDays(duration); + string expectedDate = testDate.ToString("yyyy-MM-dd"); + + string result = DevSkimRuleProcessor.GenerateSuppressionByLanguage(language, ruleId, duration: duration, reviewerName: reviewerName); + + Assert.IsTrue(result.Contains($"until {expectedDate}")); + Assert.IsTrue(result.Contains($"by {reviewerName}")); + Assert.IsTrue(result.Contains($"ignore {ruleId} until")); + Assert.IsTrue(result.EndsWith($" by {reviewerName}")); + } + + [TestMethod] + [DataRow("csharp", "DS123456", "/*", " */", DisplayName = "C# Multiline")] + [DataRow("python", "DS123456", "#", "\n", DisplayName = "Python Multiline")] + public void GenerateSuppressionByLanguageTest_MultiLinePreferred(string language, string ruleId, string expectedStart, string expectedEnd) + { + // Test multiline comment preference + string result = DevSkimRuleProcessor.GenerateSuppressionByLanguage(language, ruleId, preferMultiLine: true); + + Assert.IsTrue(result.StartsWith($"{expectedStart} DevSkim: ignore {ruleId}")); + Assert.IsTrue(result.EndsWith(expectedEnd)); + } + + [TestMethod] + [DataRow("xml", "DS123456", "", DisplayName = "XML Language")] + public void GenerateSuppressionByLanguageTest_XMLLanguage(string language, string ruleId, string expected) + { + // Test XML-like languages + string result = DevSkimRuleProcessor.GenerateSuppressionByLanguage(language, ruleId); + + Console.WriteLine($"{language} suppression result: '{result}'"); + Assert.AreEqual(expected, result); + Assert.IsNotNull(result); + } + + [TestMethod] + [DataRow(null, DisplayName = "Null Language")] + [DataRow("unknownlang", DisplayName = "Unknown Language")] + public void GenerateSuppressionByLanguageTest_InvalidLanguages(string language) + { + // Test with invalid language parameters + string result = DevSkimRuleProcessor.GenerateSuppressionByLanguage(language, "DS123456"); + + Assert.IsNotNull(result); + // Should handle invalid languages gracefully + } + + [TestMethod] + [DataRow("csharp", "DS123456", "// DevSkim: ignore DS123456", DisplayName = "C# with custom languages")] + [DataRow("python", "DS789012", "# DevSkim: ignore DS789012", DisplayName = "Python with custom languages")] + [DataRow("sql", "DS111213", "-- DevSkim: ignore DS111213", DisplayName = "SQL with custom languages")] + public void GenerateSuppressionByLanguageTest_CustomLanguagesObject(string language, string ruleId, string expected) + { + // Test with custom languages object + var customLanguages = DevSkimLanguages.LoadEmbedded(); + string result = DevSkimRuleProcessor.GenerateSuppressionByLanguage(language, ruleId, languages: customLanguages); + + Assert.AreEqual(expected, result); + } + } +} diff --git a/DevSkim-DotNet/Microsoft.DevSkim.Tests/SuppressionsTest.cs b/DevSkim-DotNet/Microsoft.DevSkim.Tests/SuppressionsTest.cs index 9d7cc85d..284cab39 100644 --- a/DevSkim-DotNet/Microsoft.DevSkim.Tests/SuppressionsTest.cs +++ b/DevSkim-DotNet/Microsoft.DevSkim.Tests/SuppressionsTest.cs @@ -11,6 +11,8 @@ namespace Microsoft.DevSkim.Tests [TestClass] public class SuppressionTest { + public TestContext? TestContext { get; set; } + [DataTestMethod] [DataRow("", 30)] [DataRow("Contoso", 30)] @@ -343,5 +345,117 @@ public void DontChangeFilesWithoutSelectedFindings(string lineBreakSequence, boo string result = File.ReadAllText(sourceFile); Assert.AreEqual(originalContent, result); } + + /// + /// Integration test for XML suppressions + /// + [TestMethod] + public void ExecuteSuppressionsForXML() + { + // Properly formatted XML content with patterns that trigger DevSkim rules (MD5 and http://) + string xmlContent = @" + + + MD5 + + http://example.com +"; + + (string basePath, string sourceFile, string sarifPath) = runAnalysis(xmlContent, "xml"); + + SuppressionCommandOptions opts = new SuppressionCommandOptions + { + Path = basePath, + SarifInput = sarifPath, + ApplyAllSuppression = true + }; + + int resultCode = new SuppressionCommand(opts).Run(); + Assert.AreEqual(0, resultCode); + + string result = File.ReadAllText(sourceFile); + + // Verify that XML-style suppressions were added + Assert.Contains("", result, "XML suppression comment should be properly closed"); + + // Verify suppressions are in correct format + string[] lines = File.ReadAllLines(sourceFile); + bool foundSuppression = false; + foreach (string line in lines) + { + if (line.Contains("" } ] \ No newline at end of file