Skip to content

Commit 210b5d1

Browse files
authored
Fix Confidence Filter at Rule Level (#672)
* Update .gitignore * Fix confidence filter at rule level. * Update Changelog.md * Add tests for rule level confidence filtering * Clarify Doc comment on WithConfidenceFilter method Update options tests to account for unspecified behavior (its the 0 value for the enum flag so always passes the check).
1 parent bb81662 commit 210b5d1

File tree

5 files changed

+187
-0
lines changed

5 files changed

+187
-0
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,6 @@ DevSkim-DotNet/Microsoft.DevSkim.VisualStudio/devskim-server-*.txt
1717

1818
# Legacy Files
1919
DevSkim-VSCode-Plugin/server/
20+
21+
# Mac OS Metadata
22+
**/.DS_Store

Changelog.md

+4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7+
## [1.0.51] - 2024-12-09
8+
## Fix
9+
Fix confidence filtering at rule level.
10+
711
## [1.0.50] - 2024-12-05
812
## Fix
913
Fixes #664 handling of options from IgnoreRuleMap when using OptionsJson

DevSkim-DotNet/Microsoft.DevSkim.Tests/OptionsTests.cs

+166
Original file line numberDiff line numberDiff line change
@@ -362,4 +362,170 @@ public void TestParsingJsonOptions()
362362
// This should be 0, because the globs exclude js files
363363
Assert.AreEqual(0, analyzerWithSerialized.Run());
364364
}
365+
366+
DevSkimRule highConfidenceRule = new DevSkimRule()
367+
{
368+
Name = "Weak/Broken Hash Algorithm",
369+
Id = "HighConfidence",
370+
Description = "Confidence Filter Tests",
371+
Tags = new List<string>() { "Tests.ConfidenceFilter" },
372+
Severity = Severity.Critical,
373+
Confidence = Confidence.High,
374+
Patterns = new[]
375+
{
376+
new SearchPattern()
377+
{
378+
Pattern = "Hello",
379+
PatternType = PatternType.Regex,
380+
Scopes = new[]
381+
{
382+
PatternScope.All
383+
}
384+
}
385+
}
386+
};
387+
388+
DevSkimRule mediumConfidenceRule = new DevSkimRule()
389+
{
390+
Name = "Weak/Broken Hash Algorithm",
391+
Id = "MediumConfidence",
392+
Description = "Confidence Filter Tests",
393+
Tags = new List<string>() { "Tests.ConfidenceFilter" },
394+
Severity = Severity.Critical,
395+
Confidence = Confidence.Medium,
396+
Patterns = new[]
397+
{
398+
new SearchPattern()
399+
{
400+
Pattern = "Hello",
401+
PatternType = PatternType.Regex,
402+
Scopes = new[]
403+
{
404+
PatternScope.All
405+
}
406+
}
407+
}
408+
};
409+
410+
DevSkimRule lowConfidenceRule = new DevSkimRule()
411+
{
412+
Name = "Weak/Broken Hash Algorithm",
413+
Id = "LowConfidence",
414+
Description = "Confidence Filter Tests",
415+
Tags = new List<string>() { "Tests.ConfidenceFilter" },
416+
Severity = Severity.Critical,
417+
Confidence = Confidence.Low,
418+
Patterns = new[]
419+
{
420+
new SearchPattern()
421+
{
422+
Pattern = "Hello",
423+
PatternType = PatternType.Regex,
424+
Scopes = new[]
425+
{
426+
PatternScope.All
427+
}
428+
}
429+
}
430+
};
431+
432+
DevSkimRule unspecifiedConfidenceRule = new DevSkimRule()
433+
{
434+
Name = "Weak/Broken Hash Algorithm",
435+
Id = "UnspecifiedConfidence",
436+
Description = "Confidence Filter Tests",
437+
Tags = new List<string>() { "Tests.ConfidenceFilter" },
438+
Severity = Severity.Critical,
439+
Confidence = Confidence.Unspecified,
440+
Patterns = new[]
441+
{
442+
new SearchPattern()
443+
{
444+
Pattern = "Hello",
445+
PatternType = PatternType.Regex,
446+
Scopes = new[]
447+
{
448+
PatternScope.All
449+
}
450+
}
451+
}
452+
};
453+
454+
[TestMethod]
455+
public void TestConfidenceFiltering()
456+
{
457+
458+
var ruleSet = new DevSkimRuleSet();
459+
ruleSet.AddRule(highConfidenceRule);
460+
ruleSet.AddRule(mediumConfidenceRule);
461+
ruleSet.AddRule(lowConfidenceRule);
462+
ruleSet.AddRule(unspecifiedConfidenceRule);
463+
Assert.AreEqual(4, ruleSet.Count());
464+
// Unspecified always passes the confidence filter
465+
Assert.AreEqual(2,
466+
ruleSet.WithConfidenceFilter(Confidence.High)
467+
.Count());
468+
Assert.AreEqual(2,
469+
ruleSet.WithConfidenceFilter(Confidence.Medium)
470+
.Count());
471+
Assert.AreEqual(2,
472+
ruleSet.WithConfidenceFilter(Confidence.Low)
473+
.Count());
474+
Assert.AreEqual(1,
475+
ruleSet.WithConfidenceFilter(Confidence.Unspecified)
476+
.Count());
477+
}
478+
479+
[TestMethod]
480+
public void TestFullFlowWithConfidenceFiltering()
481+
{
482+
var rulesContent = new List<DevSkimRule>()
483+
{
484+
unspecifiedConfidenceRule,
485+
lowConfidenceRule,
486+
mediumConfidenceRule,
487+
highConfidenceRule
488+
};
489+
var testContent = "Hello";
490+
var rulesPath = PathHelper.GetRandomTempFile("json");
491+
var csharpTestPath = PathHelper.GetRandomTempFile("cs");
492+
{
493+
using var csharpStream = File.Create(csharpTestPath);
494+
JsonSerializer.Serialize(csharpStream, testContent);
495+
File.WriteAllText(rulesPath, JsonSerializer.Serialize(rulesContent));
496+
}
497+
498+
var confidenceOptions = new AnalyzeCommandOptions()
499+
{
500+
Path = csharpTestPath,
501+
Rules = new[] { rulesPath },
502+
Confidences = new [] { Confidence.High, Confidence.Medium, Confidence.Low, Confidence.Unspecified },
503+
ExitCodeIsNumIssues = true
504+
};
505+
506+
var analyzerWithSerialized = new AnalyzeCommand(confidenceOptions);
507+
Assert.AreEqual(4, analyzerWithSerialized.Run());
508+
509+
confidenceOptions.Confidences = new[] { Confidence.High };
510+
511+
// Unspecified confidence rules are not filtered out because confidence may have been
512+
// (and should be set) at pattern level
513+
analyzerWithSerialized = new AnalyzeCommand(confidenceOptions);
514+
Assert.AreEqual(2, analyzerWithSerialized.Run());
515+
516+
confidenceOptions.Confidences = new[] { Confidence.Medium };
517+
518+
analyzerWithSerialized = new AnalyzeCommand(confidenceOptions);
519+
Assert.AreEqual(2, analyzerWithSerialized.Run());
520+
521+
confidenceOptions.Confidences = new[] { Confidence.Low };
522+
523+
analyzerWithSerialized = new AnalyzeCommand(confidenceOptions);
524+
Assert.AreEqual(2, analyzerWithSerialized.Run());
525+
526+
confidenceOptions.Confidences = new[] { Confidence.Unspecified };
527+
528+
analyzerWithSerialized = new AnalyzeCommand(confidenceOptions);
529+
Assert.AreEqual(1, analyzerWithSerialized.Run());
530+
}
365531
}

