Files
Agent-System-Dev/scripts/evidence.sh
T
weichen efa701279f Fix evidence CMD quoting and record first tool self-tests
Why: the make-variable pass-through re-quoted CMD and broke any command
containing quotes (caught by the redaction self-test before it could run).

Evidence: redaction self-test now records 'token <redacted> hello' with quoting
intact (row sha256 aae6a895); negative 'false' case earlier recorded exit=1
row and propagated rc — both in the task card evidence table.

Impact: CMD now travels via environment (CMD="..." make evidence); SRC/TAIL
stay make variables; usage strings updated in Makefile/AGENTS.md/task.sh
template comment.

Refs: task card evidence table; guidelines draft.10 tool-written-evidence rule.
2026-10-05 10:48:31 +00:00

56 lines
3.0 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# 证据写入工具:执行命令,把(命令、被测 HEAD、退出码、输出 sha256、尾部摘录、时间、来源)
# 追加到当前分支任务卡的「## 证据(Evidence)」表。规范依据:AGENTS.md「证据与验证门禁」、
# guidelines standards/verification.md「声明与证据来源」——转写/手抄的输出视为无效证据。
# 用法:CMD="<单行命令>" make evidence [SRC=SELF|REPLAY|GATE] [TAIL=15]
# (CMD 经环境变量直传;也可直接 CMD=… SRC=… TAIL=… bash scripts/evidence.sh)
# 退出码 = 被执行命令的退出码(失败可见),证据行无论成败都会写入。
set -uo pipefail
CMD="${CMD:-}"; SRC="${SRC:-SELF}"; TAILN="${TAIL:-15}"
[ -n "$CMD" ] || { echo 'usage: make evidence CMD="<command>" [SRC=SELF|REPLAY|GATE] [TAIL=15]' >&2; exit 2; }
case "$SRC" in SELF|REPLAY|GATE) ;; *) echo "ERROR: SRC 须为 SELF|REPLAY|GATE(当前:$SRC)" >&2; exit 2 ;; esac
case "$TAILN" in ''|*[!0-9]*) TAILN=15 ;; esac
case "$CMD" in *$'\n'*) echo 'ERROR: CMD 须为单行命令' >&2; exit 2 ;; esac
branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null)
[ -n "$branch" ] || { echo "ERROR: 不在 git 仓库内" >&2; exit 1; }
slug=$(echo "$branch" | tr '/' '-')
card=".task/${slug}.md"
if [ ! -f "$card" ]; then
# 回退:按卡片「分支:」字段匹配(与 task.sh cmd_sync 同款口径)
for pc in .task/*.md; do
[ -f "$pc" ] || continue
if [ "$(sed -n 's/^- 工作区:.*分支:\([A-Za-z0-9._/-]\+\).*/\1/p' "$pc" | head -1)" = "$branch" ]; then
card=$pc; break
fi
done
fi
[ -f "$card" ] || { echo "ERROR: 找不到分支 ${branch} 的任务卡(.task/${slug}.md)" >&2; exit 1; }
head=$(git rev-parse HEAD)
short_head=$(echo "$head" | cut -c1-10)
ts=$(date -u +%FT%TZ)
tmp=$(mktemp); trap 'rm -f "$tmp"' EXIT
bash -c "$CMD" >"$tmp" 2>&1; rc=$?
digest=$(sha256sum "$tmp" | cut -c1-16)
# 脱敏(baseline 硬边界 2):token 风格的 40 位 hex / Authorization 头不打进任务卡。
sanitize() {
sed -E -e 's/(token[ =:]+)[0-9a-fA-F]{40}/\1<redacted>/g' \
-e 's/(Authorization: *token +)[^ ]+/\1<redacted>/Ig' \
-e 's/(access_token[=:]+)[0-9a-fA-F]{40}/\1<redacted>/Ig'
}
if ! grep -q '^## 证据(Evidence)' "$card"; then
printf '\n## 证据(Evidence)\n\n<!-- make evidence CMD="…" 写入;手抄/转写输出视为无效证据(AGENTS.md 证据与验证门禁)。 -->\n| 时间(UTC) | 命令 | 被测HEAD | exit | 来源 | sha256(16) |\n|---|---|---|---|---|---|\n' >> "$card"
fi
cmd_cell=$(echo "$CMD" | sed -e 's/|/\\|/g' -e 's/`/‘/g')
printf '| %s | `%s` | %s | %d | %s | %s |\n' "$ts" "$cmd_cell" "$short_head" "$rc" "$SRC" "$digest" >> "$card"
printf '\n<!-- evidence:run %s -->\n```\n$ %s\n[exit %d | HEAD %s | sha256:%s] 输出尾部 %s 行:\n%s\n```\n' \
"$ts" "$CMD" "$rc" "$short_head" "$digest" "$TAILN" "$(tail -n "$TAILN" "$tmp" | sanitize)" >> "$card"
echo "[evidence] card=$card cmd=\"${CMD}\" exit=$rc src=$SRC head=$short_head sha256=$digest"
exit "$rc"