@@ -15,6 +15,7 @@ import kotlinx.coroutines.flow.channelFlow
15
15
import kotlinx.coroutines.launch
16
16
import kotlinx.coroutines.runBlocking
17
17
import kotlinx.coroutines.withContext
18
+ import kotlinx.coroutines.withTimeout
18
19
import org.apache.commons.codec.digest.DigestUtils
19
20
import org.apache.commons.io.FileUtils
20
21
import software.aws.toolkits.jetbrains.core.coroutines.getCoroutineBgContext
@@ -97,7 +98,7 @@ class FeatureDevSessionContext(val project: Project, val maxProjectSizeBytes: Lo
97
98
addAll(additionalGitIgnoreRules.map { convertGitIgnorePatternToRegex(it) })
98
99
addAll(parseGitIgnore())
99
100
}.mapNotNull { pattern ->
100
- runCatching { Regex (pattern) }.getOrNull()
101
+ runCatching { pattern?. let { Regex (it) } }.getOrNull()
101
102
}
102
103
} catch (e: Exception ) {
103
104
emptyList()
@@ -136,7 +137,13 @@ class FeatureDevSessionContext(val project: Project, val maxProjectSizeBytes: Lo
136
137
// entries against them by adding a trailing /.
137
138
// TODO: Add unit tests for gitignore matching
138
139
val relative = if (path.startsWith(projectRootPath.toString())) Paths .get(path).relativeTo(projectRootPath) else path
139
- async { pattern.matches(" $relative /" ) }
140
+ async {
141
+ try {
142
+ withTimeout(REGEX_TIMEOUT_MS ) { pattern.matches(" $relative /" ) }
143
+ } catch (e: Exception ) {
144
+ false
145
+ }
146
+ }
140
147
}
141
148
}
142
149
@@ -240,7 +247,7 @@ class FeatureDevSessionContext(val project: Project, val maxProjectSizeBytes: Lo
240
247
tempFilePath
241
248
}
242
249
243
- private fun parseGitIgnore (): Set <String > {
250
+ private fun parseGitIgnore (): Set <String ? > {
244
251
if (! gitIgnoreFile.exists()) {
245
252
return emptySet()
246
253
}
@@ -252,46 +259,57 @@ class FeatureDevSessionContext(val project: Project, val maxProjectSizeBytes: Lo
252
259
}
253
260
254
261
// gitignore patterns are not regex, method update needed.
255
- fun convertGitIgnorePatternToRegex (pattern : String ): String = pattern
256
- // Escape special regex characters except * and ?
257
- .replace(" ." , " \\ ." )
258
- .replace(" +" , " \\ +" )
259
- .replace(" (" , " \\ (" )
260
- .replace(" )" , " \\ )" )
261
- .replace(" [" , " \\ [" )
262
- .replace(" ]" , " \\ ]" )
263
- .replace(" {" , " \\ {" )
264
- .replace(" }" , " \\ }" )
265
- .replace(" ," , " \\ ," )
266
- .replace(" ^" , " \\ ^" )
267
- .replace(" $" , " \\ $" )
268
- .replace(" |" , " \\ |" )
269
- // Convert gitignore glob patterns to regex
270
- .replace(" **" , " .*?" ) // Match any directory depth
271
- .replace(" *" , " [^/]*?" ) // Match any character except path separator
272
- .replace(" ?" , " [^/]" ) // Match single character except path separator
273
- .let { pattern ->
274
- when {
275
- // If pattern starts with '/', anchor it to the start of the path
276
- pattern.startsWith(" /" ) -> " ^${pattern.substring(1 )} "
277
- // If pattern doesn't start with '/', it can match anywhere in the path
278
- else -> " (?:^|.*/?)$pattern "
279
- }
262
+ fun convertGitIgnorePatternToRegex (pattern : String ): String? {
263
+ // Skip invalid patterns for length check
264
+ if (pattern.length > MAX_PATTERN_LENGTH ) {
265
+ return null
280
266
}
281
- .let { pattern ->
282
- when {
283
- // If pattern ends with '/', it should match directories
284
- pattern.endsWith(" /" ) -> " $pattern .*"
285
- // Otherwise match exactly or with a trailing slash for directories
286
- else -> " $pattern (?:/.*)?$"
267
+ return pattern
268
+ // Escape special regex characters except * and ?
269
+ .replace(" ." , " \\ ." )
270
+ .replace(" +" , " \\ +" )
271
+ .replace(" (" , " \\ (" )
272
+ .replace(" )" , " \\ )" )
273
+ .replace(" [" , " \\ [" )
274
+ .replace(" ]" , " \\ ]" )
275
+ .replace(" {" , " \\ {" )
276
+ .replace(" }" , " \\ }" )
277
+ .replace(" ," , " \\ ," )
278
+ .replace(" ^" , " \\ ^" )
279
+ .replace(" $" , " \\ $" )
280
+ .replace(" |" , " \\ |" )
281
+ // Convert gitignore glob patterns to regex
282
+ .replace(" **" , " .*?" ) // Match any directory depth
283
+ .replace(" *" , " [^/]*?" ) // Match any character except path separator
284
+ .replace(" ?" , " [^/]" ) // Match single character except path separator
285
+ .let { pattern ->
286
+ when {
287
+ // If pattern starts with '/', anchor it to the start of the path
288
+ pattern.startsWith(" /" ) -> " ^${pattern.substring(1 )} "
289
+ // If pattern doesn't start with '/', it can match anywhere in the path
290
+ else -> " (?:^|.*/?)$pattern "
291
+ }
287
292
}
288
- }
293
+ .let { pattern ->
294
+ when {
295
+ // If pattern ends with '/', it should match directories
296
+ pattern.endsWith(" /" ) -> " $pattern .*"
297
+ // Otherwise match exactly or with a trailing slash for directories
298
+ else -> " $pattern (?:/.*)?$"
299
+ }
300
+ }
301
+ }
289
302
290
303
var selectedSourceFolder: VirtualFile
291
304
set(newRoot) {
292
305
_selectedSourceFolder = newRoot
293
306
}
294
307
get() = _selectedSourceFolder
308
+
309
+ companion object {
310
+ private const val MAX_PATTERN_LENGTH = 256 // Maximum allowed pattern length
311
+ private const val REGEX_TIMEOUT_MS = 100L // Timeout for regex operations in milliseconds
312
+ }
295
313
}
296
314
297
315
data class ZipCreationResult (val payload : File , val checksum : String , val contentLength : Long )
0 commit comments