Skip to content

Commit a0d9ef2

Browse files
feat: dynamically specify directories for scan
1 parent 76b709d commit a0d9ef2

1 file changed

Lines changed: 144 additions & 20 deletions

File tree

stepsecurity-dev-machine-guard.sh

Lines changed: 144 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
# Options:
2828
# --enable-npm-scan Enable Node.js package scanning
2929
# --disable-npm-scan Disable Node.js package scanning
30+
# --search-dir DIR Add DIR to search paths (repeatable, appends to SEARCH_DIRS)
3031
# --verbose Show progress messages
3132
# --color=WHEN auto | always | never (default: auto)
3233
# -v, --version Show version
@@ -50,6 +51,13 @@ COLOR_MODE="auto" # auto | always | never
5051
QUIET=true # Suppress progress messages by default in community mode
5152
ENABLE_NODE_PACKAGE_SCAN="auto" # auto | true | false
5253

54+
# Directories to search for projects and extensions (space-separated)
55+
# Default: user's home directory. Customize as needed, e.g.:
56+
# SEARCH_DIRS="$HOME /Volumes/code" # home + encrypted partition
57+
# SEARCH_DIRS="/Volumes/code" # only encrypted partition
58+
# SEARCH_DIRS="$HOME /Volumes/code /opt/work $HOME/project" # multiple locations
59+
SEARCH_DIRS="\$HOME"
60+
5361
#==============================================================================
5462
# STEPSECURITY ENTERPRISE CONFIGURATION
5563
# Community users: leave these unchanged. They are only used in enterprise mode.
@@ -524,6 +532,29 @@ get_user_directory() {
524532
return 0
525533
}
526534

