Skip to content

Commit e2e13ee

Browse files
authored
Fix off by one error in GetPrefixLocation recursion (#584)
* Fix off by one error in GetPrefixLocation recursion * Adds new quoted strings test case
1 parent c8bfea6 commit e2e13ee

File tree

2 files changed

+69
-2
lines changed

2 files changed

+69
-2
lines changed

AppInspector.RulesEngine/TextContainer.cs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,14 @@ public TextContainer(string content, string language, Languages languages, ILogg
276276
}
277277
}
278278

279+
/// <summary>
280+
/// Find the location of the provided prefix string if any in the text container between the provided start of line index and the current index
281+
/// </summary>
282+
/// <param name="startOfLineIndex">Minimum Character index in FullContent to locate Prefix</param>
283+
/// <param name="currentIndex">Maximal Chracter index in FullContent to locate Prefix</param>
284+
/// <param name="prefix">Prefix string to attempt to locate</param>
285+
/// <param name="multiline">If multi-line comments should be detected</param>
286+
/// <returns>The index of the specified prefix string in the FullContent if found, otherwise -1</returns>
279287
private int GetPrefixLocation(int startOfLineIndex, int currentIndex, string prefix, bool multiline)
280288
{
281289
// Find the first potential index of the prefix
@@ -300,7 +308,12 @@ private int GetPrefixLocation(int startOfLineIndex, int currentIndex, string pre
300308
// It might be like var address = "http://contoso.com";
301309
if (numDoubleQuotes % 2 == 1 || numSingleQuotes % 2 == 1)
302310
{
303-
return GetPrefixLocation(startOfLineIndex, prefixLoc, prefix, multiline);
311+
// The second argument is the maximal index to return since this calls LastIndexOf, subtract 1 to exclude this instance
312+
if ((prefixLoc -1) >= startOfLineIndex)
313+
{
314+
return GetPrefixLocation(startOfLineIndex, prefixLoc - 1, prefix, multiline);
315+
}
316+
return -1;
304317
}
305318
}
306319

AppInspector.Tests/RuleProcessor/QuotedStringsTests.cs

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010

1111
namespace AppInspector.Tests.RuleProcessor;
1212

13+
/// <summary>
14+
/// Tests for properly detecting commented/live code status in the presence of comment markers inside of quoted strings
15+
/// </summary>
1316
[TestClass]
1417
public class QuotedStringsTests
1518
{
@@ -29,6 +32,12 @@ public class QuotedStringsTests
2932
/*
3033
contoso.com
3134
*/ var url = ""https://contoso.com""";
35+
private const string testRubyInterpolatedStrings = @"findMe = ""findMe""
36+
puts ""Hello, #{findMe}!"" # findMe
37+
def inspect # :nodoc:
38+
""#<#{findMe} #{findMe}>"" #findMe
39+
end
40+
"; // Should find 5 instances, excluding the two true comments
3241

3342
private static string detectContosoRule = @"
3443
[
@@ -54,7 +63,32 @@ public class QuotedStringsTests
5463
}
5564
]
5665
";
57-
66+
67+
private static string detectFindMeRule = @"
68+
[
69+
{
70+
""id"": ""RE000001"",
71+
""name"": ""Testing.Rules.Quotes"",
72+
""tags"": [
73+
""Testing.Rules.Quotes""
74+
],
75+
""severity"": ""Critical"",
76+
""description"": ""Find findMe"",
77+
""patterns"": [
78+
{
79+
""pattern"": ""findMe"",
80+
""type"": ""regex"",
81+
""confidence"": ""High"",
82+
""scopes"": [
83+
""code""
84+
]
85+
}
86+
],
87+
""_comment"": """"
88+
}
89+
]
90+
";
91+
5892
private readonly ILoggerFactory _loggerFactory =
5993
new LogOptions { ConsoleVerbosityLevel = LogEventLevel.Verbose }.GetLoggerFactory();
6094

@@ -78,4 +112,24 @@ public void QuotedStrings(string content, int numIssues)
78112
Assert.AreEqual(numIssues,
79113
ruleProcessor.AnalyzeFile(content, new FileEntry("testfile.cs", new MemoryStream()), info).Count());
80114
}
115+
116+
/// <summary>
117+
/// Ruby interpolated strings provide an interesting test case because they use the comment character as part of interpolation
118+
/// the comment marker is one character long, and it may often come right after the quotation mark
119+
/// </summary>
120+
/// <param name="content"></param>
121+
/// <param name="numIssues"></param>
122+
123+
[DataRow(testRubyInterpolatedStrings, 5)]
124+
[DataTestMethod]
125+
public void QuotedStringsRuby(string content, int numIssues)
126+
{
127+
RuleSet rules = new(_loggerFactory);
128+
rules.AddString(detectFindMeRule, "findMeRule");
129+
Microsoft.ApplicationInspector.RulesEngine.RuleProcessor ruleProcessor =
130+
new Microsoft.ApplicationInspector.RulesEngine.RuleProcessor(rules, new RuleProcessorOptions());
131+
_languages.FromFileNameOut("testfile.rb", out LanguageInfo info);
132+
Assert.AreEqual(numIssues,
133+
ruleProcessor.AnalyzeFile(content, new FileEntry("testfile.rb", new MemoryStream()), info).Count());
134+
}
81135
}

0 commit comments

Comments
 (0)