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