Allows Multiple Paths per Pattern (#491)

This commit is contained in:
Gabe Stocco 2022-08-04 17:38:30 -07:00 коммит произвёл GitHub
Родитель 41d733abba
Коммит 284d34573c
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
9 изменённых файлов: 90 добавлений и 72 удалений

Просмотреть файл

@ -79,7 +79,7 @@ namespace Microsoft.ApplicationInspector.RulesEngine
var modifiers = pattern.Modifiers?.ToList() ?? new List<string>();
if (pattern.PatternType is PatternType.String or PatternType.Substring)
{
clauses.Add(new OatSubstringIndexClause(scopes, useWordBoundaries: pattern.PatternType == PatternType.String, xPath: pattern.XPath, jsonPath:pattern.JsonPath)
clauses.Add(new OatSubstringIndexClause(scopes, useWordBoundaries: pattern.PatternType == PatternType.String, xPaths: pattern.XPaths, jsonPaths:pattern.JsonPaths)
{
Label = clauseNumber.ToString(CultureInfo.InvariantCulture),//important to pattern index identification
Data = new List<string>() { pattern.Pattern },
@ -95,7 +95,7 @@ namespace Microsoft.ApplicationInspector.RulesEngine
}
else if (pattern.PatternType == PatternType.Regex)
{
clauses.Add(new OatRegexWithIndexClause(scopes, null, pattern.XPath, pattern.JsonPath)
clauses.Add(new OatRegexWithIndexClause(scopes, null, pattern.XPaths, pattern.JsonPaths)
{
Label = clauseNumber.ToString(CultureInfo.InvariantCulture),//important to pattern index identification
Data = new List<string>() { pattern.Pattern },
@ -112,7 +112,7 @@ namespace Microsoft.ApplicationInspector.RulesEngine
}
else if (pattern.PatternType == PatternType.RegexWord)
{
clauses.Add(new OatRegexWithIndexClause(scopes, null, pattern.XPath, pattern.JsonPath)
clauses.Add(new OatRegexWithIndexClause(scopes, null, pattern.XPaths, pattern.JsonPaths)
{
Label = clauseNumber.ToString(CultureInfo.InvariantCulture),//important to pattern index identification
Data = new List<string>() { $"\\b({pattern.Pattern})\\b" },

Просмотреть файл

@ -6,17 +6,17 @@ namespace Microsoft.ApplicationInspector.RulesEngine.OatExtensions
{
public class OatRegexWithIndexClause : Clause
{
public OatRegexWithIndexClause(PatternScope[] scopes, string? field = null, string? xPath = null, string? jsonPath = null) : base(Operation.Custom, field)
public OatRegexWithIndexClause(PatternScope[] scopes, string? field = null, string[]? xPaths = null, string[]? jsonPaths = null) : base(Operation.Custom, field)
{
Scopes = scopes;
CustomOperation = "RegexWithIndex";
XPath = xPath;
JsonPath = jsonPath;
XPaths = xPaths;
JsonPaths = jsonPaths;
}
public string? JsonPath { get; }
public string[]? JsonPaths { get; }
public string? XPath { get; }
public string[]? XPaths { get; }
public PatternScope[] Scopes { get; }
}

Просмотреть файл

@ -91,33 +91,39 @@ namespace Microsoft.ApplicationInspector.RulesEngine.OatExtensions
{
if (StringToRegex(regexString, regexOpts) is { } regex)
{
if (src.XPath is not null)
if (src.XPaths is not null)
{
var targets = tc.GetStringFromXPath(src.XPath);
foreach (var target in targets)
foreach (var xmlPath in src.XPaths)
{
var matches = GetMatches(regex, target.Item1, tc, clause, src.Scopes);
foreach (var match in matches)
var targets = tc.GetStringFromXPath(xmlPath);
foreach (var target in targets)
{
match.Item2.Index += target.Item2.Index;
outmatches.Add(match);
var matches = GetMatches(regex, target.Item1, tc, clause, src.Scopes);
foreach (var match in matches)
{
match.Item2.Index += target.Item2.Index;
outmatches.Add(match);
}
}
}
}
if (src.JsonPath is not null)
if (src.JsonPaths is not null)
{
var targets = tc.GetStringFromJsonPath(src.JsonPath);
foreach (var target in targets)
foreach (var jsonPath in src.JsonPaths)
{
var matches = GetMatches(regex, target.Item1, tc, clause, src.Scopes);
foreach (var match in matches)
var targets = tc.GetStringFromJsonPath(jsonPath);
foreach (var target in targets)
{
match.Item2.Index += target.Item2.Index;
outmatches.Add(match);
var matches = GetMatches(regex, target.Item1, tc, clause, src.Scopes);
foreach (var match in matches)
{
match.Item2.Index += target.Item2.Index;
outmatches.Add(match);
}
}
}
}
if (src.JsonPath is null && src.XPath is null)
if (src.JsonPaths is null && src.XPaths is null)
{
outmatches.AddRange(GetMatches(regex, tc.FullContent, tc, clause, src.Scopes));
}

Просмотреть файл

@ -6,18 +6,18 @@ namespace Microsoft.ApplicationInspector.RulesEngine.OatExtensions
{
public class OatSubstringIndexClause : Clause
{
public OatSubstringIndexClause(PatternScope[] scopes, string? field = null, bool useWordBoundaries = false, string? xPath = null, string? jsonPath = null) : base(Operation.Custom, field)
public OatSubstringIndexClause(PatternScope[] scopes, string? field = null, bool useWordBoundaries = false, string[]? xPaths = null, string[]? jsonPaths = null) : base(Operation.Custom, field)
{
Scopes = scopes;
CustomOperation = "SubstringIndex";
UseWordBoundaries = useWordBoundaries;
XPath = xPath;
JsonPath = jsonPath;
XPaths = xPaths;
JsonPaths = jsonPaths;
}
public string? JsonPath { get; }
public string[]? JsonPaths { get; }
public string? XPath { get; }
public string[]? XPaths { get; }
public PatternScope[] Scopes { get; }

Просмотреть файл

@ -63,33 +63,39 @@ namespace Microsoft.ApplicationInspector.RulesEngine.OatExtensions
for (int i = 0; i < stringList.Count; i++)
{
if (src.XPath is not null)
if (src.XPaths is not null)
{
var targets = tc.GetStringFromXPath(src.XPath);
foreach (var target in targets)
foreach (var xmlPath in src.XPaths)
{
var matches = GetMatches(target.Item1, stringList[i], comparisonType, tc, src);
foreach (var match in matches)
var targets = tc.GetStringFromXPath(xmlPath);
foreach (var target in targets)
{
match.Index += target.Item2.Index;
outmatches.Add((i,match));
var matches = GetMatches(target.Item1, stringList[i], comparisonType, tc, src);
foreach (var match in matches)
{
match.Index += target.Item2.Index;
outmatches.Add((i,match));
}
}
}
}
if (src.JsonPath is not null)
if (src.JsonPaths is not null)
{
var targets = tc.GetStringFromJsonPath(src.JsonPath);
foreach (var target in targets)
foreach (var jsonPath in src.JsonPaths)
{
var matches = GetMatches(target.Item1, stringList[i], comparisonType, tc, src);
foreach (var match in matches)
var targets = tc.GetStringFromJsonPath(jsonPath);
foreach (var target in targets)
{
match.Index += target.Item2.Index;
outmatches.Add((i,match));
var matches = GetMatches(target.Item1, stringList[i], comparisonType, tc, src);
foreach (var match in matches)
{
match.Index += target.Item2.Index;
outmatches.Add((i,match));
}
}
}
}
if (src.JsonPath is null && src.XPath is null)
if (src.JsonPaths is null && src.XPaths is null)
{
var matches = GetMatches(tc.FullContent, stringList[i], comparisonType, tc, src);
outmatches.AddRange(matches.Select(x => (i, x)));

Просмотреть файл

@ -155,29 +155,35 @@ namespace Microsoft.ApplicationInspector.RulesEngine
}
}
if (searchPattern.JsonPath is not null)
if (searchPattern.JsonPaths is not null)
{
try
foreach (var jsonPath in searchPattern.JsonPaths)
{
_ = JsonSelector.Parse(searchPattern.JsonPath);
}
catch (Exception e)
{
_logger?.LogError("The provided JsonPath '{JsonPath}' value was not valid in Rule {Id} : {message}", searchPattern.JsonPath, rule.Id, e.Message);
errors.Add(string.Format("The provided JsonPath '{0}' value was not valid in Rule {1} : {2}", searchPattern.JsonPath, rule.Id, e.Message));
try
{
_ = JsonSelector.Parse(jsonPath);
}
catch (Exception e)
{
_logger?.LogError("The provided JsonPath '{JsonPath}' value was not valid in Rule {Id} : {message}", searchPattern.JsonPaths, rule.Id, e.Message);
errors.Add(string.Format("The provided JsonPath '{0}' value was not valid in Rule {1} : {2}", searchPattern.JsonPaths, rule.Id, e.Message));
}
}
}
if (searchPattern.XPath is not null)
if (searchPattern.XPaths is not null)
{
try
foreach (var xpath in searchPattern.XPaths)
{
XPathExpression.Compile(searchPattern.XPath);
}
catch (Exception e)
{
_logger?.LogError("The provided XPath '{XPath}' value was not valid in Rule {Id} : {message}", searchPattern.XPath, rule.Id, e.Message);
errors.Add(string.Format("The provided XPath '{0}' value was not valid in Rule {1} : {2}", searchPattern.JsonPath, rule.Id, e.Message));
try
{
XPathExpression.Compile(xpath);
}
catch (Exception e)
{
_logger?.LogError("The provided XPath '{XPath}' value was not valid in Rule {Id} : {message}", searchPattern.XPaths, rule.Id, e.Message);
errors.Add(string.Format("The provided XPath '{0}' value was not valid in Rule {1} : {2}", searchPattern.JsonPaths, rule.Id, e.Message));
}
}
}
}

Просмотреть файл

@ -48,14 +48,14 @@ namespace Microsoft.ApplicationInspector.RulesEngine
/// If set, attempt to parse the file as XML and if that is possible,
/// before running the pattern, select down to the XPath provided
/// </summary>
[JsonProperty(PropertyName ="xpath")]
public string? XPath { get; set; }
[JsonProperty(PropertyName ="xpaths")]
public string[]? XPaths { get; set; }
/// <summary>
/// If set, attempt to parse the file as JSON and if that is possible,
/// before running the pattern, select down to the JsonPath provided
/// </summary>
[JsonProperty(PropertyName ="jsonpath")]
public string? JsonPath { get; set; }
[JsonProperty(PropertyName = "jsonpaths")]
public string[]? JsonPaths { get; set; }
}
}

Просмотреть файл

@ -196,8 +196,8 @@ namespace AppInspector.Tests.RuleProcessor
""scopes"": [
""code""
],
""jsonpath"" : ""$.books[*].title"",
""xpath"" : ""/bookstore/book/title""
""jsonpaths"" : [""$.books[*].title""],
""xpaths"" : [""/bookstore/book/title""]
}
],
""_comment"": """"
@ -221,7 +221,7 @@ namespace AppInspector.Tests.RuleProcessor
""scopes"": [
""code""
],
""jsonpath"" : ""$.books[*].title""
""jsonpaths"" : [""$.books[*].title""]
}
],
""_comment"": """"
@ -245,7 +245,7 @@ namespace AppInspector.Tests.RuleProcessor
""scopes"": [
""code""
],
""xpath"" : ""/bookstore/book/title""
""xpaths"" : [""/bookstore/book/title""]
}
],
""_comment"": """"

Просмотреть файл

@ -70,8 +70,8 @@ namespace AppInspector.Tests.RuleProcessor
""scopes"": [
""code""
],
""jsonpath"" : ""$.books[*].title"",
""xpath"" : ""/bookstore/book/title""
""jsonpaths"" : [""$.books[*].title""],
""xpaths"" : [""/bookstore/book/title""]
}
],
""_comment"": """"
@ -95,7 +95,7 @@ namespace AppInspector.Tests.RuleProcessor
""scopes"": [
""code""
],
""jsonpath"" : ""$.books[*].title""
""jsonpaths"" : [""$.books[*].title""]
}
],
""_comment"": """"
@ -119,7 +119,7 @@ namespace AppInspector.Tests.RuleProcessor
""scopes"": [
""code""
],
""xpath"" : ""/bookstore/book/title""
""xpaths"" : [""/bookstore/book/title""]
}
],
""_comment"": """"