Initial commit with translated description
This commit is contained in:
28
scripts/safe-exec-ai-wrapper.sh
Normal file
28
scripts/safe-exec-ai-wrapper.sh
Normal file
@@ -0,0 +1,28 @@
|
||||
#!/bin/bash
|
||||
# SafeExec AI Wrapper - 上下文感知集成
|
||||
# 用于 OpenClaw Agent 集成,自动传递用户消息上下文
|
||||
|
||||
SAFE_EXEC_BIN="$HOME/.local/bin/safe-exec"
|
||||
|
||||
# 从参数或环境变量获取上下文
|
||||
if [[ $# -ge 2 ]]; then
|
||||
# 命令行参数模式: safe-exec-ai "用户上下文" "命令"
|
||||
USER_CONTEXT="$1"
|
||||
COMMAND="$2"
|
||||
shift 2
|
||||
elif [[ -n "${SAFEXEC_CONTEXT:-}" ]]; then
|
||||
# 环境变量模式
|
||||
USER_CONTEXT="$SAFEXEC_CONTEXT"
|
||||
COMMAND="$1"
|
||||
shift
|
||||
else
|
||||
# 没有上下文,直接执行
|
||||
exec $SAFE_EXEC_BIN "$@"
|
||||
exit $?
|
||||
fi
|
||||
|
||||
# 导出上下文环境变量
|
||||
export SAFEXEC_CONTEXT="$USER_CONTEXT"
|
||||
|
||||
# 执行命令
|
||||
exec $SAFE_EXEC_BIN "$COMMAND"
|
||||
73
scripts/safe-exec-approve.sh
Normal file
73
scripts/safe-exec-approve.sh
Normal file
@@ -0,0 +1,73 @@
|
||||
#!/bin/bash
|
||||
# safe-exec-approve - 批准待执行的命令
|
||||
|
||||
REQUEST_ID="$1"
|
||||
SAFE_EXEC_DIR="$HOME/.openclaw/safe-exec"
|
||||
PENDING_DIR="$SAFE_EXEC_DIR/pending"
|
||||
|
||||
if [[ -z "$REQUEST_ID" ]]; then
|
||||
echo "用法: safe-exec-approve <request_id>"
|
||||
echo ""
|
||||
echo "查看待处理的请求:"
|
||||
echo " ls ~/.openclaw/safe-exec/pending/"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
REQUEST_FILE="$PENDING_DIR/$REQUEST_ID.json"
|
||||
|
||||
if [[ ! -f "$REQUEST_FILE" ]]; then
|
||||
echo "❌ 请求 $REQUEST_ID 不存在"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 读取请求信息
|
||||
COMMAND=$(jq -r '.command' "$REQUEST_FILE")
|
||||
RISK=$(jq -r '.risk' "$REQUEST_FILE")
|
||||
|
||||
# 检测运行环境
|
||||
IS_INTERACTIVE=false
|
||||
if [[ -t 0 ]]; then
|
||||
# 检查 stdin 是否是终端
|
||||
IS_INTERACTIVE=true
|
||||
fi
|
||||
|
||||
# 检查是否由 OpenClaw Agent 调用
|
||||
if [[ -n "$OPENCLAW_AGENT_CALL" ]] || [[ -n "$SAFE_EXEC_AUTO_CONFIRM" ]]; then
|
||||
IS_INTERACTIVE=false
|
||||
fi
|
||||
|
||||
echo "⚠️ 即将执行以下命令:"
|
||||
echo ""
|
||||
echo "风险等级: ${RISK^^}"
|
||||
echo "命令: $COMMAND"
|
||||
echo ""
|
||||
|
||||
# 请求确认(仅在交互式环境)
|
||||
if [[ "$IS_INTERACTIVE" == "true" ]]; then
|
||||
read -p "确认执行?(yes/no): " confirm
|
||||
if [[ "$confirm" != "yes" ]]; then
|
||||
echo "❌ 已取消"
|
||||
exit 0
|
||||
fi
|
||||
echo "✅ 已确认"
|
||||
else
|
||||
echo "🤖 非交互式环境 - 自动跳过确认"
|
||||
fi
|
||||
|
||||
# 标记为已批准并执行
|
||||
jq '.status = "approved"' "$REQUEST_FILE" > "$REQUEST_FILE.tmp" && mv "$REQUEST_FILE.tmp" "$REQUEST_FILE"
|
||||
|
||||
echo "✅ 执行中..."
|
||||
eval "$COMMAND"
|
||||
exit_code=$?
|
||||
|
||||
# 清理已处理的请求
|
||||
rm "$REQUEST_FILE"
|
||||
|
||||
if [[ $exit_code -eq 0 ]]; then
|
||||
echo "✅ 命令执行成功"
|
||||
else
|
||||
echo "⚠️ 命令执行失败(退出码: $exit_code)"
|
||||
fi
|
||||
|
||||
exit $exit_code
|
||||
41
scripts/safe-exec-list.sh
Normal file
41
scripts/safe-exec-list.sh
Normal file
@@ -0,0 +1,41 @@
|
||||
#!/bin/bash
|
||||
# safe-exec-list - 列出所有待处理的批准请求
|
||||
|
||||
SAFE_EXEC_DIR="$HOME/.openclaw/safe-exec"
|
||||
PENDING_DIR="$SAFE_EXEC_DIR/pending"
|
||||
|
||||
if [[ ! -d "$PENDING_DIR" ]]; then
|
||||
echo "没有待处理的请求"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
REQUESTS=("$PENDING_DIR"/*.json)
|
||||
|
||||
if [[ ! -e "${REQUESTS[0]}" ]]; then
|
||||
echo "没有待处理的请求"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "📋 待处理的批准请求:"
|
||||
echo ""
|
||||
|
||||
for request_file in "${REQUESTS[@]}"; do
|
||||
if [[ -f "$request_file" ]]; then
|
||||
request_id=$(basename "$request_file" .json)
|
||||
command=$(jq -r '.command' "$request_file")
|
||||
risk=$(jq -r '.risk' "$request_file")
|
||||
reason=$(jq -r '.reason' "$request_file")
|
||||
timestamp=$(jq -r '.timestamp' "$request_file")
|
||||
time_str=$(date -d "@$timestamp" "+%Y-%m-%d %H:%M:%S" 2>/dev/null || echo "未知时间")
|
||||
|
||||
echo "📌 请求 ID: $request_id"
|
||||
echo " 风险: ${risk^^}"
|
||||
echo " 命令: $command"
|
||||
echo " 原因: $reason"
|
||||
echo " 时间: $time_str"
|
||||
echo ""
|
||||
fi
|
||||
done
|
||||
|
||||
echo "批准命令: safe-exec-approve <request_id>"
|
||||
echo "拒绝命令: safe-exec-reject <request_id>"
|
||||
38
scripts/safe-exec-reject.sh
Normal file
38
scripts/safe-exec-reject.sh
Normal file
@@ -0,0 +1,38 @@
|
||||
#!/bin/bash
|
||||
# safe-exec-reject - 拒绝待执行的命令
|
||||
|
||||
REQUEST_ID="$1"
|
||||
SAFE_EXEC_DIR="$HOME/.openclaw/safe-exec"
|
||||
PENDING_DIR="$SAFE_EXEC_DIR/pending"
|
||||
|
||||
if [[ -z "$REQUEST_ID" ]]; then
|
||||
echo "用法: safe-exec-reject <request_id>"
|
||||
echo ""
|
||||
echo "查看待处理的请求:"
|
||||
echo " ls ~/.openclaw/safe-exec/pending/"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
REQUEST_FILE="$PENDING_DIR/$REQUEST_ID.json"
|
||||
|
||||
if [[ ! -f "$REQUEST_FILE" ]]; then
|
||||
echo "❌ 请求 $REQUEST_ID 不存在"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 读取请求信息
|
||||
COMMAND=$(jq -r '.command' "$REQUEST_FILE")
|
||||
|
||||
# 标记为已拒绝
|
||||
jq '.status = "rejected"' "$REQUEST_FILE" > "$REQUEST_FILE.tmp" && mv "$REQUEST_FILE.tmp" "$REQUEST_FILE"
|
||||
|
||||
echo "❌ 命令已拒绝: $COMMAND"
|
||||
|
||||
# 记录到审计日志
|
||||
AUDIT_LOG="$HOME/.openclaw/safe-exec-audit.log"
|
||||
echo "{\"timestamp\":\"$(date -u +"%Y-%m-%dT%H:%M:%S.%3NZ")\",\"event\":\"rejected\",\"requestId\":\"$REQUEST_ID\",\"command\":\"$(echo "$COMMAND" | jq -Rs .)\"}" >> "$AUDIT_LOG"
|
||||
|
||||
# 清理已处理的请求
|
||||
rm "$REQUEST_FILE"
|
||||
|
||||
echo "请求已拒绝并清理"
|
||||
404
scripts/safe-exec.sh
Normal file
404
scripts/safe-exec.sh
Normal file
@@ -0,0 +1,404 @@
|
||||
#!/bin/bash
|
||||
# SafeExec v0.3.3 - 安全增强版本
|
||||
# 移除监控组件,添加完整的 metadata 声明
|
||||
|
||||
SAFE_EXEC_DIR="$HOME/.openclaw/safe-exec"
|
||||
AUDIT_LOG="$HOME/.openclaw/safe-exec-audit.log"
|
||||
PENDING_DIR="$SAFE_EXEC_DIR/pending"
|
||||
RULES_FILE="$HOME/.openclaw/safe-exec-rules.json"
|
||||
REQUEST_TIMEOUT=300 # 5分钟超时
|
||||
|
||||
# 上下文感知配置
|
||||
USER_CONTEXT="${SAFEXEC_CONTEXT:-}"
|
||||
|
||||
mkdir -p "$PENDING_DIR"
|
||||
|
||||
# 检查 SafeExec 是否启用
|
||||
is_enabled() {
|
||||
if [[ ! -f "$RULES_FILE" ]]; then
|
||||
echo "true"
|
||||
return
|
||||
fi
|
||||
|
||||
# 检查文件格式
|
||||
local first_char=$(head -c 1 "$RULES_FILE")
|
||||
|
||||
if [[ "$first_char" == "[" ]]; then
|
||||
# 数组格式,默认启用
|
||||
echo "true"
|
||||
return
|
||||
fi
|
||||
|
||||
# 对象格式,检查 enabled 字段
|
||||
local enabled
|
||||
enabled=$(jq -r 'if .enabled == true then "true" else "false" end' "$RULES_FILE" 2>/dev/null)
|
||||
|
||||
# 如果解析失败,默认启用
|
||||
if [[ -z "$enabled" ]] || [[ "$enabled" == "null" ]]; then
|
||||
echo "true"
|
||||
else
|
||||
echo "$enabled"
|
||||
fi
|
||||
}
|
||||
|
||||
# 设置启用状态
|
||||
set_enabled() {
|
||||
local value="$1"
|
||||
|
||||
if [[ ! -f "$RULES_FILE" ]]; then
|
||||
echo "{\"enabled\":$value,\"rules\":[]}" > "$RULES_FILE"
|
||||
else
|
||||
# 检查文件格式(数组 vs 对象)
|
||||
local first_char=$(head -c 1 "$RULES_FILE")
|
||||
|
||||
if [[ "$first_char" == "[" ]]; then
|
||||
# 当前是数组格式,转换为对象格式
|
||||
local rules_array=$(cat "$RULES_FILE")
|
||||
echo "{\"enabled\":$value,\"rules\":$rules_array}" > "$RULES_FILE"
|
||||
else
|
||||
# 当前是对象格式,直接更新
|
||||
jq ".enabled = $value" "$RULES_FILE" > "$RULES_FILE.tmp" && mv "$RULES_FILE.tmp" "$RULES_FILE"
|
||||
fi
|
||||
fi
|
||||
|
||||
local status
|
||||
if [[ "$value" == "true" ]]; then
|
||||
status="✅ 已启用"
|
||||
else
|
||||
status="❌ 已禁用"
|
||||
fi
|
||||
|
||||
echo "$status"
|
||||
log_audit "toggle" "{\"enabled\":$value}"
|
||||
}
|
||||
|
||||
# 获取自定义确认关键词
|
||||
get_confirmation_keywords() {
|
||||
if [[ ! -f "$RULES_FILE" ]]; then
|
||||
# 默认关键词
|
||||
echo "我已明确风险|I understand the risk"
|
||||
return
|
||||
fi
|
||||
|
||||
# 检查文件格式
|
||||
local first_char=$(head -c 1 "$RULES_FILE")
|
||||
|
||||
if [[ "$first_char" == "[" ]]; then
|
||||
# 数组格式,返回默认关键词
|
||||
echo "我已明确风险|I understand the risk"
|
||||
return
|
||||
fi
|
||||
|
||||
# 对象格式,尝试读取自定义关键词
|
||||
local keywords
|
||||
keywords=$(jq -r '.contextAware.confirmationKeywords // "我已明确风险|I understand the risk"' "$RULES_FILE" 2>/dev/null)
|
||||
|
||||
if [[ -z "$keywords" ]] || [[ "$keywords" == "null" ]]; then
|
||||
echo "我已明确风险|I understand the risk"
|
||||
else
|
||||
echo "$keywords"
|
||||
fi
|
||||
}
|
||||
|
||||
# 检测用户明确确认
|
||||
detect_user_confirmation() {
|
||||
local context="$1"
|
||||
local keywords=$(get_confirmation_keywords)
|
||||
|
||||
# 检查上下文中是否包含确认关键词
|
||||
if echo "$context" | grep -qE "$keywords"; then
|
||||
echo "confirmed"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "normal"
|
||||
return 1
|
||||
}
|
||||
|
||||
# 显示当前状态
|
||||
show_status() {
|
||||
local enabled
|
||||
enabled=$(is_enabled)
|
||||
|
||||
echo "🛡️ SafeExec 状态"
|
||||
echo ""
|
||||
|
||||
if [[ "$enabled" == "true" ]]; then
|
||||
echo "状态: ✅ **已启用**"
|
||||
echo ""
|
||||
echo "危险命令将被拦截并请求批准。"
|
||||
else
|
||||
echo "状态: ❌ **已禁用**"
|
||||
echo ""
|
||||
echo "⚠️ 所有命令将直接执行,不受保护!"
|
||||
echo "建议仅在可信环境中禁用。"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "切换状态:"
|
||||
echo " 启用: safe-exec --enable"
|
||||
echo " 禁用: safe-exec --disable"
|
||||
}
|
||||
|
||||
# 清理过期的请求
|
||||
cleanup_expired_requests() {
|
||||
local now=$(date +%s)
|
||||
local count=0
|
||||
|
||||
for request_file in "$PENDING_DIR"/*.json; do
|
||||
if [[ -f "$request_file" ]]; then
|
||||
local timestamp=$(jq -r '.timestamp' "$request_file" 2>/dev/null)
|
||||
if [[ -n "$timestamp" ]]; then
|
||||
local age=$((now - timestamp))
|
||||
if [[ $age -gt $REQUEST_TIMEOUT ]]; then
|
||||
local request_id=$(basename "$request_file" .json)
|
||||
jq '.status = "expired"' "$request_file" > "$request_file.tmp" && mv "$request_file.tmp" "$request_file"
|
||||
echo "{\"timestamp\":\"$(date -u +"%Y-%m-%dT%H:%M:%S.%3NZ")\",\"event\":\"expired\",\"requestId\":\"$request_id\",\"age\":$age}" >> "$AUDIT_LOG"
|
||||
rm -f "$request_file"
|
||||
count=$((count + 1))
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
return $count
|
||||
}
|
||||
|
||||
log_audit() {
|
||||
local event="$1"
|
||||
local data="$2"
|
||||
local timestamp=$(date -u +"%Y-%m-%dT%H:%M:%S.%3NZ")
|
||||
|
||||
# 构造完整的 JSON 对象
|
||||
# 注意:data 参数应该已经是 JSON 格式,但不带外层花括号
|
||||
# 例如:data='"requestId":"xxx","command":"xxx"'
|
||||
# 我们需要移除 data 的外层花括号(如果有的话)
|
||||
local clean_data="${data#{}" # 移除开头的 {
|
||||
clean_data="${clean_data%\}}" # 移除结尾的 }
|
||||
|
||||
echo "{\"timestamp\":\"$timestamp\",\"event\":\"$event\",$clean_data}" >> "$AUDIT_LOG"
|
||||
}
|
||||
|
||||
assess_risk() {
|
||||
local cmd="$1"
|
||||
local risk="low"
|
||||
local reason=""
|
||||
|
||||
if [[ "$cmd" == *":(){:|:&};:"* ]] || [[ "$cmd" == *":(){ :|:& };:"* ]]; then
|
||||
risk="critical"
|
||||
reason="Fork炸弹"
|
||||
elif echo "$cmd" | grep -qE 'rm[[:space:]]+-rf[[:space:]]+[\/~]'; then
|
||||
risk="critical"
|
||||
reason="删除根目录或家目录文件"
|
||||
elif echo "$cmd" | grep -qE 'dd[[:space:]]+if='; then
|
||||
risk="critical"
|
||||
reason="磁盘破坏命令"
|
||||
elif echo "$cmd" | grep -qE 'mkfs\.'; then
|
||||
risk="critical"
|
||||
reason="格式化文件系统"
|
||||
elif echo "$cmd" | grep -qE '>[[:space:]]*/dev/sd[a-z]'; then
|
||||
risk="critical"
|
||||
reason="直接写入磁盘"
|
||||
elif echo "$cmd" | grep -qE 'chmod[[:space:]]+777'; then
|
||||
risk="high"
|
||||
reason="设置文件为全局可写"
|
||||
elif echo "$cmd" | grep -qE '>[[:space:]]*/(etc|boot|sys|root)/'; then
|
||||
risk="high"
|
||||
reason="写入系统目录"
|
||||
elif echo "$cmd" | grep -qE '(curl|wget).*|[[:space:]]*(bash|sh|python)'; then
|
||||
risk="high"
|
||||
reason="管道下载到shell"
|
||||
elif echo "$cmd" | grep -qE 'sudo[[:space:]]+'; then
|
||||
risk="medium"
|
||||
reason="使用特权执行"
|
||||
elif echo "$cmd" | grep -qE 'iptables|firewall-cmd|ufw'; then
|
||||
risk="medium"
|
||||
reason="修改防火墙规则"
|
||||
fi
|
||||
|
||||
echo "{\"risk\":\"$risk\",\"reason\":\"$reason\"}"
|
||||
}
|
||||
|
||||
request_approval() {
|
||||
local command="$1"
|
||||
local risk="$2"
|
||||
local reason="$3"
|
||||
local request_id="req_$(date +%s)_$(shuf -i 1000-9999 -n 1)"
|
||||
|
||||
echo "{\"id\":\"$request_id\",\"command\":$(echo "$command" | jq -Rs .),\"risk\":\"$risk\",\"reason\":\"$reason\",\"timestamp\":$(date +%s),\"status\":\"pending\"}" > "$PENDING_DIR/$request_id.json"
|
||||
|
||||
log_audit "approval_requested" "{\"requestId\":\"$request_id\",\"command\":$(echo "$command" | jq -Rs .),\"risk\":\"$risk\",\"reason\":\"$reason\"}"
|
||||
|
||||
cat <<EOF
|
||||
|
||||
🚨 **危险操作检测 - 命令已拦截**
|
||||
|
||||
**风险等级:** ${risk^^}
|
||||
**命令:** \`$command\`
|
||||
**原因:** $reason
|
||||
|
||||
**请求 ID:** \`$request_id\`
|
||||
|
||||
ℹ️ 此命令需要用户批准才能执行。
|
||||
|
||||
**批准方法:**
|
||||
1. 在终端运行: \`safe-exec-approve $request_id\`
|
||||
2. 或者: \`safe-exec-list\` 查看所有待处理请求
|
||||
|
||||
**拒绝方法:**
|
||||
\`safe-exec-reject $request_id\`
|
||||
|
||||
⏰ 请求将在 5 分钟后过期
|
||||
|
||||
EOF
|
||||
return 0
|
||||
}
|
||||
|
||||
main() {
|
||||
local command="$*"
|
||||
|
||||
if [[ -z "$command" ]]; then
|
||||
echo "用法: safe-exec \"<命令>\""
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 检查是否启用
|
||||
local enabled
|
||||
enabled=$(is_enabled)
|
||||
|
||||
if [[ "$enabled" != "true" ]]; then
|
||||
# SafeExec 已禁用,直接执行命令
|
||||
log_audit "bypassed" "{\"command\":$(echo "$command" | jq -Rs .),\"reason\":\"SafeExec disabled\"}"
|
||||
eval "$command"
|
||||
exit $?
|
||||
fi
|
||||
|
||||
# 自动清理过期请求
|
||||
cleanup_expired_requests
|
||||
|
||||
local assessment
|
||||
assessment=$(assess_risk "$command")
|
||||
local risk
|
||||
local reason
|
||||
risk=$(echo "$assessment" | jq -r '.risk')
|
||||
reason=$(echo "$assessment" | jq -r '.reason')
|
||||
|
||||
# ========== 上下文感知拦截 ==========
|
||||
# 检查用户是否提供了明确的确认关键词
|
||||
if [[ -n "$USER_CONTEXT" ]]; then
|
||||
local confirmation
|
||||
confirmation=$(detect_user_confirmation "$USER_CONTEXT")
|
||||
|
||||
if [[ "$confirmation" == "confirmed" ]]; then
|
||||
# 用户已明确风险,根据原风险等级决定处理方式
|
||||
if [[ "$risk" == "critical" ]]; then
|
||||
# CRITICAL 风险:降级到 MEDIUM(仍需批准,但降低警告级别)
|
||||
echo "⚠️ 检测到确认关键词,但风险等级为 CRITICAL"
|
||||
echo "ℹ️ 命令降级到 MEDIUM,但仍需批准"
|
||||
risk="medium"
|
||||
log_audit "context_aware_downgrade" "{\"originalRisk\":\"critical\",\"newRisk\":\"medium\",\"reason\":\"用户确认关键词\",\"context\":$(echo "$USER_CONTEXT" | jq -Rs .)}"
|
||||
elif [[ "$risk" == "high" ]]; then
|
||||
# HIGH 风险:降级到 LOW(直接执行)
|
||||
echo "✅ 检测到确认关键词,风险等级从 HIGH 降级到 LOW"
|
||||
echo "⚡ 直接执行命令: $command"
|
||||
log_audit "context_aware_allowed" "{\"originalRisk\":\"high\",\"newRisk\":\"low\",\"reason\":\"用户确认关键词\",\"context\":$(echo "$USER_CONTEXT" | jq -Rs .)}"
|
||||
eval "$command"
|
||||
exit $?
|
||||
elif [[ "$risk" == "medium" ]]; then
|
||||
# MEDIUM 风险:降级到 LOW(直接执行)
|
||||
echo "✅ 检测到确认关键词,风险等级从 MEDIUM 降级到 LOW"
|
||||
echo "⚡ 直接执行命令: $command"
|
||||
log_audit "context_aware_allowed" "{\"originalRisk\":\"medium\",\"newRisk\":\"low\",\"reason\":\"用户确认关键词\",\"context\":$(echo "$USER_CONTEXT" | jq -Rs .)}"
|
||||
eval "$command"
|
||||
exit $?
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
# ========== 上下文感知拦截结束 ==========
|
||||
|
||||
if [[ "$risk" == "low" ]]; then
|
||||
log_audit "allowed" "{\"command\":$(echo "$command" | jq -Rs .),\"risk\":\"low\"}"
|
||||
eval "$command"
|
||||
exit $?
|
||||
fi
|
||||
|
||||
request_approval "$command" "$risk" "$reason"
|
||||
exit 0
|
||||
}
|
||||
|
||||
# 处理命令行参数
|
||||
case "$1" in
|
||||
--enable)
|
||||
set_enabled "true"
|
||||
exit 0
|
||||
;;
|
||||
--disable)
|
||||
set_enabled "false"
|
||||
exit 0
|
||||
;;
|
||||
--status)
|
||||
show_status
|
||||
exit 0
|
||||
;;
|
||||
--approve)
|
||||
request_file="$PENDING_DIR/$2.json"
|
||||
if [[ -f "$request_file" ]]; then
|
||||
command=$(jq -r '.command' "$request_file")
|
||||
echo "✅ 执行命令: $command"
|
||||
log_audit "executed" "{\"requestId\":\"$2\"}"
|
||||
eval "$command"
|
||||
exit_code=$?
|
||||
rm -f "$request_file"
|
||||
exit $exit_code
|
||||
fi
|
||||
echo "❌ 请求不存在: $2"
|
||||
exit 1
|
||||
;;
|
||||
--reject)
|
||||
request_file="$PENDING_DIR/$2.json"
|
||||
if [[ -f "$request_file" ]]; then
|
||||
command=$(jq -r '.command' "$request_file")
|
||||
log_audit "rejected" "{\"requestId\":\"$2\"}"
|
||||
rm -f "$request_file"
|
||||
echo "❌ 请求已拒绝"
|
||||
exit 0
|
||||
fi
|
||||
echo "❌ 请求不存在: $2"
|
||||
exit 1
|
||||
;;
|
||||
--list)
|
||||
echo "📋 **待处理的批准请求:**"
|
||||
echo ""
|
||||
count=0
|
||||
for f in "$PENDING_DIR"/*.json; do
|
||||
if [[ -f "$f" ]]; then
|
||||
count=$((count + 1))
|
||||
id=$(basename "$f" .json)
|
||||
cmd=$(jq -r '.command' "$f")
|
||||
rsk=$(jq -r '.risk' "$f")
|
||||
reason=$(jq -r '.reason' "$f")
|
||||
printf "📌 **请求 %d**\n" "$count"
|
||||
printf " **ID:** \`%s\`\n" "$id"
|
||||
printf " **风险:** %s\n" "${rsk^^}"
|
||||
printf " **命令:** \`%s\`\n" "$cmd"
|
||||
printf " **原因:** %s\n" "$reason"
|
||||
echo ""
|
||||
printf " 批准: \`safe-exec-approve %s\`\n" "$id"
|
||||
printf " 拒绝: \`safe-exec-reject %s\`\n" "$id"
|
||||
echo ""
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ $count -eq 0 ]]; then
|
||||
echo "✅ 没有待处理的请求"
|
||||
fi
|
||||
exit 0
|
||||
;;
|
||||
--cleanup)
|
||||
cleanup_expired_requests
|
||||
echo "✅ 清理完成"
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user