Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Confidence Filter at Rule Level #672

Merged
merged 5 commits into from
Dec 9, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,6 @@ DevSkim-DotNet/Microsoft.DevSkim.VisualStudio/devskim-server-*.txt

# Legacy Files
DevSkim-VSCode-Plugin/server/

# Mac OS Metadata
**/.DS_Store
4 changes: 4 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.51] - 2024-12-09
## Fix
Fix confidence filtering at rule level.

## [1.0.50] - 2024-12-05
## Fix
Fixes #664 handling of options from IgnoreRuleMap when using OptionsJson
Expand Down
165 changes: 165 additions & 0 deletions DevSkim-DotNet/Microsoft.DevSkim.Tests/OptionsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -362,4 +362,169 @@ public void TestParsingJsonOptions()
// This should be 0, because the globs exclude js files
Assert.AreEqual(0, analyzerWithSerialized.Run());
}

DevSkimRule highConfidenceRule = new DevSkimRule()
{
Name = "Weak/Broken Hash Algorithm",
Id = "HighConfidence",
Description = "Confidence Filter Tests",
Tags = new List<string>() { "Tests.ConfidenceFilter" },
Severity = Severity.Critical,
Confidence = Confidence.High,
Patterns = new[]
{
new SearchPattern()
{
Pattern = "Hello",
PatternType = PatternType.Regex,
Scopes = new[]
{
PatternScope.All
}
}
}
};

DevSkimRule mediumConfidenceRule = new DevSkimRule()
{
Name = "Weak/Broken Hash Algorithm",
Id = "MediumConfidence",
Description = "Confidence Filter Tests",
Tags = new List<string>() { "Tests.ConfidenceFilter" },
Severity = Severity.Critical,
Confidence = Confidence.Medium,
Patterns = new[]
{
new SearchPattern()
{
Pattern = "Hello",
PatternType = PatternType.Regex,
Scopes = new[]
{
PatternScope.All
}
}
}
};

DevSkimRule lowConfidenceRule = new DevSkimRule()
{
Name = "Weak/Broken Hash Algorithm",
Id = "LowConfidence",
Description = "Confidence Filter Tests",
Tags = new List<string>() { "Tests.ConfidenceFilter" },
Severity = Severity.Critical,
Confidence = Confidence.Low,
Patterns = new[]
{
new SearchPattern()
{
Pattern = "Hello",
PatternType = PatternType.Regex,
Scopes = new[]
{
PatternScope.All
}
}
}
};

DevSkimRule unspecifiedConfidenceRule = new DevSkimRule()
{
Name = "Weak/Broken Hash Algorithm",
Id = "UnspecifiedConfidence",
Description = "Confidence Filter Tests",
Tags = new List<string>() { "Tests.ConfidenceFilter" },
Severity = Severity.Critical,
Confidence = Confidence.Unspecified,
Patterns = new[]
{
new SearchPattern()
{
Pattern = "Hello",
PatternType = PatternType.Regex,
Scopes = new[]
{
PatternScope.All
}
}
}
};

[TestMethod]
public void TestConfidenceFiltering()
{

var ruleSet = new DevSkimRuleSet();
ruleSet.AddRule(highConfidenceRule);
ruleSet.AddRule(mediumConfidenceRule);
ruleSet.AddRule(lowConfidenceRule);
ruleSet.AddRule(unspecifiedConfidenceRule);
Assert.AreEqual(4, ruleSet.Count());
Assert.AreEqual(1,
ruleSet.WithConfidenceFilter(Confidence.High)
.Count(x => x.Confidence.HasFlag(Confidence.High)));
Assert.AreEqual(1,
ruleSet.WithConfidenceFilter(Confidence.Medium)
.Count(x => x.Confidence.HasFlag(Confidence.Medium)));
Assert.AreEqual(1,
ruleSet.WithConfidenceFilter(Confidence.Low)
.Count(x => x.Confidence.HasFlag(Confidence.Low)));
Assert.AreEqual(1,
ruleSet.WithConfidenceFilter(Confidence.Unspecified)
.Count(x => x.Confidence.HasFlag(Confidence.Unspecified)));
}