DevSkim-DotNet/Microsoft.DevSkim/DevSkimRuleProcessor.cs

+2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ public class DevSkimRuleProcessor
1717

1818
public DevSkimRuleProcessor(DevSkimRuleSet ruleSet, DevSkimRuleProcessorOptions processorOptions)
1919
{
20+
// Application Inspector Processor filters *patterns* based on confidence but not rules
21+
ruleSet = ruleSet.WithConfidenceFilter(processorOptions.ConfidenceFilter);
2022
_aiProcessor = new RuleProcessor(ruleSet, processorOptions);
2123
_processorOptions = processorOptions;
2224
}

DevSkim-DotNet/Microsoft.DevSkim/DevSkimRuleSet.cs

+12
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,18 @@ public static DevSkimRuleSet GetDefaultRuleSet()
4040
return ruleSet;
4141
}
4242

43+
/// <summary>
44+
/// Return a new RuleSet containing only rules that have one of the flags of the specified confidence enum, or Unspecified
45+
/// </summary>
46+
/// <param name="filter">The Enum with flags set for which Confidence rules to use</param>
47+
/// <returns>A new DevSkimRuleSet with only rules that have the specified confidence set at the Rule level</returns>
48+
public DevSkimRuleSet WithConfidenceFilter(Confidence filter)
49+
{
50+
DevSkimRuleSet newSet = new DevSkimRuleSet();
51+
newSet.AddRange(this.Where(x => filter.HasFlag(x.Confidence)));
52+
return newSet;
53+
}
54+
4355
/// <summary>
4456
/// Returns a new <see cref="DevSkimRuleSet"/> with only rules that have an ID matching one of the ids provided in <paramref name="ruleIds"/>
4557
/// </summary>

0 commit comments

Comments
 (0)