535+
resolve_search_directories() {
536+
local user_home="$1"
537+
local resolved_dirs=()
538+
539+
for dir in $SEARCH_DIRS; do
540+
# Resolve $HOME to the actual user home directory
541+
local resolved="${dir/\$HOME/$user_home}"
542+
if [ -d "$resolved" ]; then
543+
resolved_dirs+=("$resolved")
544+
else
545+
print_progress "Warning: Search directory not found, skipping: $resolved"
546+
fi
547+
done
548+
549+
if [ ${#resolved_dirs[@]} -eq 0 ]; then
550+
print_progress "Warning: No valid search directories found, falling back to: $user_home"
551+
echo "$user_home"
552+
return
553+
fi
554+
555+
printf '%s\n' "${resolved_dirs[@]}"
556+
}
557+
527558
#==============================================================================
528559
# LAUNCHD MANAGEMENT
529560
#==============================================================================
@@ -3086,12 +3117,30 @@ run_scan() {
30863117
fi
30873118
step_done "Scanning MCP server configs"
30883119

3089-
# Collect extensions
3120+
# Resolve search directories
3121+
local search_dirs
3122+
search_dirs=$(resolve_search_directories "$user_home")
3123+
3124+
# Collect extensions across all search directories
30903125
step_start "Scanning IDE extensions"
3091-
local user_dir="$user_home"
3092-
local all_ext_result=$(collect_all_extensions "$user_dir")
3093-
local ide_extensions=$(echo "$all_ext_result" | head -1)
3094-
local ext_count=$(echo "$all_ext_result" | tail -1)
3126+
local ide_extensions="[]"
3127+
local ext_count=0
3128+
while IFS= read -r search_dir; do
3129+
local dir_ext_result=$(collect_all_extensions "$search_dir")
3130+
local dir_extensions=$(echo "$dir_ext_result" | head -1)
3131+
local dir_ext_count=$(echo "$dir_ext_result" | tail -1)
3132+
# Merge JSON arrays
3133+
if [ "$dir_extensions" != "[]" ] && [ -n "$dir_extensions" ]; then
3134+
if [ "$ide_extensions" = "[]" ]; then
3135+
ide_extensions="$dir_extensions"
3136+
else
3137+
local existing_content=$(echo "$ide_extensions" | sed 's/^\[//;s/\]$//')
3138+
local new_content=$(echo "$dir_extensions" | sed 's/^\[//;s/\]$//')
3139+
ide_extensions="[${existing_content},${new_content}]"
3140+
fi
3141+
fi
3142+
ext_count=$((ext_count + dir_ext_count))
3143+
done <<< "$search_dirs"
30953144
step_done "Scanning IDE extensions"
30963145

30973146
# Resolve ENABLE_NODE_PACKAGE_SCAN: in community mode, "auto" means "false"
@@ -3119,10 +3168,36 @@ run_scan() {
31193168
step_done "Scanning global packages"
31203169

31213170
step_start "Scanning Node.js projects"
3122-
local node_scan_result=$(scan_node_projects "$user_dir" "$logged_in_user")
3123-
node_projects_file=$(echo "$node_scan_result" | sed -n '1p')
3124-
node_projects_count=$(echo "$node_scan_result" | sed -n '2p')
3125-
node_scan_duration=$(echo "$node_scan_result" | sed -n '3p')
3171+
# Scan across all search directories, merge results
3172+
local combined_projects_file=$(mktemp)
3173+
echo "[]" > "$combined_projects_file"
3174+
local total_node_projects_count=0
3175+
local total_node_scan_duration=0
3176+
while IFS= read -r search_dir; do
3177+
local node_scan_result=$(scan_node_projects "$search_dir" "$logged_in_user")
3178+
local dir_projects_file=$(echo "$node_scan_result" | sed -n '1p')
3179+
local dir_projects_count=$(echo "$node_scan_result" | sed -n '2p')
3180+
local dir_scan_duration=$(echo "$node_scan_result" | sed -n '3p')
3181+
total_node_projects_count=$((total_node_projects_count + dir_projects_count))
3182+
total_node_scan_duration=$((total_node_scan_duration + dir_scan_duration))
3183+
# Merge project files
3184+
if [ -n "$dir_projects_file" ] && [ -f "$dir_projects_file" ]; then
3185+
local existing=$(cat "$combined_projects_file")
3186+
if [ "$existing" = "[]" ]; then
3187+
cat "$dir_projects_file" > "$combined_projects_file"
3188+
else
3189+
local existing_content=$(echo "$existing" | sed 's/^\[//;s/\]$//')
3190+
local new_content=$(cat "$dir_projects_file" | sed 's/^\[//;s/\]$//')
3191+
if [ -n "$new_content" ]; then
3192+
echo "[${existing_content},${new_content}]" > "$combined_projects_file"
3193+
fi
3194+
fi
3195+
rm -f "$dir_projects_file"
3196+
fi
3197+
done <<< "$search_dirs"
3198+
node_projects_file="$combined_projects_file"
3199+
node_projects_count=$total_node_projects_count
3200+
node_scan_duration=$total_node_scan_duration
31263201
step_done "Scanning Node.js projects"
31273202
else
31283203
step_skip "Node.js packages (use --enable-npm-scan)"
@@ -3297,14 +3372,29 @@ EOF
32973372
local ide_installations=$(detect_ide_installations "$logged_in_user")
32983373
echo ""
32993374

3300-
# Get user directory to scan
3301-
local user_dir=$(get_user_directory)
3375+
# Resolve search directories
3376+
local search_dirs
3377+
search_dirs=$(resolve_search_directories "$user_home")
33023378
echo ""
33033379

3304-
# Collect all IDE extensions
3305-
local all_ide_collection_result=$(collect_all_extensions "$user_dir")
3306-
local ide_extensions=$(echo "$all_ide_collection_result" | head -1)
3307-
local ide_extensions_count=$(echo "$all_ide_collection_result" | tail -1)
3380+
# Collect all IDE extensions across search directories
3381+
local ide_extensions="[]"
3382+
local ide_extensions_count=0
3383+
while IFS= read -r search_dir; do
3384+
local dir_ext_result=$(collect_all_extensions "$search_dir")
3385+
local dir_extensions=$(echo "$dir_ext_result" | head -1)
3386+
local dir_ext_count=$(echo "$dir_ext_result" | tail -1)
3387+
if [ "$dir_extensions" != "[]" ] && [ -n "$dir_extensions" ]; then
3388+
if [ "$ide_extensions" = "[]" ]; then
3389+
ide_extensions="$dir_extensions"
3390+
else
3391+
local existing_content=$(echo "$ide_extensions" | sed 's/^\[//;s/\]$//')
3392+
local new_content=$(echo "$dir_extensions" | sed 's/^\[//;s/\]$//')
3393+
ide_extensions="[${existing_content},${new_content}]"
3394+
fi
3395+
fi
3396+
ide_extensions_count=$((ide_extensions_count + dir_ext_count))
3397+
done <<< "$search_dirs"
33083398
echo ""
33093399

33103400
# AI Agent Detection (v1.6.0+)
@@ -3375,11 +3465,35 @@ EOF
33753465
node_global_packages_count=$(echo "$global_scan_result" | sed -n '2p')
33763466
echo ""
33773467

3378-
# Scan for Node.js projects (returns file path)
3379-
local node_scan_result=$(scan_node_projects "$user_dir" "$logged_in_user")
3380-
node_projects_file=$(echo "$node_scan_result" | sed -n '1p')
3381-
node_projects_count=$(echo "$node_scan_result" | sed -n '2p')
3382-
node_scan_duration=$(echo "$node_scan_result" | sed -n '3p')
3468+
# Scan for Node.js projects across all search directories
3469+
local combined_projects_file=$(mktemp)
3470+
echo "[]" > "$combined_projects_file"
3471+
local total_node_projects_count=0
3472+
local total_node_scan_duration=0
3473+
while IFS= read -r search_dir; do
3474+
local node_scan_result=$(scan_node_projects "$search_dir" "$logged_in_user")
3475+
local dir_projects_file=$(echo "$node_scan_result" | sed -n '1p')
3476+
local dir_projects_count=$(echo "$node_scan_result" | sed -n '2p')
3477+
local dir_scan_duration=$(echo "$node_scan_result" | sed -n '3p')
3478+
total_node_projects_count=$((total_node_projects_count + dir_projects_count))
3479+
total_node_scan_duration=$((total_node_scan_duration + dir_scan_duration))
3480+
if [ -n "$dir_projects_file" ] && [ -f "$dir_projects_file" ]; then
3481+
local existing=$(cat "$combined_projects_file")
3482+
if [ "$existing" = "[]" ]; then
3483+
cat "$dir_projects_file" > "$combined_projects_file"
3484+
else
3485+
local existing_content=$(echo "$existing" | sed 's/^\[//;s/\]$//')
3486+
local new_content=$(cat "$dir_projects_file" | sed 's/^\[//;s/\]$//')
3487+
if [ -n "$new_content" ]; then
3488+
echo "[${existing_content},${new_content}]" > "$combined_projects_file"
3489+
fi
3490+
fi
3491+
rm -f "$dir_projects_file"
3492+
fi
3493+
done <<< "$search_dirs"
3494+
node_projects_file="$combined_projects_file"
3495+
node_projects_count=$total_node_projects_count
3496+
node_scan_duration=$total_node_scan_duration
33833497
echo ""
33843498

33853499
else
@@ -3493,6 +3607,7 @@ Output formats (community mode, mutually exclusive):
34933607
--html FILE HTML report saved to FILE
34943608
34953609
Options:
3610+
--search-dir DIR Add DIR to search paths (repeatable, appends to SEARCH_DIRS)
34963611
--enable-npm-scan Enable Node.js package scanning
34973612
--disable-npm-scan Disable Node.js package scanning
34983613
--verbose Show progress messages (suppressed by default)
@@ -3506,6 +3621,7 @@ Examples:
35063621
$(basename "$0") --json > scan.json # JSON to file
35073622
$(basename "$0") --html report.html # HTML report
35083623
$(basename "$0") --verbose --enable-npm-scan # Verbose with npm scan
3624+
$(basename "$0") --search-dir /Volumes/code # Also search /Volumes/code
35093625
$(basename "$0") send-telemetry # Enterprise telemetry
35103626
35113627
https://github.com/step-security/dev-machine-guard
@@ -3561,6 +3677,14 @@ while [ $# -gt 0 ]; do
35613677
fi
35623678
shift
35633679
;;
3680+
--search-dir)
3681+
if [ -z "${2:-}" ]; then
3682+
print_error "--search-dir requires a directory path argument"
3683+
exit 1
3684+
fi
3685+
SEARCH_DIRS="${SEARCH_DIRS} $2"
3686+
shift 2
3687+
;;
35643688
--verbose)
35653689
QUIET=false
35663690
shift

0 commit comments

Comments
 (0)