pbl_evidence/tests/s3_trigger_probe.py
agent.develop e0acb9f4af [S3-c] develop 自有 commit 真实收口探针文件(QC#16 落地)
task OqAv27u3w8DE9nirTwPp2(S3-c 子任务:git 收口取证,不改业务逻辑、
不改 gen_s3_log.py 的切片/统计逻辑、不重跑取证链)

- 6 个探针文件(s3_trigger_probe.py / s3_sql_probe.py / s3_replay_idempotency.py /
  s3_clock_skew_probe.py / s3_db_url.py / s3_clock_compare.py)文件头 docstring
  各加一行 task-key 收口标注 → 纳入 develop 自有 commit(真实变更,非 --allow-empty)
- tests/s3_evidence_chain.sh 头部注释块加一行同源标注
- tests/gen_s3_log.py 仅同步 §7「事实陈述」prose,使措辞与本 commit 的
  `git show --stat` 文件清单一致(原「探针未内嵌 task key / 非本轮新增」表述
  已与 git 事实矛盾,按 QC#16「纳入真实变更」路径改写);切片与统计代码零改动
- 选择性 git add(逐个列名 8 文件),未使用 git add -A,未纳入 __pycache__/logs
2026-09-23 03:47:15 +08:00

119 lines
4.9 KiB
Python
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 python3
# -*- coding: utf-8 -*-
"""S3 触发真实性门禁探针:在沙箱库中对 BEFORE INSERT trigger 做 SHOW / CREATE(历史适配) / DROP。
task OqAv27u3w8DE9nirTwPp2(S3-c develop 自有 commit 收口标注):本探针随本轮 develop 自有提交纳入版本控制(非引擎代收口),与文档 §7 声明的文件清单一致。
背景:git 80156fd 时期的 harness 曾在沙箱侧建 `trg_pbl_evidence_id` BEFORE INSERT
trigger 来补 pbl_evidence.id(掩盖 collector INSERT 不带 id)。DISC.1 闭环后该适配已
从 harness 源码删除,id 由应用层 pbl_evidence.pk.gen_pk 生成。本脚本用于**取证**:
先按历史 DDL 复原该 trigger(证明"它存在过、且可被 drop"),再 DROP 之,随后重跑
harness 仍 ALL PASS,从而证明走的是真实链路而非补丁生效。
凭据唯一事实源 = <workspace>/projects/pbls/env/test.json 的 db.sandbox 段
(scope=sandbox_only),口令一律不打印;异常消息经脱敏后输出。
用法::
python3 tests/s3_trigger_probe.py show
python3 tests/s3_trigger_probe.py create
python3 tests/s3_trigger_probe.py drop
python3 tests/s3_trigger_probe.py show --schema pbl_m5a_u7rb
退出码:0 = 动作成功;非 0 = 失败(供 chain 脚本 set -e 门禁使用)。
"""
import argparse
import json
import pathlib
import sys
import pymysql
TESTS_DIR = pathlib.Path(__file__).resolve().parent
REPO_ROOT = TESTS_DIR.parent # modules/pbl_evidence
WORKSPACE_ROOT = REPO_ROOT.parent.parent # 机构工作空间
ENV_FILE = WORKSPACE_ROOT / "projects" / "pbls" / "env" / "test.json"
TRIGGER_NAME = "trg_pbl_evidence_id"
# 历史适配 trigger 的原始 DDL(逐字来自 git 80156fd 时期 harness)
HISTORIC_DDL = (
"CREATE TRIGGER `%s` BEFORE INSERT ON `pbl_evidence` FOR EACH ROW\n"
"BEGIN\n"
" IF NEW.`id` IS NULL OR NEW.`id` = '' THEN\n"
" SET NEW.`id` = REPLACE(UUID(), '-', '');\n"
" END IF;\n"
"END" % TRIGGER_NAME
)
def load_sandbox():
"""读沙箱凭据;缺段或 scope 非 sandbox_only 直接 fail-fast(不猜、不回退业务库)。"""
cfg = json.loads(ENV_FILE.read_text(encoding="utf-8"))
sb = cfg["db"]["sandbox"]
if sb.get("scope") != "sandbox_only":
raise SystemExit("refuse non-sandbox scope: %r" % sb.get("scope"))
return sb
def connect(sb, schema):
return pymysql.connect(
host=sb["host"], port=int(sb["port"]), user=sb["user"],
password=sb["password"], charset="utf8mb4", database=schema,
cursorclass=pymysql.cursors.DictCursor, autocommit=True)
def mask(sb, text):
out = str(text)
for secret in (sb.get("password"), sb.get("user")):
if secret:
out = out.replace(str(secret), "******")
return out
def main(argv=None):
ap = argparse.ArgumentParser(
description="S3 取证:沙箱库 pbl_evidence 上 BEFORE INSERT trigger 的 SHOW/CREATE/DROP")
ap.add_argument("cmd", choices=["show", "create", "drop"],
help="show=SHOW TRIGGERS 原样回显; create=按历史 DDL 复原适配 trigger; "
"drop=DROP TRIGGER IF EXISTS")
ap.add_argument("--schema", default=None,
help="沙箱 schema(缺省取 env/test.json 的 db.sandbox.sandbox_schema)")
ns = ap.parse_args(argv)
sb = load_sandbox()
schema = ns.schema or sb["sandbox_schema"]
conn = connect(sb, schema)
rc = 0
try:
with conn.cursor() as cur:
if ns.cmd == "show":
cur.execute("SHOW TRIGGERS")
rows = list(cur.fetchall() or [])
print("SHOW TRIGGERS (schema=%s) -> %d 条" % (schema, len(rows)))
for r in rows:
print(json.dumps({k: mask(sb, v) for k, v in r.items()},
ensure_ascii=False))
elif ns.cmd == "create":
cur.execute("DROP TRIGGER IF EXISTS `%s`" % TRIGGER_NAME)
cur.execute(HISTORIC_DDL)
print("SQL> " + HISTORIC_DDL.replace("\n", " "))
print("CREATE TRIGGER 执行成功(历史适配 trigger,逐字来自 git 80156fd 时期 harness)")
else:
print("SQL> DROP TRIGGER IF EXISTS `%s`" % TRIGGER_NAME)
cur.execute("DROP TRIGGER IF EXISTS `%s`" % TRIGGER_NAME)
cur.execute("SHOW TRIGGERS")
left = list(cur.fetchall() or [])
print("DROP TRIGGER 执行完成;剩余 trigger = %d 条" % len(left))
if left:
print("FAIL: DROP 后仍存在 trigger,无法证明无补丁链路")
rc = 1
except Exception as exc: # noqa: BLE001
print("ERROR: %s: %s" % (type(exc).__name__, mask(sb, exc)))
rc = 1
finally:
conn.close()
return rc
if __name__ == "__main__":
sys.exit(main())