Add JSON integrity hash checks

This commit is contained in:
Marcel Peterkau
2026-06-27 10:35:35 +02:00
parent d1dab793a6
commit 87e972bb43
9 changed files with 302 additions and 11 deletions
+47
View File
@@ -4,6 +4,7 @@ from decimal import Decimal
import pytest
from ccma.domain.contributions import claim_balance
from ccma.services.housekeeper import Housekeeper
from ccma.storage.repository import (
MemberRepository,
RepositoryError,
@@ -37,6 +38,7 @@ def test_repository_creates_transparent_member_record(tmp_path) -> None:
assert raw["person"]["first_name"] == "Ada"
assert raw["person"]["nickname"] == "Enchantress"
assert raw["schema_version"] == 1
assert raw["content_hash"]
def test_search_matches_name_email_number_and_german_birth_date(tmp_path) -> None:
@@ -376,3 +378,48 @@ def test_negative_claim_can_be_settled_with_credit(tmp_path) -> None:
data, loaded_claim = repository.get_claim(member.member_id, str(claim["claim_id"]))
assert claim_balance(data, loaded_claim) == Decimal("0.00")
assert data.credits[0]["amount"] == "25.00"
def test_member_hash_warning_does_not_block_reading(tmp_path) -> None:
repository = MemberRepository(tmp_path)
repository.initialize()
member = repository.create_member(first_name="Ada", last_name="Lovelace")
path = repository.members_root / member.member_id / "member.json"
raw = json.loads(path.read_text(encoding="utf-8"))
raw["person"]["first_name"] = "Eve"
path.write_text(json.dumps(raw, ensure_ascii=False, indent=2), encoding="utf-8")
loaded = repository.get_member(member.member_id)
warnings = repository.member_hash_warnings(member.member_id)
assert loaded.first_name == "Eve"
assert warnings
assert "Hash fehlt oder stimmt nicht" in warnings[0]
def test_refresh_member_record_hashes_clears_hash_warning(tmp_path) -> None:
repository = MemberRepository(tmp_path)
repository.initialize()
member = repository.create_member(first_name="Ada", last_name="Lovelace")
path = repository.members_root / member.member_id / "member.json"
raw = json.loads(path.read_text(encoding="utf-8"))
raw["person"]["first_name"] = "Eve"
path.write_text(json.dumps(raw, ensure_ascii=False, indent=2), encoding="utf-8")
assert repository.member_hash_warnings(member.member_id)
repository.refresh_member_record_hashes(member.member_id)
assert repository.member_hash_warnings(member.member_id) == []
def test_housekeeper_reports_json_hash_mismatch(tmp_path) -> None:
repository = MemberRepository(tmp_path)
repository.initialize()
member = repository.create_member(first_name="Ada", last_name="Lovelace")
path = repository.members_root / member.member_id / "member.json"
raw = json.loads(path.read_text(encoding="utf-8"))
raw["person"]["last_name"] = "Example"
path.write_text(json.dumps(raw, ensure_ascii=False, indent=2), encoding="utf-8")
findings = Housekeeper(repository).run()
assert any(finding.code == "json_hash_mismatch" and finding.member_id == member.member_id for finding in findings)