From f90684dc19f1baf14e020a31998ee4824bdf671c Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 4 Feb 2026 21:36:33 +0000
Subject: [PATCH 1/5] Initial plan
From 8211aa34865dbd10312a1de18c1345315b9b52f7 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 4 Feb 2026 21:39:18 +0000
Subject: [PATCH 2/5] Initial exploration complete
Co-authored-by: gfs <98900+gfs@users.noreply.github.com>
---
nuget.config | 11 +++++------
nuget.config.bak | 7 +++++++
2 files changed, 12 insertions(+), 6 deletions(-)
create mode 100644 nuget.config.bak
diff --git a/nuget.config b/nuget.config
index be6dddfa..a0b839c4 100644
--- a/nuget.config
+++ b/nuget.config
@@ -1,7 +1,6 @@
-
+
-
-
-
-
-
\ No newline at end of file
+
+
+
+
diff --git a/nuget.config.bak b/nuget.config.bak
new file mode 100644
index 00000000..751d4b6c
--- /dev/null
+++ b/nuget.config.bak
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
From 73bc3be4018bdcd8d001174d1537445f6e50e57e Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 4 Feb 2026 21:44:58 +0000
Subject: [PATCH 3/5] Add XML suppression comment syntax and comprehensive
tests
- Added XML language support to comments.json with prefix ""
- Added comprehensive unit tests for XML suppression generation
- Added unit tests for XML suppression parsing
- Added integration tests for CLI suppress command with XML files
- Added integration tests for XML suppression with duration and reviewer
- Added analysis test to verify suppressions are respected in XML files
- Restored nuget.config to original private feed configuration
Co-authored-by: gfs <98900+gfs@users.noreply.github.com>
---
.../SuppressionsTest.cs | 234 ++++++++++++++++++
.../Microsoft.DevSkim/resources/comments.json | 7 +
nuget.config | 11 +-
nuget.config.bak | 7 -
4 files changed, 247 insertions(+), 12 deletions(-)
delete mode 100644 nuget.config.bak
diff --git a/DevSkim-DotNet/Microsoft.DevSkim.Tests/SuppressionsTest.cs b/DevSkim-DotNet/Microsoft.DevSkim.Tests/SuppressionsTest.cs
index 9d7cc85d..6af4c94a 100644
--- a/DevSkim-DotNet/Microsoft.DevSkim.Tests/SuppressionsTest.cs
+++ b/DevSkim-DotNet/Microsoft.DevSkim.Tests/SuppressionsTest.cs
@@ -343,5 +343,239 @@ 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);
+ bool foundSuppression = false;
+ foreach (string line in lines)
+ {
+ if (line.Contains(""), "XML suppression comment should be properly closed");
+
+ // Verify suppression contains expected parts
+ string[] lines = File.ReadAllLines(sourceFile);
+ foreach (string line in lines)
+ {
+ if (line.Contains("";
+
+ string tempFileName = $"{Path.GetTempFileName()}.xml";
+ File.WriteAllText(tempFileName, xmlContent);
+
+ 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");
+
+ // Cleanup
+ 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
diff --git a/nuget.config b/nuget.config
index a0b839c4..be6dddfa 100644
--- a/nuget.config
+++ b/nuget.config
@@ -1,6 +1,7 @@
-
+
-
-
-
-
+
+
+
+
+
\ No newline at end of file
diff --git a/nuget.config.bak b/nuget.config.bak
deleted file mode 100644
index 751d4b6c..00000000
--- a/nuget.config.bak
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
-
From f9ee44ce70edab6911990fd7b25d0e78b3e6d392 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 4 Feb 2026 22:43:04 +0000
Subject: [PATCH 4/5] Refactor: use explicit .Where() filtering instead of
implicit if-statements in foreach loops
Co-authored-by: gfs <98900+gfs@users.noreply.github.com>
---
.../SuppressionsTest.cs | 44 ++++++++-----------
1 file changed, 19 insertions(+), 25 deletions(-)
diff --git a/DevSkim-DotNet/Microsoft.DevSkim.Tests/SuppressionsTest.cs b/DevSkim-DotNet/Microsoft.DevSkim.Tests/SuppressionsTest.cs
index 6af4c94a..222b44fe 100644
--- a/DevSkim-DotNet/Microsoft.DevSkim.Tests/SuppressionsTest.cs
+++ b/DevSkim-DotNet/Microsoft.DevSkim.Tests/SuppressionsTest.cs
@@ -471,18 +471,14 @@ public void ExecuteSuppressionsForXml()
// Verify suppression can be parsed
string[] lines = File.ReadAllLines(sourceFile);
- bool foundSuppression = false;
- foreach (string line in lines)
+ var suppressionLines = lines.Where(line => line.Contains("