123 lines
5 KiB
Shell
Executable file
123 lines
5 KiB
Shell
Executable file
#!/bin/bash
|
||
# zy-evidence-gate.sh — 提交检测站 v1.0(冰朔20260827整改令)
|
||
# 正本:TC-TCS核心卷/TCS-PROTOCOL-ZY001-EVIDENCE-GATE-0001.tcs
|
||
# 模式:参照FlagOS平台提交流——证据不全=驳回;证据齐→自动唤起核查Agent验真→PASS才执行→回执落盘。
|
||
# 用法:
|
||
# zy-evidence-gate.sh submit --action A --claim C --source-desc S --evidence-file F --quote Q --then "CMD"
|
||
# zy-evidence-gate.sh hook (PreToolUse 拦截:敏感工程命令无 @EV- 票号即驳回)
|
||
# zy-evidence-gate.sh verify (全量票据审计)
|
||
set -uo pipefail
|
||
W="/Volumes/JZAO/铸渊-ICE-GL-ZY001"
|
||
EV="$W/BRIDGE/evidence"
|
||
TICKETS="$EV/tickets"
|
||
VERIFY_AGENT="$W/BRIDGE/tools/zy-evidence-verify.mjs"
|
||
mkdir -p "$TICKETS" "$EV/sources"
|
||
|
||
die() { echo "EVIDENCE-GATE ✗ $1" >&2; [ $# -gt 1 ] && echo " $2" >&2; exit 1; }
|
||
ok() { echo "EVIDENCE-GATE ✓ $1"; }
|
||
|
||
sha256() { /usr/bin/shasum -a 256 "$1" | awk '{print $1}'; }
|
||
next_ticket_id() {
|
||
local d n id
|
||
d=$(date +%Y%m%d)
|
||
n=$(ls "$TICKETS" 2>/dev/null | grep -c "^EV-$d" || true)
|
||
printf 'EV-%s-%04d' "$d" $((n + 1))
|
||
}
|
||
|
||
case "${1:-}" in
|
||
submit)
|
||
shift
|
||
ACTION=""; CLAIM=""; SOURCE_DESC=""; EVIDENCE_FILE=""; QUOTE=""; THEN_CMD=""
|
||
while [ $# -gt 0 ]; do
|
||
case "$1" in
|
||
--action) ACTION="$2"; shift 2;;
|
||
--claim) CLAIM="$2"; shift 2;;
|
||
--source-desc) SOURCE_DESC="$2"; shift 2;;
|
||
--evidence-file) EVIDENCE_FILE="$2"; shift 2;;
|
||
--quote) QUOTE="$2"; shift 2;;
|
||
--then) THEN_CMD="$2"; shift 2;;
|
||
*) die "USAGE" "submit --action --claim --source-desc --evidence-file --quote --then CMD";;
|
||
esac
|
||
done
|
||
# ① 四要素齐全性(缺=猜)
|
||
[ -n "$ACTION" ] && [ -n "$CLAIM" ] && [ -n "$SOURCE_DESC" ] && [ -n "$EVIDENCE_FILE" ] && [ -n "$QUOTE" ] && [ -n "$THEN_CMD" ] \
|
||
|| die "REJECTED_NO_EVIDENCE" "动作/主张/来源/证据文件/引文/命令 六件缺一——拿不出证据=猜的,驳回。"
|
||
|
||
# ② 出票并自动唤起核查 Agent
|
||
TID=$(next_ticket_id)
|
||
TP="$TICKETS/$TID.json"
|
||
ABS_EV="$EVIDENCE_FILE"
|
||
case "$ABS_EV" in /*) ;; *) ABS_EV="$W/$EVIDENCE_FILE";; esac
|
||
[ -r "$ABS_EV" ] || die "REJECTED_EVIDENCE_MISSING" "证据文件不存在: ${ABS_EV}(先把原文落盘再谈提交)"
|
||
ESHA=$(sha256 "$ABS_EV")
|
||
python3 - "$TP" "$TID" "$ACTION" "$CLAIM" "$SOURCE_DESC" "$EVIDENCE_FILE" "$ESHA" "$QUOTE" "$THEN_CMD" <<'PY'
|
||
import json,sys
|
||
tp,tid,action,claim,sd,evf,esha,quote,cmd=sys.argv[1:10]
|
||
json.dump({"ticket":tid,"action":action,"claim":claim,"source_desc":sd,
|
||
"evidence_file":evf,"evidence_sha256":esha,"quote":quote,"command":cmd,
|
||
"status":"PENDING_AUDIT"},open(tp,"w"),ensure_ascii=False,indent=1)
|
||
PY
|
||
AUDIT_OUT=$(node "$VERIFY_AGENT" "$TP" 2>&1)
|
||
AUDIT_RC=$?
|
||
if [ $AUDIT_RC -ne 0 ]; then
|
||
echo "$AUDIT_OUT" >&2
|
||
die "REJECTED_BY_AUDIT_AGENT" "核查Agent判定证据不实——提交驳回,票据已留痕: $TP"
|
||
fi
|
||
echo "$AUDIT_OUT" | tail -n +2 | head -8
|
||
|
||
# ③ 核查通过 → 执行提交 → 回执
|
||
RECEIPT="RE-$(date +%Y%m%d-%H%M%S)-$(printf '%s' "$THEN_CMD" | shasum -a 256 | awk '{print substr($1,1,8)}')"
|
||
python3 - "$TP" "$RECEIPT" <<'PY'
|
||
import json,sys
|
||
tp,r=sys.argv[1:3]
|
||
t=json.load(open(tp)); t["receipt"]=r; t["status"]="EXECUTED"
|
||
json.dump(t,open(tp,"w"),ensure_ascii=False,indent=1)
|
||
PY
|
||
if eval "$THEN_CMD"; then
|
||
ok "$TID 核查PASS已执行 | 回执 $RECEIPT | $ACTION"
|
||
else
|
||
die "COMMAND_FAILED" "命令执行失败(票据 $TID 已留痕,证据链仍有效)"
|
||
fi
|
||
;;
|
||
|
||
hook)
|
||
# PreToolUse:敏感工程命令必须内联 @EV-xxxx 票号且该票核查PASS
|
||
INPUT=$(cat)
|
||
CMD_LINE=$(printf '%s' "$INPUT" | python3 -c 'import json,sys
|
||
try:
|
||
d=json.load(sys.stdin)
|
||
print(d.get("tool_input",{}).get("command",""))
|
||
except Exception:
|
||
print("")' 2>/dev/null)
|
||
SENSITIVE='zip |git (commit|push|tag)|pip3? install|curl .*(-X|--request) *(POST|PUT|DELETE)|cp .*Desktop|mv .*Desktop|rm -'
|
||
if printf '%s' "$CMD_LINE" | grep -qE "$SENSITIVE"; then
|
||
TID=$(printf '%s' "$CMD_LINE" | grep -oE '@EV-[0-9]{8}-[0-9]{4}' | head -1 | sed 's/^@//')
|
||
if [ -z "$TID" ]; then
|
||
echo "【证据门 ✗ 拦截】敏感工程命令未携带证据票号(@EV-YYYYMMDD-NNNN)。" >&2
|
||
echo "流程:证据原文先落盘 BRIDGE/evidence/sources/ → zy-evidence-gate.sh submit 出票(自动核查)→ 命令内引用 @票号。拿不出证据=猜的=驳回。" >&2
|
||
exit 2
|
||
fi
|
||
TP="$TICKETS/$TID.json"
|
||
ST=$(python3 -c "import json;print(json.load(open('$TP'))['status'])" 2>/dev/null || echo "MISSING")
|
||
if [ "$ST" != "VERIFIED" ] && [ "$ST" != "EXECUTED" ]; then
|
||
echo "【证据门 ✗ 拦截】票号 $TID 不存在或未通过核查(状态:${ST})。先走 submit 流程拿有效票。" >&2
|
||
exit 2
|
||
fi
|
||
fi
|
||
exit 0
|
||
;;
|
||
|
||
verify)
|
||
FAIL=0; N=0
|
||
for tp in "$TICKETS"/EV-*.json; do
|
||
[ -f "$tp" ] || continue
|
||
N=$((N+1))
|
||
node "$VERIFY_AGENT" "$tp" >/dev/null 2>&1 || { echo "FAIL $tp"; FAIL=$((FAIL+1)); }
|
||
done
|
||
echo "EVIDENCE-GATE verify: $N 票, $FAIL 失败"
|
||
[ $FAIL -eq 0 ]
|
||
;;
|
||
|
||
*)
|
||
die "USAGE" "zy-evidence-gate.sh submit|hook|verify";;
|
||
esac
|