123 lines
5 KiB
Shell
123 lines
5 KiB
Shell
|
|
#!/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
|