feat(m5a): selfcheck 扩展 4 项门禁 + 统一 traceback 判定(QC #4/#11/#12)
This commit is contained in:
parent
abb84b5390
commit
cc20471188
@ -28,9 +28,15 @@
|
||||
10. harness 零明文凭据:password=/user=/test123 等口令字面量 0 命中;db_kwargs() 只从 PBL_M5A_DB
|
||||
或 projects/pbls/env/test.json 取凭据,取不到即 raise(禁 fallback 到硬编码口令)
|
||||
11. 运行证据日志:projects/pbls/docs/02-develop/ 下 m5a-live-db-harness.log / m5a-selfcheck.log /
|
||||
m5a-pytest-offline.log 三份均存在且含 `# RC=0` 收尾标记,且**三份日志统一不得含
|
||||
Traceback**(函数内单点判定,含即判崩溃现场非通过证据,明细按日志名区分);harness 日志额外含
|
||||
`LIVE DB HARNESS ALL PASS` 与 C-3.1~C-3.4、IDM.1~IDM.9 全 [PASS] 行;
|
||||
m5a-pytest-offline.log 三份均存在。两份**外部**日志(harness / pytest)必须含 `# RC=0`
|
||||
收尾标记;`m5a-selfcheck.log` 是本脚本自己的运行记录,只验「12 行 [PASS]/[FAIL] 记录齐备 +
|
||||
有结论行」——它的 rc 就是本脚本自己的退出码,把「自己的 rc=0」当成自己的通过条件会自指死锁
|
||||
(第 N 次的结论取决于第 N-1 次的日志,永远无法从失败态收敛),rc 由外层 wrapper 落盘、
|
||||
由 s3/QC/CI 直接读取。三份日志统一不得含**裸 Traceback 行**(行首无缩进、无 `| ` 引用前缀):
|
||||
harness 在 C-3 fail-closed 阶段主动捕获 CollectError 后用 traceback.format_exc() 以
|
||||
` | ` 前缀回显堆栈,属**已收敛的预期异常**(同档含 ALL PASS + `# RC=0`),不再判为崩溃
|
||||
现场(QC #12 采纳方案 B;方案 A 属 harness 侧改动,归 s1,本轮不动 harness 源码)。
|
||||
harness 日志额外含 `LIVE DB HARNESS ALL PASS` 与 C-3.1~C-3.4、IDM.1~IDM.9 全 [PASS] 行;
|
||||
.qc_tmp/ 下的崩溃 traceback 日志不计为证据
|
||||
12. harness DDL 与模型一致:DDL_PBL_EVIDENCE 解析出的列集合 ⊆ models/pbl_evidence.json fields,
|
||||
且 UNIQUE KEY uk_ev_dedup 列组合 == (tenant_id, source_event_id, evidence_type)
|
||||
@ -97,8 +103,18 @@ CREDENTIAL_PATTERNS = (
|
||||
PARAM_SWALLOW_PATTERNS = ('args or {}', 'params or {}', 'dict(params or {})', 'or {}')
|
||||
# harness 里需要收敛为断言的 phase 调用(main 外层 try 必须包住它们)
|
||||
HARNESS_PHASE_CALLS = ('install_stub', 'phase_fail_closed', 'phase_idempotent', 'phase_third_run')
|
||||
# 崩溃 traceback 特征(出现即说明该日志是崩溃现场,不是通过证据)
|
||||
# 崩溃 traceback 特征串(用于构造「裸行」正则,单一真源)
|
||||
TRACEBACK_TOKEN = 'Traceback (most recent call last)'
|
||||
# 「裸」Traceback 行 = 行首既无缩进也无 `| ` 引用前缀(re.M 下 ^ 只在行首匹配,
|
||||
# 因此 harness 主动回显的 ` | Traceback (most recent call last):` 不会命中)。
|
||||
# 旧口径用 `TRACEBACK_TOKEN in text` 全文子串匹配,把已收敛的预期异常堆栈误判为
|
||||
# 「未收敛的未捕获异常」,与同档 ALL PASS + `# RC=0` 事实矛盾(QC #12 假阳性)。
|
||||
BARE_TRACEBACK_RE = re.compile(r'^' + re.escape(TRACEBACK_TOKEN), re.M)
|
||||
# 本脚本自己的运行记录(其 rc 不作为本门禁通过条件,见 docstring 第 11 项)
|
||||
SELFCHECK_LOG_NAME = 'm5a-selfcheck.log'
|
||||
# 自检日志的「完整运行记录」特征:12 行 [PASS]/[FAIL] + 一条结论行
|
||||
CHECK_LINE_RE = re.compile(r'^\[(?:PASS|FAIL)\] \d+\.', re.M)
|
||||
VERDICT_TOKENS = ('ALL PASS (', 'SELF CHECK FAILED (')
|
||||
|
||||
|
||||
def _read(path):
|
||||
@ -704,10 +720,21 @@ def check_no_hardcoded_credentials():
|
||||
|
||||
|
||||
def check_evidence_logs():
|
||||
"""⑪ 运行证据日志:三份日志齐备且含 `# RC=0`;harness 日志含 ALL PASS 与全 [PASS] 行。
|
||||
"""⑪ 运行证据日志:三份日志齐备;外部两份含 `# RC=0`;无裸 Traceback 崩溃现场。
|
||||
|
||||
只认 projects/pbls/docs/02-develop/ 顶层文件:.qc_tmp/ 下的是崩溃 traceback 现场,
|
||||
属于「跑挂了」的记录而非「跑过了」的证据,计入会把失败伪装成交付。
|
||||
|
||||
两条口径(均为 QC #12 退回意见列明的改法,非本角色自行放宽):
|
||||
1. traceback 判定收窄为「裸 `Traceback (most recent call last)` 行」——harness 在
|
||||
C-3 fail-closed 阶段主动 `except CollectError` 后以 ` | ` 前缀回显 format_exc()
|
||||
原文(tests/m5a_live_db_harness.py:308/311/316),是预期且已收敛的堆栈,同档另有
|
||||
`LIVE DB HARNESS ALL PASS` + `# RC=0`,旧口径判其「未收敛的未捕获异常」属假阳性。
|
||||
真正的崩溃现场(异常逃逸到进程外)必然以顶格裸 Traceback 出现,仍然被拦。
|
||||
2. `m5a-selfcheck.log` 是本脚本自身运行的落盘记录,其 rc 与本门禁的结论互为因果
|
||||
(自指),故只验「12 行 [PASS]/[FAIL] 记录齐备 + 存在结论行」,并在明细里
|
||||
**原样回显该日志的结论行**(历史记录若为 FAILED 会直接可见,不做静默放过);
|
||||
harness / pytest 两份外部日志的 rc 与本门禁无因果,仍严格要求 `# RC=0`。
|
||||
"""
|
||||
docs = _find_docs_dir()
|
||||
if not os.path.isdir(docs):
|
||||
@ -730,17 +757,30 @@ def check_evidence_logs():
|
||||
continue
|
||||
text = _read(os.path.join(docs, name))
|
||||
contents[name] = text
|
||||
if RC_MARKER not in text:
|
||||
if name == SELFCHECK_LOG_NAME:
|
||||
# 自指豁免(见本函数 docstring 第 2 条):只验运行记录完整性,不验其 rc。
|
||||
n_lines = len(CHECK_LINE_RE.findall(text))
|
||||
if n_lines != len(CHECKS):
|
||||
problems.append('%s 运行记录不完整([PASS]/[FAIL] 行数 %d != %d)'
|
||||
% (name, n_lines, len(CHECKS)))
|
||||
verdict = next((ln for ln in text.splitlines()
|
||||
if ln.startswith(VERDICT_TOKENS)), '')
|
||||
if not verdict:
|
||||
problems.append('%s 缺结论行(%s)' % (name, ' / '.join(VERDICT_TOKENS)))
|
||||
detail.append('%s 为自检历史运行记录(12 行齐备),其结论行原样回显: %s'
|
||||
'(rc 由外层 wrapper 落盘、由调用方读取,不回填本门禁)'
|
||||
% (name, verdict))
|
||||
elif RC_MARKER not in text:
|
||||
problems.append('%s 缺 `%s` 收尾标记(未记录退出码=无法证明 rc=0)' % (name, RC_MARKER))
|
||||
# 统一口径(QC #4 退回项 #3):三份日志一律不得含 traceback——崩溃现场不是
|
||||
# 通过证据。旧实现循环内对 harness 日志豁免、循环外再单独判一次,同一语义
|
||||
# 两处分叉(隐式双标),后续维护易漏判。现合并为循环内单点判定,明细带日志名。
|
||||
if TRACEBACK_TOKEN in text:
|
||||
problems.append('%s 含崩溃 traceback(未收敛的未捕获异常)' % name)
|
||||
# 单点判定(三份日志同一口径,明细带日志名):只有「裸 Traceback 行」才算崩溃
|
||||
# 现场;引用式回显(` | Traceback ...`)属 harness 主动捕获后的预期输出。
|
||||
if BARE_TRACEBACK_RE.search(text):
|
||||
problems.append('%s 含未收敛 traceback(裸 Traceback 崩溃现场)或缺 '
|
||||
'ALL PASS/# RC=0 收尾' % name)
|
||||
if problems:
|
||||
return False, '; '.join(problems)
|
||||
|
||||
detail.append('三份证据日志齐备,均含 `%s` 且无 traceback: %s'
|
||||
detail.append('三份证据日志齐备(外部两份含 `%s`,自检日志验 12 行记录),均无裸 Traceback 崩溃现场: %s'
|
||||
% (RC_MARKER, ', '.join(sorted(EVIDENCE_LOGS))))
|
||||
|
||||
hlog = contents['m5a-live-db-harness.log']
|
||||
@ -850,7 +890,7 @@ CHECKS = [
|
||||
('README 引用的 scripts/*.py 路径全部磁盘命中(含 selfcheck_m5a.py)', check_readme_reference),
|
||||
('harness 静态门禁:main() 外层 try/except 收敛 + 无吞参反模式 + 种子 INSERT 具名参数', check_harness_static),
|
||||
('harness 零明文凭据:无 password/test123 字面量,db_kwargs() 只读 PBL_M5A_DB/env test.json 且缺即 raise', check_no_hardcoded_credentials),
|
||||
('运行证据日志:docs/02-develop 三份日志含 # RC=0,harness 日志含 ALL PASS 与 C-3.x/IDM.x 全 [PASS]', check_evidence_logs),
|
||||
('运行证据日志:docs/02-develop 三份日志齐备(外部两份含 # RC=0、自检日志含 12 行记录)且无裸 Traceback 崩溃现场,harness 日志含 ALL PASS 与 C-3.x/IDM.x 全 [PASS]', check_evidence_logs),
|
||||
('harness DDL 与模型一致:DDL 列 ⊆ models fields 且 uk_ev_dedup == (tenant_id, source_event_id, evidence_type)', check_harness_matches_model),
|
||||
]
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user