@furongjun1999/dsh-memory 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +618 -572
- package/codebuddy/CODEBUDDY.md +10 -10
- package/data/policy.json +27 -0
- package/docs/README.md +1 -0
- package/docs/discipline/harnesses.yaml +31 -0
- package/docs/discipline/templates/full.md.tmpl +1 -1
- package/docs/discipline/templates/rules.mdc.tmpl +1 -1
- package/docs/eval/N225_/347/264/242/345/274/225/346/227/245/345/277/227/351/235/236/345/257/271/350/261/241/350/243/205/350/275/275/351/235/242/347/261/273/345/236/213/351/227/270_v1.0.md +418 -0
- package/docs/eval/issue43_/351/273/230/350/256/244/347/255/226/347/225/245/344/270/216/351/224/256/347/261/273/345/236/213/351/227/270_v1.1.md +441 -0
- package/docs/eval/issue43_/351/273/230/350/256/244/347/255/226/347/225/245/345/212/240/350/275/275/344/270/216/345/207/255/346/215/256/346/230/216/346/226/207/351/230/237/345/210/227_v1.0.md +398 -0
- package/docs/eval//344/274/230/345/214/226/347/254/254/344/270/200/346/211/271_/346/216/245/347/272/277/344/270/216/347/255/211/344/273/267/345/217/230/346/215/242_v1.0.md +498 -0
- package/docs/eval//344/274/230/345/214/226/347/254/254/344/270/211/346/211/271_/351/227/250/347/246/201/350/275/254/346/255/243/344/270/216/350/260/203/345/272/246/346/255/242/350/241/200/344/270/216/351/227/250/346/216/247/346/224/266/345/217/243_v1.0.md +669 -0
- package/docs/eval//344/274/230/345/214/226/347/254/254/344/272/214/346/211/271_/344/276/235/350/265/226/351/200/217/344/274/240/344/270/216/345/257/271/346/213/215/345/217/243/345/276/204/344/270/216/350/264/237/347/274/223/345/255/230_v1.0.md +683 -0
- package/docs/eval//345/207/272/350/264/247/351/235/242/345/206/222/347/203/237_/350/277/233/350/264/247/351/227/250/347/246/201_v1.0.md +460 -0
- package/docs/eval//345/217/221/345/270/20307_/345/244/226/351/203/250/346/212/245/345/221/212/345/233/233/346/211/271/344/277/256/345/244/215/344/270/216/346/217/222/344/273/266/351/235/242/345/212/240/345/233/272_v1.0.md +205 -0
- package/docs/eval//345/217/221/345/270/20308_/350/207/252/350/277/255/344/273/243/344/270/216/347/235/241/347/234/240_/345/233/276/346/243/200/347/264/242/350/267/257/344/270/216/346/235/203/351/207/215_v1.0.md +97 -0
- package/docs/eval//345/275/222/344/270/200/345/261/202/347/274/272/347/234/201/347/277/273/345/205/263_/344/277/256/345/244/215/350/256/260/345/275/225_v1.0.md +458 -0
- package/docs/eval//346/200/247/350/203/275/344/270/223/351/241/271_/345/206/267/346/237/245/350/257/242/344/270/216/345/206/205/345/255/230_v1.0.md +218 -0
- package/docs/eval//346/225/205/351/232/234/346/263/250/345/205/245/345/256/236/346/265/213_v1.0.md +10 -0
- package/docs/eval//347/274/226/347/240/201/351/235/242/345/211/215/347/275/256_/345/205/245/345/217/243/350/207/252/344/277/235/350/257/201UTF8/344/270/216/346/226/207/346/234/254open/345/256/210/345/215/253_v1.0.md +646 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v20.md +283 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v21.md +224 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v22.md +223 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v23.md +293 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v24.md +303 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v25.md +230 -0
- package/docs/hive//346/243/200/347/264/242/347/256/227/346/263/225/345/217/243/345/276/204/345/257/271/347/205/247_v0.1.md +136 -11
- package/docs/hive//346/243/200/347/264/242/350/267/257/345/276/204/344/270/216/350/256/244/347/237/245/347/273/223/346/236/204/345/245/221/347/272/246_v0.1.md +52 -2
- package/docs/hive//350/234/202/345/267/242M6_ingest/345/256/236/346/226/275/350/256/241/345/210/222_v0.1.md +1 -1
- package/docs/mdcg/README/350/257/246/347/273/206/347/211/210_v0.4.10.md +100 -0
- package/docs/mdcg//345/212/237/350/203/275/350/260/203/347/224/250/346/230/240/345/260/204/350/241/250_v0.1.md +40 -40
- package/docs/mdcg//345/217/221/345/270/203/351/227/250/347/246/201/351/223/276_v0.1.md +57 -9
- package/docs/mdcg//347/201/265/346/236/242/350/256/260/345/277/206/345/212/250/350/257/215/345/215/217/350/256/256_v1.0-draft.md +7 -2
- package/docs/mdcg//347/235/241/347/234/240/345/221/250/346/234/237_/350/277/220/347/273/264/345/211/215/346/217/220/344/270/216/347/273/264/346/212/244/346/214/207/345/215/227_v1.0.md +183 -0
- package/docs/mdcg//350/256/244/347/237/245/345/233/276_/347/264/242/345/274/225/344/270/216/345/267/245/347/250/213/350/247/204/350/214/203/345/214/226_/350/256/241/345/210/222_v0.1.md +39 -3
- package/docs/plans//345/205/250/344/270/255/346/226/207/347/274/226/347/240/201/344/270/216/350/234/202/345/267/242/344/273/273/345/212/241/346/240/207/350/257/206/345/245/221/347/272/246_v2.0.md +220 -0
- package/docs/plans//347/234/237/346/272/220/347/264/242/345/274/225_/351/200/232/347/224/250/346/234/272/345/210/266_v0.3.md +227 -0
- package/docs/plans//347/235/241/347/234/240/344/270/216/350/207/252/350/277/255/344/273/243_/345/212/237/350/203/275/344/274/230/345/214/226/350/256/276/350/256/241_v0.4.md +547 -0
- package/docs/plans//350/234/202/345/267/242/346/250/241/345/236/213/345/257/206/351/222/245/351/205/215/347/275/256/351/235/242_v1.0.md +385 -0
- package/docs//345/267/245/344/275/234/347/272/252/345/276/213_/350/256/244/347/237/245/345/233/276/346/235/241/347/233/256_v1.1.json +460 -460
- package/lib/bridge.js +24 -2
- package/lib/hooks.d.ts +31 -2
- package/lib/hooks.js +219 -16
- package/lib/init.js +16 -1
- package/lib/lib/prompt_safety.d.ts +52 -1
- package/lib/lib/prompt_safety.js +76 -1
- package/md_cg/audit.py +652 -379
- package/md_cg/bench6_arms.py +1 -1
- package/md_cg/bench_e2e_locomo_qa.py +11 -4
- package/md_cg/bench_p0.py +1 -1
- package/md_cg/branches.py +2 -2
- package/md_cg/ccgc.py +1071 -1006
- package/md_cg/chain.py +48 -1
- package/md_cg/consistency.py +97 -9
- package/md_cg/consolidate.py +34 -9
- package/md_cg/crypto.py +59 -26
- package/md_cg/docindex.py +16 -1
- package/md_cg/evolution.py +17 -1
- package/md_cg/export.py +1 -1
- package/md_cg/forgetting.py +309 -13
- package/md_cg/freshness.py +511 -0
- package/md_cg/fsutil.py +454 -8
- package/md_cg/generation.py +409 -0
- package/md_cg/hotcache.py +4 -1
- package/md_cg/identity.py +3 -3
- package/md_cg/insight.py +24 -3
- package/md_cg/linkref.py +1 -1
- package/md_cg/logref.py +327 -0
- package/md_cg/mcp_server.py +4261 -3818
- package/md_cg/mdcg.py +4695 -3547
- package/md_cg/mdcos.py +4672 -4159
- package/md_cg/mreview/pipeline.py +15 -1
- package/md_cg/nodefile.py +713 -576
- package/md_cg/protect.py +158 -11
- package/md_cg/protocol.py +41 -2
- package/md_cg/provenance.py +22 -4
- package/md_cg/reach.py +4 -4
- package/md_cg/readcache.py +76 -15
- package/md_cg/reconcile.py +1 -1
- package/md_cg/refindex.py +246 -37
- package/md_cg/refine.py +1 -1
- package/md_cg/routing.py +32 -5
- package/md_cg/run_tests.py +17 -0
- package/md_cg/scrub.py +30 -3
- package/md_cg/security.py +47 -1
- package/md_cg/self_state.py +5 -5
- package/md_cg/semantic/canonical.py +22 -0
- package/md_cg/semantic/unify.py +73 -22
- package/md_cg/semantic/unify_fixture.json +25 -0
- package/md_cg/sleep.py +1297 -0
- package/md_cg/sources.py +23 -6
- package/md_cg/srcindex.py +352 -0
- package/md_cg/stg.py +47 -3
- package/md_cg/subgraph.py +2 -2
- package/md_cg/sustain.py +1436 -1168
- package/md_cg/tasks.py +469 -470
- package/md_cg/test_auto_defaults.py +424 -0
- package/md_cg/test_b1_auto_id_multiproc.py +277 -0
- package/md_cg/test_b1b2_write_face.py +417 -0
- package/md_cg/test_b2_sensitivity_landing.py +223 -0
- package/md_cg/test_b3_merge_keeps_content.py +576 -0
- package/md_cg/test_b4_shard_dir_selfheal.py +843 -0
- package/md_cg/test_b4_shard_dir_selfheal_guard.py +238 -0
- package/md_cg/test_boundary_hit.py +410 -0
- package/md_cg/test_c3_transient_read_negative.py +793 -0
- package/md_cg/test_c8_search_rrf_gates.py +502 -0
- package/md_cg/test_ccg_form_parity.py +188 -0
- package/md_cg/test_ccgc.py +28 -3
- package/md_cg/test_en_pipeline.py +22 -13
- package/md_cg/test_generation_guard.py +352 -0
- package/md_cg/test_govern_directread.py +17 -4
- package/md_cg/test_h2_session_view_norm.py +233 -0
- package/md_cg/test_h4_sustain_snapshot.py +1387 -0
- package/md_cg/test_hive_ingest.py +285 -285
- package/md_cg/test_issue39_utf8_stdio.py +307 -16
- package/md_cg/test_issue43_default_policy.py +865 -0
- package/md_cg/test_legacy_p3_node_id_type.py +375 -0
- package/md_cg/test_linkref.py +10 -3
- package/md_cg/test_lock.py +2 -2
- package/md_cg/test_logref.py +1109 -0
- package/md_cg/test_m3_h9_bucket_health_protect_mark.py +301 -0
- package/md_cg/test_m3_h9_semantic_guard.py +525 -0
- package/md_cg/test_mr_m2.py +15 -3
- package/md_cg/test_n130_verify_falsified_protect.py +1 -1
- package/md_cg/test_n139_dek_provision_failclosed.py +185 -0
- package/md_cg/test_n176_link_trust.py +221 -0
- package/md_cg/test_n178_units_jobid_gate.py +212 -0
- package/md_cg/test_n184_keys_concurrent_provision.py +307 -0
- package/md_cg/test_n195_writepath_reload.py +283 -0
- package/md_cg/test_n196_stale_gate_skip.py +169 -0
- package/md_cg/test_n197_n208_write_face_gates.py +471 -0
- package/md_cg/test_n198_tokens_corrupt_failclosed.py +225 -0
- package/md_cg/test_n199_tokens_concurrent_write.py +378 -0
- package/md_cg/test_n201_proposal_visibility.py +382 -0
- package/md_cg/test_n202_session_notes_visibility.py +461 -0
- package/md_cg/test_n204_n205_n226_n227_n228_n229_exit_gates.py +542 -0
- package/md_cg/test_n206_stdio_jsonrpc_type.py +403 -0
- package/md_cg/test_n209_verify_write_face_gates.py +461 -0
- package/md_cg/test_n212_n213_n224_generation_gates.py +519 -0
- package/md_cg/test_n214_n215_n221_n222_write_face_gates.py +563 -0
- package/md_cg/test_n225_nonobject_load.py +1110 -0
- package/md_cg/test_n230_dirty_replay.py +375 -0
- package/md_cg/test_n62_tenant_bind_failclosed.py +200 -0
- package/md_cg/test_neg_condition_hits.py +333 -0
- package/md_cg/test_neg_tail_honesty.py +663 -0
- package/md_cg/test_none_id_write_guard.py +4 -3
- package/md_cg/test_opt_batch1_md_cg.py +451 -0
- package/md_cg/test_p1.py +5 -5
- package/md_cg/test_p11_consistency.py +161 -12
- package/md_cg/test_p26_refindex.py +2 -2
- package/md_cg/test_p27_docindex.py +777 -774
- package/md_cg/test_p28_refcheck.py +740 -13
- package/md_cg/test_p29_session_ingest_export.py +2 -2
- package/md_cg/test_p2_mcp.py +12 -1
- package/md_cg/test_p2_six_elements.py +463 -0
- package/md_cg/test_p30_maintain.py +33 -2
- package/md_cg/test_p31_insight.py +1 -0
- package/md_cg/test_p3_legacy_closure.py +433 -0
- package/md_cg/test_p4_freshness.py +680 -0
- package/md_cg/test_p8_subgraph_chain.py +14 -1
- package/md_cg/test_p9c_dedup_hints.py +276 -0
- package/md_cg/test_policy_required_ccg.py +426 -0
- package/md_cg/test_protocol.py +22 -0
- package/md_cg/test_rank_parity_score_mode.py +522 -0
- package/md_cg/test_read_face_input_gates.py +363 -0
- package/md_cg/test_read_face_semantics.py +489 -0
- package/md_cg/test_recall_face_guards.py +812 -0
- package/md_cg/test_rejected_credential_forms.py +188 -0
- package/md_cg/test_rejected_redact.py +146 -0
- package/md_cg/test_retr_s1b.py +2 -2
- package/md_cg/test_retr_s5.py +20 -7
- package/md_cg/test_review_conformance.py +21 -3
- package/md_cg/test_security_audit_v21.py +2 -2
- package/md_cg/test_semantic_canonical.py +5 -3
- package/md_cg/test_server_version.py +67 -0
- package/md_cg/test_sleep.py +611 -0
- package/md_cg/test_sleep_p1.py +784 -0
- package/md_cg/test_srcindex.py +171 -0
- package/md_cg/test_tenant_env_override_warn.py +63 -50
- package/md_cg/test_time_core_lint.py +968 -0
- package/md_cg/test_token_lowercase_form.py +315 -0
- package/md_cg/test_unify_default_off.py +701 -0
- package/md_cg/test_unify_scope.py +182 -0
- package/md_cg/test_v21r1_package_version.py +310 -0
- package/md_cg/test_writepipe.py +10 -4
- package/md_cg/tokens.py +225 -95
- package/md_cg/tool_face.py +4 -4
- package/md_cg/trust.py +49 -5
- package/md_cg/units.py +204 -6
- package/md_cg/weights.py +4 -4
- package/md_cg/whitebox_kb/aeis_core/time_core.py +8 -0
- package/md_cg/whitebox_kb/wisdom/knowledge_points.py +1 -1
- package/md_cg/writelimit.py +42 -8
- package/md_cg/writepipe.py +651 -554
- package/package.json +4 -2
- package/skills/plugin.json +1 -1
- package/src/bridge.ts +25 -2
- package/src/hooks.ts +229 -16
- package/src/init.ts +15 -1
- package/src/lib/prompt_safety.ts +88 -1
- package/utf8_boot.py +237 -0
- package/zcode/AGENTS.md +10 -10
|
@@ -0,0 +1,461 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""md_cg · verify 写面全域层闸守卫(N209:同族未接线的相邻写面入口)
|
|
3
|
+
|
|
4
|
+
缺陷(修复前,本守卫红态实跑):verify 角色的写面**只有 `falsified` 一态**有层闸
|
|
5
|
+
(N130/N196,`md_cg/mdcos.py:3934-3949` 里 `if verdict == "falsified":` 才加闸),
|
|
6
|
+
`confirmed` / `weakened` 分支全程零闸——`md_cg/mdcg.py:3502` 直写
|
|
7
|
+
`self._write_node(...)`、`:3492` 直调 `self._move_layer(node_id, "contextual", …)`,
|
|
8
|
+
上下无 `require_layer_write`、无 `guard_write`。连带三条腿:
|
|
9
|
+
|
|
10
|
+
① 持 verify 令牌(`md_cg/tokens.py:156-172`:`layers_allow=('rejected','contextual')`,
|
|
11
|
+
forbidden 明列「knowledge/self/anchor 层(不得改被验证内容)」)对任意
|
|
12
|
+
clearance 可读的 knowledge 节点发 `verdict=weakened/confirmed` → 重写其
|
|
13
|
+
frontmatter(confidence/evidence_count/positive|negative_evidence/evidence_log);
|
|
14
|
+
② `trust.mark_dependents` → `trust.set_state`(`md_cg/trust.py:697-698` 直写
|
|
15
|
+
`cg._write_node(...)`)→ 把**任意层**依赖者(实证含 self 层)置 doubted:
|
|
16
|
+
`MdCGSecure` 对 `set_state`/`set_verification`/`mark_dependents` 无任何覆盖,
|
|
17
|
+
state/verification 写路径全程无层闸;
|
|
18
|
+
③ 连续 weakened 把 knowledge 层节点降级迁出到 contextual(`_move_layer` 只过
|
|
19
|
+
保护闸 `guard_move`,无层闸——而搬迁 = 源层一次删除写 + 目标层一次新增写)。
|
|
20
|
+
无需 admin、无需 override(对照同一节点走 `falsified` 已被 AccessDenied 拦)。
|
|
21
|
+
|
|
22
|
+
修复(最小改动 · 三个单点,全部 fail-closed):
|
|
23
|
+
① 新增 `protect.require_layer(cg, node_id, layer=…, sensitivity=…)`:「既有节点
|
|
24
|
+
写面的 principal 层闸」单点(解析顺序:实参层/敏感度 → 索引条目 → 节点
|
|
25
|
+
frontmatter → 缺省口径同 `require_layer_write`;进入前索引代际探活 N195);
|
|
26
|
+
`guard_overwrite` 复用同一解析(第二份口径 = 下一个漏点)。
|
|
27
|
+
② `MdCGSecure.verify` 的闸从「仅 falsified」放宽到**三态全覆盖**——verify 写面
|
|
28
|
+
与 `add`/`add_rejected`(`:3889`/`:3898`)同闸;「真不存在」语义照旧由基类
|
|
29
|
+
not_found 承接(索引无条目时不加闸、也不写盘)。
|
|
30
|
+
③ `trust.set_state`(验证态**唯一推进入口**,同时覆盖 `mark_dependents` 与
|
|
31
|
+
`set_verification` 两条写路)与 `MdCG._move_layer`(降级搬迁入口,同时覆盖
|
|
32
|
+
`scrub.decontaminate` 与 `evolution` 回滚两个调用者)各自补层闸。
|
|
33
|
+
`set_state` 走**负路由**(`ok=False, error="layer_denied"`)而非抛:该函数契约
|
|
34
|
+
是「非法迁移不抛异常」、`mark_dependents` 契约是「永不抛、不阻断本次裁决」——
|
|
35
|
+
但**绝不写盘**,并把拒绝记进 `_trust.jsonl`(不静默)。
|
|
36
|
+
|
|
37
|
+
守卫(五组,全临时库 + 哑主密钥 + 临时令牌库,**绝不触真实 ~/.mdcg**):
|
|
38
|
+
⓿ 隔离自证:aux 根 / 令牌库都须落在守卫临时目录,否则中止;
|
|
39
|
+
① verify 三态的层闸:verify 令牌对 knowledge 节点 weakened/confirmed 被拒且
|
|
40
|
+
盘面零改写(含依赖者未被连带改写);对照 falsified 早已被拒;反向腿为
|
|
41
|
+
verify 令牌对 contextual 节点 confirmed 仍成立(防一刀切收紧);
|
|
42
|
+
② 连续 weakened 的降级迁出:verify 令牌连发 4 次全拒、盘面仍在 knowledge/;
|
|
43
|
+
反向腿 designer 同链路降级迁出仍生效(fail-closed ≠ 掐死合法路径);
|
|
44
|
+
③ 依赖者写面单点(`trust.set_state`):verify 令牌直调被负路由拒绝且盘面零
|
|
45
|
+
改写;端到端 falsified(合法)→ mark_dependents 一跳传播对 self 层依赖者
|
|
46
|
+
不再落盘(拒绝入 `skipped`);反向腿 sustain 对 self 层节点推进仍成功;
|
|
47
|
+
④ 搬迁写面单点(`_move_layer`):sustain 令牌越层搬迁被拒且文件未移动;
|
|
48
|
+
反向腿 designer 搬迁仍生效;同族邻接出口 `scrub._weaken` 被同一单点拒;
|
|
49
|
+
邻接 op 面 `op=scrub action=decontaminate`(expired/high 实靶)零改写且失败
|
|
50
|
+
动作在审计里显式可见(修前该 op 实测 conf 0.5→0.35 且迁出 contextual);
|
|
51
|
+
⑤ 源断言 + floor:三处单点的代码形态(闸必须在写点之前)与实弹计数下限。
|
|
52
|
+
|
|
53
|
+
留档(本席未改,属邻接面的既有口径):`scrub.decontaminate` 对每个 issue 的
|
|
54
|
+
try/except(`md_cg/scrub.py:683-696`)把 `_move_layer` 的 AccessDenied 记成
|
|
55
|
+
`demote_failed:AccessDenied`、`_weaken` 的记成 `weaken_failed:AccessDenied`
|
|
56
|
+
(留痕正确),但该 issue 仍计入 `n_applied` 并返回 `applied: True` ——「阻挡成功、
|
|
57
|
+
计数仍算已处置」是 scrub 自己的聚合口径,不在本席(写面层闸)范围。
|
|
58
|
+
|
|
59
|
+
实测(本机):修前 8 passed / 15 failed(红腿 = 1a/1b/1c/1e/2a/2b/3a/3b/4a/4c/4d
|
|
60
|
+
十一条端到端腿 + 5a-5d 四条源断言腿;复跑法:把 md_cg 包整份复制到临时目录,再用
|
|
61
|
+
`git show HEAD:md_cg/{mdcg,protect,trust,mdcos}.py` 覆盖回修复前版本后实跑);
|
|
62
|
+
修后 23 passed / 0 failed(live=16)。
|
|
63
|
+
|
|
64
|
+
运行:python -X utf8 -m md_cg.test_n209_verify_write_face_gates
|
|
65
|
+
"""
|
|
66
|
+
from __future__ import annotations
|
|
67
|
+
|
|
68
|
+
import atexit
|
|
69
|
+
import os
|
|
70
|
+
import shutil
|
|
71
|
+
import sys
|
|
72
|
+
import tempfile
|
|
73
|
+
import time
|
|
74
|
+
|
|
75
|
+
# ── 隔离前置:必须在 import md_cg 子模块**之前**(tokens/theory 等在模块级把
|
|
76
|
+
# aux_root() 冻成常量)——否则会指到真实 ~/.mdcg 并在那里建密钥/令牌库。 ──
|
|
77
|
+
_TMP = tempfile.mkdtemp(prefix="n209v_")
|
|
78
|
+
os.environ["MDCG_AUX_ROOT"] = os.path.join(_TMP, "auxroot")
|
|
79
|
+
os.environ["MDCG_MASTER_KEY"] = "ef" * 32 # 哑主密钥(绝不触真实密钥面)
|
|
80
|
+
os.environ["MDCG_TOKEN_FILE"] = os.path.join(_TMP, "tokens.json")
|
|
81
|
+
os.environ["MDCG_ROOT"] = os.path.join(_TMP, "cgroot")
|
|
82
|
+
for _k in ("MDCG_TOKEN", "MDCG_TENANT", "MDCG_CLEARANCE", "MDCG_SESSION",
|
|
83
|
+
"DSH_SESSION_ID", "MDCG_LEGACY_ENV_AUTH", "MDCG_LEGACY_ENV_ADMIN",
|
|
84
|
+
"MDCG_CAN_ADMIN", "MDCG_CAN_WRITE", "MDCG_STATE_ROOT",
|
|
85
|
+
"MDCG_DATA_ROOT", "MDCG_TENANT_REGISTRY", "MDCG_VERIFIER_MODULES",
|
|
86
|
+
"PYTHONIOENCODING", "PYTHONUTF8"):
|
|
87
|
+
os.environ.pop(_k, None)
|
|
88
|
+
|
|
89
|
+
from . import mcp_server, protect, scrub, tokens, trust # noqa: E402
|
|
90
|
+
from .datapath import aux_root # noqa: E402
|
|
91
|
+
from .mdcos import MdCGSecure # noqa: E402
|
|
92
|
+
from .security import Principal # noqa: E402
|
|
93
|
+
|
|
94
|
+
atexit.register(lambda: _cleanup(_TMP)) # LIFO:晚于库层 _atexit_flush_all
|
|
95
|
+
|
|
96
|
+
try:
|
|
97
|
+
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
|
|
98
|
+
except AttributeError:
|
|
99
|
+
pass
|
|
100
|
+
|
|
101
|
+
ROOT = os.path.join(_TMP, "cgroot")
|
|
102
|
+
PASS = FAIL = LIVE = 0
|
|
103
|
+
LIVE_FLOOR = 16
|
|
104
|
+
FAILS = []
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def check(name, cond, detail="", live=False):
|
|
108
|
+
global PASS, FAIL, LIVE
|
|
109
|
+
if live:
|
|
110
|
+
LIVE += 1
|
|
111
|
+
if cond:
|
|
112
|
+
PASS += 1
|
|
113
|
+
print(" [PASS] %s" % name)
|
|
114
|
+
else:
|
|
115
|
+
FAIL += 1
|
|
116
|
+
FAILS.append(name)
|
|
117
|
+
print(" [FAIL] %s · %s" % (name, detail))
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def _princ(role, clearance="internal", can_admin=False):
|
|
121
|
+
spec = tokens.role_spec(role)
|
|
122
|
+
return Principal(tenant="default", actor="n209-" + role,
|
|
123
|
+
clearance=clearance, can_write=bool(spec["can_write"]),
|
|
124
|
+
can_admin=can_admin, role=role,
|
|
125
|
+
layers_allow=spec["layers_allow"],
|
|
126
|
+
ops_allow=spec["ops_allow"], auth_mode="test")
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
_OPEN = []
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def _secured(principal):
|
|
133
|
+
cg = MdCGSecure(ROOT, principal=principal)
|
|
134
|
+
_OPEN.append(cg)
|
|
135
|
+
return cg
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def _cleanup(path) -> bool:
|
|
139
|
+
import gc
|
|
140
|
+
for cg in _OPEN:
|
|
141
|
+
try:
|
|
142
|
+
cg.close()
|
|
143
|
+
except Exception: # noqa: BLE001 —— 清理面不得再抛
|
|
144
|
+
pass
|
|
145
|
+
for _ in range(6):
|
|
146
|
+
shutil.rmtree(path, ignore_errors=True)
|
|
147
|
+
if not os.path.exists(path):
|
|
148
|
+
return True
|
|
149
|
+
gc.collect()
|
|
150
|
+
time.sleep(0.25)
|
|
151
|
+
return not os.path.exists(path)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def _fm_of(cg, nid):
|
|
155
|
+
node = cg.get(nid)
|
|
156
|
+
return (node or {}).get("frontmatter") or {}, (node or {}).get("content") or ""
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
VERIFY_FIELDS = ("confidence", "evidence_count", "positive_evidence",
|
|
160
|
+
"negative_evidence", "evidence_log", "verification_state",
|
|
161
|
+
"layer", "path")
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def _vstate(cg, nid):
|
|
165
|
+
"""frontmatter 关键位 + 正文 —— 用于「盘面零改写」断言。"""
|
|
166
|
+
fm, content = _fm_of(cg, nid)
|
|
167
|
+
return {k: fm.get(k) for k in VERIFY_FIELDS}, content
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def _disk_layers(nid):
|
|
171
|
+
"""盘上真实所在层(不依赖索引快照:搬迁断言必须看文件系统)。"""
|
|
172
|
+
out = []
|
|
173
|
+
for r, _d, files in os.walk(ROOT):
|
|
174
|
+
if nid + ".md" in files:
|
|
175
|
+
seg = os.path.relpath(r, ROOT).replace("\\", "/").split("/")[0]
|
|
176
|
+
if seg not in out:
|
|
177
|
+
out.append(seg)
|
|
178
|
+
out.sort()
|
|
179
|
+
return out
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def _raises(fn, *a, **kw):
|
|
183
|
+
"""执行并返回 (ok, 异常类名/空, 结果/异常文本)。"""
|
|
184
|
+
try:
|
|
185
|
+
return True, "", fn(*a, **kw)
|
|
186
|
+
except Exception as exc: # noqa: BLE001 —— 守卫要的是拒绝形态
|
|
187
|
+
return False, type(exc).__name__, str(exc)
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def _src_of(fname):
|
|
191
|
+
with open(os.path.join(os.path.dirname(os.path.abspath(__file__)), fname),
|
|
192
|
+
encoding="utf-8", errors="replace") as fh:
|
|
193
|
+
return fh.read().replace("\r\n", "\n")
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def _src_window(src, start, end):
|
|
197
|
+
i = src.find(start)
|
|
198
|
+
if i < 0:
|
|
199
|
+
return ""
|
|
200
|
+
j = src.find(end, i)
|
|
201
|
+
return src[i:] if j < 0 else src[i:j]
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def main():
|
|
205
|
+
global LIVE
|
|
206
|
+
print("[0] 隔离自证")
|
|
207
|
+
_tok = tokens.token_file()
|
|
208
|
+
check("0a 默认令牌库与 aux 根都落在守卫临时目录(绝不触真实凭据)",
|
|
209
|
+
os.path.abspath(_tok).lower().startswith(os.path.abspath(_TMP).lower())
|
|
210
|
+
and os.path.abspath(aux_root()).lower().startswith(
|
|
211
|
+
os.path.abspath(_TMP).lower()),
|
|
212
|
+
"tok=%s aux=%s" % (_tok, aux_root()))
|
|
213
|
+
if not os.path.abspath(ROOT).lower().startswith(os.path.abspath(_TMP).lower()):
|
|
214
|
+
print("FATAL: 隔离失败,中止(绝不带病跑真实库)")
|
|
215
|
+
return 2
|
|
216
|
+
|
|
217
|
+
designer = _secured(_princ("designer", clearance="internal", can_admin=True))
|
|
218
|
+
k_rule = designer.add("k_rule", "# 正文:知识规则 A\n", layer="knowledge",
|
|
219
|
+
confidence=0.6)
|
|
220
|
+
k_low = designer.add("k_low", "# 正文:知识规则 B\n", layer="knowledge",
|
|
221
|
+
confidence=0.4)
|
|
222
|
+
k_low2 = designer.add("k_low2", "# 正文:知识规则 C\n", layer="knowledge",
|
|
223
|
+
confidence=0.1)
|
|
224
|
+
k_move = designer.add("k_move", "# 正文:待搬迁知识节点\n", layer="knowledge")
|
|
225
|
+
k_move2 = designer.add("k_move2", "# 正文:待搬迁知识节点 2\n", layer="knowledge")
|
|
226
|
+
k_scrub = designer.add("k_scrub", "# 正文:scrub 邻接出口探针\n",
|
|
227
|
+
layer="knowledge", confidence=0.6)
|
|
228
|
+
k_exp = designer.add("k_exp", "# 正文:时效已过的知识节点\n",
|
|
229
|
+
layer="knowledge", confidence=0.5,
|
|
230
|
+
valid_until=time.time() - 86400 * 30)
|
|
231
|
+
c_hyp = designer.add("c_hyp", "# 正文:情境假设 D\n", layer="contextual",
|
|
232
|
+
confidence=0.6)
|
|
233
|
+
c_bad = designer.add("c_bad", "# 正文:情境假设 C\n", layer="contextual")
|
|
234
|
+
s_prop = designer.add("s_prop", "# 正文:自我层依赖者(prop)\n", layer="self",
|
|
235
|
+
depends_on=["k_rule"])
|
|
236
|
+
s_set = designer.add("s_set", "# 正文:自我层节点(set_state 直调)\n",
|
|
237
|
+
layer="self")
|
|
238
|
+
s_dep = designer.add("s_dep", "# 正文:自我层依赖者(falsified 一跳)\n",
|
|
239
|
+
layer="self", depends_on=["c_bad"])
|
|
240
|
+
s_ok = designer.add("s_ok", "# 正文:自我层节点(反向腿)\n", layer="self")
|
|
241
|
+
_idx = designer.index["nodes"]
|
|
242
|
+
check("0b 夹具就位(层 + depends_on 落入索引快照)",
|
|
243
|
+
all(_idx.get(n) for n in (k_rule, k_low, k_low2, k_move, k_move2,
|
|
244
|
+
c_hyp, c_bad, s_prop, s_set, s_dep, s_ok))
|
|
245
|
+
and (_idx[s_prop].get("depends_on") == ["k_rule"])
|
|
246
|
+
and (_idx[s_dep].get("depends_on") == ["c_bad"])
|
|
247
|
+
and _idx[s_prop].get("layer") == "self",
|
|
248
|
+
"deps=%s/%s" % (_idx.get(s_prop, {}).get("depends_on"),
|
|
249
|
+
_idx.get(s_dep, {}).get("depends_on")))
|
|
250
|
+
|
|
251
|
+
# ---------- ① verify 三态的层闸(缺陷腿 ① + 对照 falsified) ----------
|
|
252
|
+
print("[1] verify 三态全覆盖:越层裁决被拒(含依赖者连带写面)")
|
|
253
|
+
v = _secured(_princ("verify"))
|
|
254
|
+
before_k, before_kc = _vstate(v, k_rule)
|
|
255
|
+
before_s, before_sc = _vstate(v, s_prop)
|
|
256
|
+
ok1, exc1, out1 = _raises(mcp_server.call_tool, v, "cg",
|
|
257
|
+
{"op": "verify", "node_id": k_rule,
|
|
258
|
+
"evidence": "越层探针证据", "verdict": "weakened"})
|
|
259
|
+
after_k, after_kc = _vstate(v, k_rule)
|
|
260
|
+
after_s, after_sc = _vstate(v, s_prop)
|
|
261
|
+
check("1a verify 令牌对 knowledge 节点 weakened 被拒(修前 = 改 knowledge 层 "
|
|
262
|
+
"frontmatter 成功且无痕)",
|
|
263
|
+
(not ok1) and exc1 == "AccessDenied",
|
|
264
|
+
"exc=%s out=%s" % (exc1, str(out1)[:80]), live=True)
|
|
265
|
+
check("1b 盘面零改写:confidence/evidence_count/negative_evidence/evidence_log "
|
|
266
|
+
"与正文全等、层与路径不变",
|
|
267
|
+
after_k == before_k and after_kc == before_kc,
|
|
268
|
+
"before=%s after=%s" % (before_k, after_k), live=True)
|
|
269
|
+
check("1c 依赖者(self 层)未被连带改写:verification_state 仍非 doubted",
|
|
270
|
+
after_s == before_s and after_sc == before_sc
|
|
271
|
+
and after_s.get("verification_state") != "doubted",
|
|
272
|
+
"before=%s after=%s" % (before_s, after_s), live=True)
|
|
273
|
+
ok2, exc2, out2 = _raises(mcp_server.call_tool, v, "cg",
|
|
274
|
+
{"op": "verify", "node_id": k_rule,
|
|
275
|
+
"evidence": "对照腿", "verdict": "falsified"})
|
|
276
|
+
check("1d 对照腿(材料口径):同一 verify 令牌对同一节点走 falsified 早已被拒",
|
|
277
|
+
(not ok2) and exc2 == "AccessDenied"
|
|
278
|
+
and _disk_layers(k_rule) == ["knowledge"],
|
|
279
|
+
"exc=%s layers=%s" % (exc2, _disk_layers(k_rule)), live=True)
|
|
280
|
+
ok3, exc3, out3 = _raises(mcp_server.call_tool, v, "cg",
|
|
281
|
+
{"op": "verify", "node_id": k_rule,
|
|
282
|
+
"evidence": "confirmed 探针", "verdict": "confirmed"})
|
|
283
|
+
after_k3, _c3 = _vstate(v, k_rule)
|
|
284
|
+
check("1e confirmed 同臂同样被拒且盘面零改写(三态全覆盖,非只补 weakened)",
|
|
285
|
+
(not ok3) and exc3 == "AccessDenied" and after_k3 == before_k,
|
|
286
|
+
"exc=%s out=%s" % (exc3, str(out3)[:80]), live=True)
|
|
287
|
+
c_h_before, c_h_bc = _vstate(v, c_hyp)
|
|
288
|
+
ok4, exc4, out4 = _raises(mcp_server.call_tool, v, "cg",
|
|
289
|
+
{"op": "verify", "node_id": c_hyp,
|
|
290
|
+
"evidence": "同层正当裁决", "verdict": "confirmed"})
|
|
291
|
+
c_h_after, c_h_ac = _vstate(v, c_hyp)
|
|
292
|
+
check("1f 反向腿:verify 令牌对 contextual 节点 confirmed 仍成立(同层正当写入 "
|
|
293
|
+
"未被一刀切掐死)",
|
|
294
|
+
ok4 and isinstance(out4, dict) and out4.get("action") == "confirmed"
|
|
295
|
+
and c_h_after["evidence_count"] == (c_h_before["evidence_count"] or 0) + 1
|
|
296
|
+
and c_h_after["confidence"] == 0.65,
|
|
297
|
+
"exc=%s out=%s" % (exc4, str(out4)[:80]), live=True)
|
|
298
|
+
|
|
299
|
+
# ---------- ② 连续 weakened 的降级迁出 ----------
|
|
300
|
+
print("[2] 连续 weakened 降级迁出:越层搬迁被拒(缺陷腿 ③)")
|
|
301
|
+
v2 = _secured(_princ("verify"))
|
|
302
|
+
denied = 0
|
|
303
|
+
for _i in range(4):
|
|
304
|
+
_ok, _exc, _out = _raises(mcp_server.call_tool, v2, "cg",
|
|
305
|
+
{"op": "verify", "node_id": k_low,
|
|
306
|
+
"evidence": "连续 weakened 探针 #%d" % _i,
|
|
307
|
+
"verdict": "weakened"})
|
|
308
|
+
if (not _ok) and _exc == "AccessDenied":
|
|
309
|
+
denied += 1
|
|
310
|
+
check("2a verify 令牌连发 4 次 weakened 全被拒(修前 3 次即跌破 "
|
|
311
|
+
"DEMOTE_CONFIDENCE 并迁出)",
|
|
312
|
+
denied == 4, "denied=%d" % denied, live=True)
|
|
313
|
+
check("2b 盘面仍在 knowledge 层且 layer=knowledge、confidence=0.4"
|
|
314
|
+
"(迁出后盘上落在 contextual/)",
|
|
315
|
+
_disk_layers(k_low) == ["knowledge"]
|
|
316
|
+
and _vstate(v2, k_low)[0]["layer"] == "knowledge"
|
|
317
|
+
and _vstate(v2, k_low)[0]["confidence"] == 0.4,
|
|
318
|
+
"layers=%s layer=%s conf=%s" % (_disk_layers(k_low),
|
|
319
|
+
_vstate(v2, k_low)[0].get("layer"),
|
|
320
|
+
_vstate(v2, k_low)[0].get("confidence")),
|
|
321
|
+
live=True)
|
|
322
|
+
okd, excd, _outd = _raises(designer.verify, k_low2, "合法降级腿", "weakened")
|
|
323
|
+
check("2c 反向腿:designer(layers='*')同链路降级迁出仍生效(confidence "
|
|
324
|
+
"0.1→0.0 < 0.2 → contextual)",
|
|
325
|
+
okd and _disk_layers(k_low2) == ["contextual"],
|
|
326
|
+
"exc=%s layers=%s" % (excd, _disk_layers(k_low2)), live=True)
|
|
327
|
+
|
|
328
|
+
# ---------- ③ 依赖者写面单点:trust.set_state ----------
|
|
329
|
+
print("[3] 依赖者/验证态写面单点(trust.set_state)")
|
|
330
|
+
v3 = _secured(_princ("verify"))
|
|
331
|
+
s_set_before = _vstate(v3, s_set)
|
|
332
|
+
ok5, exc5, out5 = _raises(trust.set_state, v3, s_set, "doubted",
|
|
333
|
+
reason="N209 越层写面探针", actor="n209")
|
|
334
|
+
s_set_after = _vstate(v3, s_set)
|
|
335
|
+
check("3a verify 令牌直调 trust.set_state 对 self 层节点被**负路由**拒绝"
|
|
336
|
+
"(修前 ok=True 且写盘)",
|
|
337
|
+
ok5 and isinstance(out5, dict) and out5.get("ok") is False
|
|
338
|
+
and out5.get("changed") is False
|
|
339
|
+
and out5.get("error") == "layer_denied"
|
|
340
|
+
and s_set_after == s_set_before
|
|
341
|
+
and s_set_after[0].get("verification_state") != "doubted",
|
|
342
|
+
"out=%s" % (str(out5)[:120]), live=True)
|
|
343
|
+
v4 = _secured(_princ("verify"))
|
|
344
|
+
s_dep_before = _vstate(v4, s_dep)
|
|
345
|
+
ok6, exc6, out6 = _raises(mcp_server.call_tool, v4, "cg",
|
|
346
|
+
{"op": "verify", "node_id": c_bad,
|
|
347
|
+
"evidence": "情境假设被证伪", "verdict": "falsified"})
|
|
348
|
+
s_dep_after = _vstate(v4, s_dep)
|
|
349
|
+
prop = (out6 or {}).get("propagation") if isinstance(out6, dict) else None
|
|
350
|
+
check("3b 端到端:falsified(contextual 层,合法)的一跳传播不再写 self 层依赖者"
|
|
351
|
+
"——本裁决仍成功、传播记 skipped 而非落盘",
|
|
352
|
+
ok6 and isinstance(out6, dict) and out6.get("action") == "falsified"
|
|
353
|
+
and s_dep_after == s_dep_before
|
|
354
|
+
and s_dep_after[0].get("verification_state") != "doubted"
|
|
355
|
+
and isinstance(prop, dict) and prop.get("changed") == 0
|
|
356
|
+
and any("layer_denied" in str(x) for x in (prop.get("skipped") or [])),
|
|
357
|
+
"exc=%s prop=%s" % (exc6, str(prop)[:150]), live=True)
|
|
358
|
+
sustain = _secured(_princ("sustain"))
|
|
359
|
+
ok7, exc7, out7 = _raises(sustain.set_verification, s_ok, "doubted",
|
|
360
|
+
reason="sustain 自层运维", actor="n209-sustain")
|
|
361
|
+
check("3c 反向腿:sustain(layers=('self',))对 self 层节点推进仍成功"
|
|
362
|
+
"(同层正当写面未被收紧误伤)",
|
|
363
|
+
ok7 and isinstance(out7, dict) and out7.get("ok") is True
|
|
364
|
+
and _vstate(sustain, s_ok)[0].get("verification_state") == "doubted",
|
|
365
|
+
"exc=%s out=%s" % (exc7, str(out7)[:100]), live=True)
|
|
366
|
+
|
|
367
|
+
# ---------- ④ 搬迁写面单点:_move_layer ----------
|
|
368
|
+
print("[4] 降级搬迁写面单点(_move_layer,同族未接线入口)")
|
|
369
|
+
ok8, exc8, out8 = _raises(sustain._move_layer, k_move, "contextual",
|
|
370
|
+
reason="N209 越层搬迁探针")
|
|
371
|
+
check("4a sustain(layers=('self',))把 knowledge 节点搬出层被拒(修前成功搬入 "
|
|
372
|
+
"contextual)",
|
|
373
|
+
(not ok8) and exc8 == "AccessDenied"
|
|
374
|
+
and _disk_layers(k_move) == ["knowledge"],
|
|
375
|
+
"exc=%s layers=%s" % (exc8, _disk_layers(k_move)), live=True)
|
|
376
|
+
ok9, exc9, out9 = _raises(designer._move_layer, k_move2, "contextual",
|
|
377
|
+
reason="N209 反向腿合法搬迁")
|
|
378
|
+
check("4b 反向腿:designer 同调用仍生效(文件已到 contextual/)",
|
|
379
|
+
ok9 and isinstance(out9, dict) and out9.get("to") == "contextual"
|
|
380
|
+
and _disk_layers(k_move2) == ["contextual"],
|
|
381
|
+
"exc=%s layers=%s" % (exc9, _disk_layers(k_move2)), live=True)
|
|
382
|
+
ok10, exc10, out10 = _raises(scrub._weaken, sustain, k_scrub, "stale",
|
|
383
|
+
"N209 邻接出口探针")
|
|
384
|
+
check("4c 同族邻接调用者:scrub._weaken 经 cg.verify 同一单点被拒且盘面零改写"
|
|
385
|
+
"(scrub ∈ sustain ops_allow,修前可对 knowledge 节点 weaken)",
|
|
386
|
+
(not ok10) and exc10 == "AccessDenied"
|
|
387
|
+
and _vstate(sustain, k_scrub)[0]["confidence"] == 0.6,
|
|
388
|
+
"exc=%s out=%s" % (exc10, str(out10)[:80]), live=True)
|
|
389
|
+
sus2 = _secured(_princ("sustain"))
|
|
390
|
+
ok11, exc11, out11 = _raises(mcp_server.call_tool, sus2, "cg",
|
|
391
|
+
{"op": "scrub", "action": "decontaminate",
|
|
392
|
+
"node_ids": [k_exp], "kinds": ["expired"],
|
|
393
|
+
"min_severity": "info", "dry_run": False})
|
|
394
|
+
fm11, _c11 = _vstate(sus2, k_exp)
|
|
395
|
+
acts = (out11 or {}).get("actions") if isinstance(out11, dict) else None
|
|
396
|
+
_done0 = (acts[0].get("done") if isinstance(acts, list) and acts
|
|
397
|
+
and isinstance(acts[0], dict) else []) or []
|
|
398
|
+
check("4d 同族邻接 op 面:sustain 经 op=scrub action=decontaminate 对 "
|
|
399
|
+
"expired/high 实靶不再能 weaken/降级 knowledge 节点——零改写,且两条"
|
|
400
|
+
"失败动作在审计里显式可见(不静默假装成功)",
|
|
401
|
+
ok11 and isinstance(out11, dict) and fm11["confidence"] == 0.5
|
|
402
|
+
and fm11["layer"] == "knowledge"
|
|
403
|
+
and _disk_layers(k_exp) == ["knowledge"]
|
|
404
|
+
and "weaken_failed:AccessDenied" in _done0
|
|
405
|
+
and "demote_failed:AccessDenied" in _done0,
|
|
406
|
+
"exc=%s conf=%s layer=%s done=%s"
|
|
407
|
+
% (exc11, fm11.get("confidence"), fm11.get("layer"), _done0), live=True)
|
|
408
|
+
|
|
409
|
+
# ---------- ⑤ 源断言 + floor ----------
|
|
410
|
+
print("[5] 源断言 + 守卫自检")
|
|
411
|
+
src_t = _src_of("trust.py")
|
|
412
|
+
src_m = _src_of("mdcg.py")
|
|
413
|
+
src_o = _src_of("mdcos.py")
|
|
414
|
+
src_p = _src_of("protect.py")
|
|
415
|
+
win_set = _src_window(src_t, "def set_state(cg, node_id: str, dst: str",
|
|
416
|
+
"# ---------------------------------------------------------")
|
|
417
|
+
win_mv = _src_window(src_m, " def _move_layer(self, node_id: str",
|
|
418
|
+
"# 生效条件:verdict 不在")
|
|
419
|
+
win_v = _src_window(src_o, " def verify(self, node_id: str, evidence: str",
|
|
420
|
+
"# 生效条件:sens 取 sensitivity or DEFAULT_SENSITIVITY")
|
|
421
|
+
check("5a trust.set_state 写点前紧邻 protect.require_layer(负路由,写盘前)",
|
|
422
|
+
"protect.require_layer(cg, node_id" in win_set
|
|
423
|
+
and win_set.index("protect.require_layer(cg, node_id")
|
|
424
|
+
< win_set.index("cg._write_node(")
|
|
425
|
+
and '"error": "layer_denied"' in win_set,
|
|
426
|
+
"win_len=%d" % len(win_set))
|
|
427
|
+
check("5b MdCG._move_layer 对**源层与目标层**各过一道层闸,且都在 "
|
|
428
|
+
"self._write_node( 之前",
|
|
429
|
+
win_mv.count("protect.require_layer(") >= 2
|
|
430
|
+
and win_mv.index("protect.require_layer(")
|
|
431
|
+
< win_mv.index("self._write_node(")
|
|
432
|
+
and "layer=to_layer" in win_mv and "layer=from_layer" in win_mv,
|
|
433
|
+
"n=%d" % win_mv.count("protect.require_layer("))
|
|
434
|
+
check("5c MdCGSecure.verify 的闸已从「仅 falsified」放宽到三态全覆盖",
|
|
435
|
+
'v in ("confirmed", "weakened", "falsified")' in win_v
|
|
436
|
+
and "protect.require_layer(" in win_v
|
|
437
|
+
and '== "falsified"' not in win_v,
|
|
438
|
+
"win_len=%d" % len(win_v))
|
|
439
|
+
win_go = _src_window(src_p, "def guard_overwrite(cg, node_id",
|
|
440
|
+
"def mark(cg, node_id")
|
|
441
|
+
check("5d protect.require_layer 单点存在,且 guard_overwrite 复用同一解析"
|
|
442
|
+
"(第二份口径 = 下一个漏点)",
|
|
443
|
+
"\ndef require_layer(cg, node_id, layer=None, sensitivity=None," in src_p
|
|
444
|
+
and "require_layer(cg, node_id" in win_go
|
|
445
|
+
and src_p.count("def _resolve_target(") == 1
|
|
446
|
+
and src_p.count("def require_layer(") == 1,
|
|
447
|
+
"n_resolve_def=%d" % src_p.count("def _resolve_target("))
|
|
448
|
+
check("5e 实弹断言计数下限(防某条腿被静默跳过/提前 return)",
|
|
449
|
+
LIVE >= LIVE_FLOOR,
|
|
450
|
+
"LIVE=%d floor=%d" % (LIVE, LIVE_FLOOR))
|
|
451
|
+
|
|
452
|
+
print("\n[RESULT] %d passed / %d failed · live=%d" % (PASS, FAIL, LIVE))
|
|
453
|
+
if FAILS:
|
|
454
|
+
print("失败清单:")
|
|
455
|
+
for n in FAILS:
|
|
456
|
+
print(" · %s" % n)
|
|
457
|
+
return 0 if FAIL == 0 else 1
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
if __name__ == "__main__":
|
|
461
|
+
sys.exit(main())
|