Skip to content

Commit e4b6be3

Browse files
Copilotjoe10832
andcommitted
Add secure clone-demo.sh script with comprehensive safety features
Co-authored-by: joe10832 <[email protected]>
1 parent 6a23498 commit e4b6be3

File tree

1 file changed

+336
-0
lines changed

1 file changed

+336
-0
lines changed

clone-demo.sh

Lines changed: 336 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,336 @@
1+
#!/usr/bin/env bash
2+
#
3+
# Clone Demo Script - Secure Version
4+
# This script safely clones and sets up demo projects for onchain testing
5+
#
6+
7+
set -euo pipefail
8+
9+
# Enhanced portability - use /usr/bin/env bash for better cross-platform support
10+
# Exit on any command failure, undefined variables, or pipe failures
11+
12+
# Color codes for output
13+
readonly RED='\033[0;31m'
14+
readonly GREEN='\033[0;32m'
15+
readonly YELLOW='\033[1;33m'
16+
readonly BLUE='\033[0;34m'
17+
readonly NC='\033[0m' # No Color
18+
19+
# Default configuration
20+
readonly DEFAULT_DEMO_DIR="onchain-demo"
21+
readonly DEMO_REPO_URL="https://github.com/coinbase/onchain-kit"
22+
23+
# Critical safety validation: Protected directories that should never be removed
24+
readonly PROTECTED_DIRS=(
25+
"/"
26+
"/bin"
27+
"/boot"
28+
"/dev"
29+
"/etc"
30+
"/home"
31+
"/lib"
32+
"/lib32"
33+
"/lib64"
34+
"/mnt"
35+
"/opt"
36+
"/proc"
37+
"/root"
38+
"/run"
39+
"/sbin"
40+
"/srv"
41+
"/sys"
42+
"/tmp"
43+
"/usr"
44+
"/var"
45+
"$HOME"
46+
)
47+
48+
# Function to print colored output
49+
print_status() {
50+
local color=$1
51+
local message=$2
52+
echo -e "${color}${message}${NC}"
53+
}
54+
55+
# Function to validate directory path for safety
56+
validate_directory_path() {
57+
local target_dir="$1"
58+
59+
# Convert to absolute path for comparison
60+
local abs_path
61+
abs_path="$(readlink -f "$target_dir" 2>/dev/null || echo "$target_dir")"
62+
63+
# Check if path is empty or contains dangerous patterns
64+
if [[ -z "$target_dir" ]]; then
65+
print_status "$RED" "❌ Error: Directory path cannot be empty"
66+
return 1
67+
fi
68+
69+
# Check for dangerous patterns
70+
if [[ "$target_dir" =~ ^[[:space:]]*$ ]]; then
71+
print_status "$RED" "❌ Error: Directory path cannot contain only whitespace"
72+
return 1
73+
fi
74+
75+
# Check against protected directories
76+
for protected_dir in "${PROTECTED_DIRS[@]}"; do
77+
if [[ "$abs_path" == "$protected_dir" ]] || [[ "$target_dir" == "$protected_dir" ]]; then
78+
print_status "$RED" "❌ Error: Cannot remove protected directory: $target_dir"
79+
print_status "$RED" " This is a critical system directory and cannot be safely removed."
80+
return 1
81+
fi
82+
done
83+
84+
# Check for parent directory traversal that could affect protected paths
85+
case "$abs_path" in
86+
"/")
87+
print_status "$RED" "❌ Error: Cannot remove root directory"
88+
return 1
89+
;;
90+
"/home"|"/home/"*)
91+
if [[ "$abs_path" == "/home" ]]; then
92+
print_status "$RED" "❌ Error: Cannot remove /home directory"
93+
return 1
94+
fi
95+
;;
96+
"/usr"|"/usr/"*)
97+
if [[ "$abs_path" == "/usr" ]]; then
98+
print_status "$RED" "❌ Error: Cannot remove /usr directory"
99+
return 1
100+
fi
101+
;;
102+
esac
103+
104+
return 0
105+
}
106+
107+
# Function to safely remove directory with comprehensive validation
108+
safe_remove_directory() {
109+
local target_dir="$1"
110+
local force_mode="${2:-false}"
111+
112+
print_status "$BLUE" "🔍 Validating directory for safe removal: $target_dir"
113+
114+
# Comprehensive protection against dangerous directory values
115+
if ! validate_directory_path "$target_dir"; then
116+
return 1
117+
fi
118+
119+
# Check if directory exists
120+
if [[ ! -d "$target_dir" ]]; then
121+
print_status "$YELLOW" "⚠️ Directory does not exist: $target_dir"
122+
return 0
123+
fi
124+
125+
# Additional safety check - ensure we're not in a protected location
126+
local current_dir
127+
current_dir="$(pwd)"
128+
case "$current_dir" in
129+
"/"|"/home"|"/usr"|"/etc"|"/var"|"/opt")
130+
print_status "$RED" "❌ Error: Cannot perform removal operations from protected directory: $current_dir"
131+
return 1
132+
;;
133+
esac
134+
135+
# User confirmation for destructive operations (unless in force mode)
136+
if [[ "$force_mode" != "true" ]]; then
137+
print_status "$YELLOW" "⚠️ This will permanently delete: $target_dir"
138+
print_status "$YELLOW" " All contents will be lost!"
139+
echo -n "Do you want to continue? [y/N]: "
140+
read -r confirmation
141+
case "$confirmation" in
142+
[Yy]|[Yy][Ee][Ss])
143+
print_status "$BLUE" "Proceeding with removal..."
144+
;;
145+
*)
146+
print_status "$GREEN" "✅ Operation cancelled by user"
147+
return 0
148+
;;
149+
esac
150+
fi
151+
152+
# Final safety check before removal
153+
print_status "$BLUE" "🔒 Performing final safety validation..."
154+
if ! validate_directory_path "$target_dir"; then
155+
return 1
156+
fi
157+
158+
# Perform the actual removal with proper error handling
159+
print_status "$BLUE" "🗑️ Removing directory: $target_dir"
160+
if rm -rf "$target_dir"; then
161+
print_status "$GREEN" "✅ Successfully removed directory: $target_dir"
162+
else
163+
print_status "$RED" "❌ Failed to remove directory: $target_dir"
164+
return 1
165+
fi
166+
167+
return 0
168+
}
169+
170+
# Function to display usage information
171+
show_usage() {
172+
cat << EOF
173+
Usage: $0 [OPTIONS] [DEMO_DIRECTORY]
174+
175+
Clone and set up onchain demo projects safely.
176+
177+
OPTIONS:
178+
-h, --help Show this help message
179+
-f, --force Force removal without confirmation prompts
180+
-c, --clean Clean existing demo directory before cloning
181+
-r, --repo URL Specify custom repository URL (default: $DEMO_REPO_URL)
182+
183+
DEMO_DIRECTORY:
184+
Directory name for the demo (default: $DEFAULT_DEMO_DIR)
185+
Must be a safe, non-system directory path.
186+
187+
EXAMPLES:
188+
$0 # Clone to default directory
189+
$0 my-demo # Clone to custom directory
190+
$0 --clean my-demo # Clean existing and clone
191+
$0 --repo https://github.com/user/repo demo # Custom repo
192+
193+
SAFETY FEATURES:
194+
✓ Enhanced portability with improved shebang declaration
195+
✓ Critical safety validation before directory removal operations
196+
✓ Comprehensive protection against dangerous directory values
197+
✓ User confirmation for destructive operations
198+
✓ Protected system directories validation
199+
200+
EOF
201+
}
202+
203+
# Main function
204+
main() {
205+
local demo_dir="$DEFAULT_DEMO_DIR"
206+
local repo_url="$DEMO_REPO_URL"
207+
local force_mode="false"
208+
local clean_mode="false"
209+
210+
print_status "$BLUE" "🚀 Onchain Test Kit - Demo Clone Script"
211+
print_status "$BLUE" " Enhanced with security and safety features"
212+
echo
213+
214+
# Parse command line arguments
215+
while [[ $# -gt 0 ]]; do
216+
case $1 in
217+
-h|--help)
218+
show_usage
219+
exit 0
220+
;;
221+
-f|--force)
222+
force_mode="true"
223+
shift
224+
;;
225+
-c|--clean)
226+
clean_mode="true"
227+
shift
228+
;;
229+
-r|--repo)
230+
if [[ -z "${2:-}" ]]; then
231+
print_status "$RED" "❌ Error: --repo requires a URL argument"
232+
exit 1
233+
fi
234+
repo_url="$2"
235+
shift 2
236+
;;
237+
-*)
238+
print_status "$RED" "❌ Error: Unknown option $1"
239+
show_usage
240+
exit 1
241+
;;
242+
*)
243+
demo_dir="$1"
244+
shift
245+
;;
246+
esac
247+
done
248+
249+
# Validate demo directory argument
250+
if ! validate_directory_path "$demo_dir"; then
251+
print_status "$RED" "❌ Error: Invalid or unsafe directory path: $demo_dir"
252+
exit 1
253+
fi
254+
255+
# Clean existing directory if requested
256+
if [[ "$clean_mode" == "true" ]] && [[ -d "$demo_dir" ]]; then
257+
print_status "$YELLOW" "🧹 Cleaning existing directory..."
258+
if ! safe_remove_directory "$demo_dir" "$force_mode"; then
259+
print_status "$RED" "❌ Failed to clean existing directory"
260+
exit 1
261+
fi
262+
fi
263+
264+
# Check if directory already exists
265+
if [[ -d "$demo_dir" ]]; then
266+
print_status "$YELLOW" "⚠️ Directory already exists: $demo_dir"
267+
if [[ "$force_mode" != "true" ]]; then
268+
echo -n "Do you want to remove it and continue? [y/N]: "
269+
read -r confirmation
270+
case "$confirmation" in
271+
[Yy]|[Yy][Ee][Ss])
272+
if ! safe_remove_directory "$demo_dir" "$force_mode"; then
273+
exit 1
274+
fi
275+
;;
276+
*)
277+
print_status "$GREEN" "✅ Operation cancelled by user"
278+
exit 0
279+
;;
280+
esac
281+
else
282+
if ! safe_remove_directory "$demo_dir" "$force_mode"; then
283+
exit 1
284+
fi
285+
fi
286+
fi
287+
288+
# Clone the repository
289+
print_status "$BLUE" "📁 Cloning repository..."
290+
print_status "$BLUE" " Repository: $repo_url"
291+
print_status "$BLUE" " Directory: $demo_dir"
292+
293+
if git clone "$repo_url" "$demo_dir"; then
294+
print_status "$GREEN" "✅ Successfully cloned repository"
295+
else
296+
print_status "$RED" "❌ Failed to clone repository"
297+
exit 1
298+
fi
299+
300+
# Change to demo directory
301+
cd "$demo_dir" || {
302+
print_status "$RED" "❌ Failed to change to demo directory"
303+
exit 1
304+
}
305+
306+
# Set up the demo
307+
print_status "$BLUE" "⚙️ Setting up demo environment..."
308+
309+
# Check if package.json exists and install dependencies
310+
if [[ -f "package.json" ]]; then
311+
print_status "$BLUE" "📦 Installing dependencies..."
312+
if command -v yarn &> /dev/null; then
313+
yarn install
314+
elif command -v npm &> /dev/null; then
315+
npm install
316+
else
317+
print_status "$YELLOW" "⚠️ Neither yarn nor npm found. Please install dependencies manually."
318+
fi
319+
fi
320+
321+
# Success message
322+
print_status "$GREEN" "🎉 Demo setup completed successfully!"
323+
print_status "$GREEN" " Directory: $(pwd)"
324+
print_status "$GREEN" " You can now start exploring the demo."
325+
326+
echo
327+
print_status "$BLUE" "📚 Next steps:"
328+
print_status "$BLUE" " 1. cd $demo_dir"
329+
print_status "$BLUE" " 2. Read the README.md for usage instructions"
330+
print_status "$BLUE" " 3. Run the example tests or start the demo application"
331+
}
332+
333+
# Script entry point with error handling
334+
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
335+
main "$@"
336+
fi

0 commit comments

Comments
 (0)