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 LanguageRuleIgnoreMap and Add Positive Globs #665

Merged
merged 7 commits into from
Dec 6, 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
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public int Run()

IEnumerable<FileEntry> fileListing;
Extractor extractor = new Extractor();
ExtractorOptions extractorOpts = new ExtractorOptions() { ExtractSelfOnFail = false, DenyFilters = _opts.Globs };
ExtractorOptions extractorOpts = new ExtractorOptions() { ExtractSelfOnFail = false, AllowFilters = _opts.IncludeGlobs, DenyFilters = _opts.Globs };
gfs marked this conversation as resolved.
Show resolved Hide resolved
// Analysing a single file
if (!Directory.Exists(fullPath))
{
Expand Down Expand Up @@ -424,7 +424,7 @@ void parseFileEntry(FileEntry fileEntry)
if (serializedAnalyzeCommandOptions.LanguageRuleIgnoreMap.TryGetValue(languageInfo.Name,
out List<string>? maybeRulesToIgnore) && maybeRulesToIgnore is { } rulesToIgnore)
{
var numRemoved = issues.RemoveAll(x => !rulesToIgnore.Contains(x.Rule.Id));
var numRemoved = issues.RemoveAll(x => rulesToIgnore.Contains(x.Rule.Id));
_logger.LogDebug($"Removed {numRemoved} results because of language rule filters.");
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ public record BaseAnalyzeCommandOptions : LogOptions
[Option('g', "ignore-globs", HelpText = "Comma-separated Globs for files to skip analyzing", Separator = ',', Default = new[] { "**/.git/**", "**/bin/**" })]
public IEnumerable<string> Globs { get; set; } = new[] { "**/.git/**", "**/bin/**" };

[Option("include-globs", HelpText = "If set, files must match one of these globs to be analyzed", Separator = ',', Default = new string[]{})]
public IEnumerable<string> IncludeGlobs { get; set; } = new string[]{};

[Option('d', "disable-supression", HelpText = "Disable comment suppressions", Default = false)]
public bool DisableSuppression { get; set; }

Expand Down
223 changes: 216 additions & 7 deletions DevSkim-DotNet/Microsoft.DevSkim.Tests/OptionsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,214 @@ namespace Microsoft.DevSkim.Tests;
[TestClass]
public class OptionsTests
{
[TestMethod]
public void TestExcludeGlobs()
{
var serializedOptsExcludeGlobs = new SerializedAnalyzeCommandOptions()
{
Severities = new[] { Severity.Critical | Severity.Important },
ExitCodeIsNumIssues = true,
Globs = new List<string>() {"*.js"}
};
var testContent = "Hello World";
var testRule =
@"[
{
""name"": ""Weak/Broken Hash Algorithm"",
""id"": ""JsonOptionParseTest"",
""description"": ""A test that finds hello"",
""tags"": [
""Tests.JsonOptionsTest""
],
""severity"": ""critical"",
""patterns"": [
{
""pattern"": ""Hello"",
""type"": ""regex"",
""scopes"": [
""code""
]
}
]
}]";
var rulesPath = PathHelper.GetRandomTempFile("json");
var serializedJsonPath = PathHelper.GetRandomTempFile("json");
var csharpTestPath = PathHelper.GetRandomTempFile("cs");
var jsTestPath = PathHelper.GetRandomTempFile("js");
{
using var serializedJsonStream = File.Create(serializedJsonPath);
JsonSerializer.Serialize(serializedJsonStream, serializedOptsExcludeGlobs, new JsonSerializerOptions() { });
using var csharpStream = File.Create(csharpTestPath);
JsonSerializer.Serialize(csharpStream, testContent);
using var jsStream = File.Create(jsTestPath);
JsonSerializer.Serialize(jsStream, testContent);
File.WriteAllText(rulesPath, testRule);
}

// Create an AnalyzeCommandOptions object referencing our serialized options
var analyzeOpts = new AnalyzeCommandOptions()
{
Path = csharpTestPath,
Rules = new[] { rulesPath },
PathToOptionsJson = serializedJsonPath
};

var analyzerWithSerialized = new AnalyzeCommand(analyzeOpts);
// We set exit code is num issues so this should be 1, as csharp files aren't ignored
Assert.AreEqual(1, analyzerWithSerialized.Run());

// Create an AnalyzeCommandOptions object referencing our serialized options
analyzeOpts = new AnalyzeCommandOptions()
{
Path = jsTestPath,
Rules = new[] { rulesPath },
PathToOptionsJson = serializedJsonPath
};

analyzerWithSerialized = new AnalyzeCommand(analyzeOpts);
// We set exit code is num issues so this should be 0, as js files are ignored
Assert.AreEqual(0, analyzerWithSerialized.Run());
}

[TestMethod]
public void TestIncludeGlobs()
{
var serializedOptsExcludeGlobs = new SerializedAnalyzeCommandOptions()
{
Severities = new[] { Severity.Critical | Severity.Important },
ExitCodeIsNumIssues = true,
IncludeGlobs = new List<string>() {"*.js"}
};
var testContent = "Hello World";
var testRule =
@"[
{
""name"": ""Weak/Broken Hash Algorithm"",
""id"": ""JsonOptionParseTest"",
""description"": ""A test that finds hello"",
""tags"": [
""Tests.JsonOptionsTest""
],
""severity"": ""critical"",
""patterns"": [
{
""pattern"": ""Hello"",
""type"": ""regex"",
""scopes"": [
""code""
]
}
]
}]";
var rulesPath = PathHelper.GetRandomTempFile("json");
var serializedJsonPath = PathHelper.GetRandomTempFile("json");
var csharpTestPath = PathHelper.GetRandomTempFile("cs");
var jsTestPath = PathHelper.GetRandomTempFile("js");
{
using var serializedJsonStream = File.Create(serializedJsonPath);
JsonSerializer.Serialize(serializedJsonStream, serializedOptsExcludeGlobs, new JsonSerializerOptions() { });
using var csharpStream = File.Create(csharpTestPath);
JsonSerializer.Serialize(csharpStream, testContent);
using var jsStream = File.Create(jsTestPath);
JsonSerializer.Serialize(jsStream, testContent);
File.WriteAllText(rulesPath, testRule);
}

// Create an AnalyzeCommandOptions object referencing our serialized options
var analyzeOpts = new AnalyzeCommandOptions()
{
Path = csharpTestPath,
Rules = new[] { rulesPath },
PathToOptionsJson = serializedJsonPath
};

var analyzerWithSerialized = new AnalyzeCommand(analyzeOpts);
// We set exit code is num issues so this should be 0, as csharp are implicitly ignored
Assert.AreEqual(0, analyzerWithSerialized.Run());

// Create an AnalyzeCommandOptions object referencing our serialized options
analyzeOpts = new AnalyzeCommandOptions()
{
Path = jsTestPath,
Rules = new[] { rulesPath },
PathToOptionsJson = serializedJsonPath
};

analyzerWithSerialized = new AnalyzeCommand(analyzeOpts);
// We set exit code is num issues so this should be 1, as js files are included
Assert.AreEqual(1, analyzerWithSerialized.Run());
}

[TestMethod]
public void TestIncludeAndExcludeGlobs()
{
var serializedOptsExcludeGlobs = new SerializedAnalyzeCommandOptions()
{
Severities = new[] { Severity.Critical | Severity.Important },
ExitCodeIsNumIssues = true,
IncludeGlobs = new List<string>() {"*.js"},
Globs = new List<string>() {"*hello.js"}
};
var testContent = "Hello World";
var testRule =
@"[
{
""name"": ""Weak/Broken Hash Algorithm"",
""id"": ""JsonOptionParseTest"",
""description"": ""A test that finds hello"",
""tags"": [
""Tests.JsonOptionsTest""
],
""severity"": ""critical"",
""patterns"": [
{
""pattern"": ""Hello"",
""type"": ""regex"",
""scopes"": [
""code""
]
}
]
}]";
var rulesPath = PathHelper.GetRandomTempFile("json");
var serializedJsonPath = PathHelper.GetRandomTempFile("json");
var helloJsTestPath = PathHelper.GetRandomTempFile("hello.js");
var jsTestPath = PathHelper.GetRandomTempFile("js");
{
using var serializedJsonStream = File.Create(serializedJsonPath);
JsonSerializer.Serialize(serializedJsonStream, serializedOptsExcludeGlobs, new JsonSerializerOptions() { });
using var helloJsStream = File.Create(helloJsTestPath);
JsonSerializer.Serialize(helloJsStream, testContent);
using var jsStream = File.Create(jsTestPath);
JsonSerializer.Serialize(jsStream, testContent);
File.WriteAllText(rulesPath, testRule);
}

// Create an AnalyzeCommandOptions object referencing our serialized options
var analyzeOpts = new AnalyzeCommandOptions()
{
Path = helloJsTestPath,
Rules = new[] { rulesPath },
PathToOptionsJson = serializedJsonPath
};

var analyzerWithSerialized = new AnalyzeCommand(analyzeOpts);
// We set exit code is num issues so this should be 0, as hello.js files are ignored
Assert.AreEqual(0, analyzerWithSerialized.Run());

// Create an AnalyzeCommandOptions object referencing our serialized options
analyzeOpts = new AnalyzeCommandOptions()
{
Path = jsTestPath,
Rules = new[] { rulesPath },
PathToOptionsJson = serializedJsonPath
};

analyzerWithSerialized = new AnalyzeCommand(analyzeOpts);
// We set exit code is num issues so this should be 1, as regular js files are included
Assert.AreEqual(1, analyzerWithSerialized.Run());
}

