Skip to content

Commit

Permalink
Added Timeout and length check for pattern matching
Browse files Browse the repository at this point in the history
  • Loading branch information
ashishrp-aws committed Jan 15, 2025
1 parent f19f44a commit 7365162
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ class FeatureDevSessionContextTest : FeatureDevTestBase(HeavyJavaCodeInsightTest
"settings.gradle",
"build.gradle",
"gradle/wrapper/gradle-wrapper.properties",
"builder/GetTestBuilder.java", //check for false positives
"builder/GetTestBuilder.java", // check for false positives
".aws-sam/build/function1",
".gem/specs.rb",
"archive.zip",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import kotlinx.coroutines.flow.channelFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import kotlinx.coroutines.withTimeout
import org.apache.commons.codec.digest.DigestUtils
import org.apache.commons.io.FileUtils
import software.aws.toolkits.jetbrains.core.coroutines.getCoroutineBgContext
Expand Down Expand Up @@ -97,7 +98,7 @@ class FeatureDevSessionContext(val project: Project, val maxProjectSizeBytes: Lo
addAll(additionalGitIgnoreRules.map { convertGitIgnorePatternToRegex(it) })
addAll(parseGitIgnore())
}.mapNotNull { pattern ->
runCatching { Regex(pattern) }.getOrNull()
runCatching { pattern?.let { Regex(it) } }.getOrNull()
}
} catch (e: Exception) {
emptyList()
Expand Down Expand Up @@ -136,7 +137,13 @@ class FeatureDevSessionContext(val project: Project, val maxProjectSizeBytes: Lo
// entries against them by adding a trailing /.
// TODO: Add unit tests for gitignore matching
val relative = if (path.startsWith(projectRootPath.toString())) Paths.get(path).relativeTo(projectRootPath) else path
async { pattern.matches("$relative/") }
async {
try {
withTimeout(REGEX_TIMEOUT_MS) { pattern.matches("$relative/") }
} catch (e: Exception) {
false
}
}
}
}

Expand Down Expand Up @@ -240,7 +247,7 @@ class FeatureDevSessionContext(val project: Project, val maxProjectSizeBytes: Lo
tempFilePath
}

private fun parseGitIgnore(): Set<String> {
private fun parseGitIgnore(): Set<String?> {
if (!gitIgnoreFile.exists()) {
return emptySet()
}
Expand All @@ -252,46 +259,57 @@ class FeatureDevSessionContext(val project: Project, val maxProjectSizeBytes: Lo
}

// gitignore patterns are not regex, method update needed.
fun convertGitIgnorePatternToRegex(pattern: String): String = pattern
// Escape special regex characters except * and ?
.replace(".", "\\.")
.replace("+", "\\+")
.replace("(", "\\(")
.replace(")", "\\)")
.replace("[", "\\[")
.replace("]", "\\]")
.replace("{", "\\{")
.replace("}", "\\}")
.replace(",", "\\,")
.replace("^", "\\^")
.replace("$", "\\$")
.replace("|", "\\|")
// Convert gitignore glob patterns to regex
.replace("**", ".*?") // Match any directory depth
.replace("*", "[^/]*?") // Match any character except path separator
.replace("?", "[^/]") // Match single character except path separator
.let { pattern ->
when {
// If pattern starts with '/', anchor it to the start of the path
pattern.startsWith("/") -> "^${pattern.substring(1)}"
// If pattern doesn't start with '/', it can match anywhere in the path
else -> "(?:^|.*/?)$pattern"
}
fun convertGitIgnorePatternToRegex(pattern: String): String? {
// Skip invalid patterns for length check
if (pattern.length > MAX_PATTERN_LENGTH) {
return null
}
.let { pattern ->
when {
// If pattern ends with '/', it should match directories
pattern.endsWith("/") -> "$pattern.*"
// Otherwise match exactly or with a trailing slash for directories
else -> "$pattern(?:/.*)?$"
return pattern
// Escape special regex characters except * and ?
.replace(".", "\\.")
.replace("+", "\\+")
.replace("(", "\\(")
.replace(")", "\\)")
.replace("[", "\\[")
.replace("]", "\\]")
.replace("{", "\\{")
.replace("}", "\\}")
.replace(",", "\\,")
.replace("^", "\\^")
.replace("$", "\\$")
.replace("|", "\\|")
// Convert gitignore glob patterns to regex
.replace("**", ".*?") // Match any directory depth
.replace("*", "[^/]*?") // Match any character except path separator
.replace("?", "[^/]") // Match single character except path separator
.let { pattern ->
when {
// If pattern starts with '/', anchor it to the start of the path
pattern.startsWith("/") -> "^${pattern.substring(1)}"
// If pattern doesn't start with '/', it can match anywhere in the path
else -> "(?:^|.*/?)$pattern"
}
}
}
.let { pattern ->
when {
// If pattern ends with '/', it should match directories
pattern.endsWith("/") -> "$pattern.*"
// Otherwise match exactly or with a trailing slash for directories
else -> "$pattern(?:/.*)?$"
}
}
}

var selectedSourceFolder: VirtualFile
set(newRoot) {
_selectedSourceFolder = newRoot
}
get() = _selectedSourceFolder

companion object {
private const val MAX_PATTERN_LENGTH = 256 // Maximum allowed pattern length
private const val REGEX_TIMEOUT_MS = 100L // Timeout for regex operations in milliseconds
}
}

data class ZipCreationResult(val payload: File, val checksum: String, val contentLength: Long)

0 comments on commit 7365162

Please sign in to comment.