|
19 | 19 | from codeflash.code_utils.config_parser import find_pyproject_toml, get_all_closest_config_files |
20 | 20 | from codeflash.lsp.helpers import is_LSP_enabled |
21 | 21 |
|
| 22 | +_DANGEROUS_PATTERNS = [ |
| 23 | + "cd ", |
| 24 | + "ls ", |
| 25 | + "rm ", |
| 26 | + "mkdir ", |
| 27 | + "rmdir ", |
| 28 | + "del ", |
| 29 | + "dir ", |
| 30 | + "type ", |
| 31 | + "cat ", |
| 32 | + "echo ", |
| 33 | + "&&", |
| 34 | + "||", |
| 35 | + ";", |
| 36 | + "|", |
| 37 | + ">", |
| 38 | + "<", |
| 39 | + "$", |
| 40 | + "`", |
| 41 | +] |
| 42 | + |
| 43 | +_DANGEROUS_PATTERNS_SET = set(_DANGEROUS_PATTERNS) |
| 44 | + |
| 45 | +_DANGEROUS_PATTERNS_LOWER = tuple(pat.lower() for pat in _DANGEROUS_PATTERNS) |
| 46 | + |
| 47 | +_INVALID_CHARS_NT = {"<", ">", ":", '"', "|", "?", "*"} |
| 48 | + |
| 49 | +_INVALID_CHARS_UNIX = {"\0"} |
| 50 | + |
22 | 51 | ImportErrorPattern = re.compile(r"ModuleNotFoundError.*$", re.MULTILINE) |
23 | 52 |
|
24 | 53 | BLACKLIST_ADDOPTS = ("--benchmark", "--sugar", "--codespeed", "--cov", "--profile", "--junitxml", "-n") |
@@ -393,50 +422,31 @@ def validate_relative_directory_path(path: str) -> tuple[bool, str]: |
393 | 422 | - error_message: Empty string if valid, error description if invalid |
394 | 423 |
|
395 | 424 | """ |
396 | | - # Check for empty path |
397 | 425 | if not path or not path.strip(): |
398 | 426 | return False, "Path cannot be empty" |
399 | 427 |
|
400 | 428 | # Normalize whitespace |
401 | 429 | path = path.strip() |
402 | | - |
403 | | - # Check for shell commands or dangerous patterns |
404 | | - dangerous_patterns = [ |
405 | | - "cd ", |
406 | | - "ls ", |
407 | | - "rm ", |
408 | | - "mkdir ", |
409 | | - "rmdir ", |
410 | | - "del ", |
411 | | - "dir ", |
412 | | - "type ", |
413 | | - "cat ", |
414 | | - "echo ", |
415 | | - "&&", |
416 | | - "||", |
417 | | - ";", |
418 | | - "|", |
419 | | - ">", |
420 | | - "<", |
421 | | - "$", |
422 | | - "`", |
423 | | - ] |
424 | 430 | path_lower = path.lower() |
425 | | - for pattern in dangerous_patterns: |
426 | | - if pattern in path_lower: |
427 | | - return False, f"Path contains invalid characters or commands: {pattern.strip()}" |
| 431 | + # Instead of for-loop, use generator with next() for early exit |
| 432 | + found_pattern = next((pattern for pattern in _DANGEROUS_PATTERNS_LOWER if pattern in path_lower), None) |
| 433 | + if found_pattern is not None: |
| 434 | + return False, f"Path contains invalid characters or commands: {found_pattern.strip()}" |
428 | 435 |
|
429 | 436 | # Check for path traversal attempts (cross-platform) |
| 437 | + # Normalize path separators for checking |
430 | 438 | normalized = path.replace("\\", "/") |
431 | 439 | if ".." in normalized: |
432 | 440 | return False, "Path cannot contain '..' (parent directory traversal)" |
433 | 441 |
|
434 | | - # Check for absolute paths and invalid characters |
435 | | - invalid_chars = {"<", ">", ":", '"', "|", "?", "*"} if os.name == "nt" else {"\0"} |
| 442 | + # Check for absolute paths, invalid characters, and validate path format |
436 | 443 | error_msg = "" |
437 | 444 | if Path(path).is_absolute(): |
438 | 445 | error_msg = "Path must be relative, not absolute" |
439 | | - elif any(char in path for char in invalid_chars): |
| 446 | + elif os.name == "nt": # Windows |
| 447 | + if any(char in _INVALID_CHARS_NT for char in path): |
| 448 | + error_msg = "Path contains invalid characters for this operating system" |
| 449 | + elif "\0" in path: # Unix-like |
440 | 450 | error_msg = "Path contains invalid characters for this operating system" |
441 | 451 | else: |
442 | 452 | # Validate using pathlib to ensure it's a valid path structure |
|
0 commit comments