[TestMethod]
public void TestParsingJsonOptions()
{
Expand All @@ -29,7 +237,8 @@ public void TestParsingJsonOptions()
Globs = new List<string>() {"*.js"}
};
// Serialize it to a file
var testContent = "Hello World";
// Include world twice so we can disinguish between the two rules
var testContent = "Hello World World";
var testRule =
@"[
{
Expand Down Expand Up @@ -95,8 +304,8 @@ public void TestParsingJsonOptions()
};

var analyzerWithSerialized = new AnalyzeCommand(analyzeOpts);
// We set exit code is num issues so this should be 1, from the 1 rule that isn't ignored
Assert.AreEqual(1, analyzerWithSerialized.Run());
// We set exit code is num issues so this should be 2, from the two matchs for the rule that isn't ignored
Assert.AreEqual(2, analyzerWithSerialized.Run());
// Create an AnalyzeCommandOptions object that references the path to the file which ignores a specific rule
analyzeOpts = new AnalyzeCommandOptions()
{
Expand All @@ -117,8 +326,8 @@ public void TestParsingJsonOptions()
PathToOptionsJson = serializedJsonPath
};
analyzerWithSerialized = new AnalyzeCommand(analyzeOpts);
// This should be 2, because 2 rules aren't ignored
Assert.AreEqual(2, analyzerWithSerialized.Run());
// This should be 3, because no rules are ignored
Assert.AreEqual(3, analyzerWithSerialized.Run());
// Try the js which it should find both
analyzeOpts = new AnalyzeCommandOptions()
{
Expand All @@ -140,8 +349,8 @@ public void TestParsingJsonOptions()
PathToOptionsJson = serializedJsonPath2
};
analyzerWithSerialized = new AnalyzeCommand(analyzeOpts);
// This should be 2, because the globs dont exclude cs files
Assert.AreEqual(2, analyzerWithSerialized.Run());
// This should be 3, because the globs dont exclude cs files
Assert.AreEqual(3, analyzerWithSerialized.Run());
// set of options to test enumerable parsing
analyzeOpts = new AnalyzeCommandOptions()
{
Expand Down
Loading