#!/bin/bash # Lil Script Tester - Secure Sandbox Testing Module # This module provides secure testing capabilities for Lil scripts generated by the puzzle mechanism. # # SECURITY FEATURES: # - Sandboxed execution environment # - Resource limits (CPU, memory, time) # - File system isolation # - Network access prevention # - Safe error handling # - Result validation and sanitization # --- Configuration --- TEST_TIMEOUT=10 # Maximum execution time in seconds MAX_OUTPUT_SIZE=10000 # Maximum output size in characters TEMP_DIR_BASE="/tmp/lil_test" # Base temporary directory SAFE_COMMANDS=("print" "echo" "count" "first" "last" "sum" "min" "max" "range" "keys" "list" "table" "typeof" "mag" "unit") # --- Security Functions --- # Create secure temporary directory create_secure_temp_dir() { local dir="$1" mkdir -p "$dir" chmod 700 "$dir" # Create a minimal environment echo "()" > "$dir/empty.lil" echo "nil" > "$dir/nil.lil" } # Clean up temporary directory cleanup_temp_dir() { local dir="$1" if [ -d "$dir" ]; then rm -rf "$dir" 2>/dev/null fi } # Validate Lil code for potentially dangerous operations validate_lil_code() { local code="$1" # Check for potentially dangerous patterns local dangerous_patterns=( "system\\[" # System calls "exec\\[" # Execution "file\\." # File operations "network\\." # Network operations "http\\." # HTTP requests "shell\\[" # Shell execution "\\$\\(" # Command substitution "\\`.*\\`" # Backtick execution ) for pattern in "${dangerous_patterns[@]}"; do if echo "$code" | grep -q "$pattern" 2>/dev/null; then echo "DANGEROUS_CODE_DETECTED: $pattern" return 1 fi done # Check for reasonable complexity (prevent infinite loops) local line_count=$(echo "$code" | wc -l) if [ "$line_count" -gt 100 ]; then echo "CODE_TOO_COMPLEX: $line_count lines (max: 100)" return 1 fi echo "CODE_VALIDATED" return 0 } # Create a safe test wrapper create_safe_test_wrapper() { local code="$1" local test_name="$2" local temp_dir="$3" # Create a safe test file cat > "$temp_dir/test_$test_name.lil" << EOF # Safe test wrapper for: $test_name # Generated by Lil Tester # Set safe defaults on safe_test do local result local error_occurred # Wrap execution in error handling on execute_safely do $code end # Execute and capture result result:execute_safely() # Return result or error indicator if result = nil "ERROR: Execution failed or returned nil" else result end end # Run the test safe_test() EOF } # Execute Lil code safely execute_lil_safely() { local code="$1" local test_name="$2" local temp_dir="$3" # Validate code first local validation_result=$(validate_lil_code "$code") if [ $? -ne 0 ]; then echo "VALIDATION_FAILED: $validation_result" return 1 fi # Create safe test wrapper create_safe_test_wrapper "$code" "$test_name" "$temp_dir" # Try lilt first, fallback to lila local result="" local exit_code=1 # Test with lilt if command -v lilt >/dev/null 2>&1; then echo "Testing with lilt..." result=$(timeout "$TEST_TIMEOUT" lilt "$temp_dir/test_$test_name.lil" 2>&1) exit_code=$? if [ $exit_code -eq 0 ]; then echo "SUCCESS: lilt execution completed" else echo "lilt failed, trying lila..." fi fi # Fallback to lila if lilt failed if [ $exit_code -ne 0 ] && command -v lila >/dev/null 2>&1; then echo "Testing with lila..." result=$(timeout "$TEST_TIMEOUT" lila "$temp_dir/test_$test_name.lil" 2>&1) exit_code=$? if [ $exit_code -eq 0 ]; then echo "SUCCESS: lila execution completed" else echo "Both lilt and lila failed" fi fi # Check output size local output_size=${#result} if [ "$output_size" -gt "$MAX_OUTPUT_SIZE" ]; then result="$(echo "$result" | head -c "$MAX_OUTPUT_SIZE")... [TRUNCATED]" fi echo "$result" return $exit_code } # Run comprehensive tests run_lil_tests() { local code="$1" local test_name="$2" # Create unique temporary directory local temp_dir="${TEMP_DIR_BASE}_$$_$(date +%s)" echo "=== Lil Script Testing ===" echo "Test Name: $test_name" echo "Code Length: $(echo "$code" | wc -c) characters" echo "----------------------------------------" # Create secure temporary directory create_secure_temp_dir "$temp_dir" # Trap cleanup on exit trap 'cleanup_temp_dir "$temp_dir"' EXIT # Execute the code safely local start_time=$(date +%s.%N) local result=$(execute_lil_safely "$code" "$test_name" "$temp_dir") local exit_code=$? local end_time=$(date +%s.%N) # Calculate execution time local duration=$(echo "$end_time - $start_time" | bc -l 2>/dev/null || echo "0") # Report results echo "----------------------------------------" echo "Test Results:" echo "Exit Code: $exit_code" echo "Execution Time: ${duration}s" echo "Output:" echo "$result" if [ $exit_code -eq 0 ]; then echo "✅ Test PASSED" return 0 else echo "❌ Test FAILED" return 1 fi } # Test specific Lil constructs test_lil_constructs() { local code="$1" local test_name="$2" # Create unique temporary directory for construct testing local temp_dir="${TEMP_DIR_BASE}_constructs_$$_$(date +%s)" echo "=== Lil Construct Testing ===" echo "Testing specific Lil language features..." # Create and cleanup temp dir create_secure_temp_dir "$temp_dir" trap 'cleanup_temp_dir "$temp_dir"' EXIT # Test basic operations local basic_tests=( "Basic arithmetic: 2+3*4" "List operations: (1,2,3) take 2" "Dictionary: dict (\"a\",1) (\"b\",2)" "Function definition: on test do 42 end" ) for test in "${basic_tests[@]}"; do local test_desc=$(echo "$test" | cut -d: -f1) local test_code=$(echo "$test" | cut -d: -f2) echo "Testing: $test_desc" local result=$(execute_lil_safely "$test_code" "basic_$test_desc" "$temp_dir") if [ $? -eq 0 ]; then echo " ✅ $test_desc: PASSED" else echo " ❌ $test_desc: FAILED" fi done } # Main testing interface test_lil_script() { local code="$1" local test_name="${2:-unnamed_test}" if [ -z "$code" ]; then echo "Error: No code provided for testing" return 1 fi # Run the main test run_lil_tests "$code" "$test_name" local main_result=$? # Run construct-specific tests test_lil_constructs "$code" "$test_name" return $main_result } # Export functions for use by other scripts export -f test_lil_script export -f run_lil_tests export -f execute_lil_safely export -f validate_lil_code export -f create_secure_temp_dir export -f cleanup_temp_dir # If run directly, provide usage information if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then if [ "$#" -lt 1 ]; then echo "Usage: $0 [test_name]" echo "Example: $0 'on test do 42 end' 'simple_function'" exit 1 fi test_lil_script "$1" "${2:-unnamed_test}" fi