diff --git a/DevSkim-DotNet/Microsoft.DevSkim.Tests/SuppressionsTest.cs b/DevSkim-DotNet/Microsoft.DevSkim.Tests/SuppressionsTest.cs
index 9d7cc85d..5f03d871 100644
--- a/DevSkim-DotNet/Microsoft.DevSkim.Tests/SuppressionsTest.cs
+++ b/DevSkim-DotNet/Microsoft.DevSkim.Tests/SuppressionsTest.cs
@@ -343,5 +343,241 @@ public void DontChangeFilesWithoutSelectedFindings(string lineBreakSequence, boo
string result = File.ReadAllText(sourceFile);
Assert.AreEqual(originalContent, result);
}
+
+ ///
+ /// Test that XML suppression comments are generated correctly
+ ///
+ [TestMethod]
+ public void GenerateXmlSuppression()
+ {
+ // Test basic XML suppression generation
+ string suppression = DevSkimRuleProcessor.GenerateSuppressionByLanguage("xml", "DS123456");
+ Assert.IsTrue(suppression.StartsWith(""), "XML suppression should end with -->");
+ Assert.IsTrue(suppression.Contains("DevSkim: ignore DS123456"), "XML suppression should contain DevSkim ignore directive");
+ }
+
+ ///
+ /// Test that XML suppression comments with duration are generated correctly
+ ///
+ [TestMethod]
+ public void GenerateXmlSuppressionWithDuration()
+ {
+ int duration = 30;
+ DateTime expectedDate = DateTime.Now.AddDays(duration);
+ string expectedDateStr = expectedDate.ToString("yyyy-MM-dd");
+
+ string suppression = DevSkimRuleProcessor.GenerateSuppressionByLanguage("xml", "DS123456", duration: duration);
+ Assert.IsTrue(suppression.StartsWith(""), "XML suppression should end with -->");
+ Assert.IsTrue(suppression.Contains($"until {expectedDateStr}"), "XML suppression should contain expiration date");
+ }
+
+ ///
+ /// Test that XML suppression comments with reviewer are generated correctly
+ ///
+ [TestMethod]
+ public void GenerateXmlSuppressionWithReviewer()
+ {
+ string suppression = DevSkimRuleProcessor.GenerateSuppressionByLanguage("xml", "DS123456", reviewerName: "TestReviewer");
+ Assert.IsTrue(suppression.StartsWith(""), "XML suppression should end with -->");
+ Assert.IsTrue(suppression.Contains("by TestReviewer"), "XML suppression should contain reviewer name");
+ }
+
+ ///
+ /// Test that XML suppression comments are properly recognized by the Suppression parser
+ ///
+ [TestMethod]
+ public void ParseXmlSuppression()
+ {
+ string xmlLine = "";
+ Suppression suppression = new Suppression(xmlLine);
+
+ Assert.IsTrue(suppression.IsInEffect, "Suppression should be in effect");
+ Assert.AreEqual("DS123456", suppression.GetSuppressedIds.First(), "Suppression should contain the correct rule ID");
+ }
+
+ ///
+ /// Test that XML suppression comments with expiration are properly recognized by the Suppression parser
+ ///
+ [TestMethod]
+ public void ParseXmlSuppressionWithExpiration()
+ {
+ string futureDate = DateTime.Now.AddDays(30).ToString("yyyy-MM-dd");
+ string xmlLine = $"";
+ Suppression suppression = new Suppression(xmlLine);
+
+ Assert.IsTrue(suppression.IsInEffect, "Suppression should be in effect");
+ Assert.AreEqual("DS123456", suppression.GetSuppressedIds.First(), "Suppression should contain the correct rule ID");
+ Assert.AreEqual(DateTime.ParseExact(futureDate, "yyyy-MM-dd", System.Globalization.CultureInfo.InvariantCulture),
+ suppression.ExpirationDate, "Suppression should have the correct expiration date");
+ }
+
+ ///
+ /// Test that expired XML suppression comments are not in effect
+ ///
+ [TestMethod]
+ public void ParseExpiredXmlSuppression()
+ {
+ string pastDate = DateTime.Now.AddDays(-30).ToString("yyyy-MM-dd");
+ string xmlLine = $"";
+ Suppression suppression = new Suppression(xmlLine);
+
+ Assert.IsFalse(suppression.IsInEffect, "Expired suppression should not be in effect");
+ Assert.IsTrue(suppression.IsExpired, "Suppression should be marked as expired");
+ }
+
+ ///
+ /// Test that XML suppression comments with reviewer are properly recognized by the Suppression parser
+ ///
+ [TestMethod]
+ public void ParseXmlSuppressionWithReviewer()
+ {
+ string xmlLine = "";
+ Suppression suppression = new Suppression(xmlLine);
+
+ Assert.IsTrue(suppression.IsInEffect, "Suppression should be in effect");
+ Assert.AreEqual("DS123456", suppression.GetSuppressedIds.First(), "Suppression should contain the correct rule ID");
+ Assert.AreEqual("TestReviewer", suppression.Reviewer, "Suppression should have the correct reviewer");
+ }
+
+ ///
+ /// Integration test: Execute suppressions for XML files
+ ///
+ [TestMethod]
+ public void ExecuteSuppressionsForXml()
+ {
+ // XML content with an MD5 reference that triggers DevSkim rule
+ string xmlContent = @"MD5";
+
+ (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.IsTrue(result.Contains(""), "XML suppression comment should be properly closed");
+
+ // Verify suppression can be parsed
+ string[] lines = File.ReadAllLines(sourceFile);
+ var suppressions = lines
+ .Where(line => line.Contains(""), "XML suppression comment should be properly closed");
+
+ // Verify suppression contains expected parts
+ string[] lines = File.ReadAllLines(sourceFile);
+ var suppressionLines = lines.Where(line => line.Contains("";
+
+ string tempFileName = $"{Path.GetTempFileName()}.xml";
+ File.WriteAllText(tempFileName, xmlContent);
+
+ try
+ {
+ DevSkimRuleSet devSkimRuleSet = DevSkimRuleSet.GetDefaultRuleSet();
+ DevSkimRuleProcessor processor = new DevSkimRuleProcessor(devSkimRuleSet, new DevSkimRuleProcessorOptions()
+ {
+ EnableSuppressions = true
+ });
+
+ IEnumerable issues = processor.Analyze(xmlContent, tempFileName);
+
+ // The DS126858 (MD5) issue should be suppressed
+ var unsuppressedIssues = issues.Where(i => !i.IsSuppressionInfo && i.Rule.Id == "DS126858");
+ Assert.AreEqual(0, unsuppressedIssues.Count(), "MD5 issue should be suppressed");
+ }
+ finally
+ {
+ if (File.Exists(tempFileName))
+ {
+ File.Delete(tempFileName);
+ }
+ }
+ }
+
+ ///
+ /// Test that XML suppression is generated correctly via filename-based method
+ ///
+ [TestMethod]
+ public void GenerateXmlSuppressionByFilename()
+ {
+ string suppression = DevSkimRuleProcessor.GenerateSuppressionByFileName("test.xml", "DS123456");
+ Assert.IsTrue(suppression.StartsWith(""), "XML suppression should end with -->");
+ Assert.IsTrue(suppression.Contains("DevSkim: ignore DS123456"), "XML suppression should contain DevSkim ignore directive");
+ }
}
}
\ No newline at end of file
diff --git a/DevSkim-DotNet/Microsoft.DevSkim/resources/comments.json b/DevSkim-DotNet/Microsoft.DevSkim/resources/comments.json
index e892c1dd..540ab45f 100644
--- a/DevSkim-DotNet/Microsoft.DevSkim/resources/comments.json
+++ b/DevSkim-DotNet/Microsoft.DevSkim/resources/comments.json
@@ -74,5 +74,12 @@
"inline": "::",
"prefix": "Rem",
"suffix": "\n"
+ },
+ {
+ "language": [
+ "xml"
+ ],
+ "prefix": ""
}
]
\ No newline at end of file