fix: improve output_file validation and error messages

Co-Authored-By: Joe Moura <joao@crewai.com>
This commit is contained in:
Devin AI
2024-12-29 03:38:33 +00:00
parent 83b4e0b4c0
commit bdb32dd3e6
2 changed files with 57 additions and 19 deletions

View File

@@ -236,12 +236,13 @@ class Task(BaseModel):
if ".." in value: if ".." in value:
raise ValueError("Path traversal attempts are not allowed in output_file paths") raise ValueError("Path traversal attempts are not allowed in output_file paths")
if any(char in value for char in ['|', '>', '<', '&', ';', '$']): # Check for shell expansion first
raise ValueError("Shell special characters are not allowed in output_file paths")
# Check for absolute paths that might bypass restrictions
if value.startswith('~') or value.startswith('$'): if value.startswith('~') or value.startswith('$'):
raise ValueError("Shell expansion characters are not allowed in output_file paths") raise ValueError("Shell expansion characters are not allowed in output_file paths")
# Then check other shell special characters
if any(char in value for char in ['|', '>', '<', '&', ';']):
raise ValueError("Shell special characters are not allowed in output_file paths")
# Don't strip leading slash if it's a template path with variables # Don't strip leading slash if it's a template path with variables
if "{" in value or "}" in value: if "{" in value or "}" in value:
@@ -478,24 +479,25 @@ class Task(BaseModel):
Args: Args:
input_string: The string containing template variables to interpolate. input_string: The string containing template variables to interpolate.
Can be None, in which case an empty string is returned. Can be None or empty, in which case an empty string is returned.
inputs: Dictionary mapping template variables to their values. inputs: Dictionary mapping template variables to their values.
Supported value types are strings, integers, and floats. Supported value types are strings, integers, and floats.
If input_string is empty or has no placeholders, inputs can be empty.
Returns: Returns:
The interpolated string with all template variables replaced with their values. The interpolated string with all template variables replaced with their values.
Empty string if input_string is None. Empty string if input_string is None or empty.
Raises: Raises:
ValueError: If a required template variable is missing from inputs. ValueError: If a required template variable is missing from inputs.
KeyError: If a template variable is not found in the inputs dictionary. KeyError: If a template variable is not found in the inputs dictionary.
""" """
if input_string is None: if input_string is None or not input_string:
return "" return ""
if not input_string: if "{" not in input_string and "}" not in input_string:
raise ValueError("Input string cannot be empty when provided") return input_string
if not inputs: if not inputs:
raise ValueError("Inputs dictionary cannot be empty") raise ValueError("Inputs dictionary cannot be empty when interpolating variables")
try: try:
# Validate input types # Validate input types

View File

@@ -880,20 +880,56 @@ def test_key():
def test_output_file_validation(): def test_output_file_validation():
"""Test output file path validation.""" """Test output file path validation."""
# Valid paths # Valid paths
assert Task(output_file="output.txt").output_file == "output.txt" assert Task(
assert Task(output_file="/tmp/output.txt").output_file == "tmp/output.txt" description="Test task",
assert Task(output_file="{dir}/output_{date}.txt").output_file == "{dir}/output_{date}.txt" expected_output="Test output",
output_file="output.txt"
).output_file == "output.txt"
assert Task(
description="Test task",
expected_output="Test output",
output_file="/tmp/output.txt"
).output_file == "tmp/output.txt"
assert Task(
description="Test task",
expected_output="Test output",
output_file="{dir}/output_{date}.txt"
).output_file == "{dir}/output_{date}.txt"
# Invalid paths # Invalid paths
with pytest.raises(ValueError, match="Path traversal"): with pytest.raises(ValueError, match="Path traversal"):
Task(output_file="../output.txt") Task(
description="Test task",
expected_output="Test output",
output_file="../output.txt"
)
with pytest.raises(ValueError, match="Path traversal"): with pytest.raises(ValueError, match="Path traversal"):
Task(output_file="folder/../output.txt") Task(
description="Test task",
expected_output="Test output",
output_file="folder/../output.txt"
)
with pytest.raises(ValueError, match="Shell special characters"): with pytest.raises(ValueError, match="Shell special characters"):
Task(output_file="output.txt | rm -rf /") Task(
description="Test task",
expected_output="Test output",
output_file="output.txt | rm -rf /"
)
with pytest.raises(ValueError, match="Shell expansion"): with pytest.raises(ValueError, match="Shell expansion"):
Task(output_file="~/output.txt") Task(
description="Test task",
expected_output="Test output",
output_file="~/output.txt"
)
with pytest.raises(ValueError, match="Shell expansion"): with pytest.raises(ValueError, match="Shell expansion"):
Task(output_file="$HOME/output.txt") Task(
description="Test task",
expected_output="Test output",
output_file="$HOME/output.txt"
)
with pytest.raises(ValueError, match="Invalid template variable"): with pytest.raises(ValueError, match="Invalid template variable"):
Task(output_file="{invalid-name}/output.txt") Task(
description="Test task",
expected_output="Test output",
output_file="{invalid-name}/output.txt"
)