141 lines
6.1 KiB
Bash
Executable File
141 lines
6.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# S3 取证链:真实沙箱库 live DB harness 端到端 + 删 trigger 复验 + collector 重放幂等
|
||
# 一次原子执行(外部把 stdout+stderr 整体重定向到 chain log),避免沙箱库被并发进程
|
||
# DROP 造成竞态,也保证「日志内时间」与「日志文件本身」同源,不可事后拼接。
|
||
#
|
||
# 顺序:
|
||
# [1] 环境 + 时钟基线(date 与文件系统 mtime 两时钟源偏移实测)
|
||
# [2] RUN A:python3 tests/m5a_live_db_harness.py --keep(必做项2,grep ALL PASS 门禁)
|
||
# [3-0] RUN A 后 trigger 现状(0 条:harness 已不含 BEFORE INSERT 适配)
|
||
# [3-1] 按历史 DDL(git 80156fd) 复原适配 trigger → [3-2] drop 前 SHOW TRIGGERS
|
||
# [3-3] DROP 语句 → [3-4] drop 后 SHOW TRIGGERS(0 条)
|
||
# [3-5] RUN B:无该 trigger 状态下重跑 harness(必做项3,grep ALL PASS 门禁)
|
||
# [4] collector 重放幂等(必做项4,脚本自带 exit 1 判定)
|
||
# [4b] 重放后 id/行数复核 + trigger 终态
|
||
# [5] 清理沙箱库(DROP DATABASE 仅沙箱 schema,凭据不落盘)
|
||
# [6] 产物文件系统实测时间(ls -l --time-style=full-iso + stat + 同进程成对打印)
|
||
#
|
||
# 任一步失败立即终止(set -euo pipefail + 显式 grep 门禁),最终退出码写进日志末行。
|
||
# 路径全部由脚本自身位置推导,无绝对路径硬编码;OUT 目录可用 S3_OUT 覆盖。
|
||
set -euo pipefail
|
||
|
||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
REPO_ROOT="$(dirname "$SCRIPT_DIR")" # modules/pbl_evidence
|
||
WS="$(dirname "$(dirname "$REPO_ROOT")")" # 机构工作空间
|
||
OUT="${S3_OUT:-$WS/projects/pbls/docs/02-develop/evidence/s3}"
|
||
CHAIN_LOG="${S3_CHAIN_LOG:-$OUT/s3_chain.log}"
|
||
mkdir -p "$OUT"
|
||
cd "$REPO_ROOT"
|
||
|
||
ts() { date '+%Y-%m-%d %H:%M:%S %z'; }
|
||
now_ns() { date '+%s.%N'; }
|
||
gate() { # gate <日志文件> <必须命中的行> —— 命不中就 exit 1,杜绝「崩了也往下跑」
|
||
local f="$1" pat="$2"
|
||
if grep -q "$pat" "$f"; then
|
||
echo "[GATE] PASS 在 $f 中命中 '$pat'"
|
||
else
|
||
echo "[GATE] FAIL $f 未命中 '$pat' —— 取证链终止"
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
export OUT REPO_ROOT WS CHAIN_LOG
|
||
|
||
echo "########## S3 EVIDENCE CHAIN START $(ts) (epoch=$(now_ns)) ##########"
|
||
echo "[path] REPO_ROOT=$REPO_ROOT"
|
||
echo "[path] OUT=$OUT"
|
||
echo "[path] CHAIN_LOG=$CHAIN_LOG"
|
||
echo "[env] python3 = $(command -v python3) ($(python3 -V 2>&1))"
|
||
echo "[env] 凭据唯一事实源 = projects/pbls/env/test.json 的 db.sandbox(scope=sandbox_only,口令不打印)"
|
||
echo "[env] 沙箱连接串(脱敏)= $(python3 tests/s3_db_url.py)"
|
||
|
||
echo
|
||
echo "########## [1] 时钟基线:date/time() 与文件系统 mtime 两时钟源偏移实测 ($(ts)) ##########"
|
||
python3 tests/s3_clock_skew_probe.py --samples 5 --dir "$OUT"
|
||
|
||
echo
|
||
echo "########## [2] RUN A: python3 tests/m5a_live_db_harness.py --keep ($(ts)) ##########"
|
||
T0=$(now_ns)
|
||
set +e
|
||
python3 tests/m5a_live_db_harness.py --keep > "$OUT/runA.log" 2>&1
|
||
RC_A=$?
|
||
set -e
|
||
T1=$(now_ns)
|
||
echo "\$ python3 tests/m5a_live_db_harness.py --keep"
|
||
echo "RC=$RC_A 耗时=$(awk -v a="$T0" -v b="$T1" 'BEGIN{printf "%.3f", b-a}')s ($(ts))"
|
||
cat "$OUT/runA.log"
|
||
[ "$RC_A" -eq 0 ] || { echo "[GATE] FAIL RUN A RC=$RC_A"; exit 1; }
|
||
gate "$OUT/runA.log" "LIVE DB HARNESS ALL PASS"
|
||
|
||
echo
|
||
echo "########## [3-0] RUN A 之后沙箱库 trigger 现状(harness 已不再建适配 trigger)($(ts)) ##########"
|
||
python3 tests/s3_trigger_probe.py show
|
||
|
||
echo
|
||
echo "########## [3-1] 复原「适配补丁」时代的 BEFORE INSERT trigger(历史版本 git 80156fd 所建)##########"
|
||
python3 tests/s3_trigger_probe.py create
|
||
|
||
echo
|
||
echo "########## [3-2] drop 前 SHOW TRIGGERS ($(ts)) ##########"
|
||
python3 tests/s3_trigger_probe.py show
|
||
|
||
echo
|
||
echo "########## [3-3] DROP 语句执行 ($(ts)) ##########"
|
||
python3 tests/s3_trigger_probe.py drop
|
||
|
||
echo
|
||
echo "########## [3-4] drop 后 SHOW TRIGGERS ($(ts)) ##########"
|
||
python3 tests/s3_trigger_probe.py show
|
||
|
||
echo
|
||
echo "########## [3-5] RUN B: 无该 trigger 状态下重跑 harness ($(ts)) ##########"
|
||
T2=$(now_ns)
|
||
set +e
|
||
python3 tests/m5a_live_db_harness.py --keep > "$OUT/runB.log" 2>&1
|
||
RC_B=$?
|
||
set -e
|
||
T3=$(now_ns)
|
||
echo "\$ python3 tests/m5a_live_db_harness.py --keep # trigger 已 DROP"
|
||
echo "RC=$RC_B 耗时=$(awk -v a="$T2" -v b="$T3" 'BEGIN{printf "%.3f", b-a}')s ($(ts))"
|
||
cat "$OUT/runB.log"
|
||
[ "$RC_B" -eq 0 ] || { echo "[GATE] FAIL RUN B RC=$RC_B"; exit 1; }
|
||
gate "$OUT/runB.log" "LIVE DB HARNESS ALL PASS"
|
||
echo "########## RUN B 结束后再次确认 trigger(harness 自建库、全程无 trigger)##########"
|
||
python3 tests/s3_trigger_probe.py show
|
||
|
||
echo
|
||
echo "########## [4] collector 重放幂等(同一批事件重放 3 次)($(ts)) ##########"
|
||
set +e
|
||
python3 tests/s3_replay_idempotency.py --replays 3 > "$OUT/replay.log" 2>&1
|
||
RC_R=$?
|
||
set -e
|
||
echo "\$ python3 tests/s3_replay_idempotency.py --replays 3"
|
||
echo "RC=$RC_R"
|
||
cat "$OUT/replay.log"
|
||
[ "$RC_R" -eq 0 ] || { echo "[GATE] FAIL replay RC=$RC_R"; exit 1; }
|
||
gate "$OUT/replay.log" "REPLAY IDEMPOTENT OK"
|
||
|
||
echo
|
||
echo "########## [4b] 重放后 id/行数复核 + trigger 终态 ($(ts)) ##########"
|
||
python3 tests/s3_sql_probe.py \
|
||
"SELECT COUNT(*) AS evidence_rows FROM pbl_evidence" \
|
||
"SELECT COUNT(*) AS event_rows FROM pbl_runtime_event" \
|
||
"SELECT id, LENGTH(id) AS id_len, tenant_id, source_event_id, evidence_type FROM pbl_evidence ORDER BY id" \
|
||
"SHOW TRIGGERS"
|
||
|
||
echo
|
||
echo "########## [5] 清理沙箱库(DROP DATABASE 仅沙箱 schema,凭据不落盘)($(ts)) ##########"
|
||
python3 tests/s3_sql_probe.py --drop-sandbox
|
||
|
||
echo
|
||
echo "########## [6] 产物文件系统实测时间(与日志内 date 对照,排除拼接/事后改写)##########"
|
||
echo "[6] 本行 date = $(ts) (epoch=$(now_ns))"
|
||
ls -l --time-style=full-iso "$OUT"
|
||
echo "--- stat 逐文件(size + mtime)---"
|
||
stat -c '%n size=%s mtime=%y' "$OUT/runA.log" "$OUT/runB.log" "$OUT/replay.log" "$CHAIN_LOG"
|
||
echo "--- 同一 Python 进程内成对打印 time() 与各文件 mtime(消除跨调用干扰,直接暴露两时钟源偏移)---"
|
||
python3 tests/s3_clock_compare.py
|
||
|
||
echo "########## S3 EVIDENCE CHAIN END $(ts) (epoch=$(now_ns)) ##########"
|
||
echo "CHAIN_RC=0"
|