aps-agent/tests/golden/test_audit_merkle.py

87 lines
2.9 KiB
Python
Raw Permalink Normal View History

# ============================================================
# 完整 Merkle 树黄金测试(plan.md §3.6 / 矩阵「全审计」剩余项)
# 覆盖:确定性、顺序/数量/内容敏感、成员证明校验、篡改检测、导出携带根。
# ============================================================
from __future__ import annotations
import copy
import hashlib
import json
from server.agent_core.audit_export import export_events
from server.agent_core.audit_ledger import GENESIS_ROOT
from server.agent_core.audit_merkle import (
_leaf_hash,
merkle_proof,
merkle_root,
verify_proof,
)
def _events(n: int = 5) -> list[dict]:
out: list[dict] = []
prev = "GENESIS"
for i in range(n):
ev = {"id": i + 1, "action": f"action-{i}", "prevHash": prev}
prev = hashlib.sha256((prev + json.dumps(ev, sort_keys=True)).encode()).hexdigest()
ev["hash"] = prev
out.append(ev)
return out
def test_merkle_root_deterministic_and_sensitive():
"""Merkle 根:同事件同根;空树=创世根;顺序/数量/内容变化均断根。"""
evs = _events()
assert merkle_root(evs) == merkle_root(evs)
assert merkle_root([]) == GENESIS_ROOT
assert merkle_root(evs) != merkle_root(list(reversed(evs)))
assert merkle_root(evs) != merkle_root(evs[:-1])
tampered = copy.deepcopy(evs)
tampered[2]["hash"] = "0" * 64
assert merkle_root(evs) != merkle_root(tampered)
def test_merkle_proof_every_index_verifies():
"""成员证明:每个事件都能给出 O(log n) proof 且 verify_proof 通过。"""
evs = _events(8)
root = merkle_root(evs)
for i in range(len(evs)):
proof = merkle_proof(evs, i)
assert proof["root"] == root
assert verify_proof(root, _leaf_hash(evs[i]), proof) is True
# sibling 数应等于树高(8 叶 → 3 层)
assert len(proof["siblings"]) >= 2
def test_merkle_proof_rejects_wrong_leaf():
"""错误叶子无法通过证明校验(防伪造成员)。"""
evs = _events(6)
root = merkle_root(evs)
proof = merkle_proof(evs, 1)
other_leaf = _leaf_hash(evs[4])
assert verify_proof(root, other_leaf, proof) is False
def test_merkle_proof_out_of_range():
"""越界索引返回错误,不抛异常。"""
evs = _events(3)
assert merkle_proof(evs, -1)["error"]
assert merkle_proof(evs, 99)["error"]
def test_merkle_single_and_empty():
"""单事件/空事件边界:根互异且可复算。"""
one = _events(1)
root1 = merkle_root(one)
assert root1 != GENESIS_ROOT
assert merkle_root(_events(1)) == root1
proof = merkle_proof(one, 0)
assert verify_proof(root1, _leaf_hash(one[0]), proof) is True
def test_export_json_carries_merkle_root():
"""合规导出 JSON 携带 merkleRoot,且与本地复算一致。"""
evs = _events(4)
payload = json.loads(export_events(evs, fmt="json"))
assert payload["merkleRoot"] == merkle_root(evs)