[TestMethod]
public void TestFullFlowWithConfidenceFiltering()
{
var rulesContent = new List<DevSkimRule>()
{
unspecifiedConfidenceRule,
lowConfidenceRule,
mediumConfidenceRule,
highConfidenceRule
};
var testContent = "Hello";
var rulesPath = PathHelper.GetRandomTempFile("json");
var csharpTestPath = PathHelper.GetRandomTempFile("cs");
{
using var csharpStream = File.Create(csharpTestPath);
JsonSerializer.Serialize(csharpStream, testContent);
File.WriteAllText(rulesPath, JsonSerializer.Serialize(rulesContent));
}

var confidenceOptions = new AnalyzeCommandOptions()
{
Path = csharpTestPath,
Rules = new[] { rulesPath },
Confidences = new [] { Confidence.High, Confidence.Medium, Confidence.Low, Confidence.Unspecified },
ExitCodeIsNumIssues = true
};

var analyzerWithSerialized = new AnalyzeCommand(confidenceOptions);
Assert.AreEqual(4, analyzerWithSerialized.Run());

confidenceOptions.Confidences = new[] { Confidence.High };

// Unspecified confidence rules are not filtered out because confidence may have been
// (and should be set) at pattern level
analyzerWithSerialized = new AnalyzeCommand(confidenceOptions);
Assert.AreEqual(2, analyzerWithSerialized.Run());

confidenceOptions.Confidences = new[] { Confidence.Medium };

analyzerWithSerialized = new AnalyzeCommand(confidenceOptions);
Assert.AreEqual(2, analyzerWithSerialized.Run());

confidenceOptions.Confidences = new[] { Confidence.Low };

analyzerWithSerialized = new AnalyzeCommand(confidenceOptions);
Assert.AreEqual(2, analyzerWithSerialized.Run());

confidenceOptions.Confidences = new[] { Confidence.Unspecified };

analyzerWithSerialized = new AnalyzeCommand(confidenceOptions);
Assert.AreEqual(1, analyzerWithSerialized.Run());
}
}
2 changes: 2 additions & 0 deletions DevSkim-DotNet/Microsoft.DevSkim/DevSkimRuleProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ public class DevSkimRuleProcessor

public DevSkimRuleProcessor(DevSkimRuleSet ruleSet, DevSkimRuleProcessorOptions processorOptions)
{
// Application Inspector Processor filters *patterns* based on confidence but not rules
ruleSet = ruleSet.WithConfidenceFilter(processorOptions.ConfidenceFilter);
_aiProcessor = new RuleProcessor(ruleSet, processorOptions);
_processorOptions = processorOptions;
}
Expand Down
12 changes: 12 additions & 0 deletions DevSkim-DotNet/Microsoft.DevSkim/DevSkimRuleSet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,18 @@ public static DevSkimRuleSet GetDefaultRuleSet()
return ruleSet;
}

/// <summary>
/// Return a new RuleSet containing only rules that have one of the flags of the specified confidence enum
/// </summary>
/// <param name="filter">The Enum with flags set for which Confidence rules to use</param>
/// <returns>A new DevSkimRuleSet with only rules that have the specified confidence set at the Rule level</returns>
public DevSkimRuleSet WithConfidenceFilter(Confidence filter)
{
DevSkimRuleSet newSet = new DevSkimRuleSet();
newSet.AddRange(this.Where(x => filter.HasFlag(x.Confidence)));
return newSet;
}

/// <summary>
/// Returns a new <see cref="DevSkimRuleSet"/> with only rules that have an ID matching one of the ids provided in <paramref name="ruleIds"/>
/// </summary>
Expand Down
Loading