"""Memory ledger: hash-only stamp, verify, report. Same hash is idempotent.""" import pytest from verae_mcp_timestamping_server.ledger import MemoryLedger, SHA256_EMPTY pytestmark = pytest.mark.anyio async def test_stamp_returns_json_array_with_one_receipt(): ledger = MemoryLedger() receipts = await ledger.stamp(SHA256_EMPTY, scope="local") assert isinstance(receipts, list) assert len(receipts) == 1 rec = receipts[0] assert rec.hash == SHA256_EMPTY assert rec.scope == "local" assert rec.receipt_id assert rec.created_at assert rec.merkle async def test_same_hash_returns_same_receipt(): ledger = MemoryLedger() first = await ledger.stamp(SHA256_EMPTY, scope="local") second = await ledger.stamp(SHA256_EMPTY, scope="local") assert first[0].receipt_id == second[0].receipt_id assert first[0].created_at == second[0].created_at async def test_rejects_non_sha256(): ledger = MemoryLedger() with pytest.raises(ValueError, match="sha256"): await ledger.stamp("not-a-hash", scope="local") async def test_verify_receipt_and_scope_rank(): ledger = MemoryLedger() [rec] = await ledger.stamp(SHA256_EMPTY, scope="local") ok = await ledger.verify(rec.receipt_id, want_scope="local") assert ok.valid is True assert ok.receipt is not None assert ok.receipt.receipt_id == rec.receipt_id weak = await ledger.verify(rec.receipt_id, want_scope="global") assert weak.valid is False async def test_hash_report_is_json_array(): ledger = MemoryLedger() await ledger.stamp(SHA256_EMPTY, scope="local") report = await ledger.hash_report(SHA256_EMPTY) assert isinstance(report, list) assert report[0].hash == SHA256_EMPTY def test_validate_sha256_rejects_content_shaped_strings(): from verae_mcp_timestamping_server.ledger import validate_sha256 import base64 import pytest with pytest.raises(ValueError, match="sha256"): validate_sha256("") with pytest.raises(ValueError, match="sha256"): validate_sha256(base64.b64encode(b"hello world file bytes").decode()) with pytest.raises(ValueError, match="sha256"): validate_sha256("line1\nline2") def test_reject_content_keys_lists_forbidden(): import pytest from pydantic import ValidationError from verae_mcp_timestamping_server.guard import reject_content_keys with pytest.raises(ValidationError, match="content/bytes paths are rejected"): reject_content_keys({"sha256": "a" * 64, "content": "nope"}) reject_content_keys({"sha256": "a" * 64, "scope": "local"}) # ok