-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinstall.sh
More file actions
287 lines (252 loc) · 10.4 KB
/
Copy pathinstall.sh
File metadata and controls
287 lines (252 loc) · 10.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
#!/usr/bin/env bash
# ShellGuard — One-click installer and configuration guide
# Usage: bash install.sh
set -e
SHELLGUARD_DIR="$HOME/.shellguard"
LIB_DIR="$SHELLGUARD_DIR/lib"
BIN_DIR="$HOME/.local/bin"
HOOK_MARKER="# >>> shellguard hook >>>"
HOOK_END_MARKER="# <<< shellguard hook <<<"
# Color helpers
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
BOLD='\033[1m'
RESET='\033[0m'
info() { echo -e "${CYAN}[ShellGuard]${RESET} $*"; }
success() { echo -e "${GREEN}[ShellGuard]${RESET} $*"; }
warn() { echo -e "${YELLOW}[ShellGuard]${RESET} $*"; }
error() { echo -e "${RED}[ShellGuard]${RESET} $*" >&2; }
echo ""
echo -e "${BOLD}${CYAN}╔══════════════════════════════════════════╗${RESET}"
echo -e "${BOLD}${CYAN}║ ShellGuard Installer ║${RESET}"
echo -e "${BOLD}${CYAN}║ Lightweight Terminal Security Monitor ║${RESET}"
echo -e "${BOLD}${CYAN}╚══════════════════════════════════════════╝${RESET}"
echo ""
# ── Step 1: Check Python 3.8+ ──────────────────────────────────────────────
info "Checking Python version..."
PYTHON=""
for py in python3 python; do
if command -v "$py" &>/dev/null; then
ver=$("$py" -c "import sys; print(sys.version_info >= (3,8))" 2>/dev/null)
if [ "$ver" = "True" ]; then
PYTHON="$py"
break
fi
fi
done
if [ -z "$PYTHON" ]; then
error "Python 3.8+ is required but not found."
error "Please install Python 3.8+ and re-run this script."
exit 1
fi
success "Found Python: $($PYTHON --version)"
# ── Step 2: Install rich ────────────────────────────────────────────────────
VENV_DIR="$SHELLGUARD_DIR/venv"
VENV_PYTHON=""
info "Checking for 'rich' library..."
# Helper: try to install rich using the best available method
install_rich() {
# Strategy 1: use existing venv if already created
if [ -f "$VENV_DIR/bin/python" ]; then
VENV_PYTHON="$VENV_DIR/bin/python"
if "$VENV_PYTHON" -c "import rich" &>/dev/null; then
return 0
fi
"$VENV_PYTHON" -m pip install rich --quiet && return 0
fi
# Strategy 2: try pip install --user (works on most systems)
if "$PYTHON" -m pip install rich --user --quiet 2>/dev/null; then
return 0
fi
# Strategy 3: create a dedicated venv under ~/.shellguard/venv
info "Creating isolated virtual environment at $VENV_DIR ..."
"$PYTHON" -m venv "$VENV_DIR" && \
"$VENV_DIR/bin/pip" install rich --quiet && \
VENV_PYTHON="$VENV_DIR/bin/python" && \
return 0
# Strategy 4: last resort — break-system-packages (user must confirm)
warn "Could not install 'rich' automatically."
warn "Options:"
warn " a) brew install python-rich (recommended on macOS)"
warn " b) pip install rich --break-system-packages"
warn " c) pipx install rich"
read -rp "Try '--break-system-packages' now? [y/N]: " _confirm
if [[ "$_confirm" =~ ^[Yy]$ ]]; then
"$PYTHON" -m pip install rich --break-system-packages --quiet && return 0
fi
return 1
}
if "$PYTHON" -c "import rich" &>/dev/null; then
success "'rich' already installed (system)."
elif [ -f "$VENV_DIR/bin/python" ] && "$VENV_DIR/bin/python" -c "import rich" &>/dev/null; then
VENV_PYTHON="$VENV_DIR/bin/python"
success "'rich' already installed (venv)."
else
if ! install_rich; then
error "Failed to install 'rich'. Please install it manually and re-run."
exit 1
fi
success "'rich' installed."
fi
# If using venv python, point PYTHON to it for subsequent imports
if [ -n "$VENV_PYTHON" ]; then
PYTHON="$VENV_PYTHON"
info "Using venv Python: $VENV_PYTHON"
fi
# ── Step 3: Interactive configuration ──────────────────────────────────────
echo ""
echo -e "${BOLD}Configuration Setup${RESET}"
echo "Press Enter to accept defaults (shown in brackets)."
echo ""
# Check for existing config
existing_base_url=""
existing_api_key=""
existing_model=""
existing_max_history=""
if [ -f "$SHELLGUARD_DIR/config.json" ] && command -v "$PYTHON" &>/dev/null; then
existing_base_url=$("$PYTHON" -c "import json; d=json.load(open('$SHELLGUARD_DIR/config.json')); print(d.get('base_url',''))" 2>/dev/null || echo "")
existing_api_key=$("$PYTHON" -c "import json; d=json.load(open('$SHELLGUARD_DIR/config.json')); print(d.get('api_key',''))" 2>/dev/null || echo "")
existing_model=$("$PYTHON" -c "import json; d=json.load(open('$SHELLGUARD_DIR/config.json')); print(d.get('model',''))" 2>/dev/null || echo "")
existing_max_history=$("$PYTHON" -c "import json; d=json.load(open('$SHELLGUARD_DIR/config.json')); print(d.get('max_history_display',''))" 2>/dev/null || echo "")
fi
DEFAULT_BASE_URL="${existing_base_url:-https://api.openai.com/v1}"
DEFAULT_API_KEY="${existing_api_key:-}"
DEFAULT_MODEL="${existing_model:-gpt-4o-mini}"
DEFAULT_MAX_HISTORY="${existing_max_history:-50}"
read -rp "API Base URL [$DEFAULT_BASE_URL]: " INPUT_BASE_URL
BASE_URL="${INPUT_BASE_URL:-$DEFAULT_BASE_URL}"
read -rp "API Key [${DEFAULT_API_KEY:+****}]: " INPUT_API_KEY
API_KEY="${INPUT_API_KEY:-$DEFAULT_API_KEY}"
read -rp "Model [$DEFAULT_MODEL]: " INPUT_MODEL
MODEL="${INPUT_MODEL:-$DEFAULT_MODEL}"
read -rp "Max history to display [$DEFAULT_MAX_HISTORY]: " INPUT_MAX_HISTORY
MAX_HISTORY="${INPUT_MAX_HISTORY:-$DEFAULT_MAX_HISTORY}"
# ── Step 4: Write config ────────────────────────────────────────────────────
mkdir -p "$SHELLGUARD_DIR"
"$PYTHON" -c "
import json
config = {
'base_url': '$BASE_URL',
'api_key': '$API_KEY',
'model': '$MODEL',
'max_history_display': int('$MAX_HISTORY'),
'risk_cache_ttl_seconds': 3600,
'auto_analyze': False,
}
with open('$SHELLGUARD_DIR/config.json', 'w') as f:
json.dump(config, f, indent=2)
"
success "Config written to $SHELLGUARD_DIR/config.json"
# ── Step 5: Copy files ──────────────────────────────────────────────────────
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
mkdir -p "$BIN_DIR"
mkdir -p "$LIB_DIR"
# Copy CLI scripts
cp "$SCRIPT_DIR/shellguard" "$BIN_DIR/shellguard"
cp "$SCRIPT_DIR/shellguard-log" "$BIN_DIR/shellguard-log"
chmod +x "$BIN_DIR/shellguard" "$BIN_DIR/shellguard-log"
# Copy library
cp -r "$SCRIPT_DIR/shellguard_core" "$LIB_DIR/"
success "Files installed to $BIN_DIR/"
success "Library installed to $LIB_DIR/"
# Ensure ~/.local/bin is in PATH message
if [[ ":$PATH:" != *":$HOME/.local/bin:"* ]]; then
warn "$BIN_DIR is not in your PATH."
warn "Add this to your shell config: export PATH=\"\$HOME/.local/bin:\$PATH\""
fi
# ── Step 6: Inject shell hooks (idempotent) ─────────────────────────────────
inject_bash_hook() {
local RC="$1"
if [ ! -f "$RC" ]; then
touch "$RC"
fi
if grep -qF "$HOOK_MARKER" "$RC" 2>/dev/null; then
warn "Bash hook already present in $RC (skipping)"
return
fi
cat >> "$RC" << 'BASH_HOOK'
# >>> shellguard hook >>>
# ShellGuard — terminal security monitor hook
_shellguard_prev_cmd=""
_shellguard_preexec() {
_shellguard_prev_cmd="$BASH_COMMAND"
}
_shellguard_precmd() {
local _exit=$?
local _cmd="$_shellguard_prev_cmd"
local _cwd="$PWD"
if [ -n "$_cmd" ] && [ "$_cmd" != "$PROMPT_COMMAND" ]; then
"$HOME/.local/bin/shellguard-log" --cmd "$_cmd" --cwd "$_cwd" --exit "$_exit" &>/dev/null &
fi
_shellguard_prev_cmd=""
}
trap '_shellguard_preexec' DEBUG
if [[ "$PROMPT_COMMAND" != *"_shellguard_precmd"* ]]; then
PROMPT_COMMAND="_shellguard_precmd${PROMPT_COMMAND:+; $PROMPT_COMMAND}"
fi
# <<< shellguard hook <<<
BASH_HOOK
success "Bash hook injected into $RC"
}
inject_zsh_hook() {
local RC="$1"
if [ ! -f "$RC" ]; then
touch "$RC"
fi
if grep -qF "$HOOK_MARKER" "$RC" 2>/dev/null; then
warn "Zsh hook already present in $RC (skipping)"
return
fi
cat >> "$RC" << 'ZSH_HOOK'
# >>> shellguard hook >>>
# ShellGuard — terminal security monitor hook
_shellguard_cmd=""
_shellguard_preexec() {
_shellguard_cmd="$1"
}
_shellguard_precmd() {
local _exit=$?
if [ -n "$_shellguard_cmd" ]; then
"$HOME/.local/bin/shellguard-log" --cmd "$_shellguard_cmd" --cwd "$PWD" --exit "$_exit" &>/dev/null &
_shellguard_cmd=""
fi
}
autoload -Uz add-zsh-hook 2>/dev/null || true
add-zsh-hook preexec _shellguard_preexec 2>/dev/null || preexec_functions+=(_shellguard_preexec)
add-zsh-hook precmd _shellguard_precmd 2>/dev/null || precmd_functions+=(_shellguard_precmd)
# <<< shellguard hook <<<
ZSH_HOOK
success "Zsh hook injected into $RC"
}
# Detect which shell configs to update
INJECTED=0
if [ -f "$HOME/.bashrc" ] || [ "$SHELL" = "/bin/bash" ] || [ "$SHELL" = "/usr/bin/bash" ]; then
inject_bash_hook "$HOME/.bashrc"
INJECTED=1
fi
if [ -f "$HOME/.zshrc" ] || [ "$SHELL" = "/bin/zsh" ] || [ "$SHELL" = "/usr/bin/zsh" ]; then
inject_zsh_hook "$HOME/.zshrc"
INJECTED=1
fi
if [ "$INJECTED" -eq 0 ]; then
warn "Could not detect shell type. Manually add hooks to your shell config."
warn "Bash: Add the contents of install.sh's BASH_HOOK section to ~/.bashrc"
warn "Zsh: Add the contents of install.sh's ZSH_HOOK section to ~/.zshrc"
fi
# ── Step 7: Final instructions ──────────────────────────────────────────────
echo ""
echo -e "${BOLD}${GREEN}✔ ShellGuard installed successfully!${RESET}"
echo ""
echo "Next steps:"
echo " 1. Reload your shell: source ~/.bashrc (or ~/.zshrc)"
echo " 2. Run a few commands, then launch the TUI:"
echo " shellguard"
echo ""
echo "Commands:"
echo " shellguard — Open TUI (command history + risk analysis)"
echo " shellguard analyze — Batch analyze all untagged commands"
echo " shellguard ask \"...\" — One-shot question about your history"
echo " shellguard clear — Clear LLM analysis cache"
echo ""