tests/test_segment.py
2.0 KB · 69 lines · python Raw
1 """Tests for AuditSegment and SegmentHeader."""
2
3 from __future__ import annotations
4
5 from pqc_audit_log_fs.event import InferenceEvent
6 from pqc_audit_log_fs.segment import AuditSegment, SegmentHeader
7
8
9 def _make_event(i: int) -> InferenceEvent:
10 return InferenceEvent.create(
11 model_did="did:pqaid:m",
12 model_version="1.0",
13 input_bytes=f"in-{i}".encode(),
14 output_bytes=f"out-{i}".encode(),
15 )
16
17
18 def test_recompute_root_fills_fields() -> None:
19 header = SegmentHeader(
20 segment_id="segment-00001",
21 segment_number=1,
22 created_at="2026-04-20T00:00:00+00:00",
23 )
24 segment = AuditSegment(header=header, events=[_make_event(i) for i in range(4)])
25 root = segment.recompute_root()
26 assert len(root) == 64
27 assert segment.header.event_count == 4
28 assert segment.header.merkle_root == root
29
30
31 def test_header_roundtrip() -> None:
32 h1 = SegmentHeader(
33 segment_id="segment-00002",
34 segment_number=2,
35 created_at="2026-04-20T01:00:00+00:00",
36 sealed_at="2026-04-20T02:00:00+00:00",
37 event_count=3,
38 merkle_root="deadbeef" * 8,
39 previous_segment_root="cafef00d" * 8,
40 log_id="urn:pqc-audit-log:xyz",
41 signer_did="did:pqaid:signer",
42 algorithm="ML-DSA-65",
43 signature="ab" * 64,
44 public_key="cd" * 64,
45 )
46 data = h1.to_dict()
47 h2 = SegmentHeader.from_dict(data)
48 assert h1 == h2
49
50
51 def test_canonical_bytes_deterministic() -> None:
52 h = SegmentHeader(
53 segment_id="segment-00001",
54 segment_number=1,
55 created_at="2026-04-20T00:00:00+00:00",
56 sealed_at="2026-04-20T00:10:00+00:00",
57 event_count=5,
58 merkle_root="ab" * 32,
59 previous_segment_root="",
60 log_id="urn:pqc-audit-log:1",
61 )
62 b1 = h.canonical_bytes()
63 b2 = h.canonical_bytes()
64 assert b1 == b2
65 # Signature/public_key fields are NOT part of the canonical payload.
66 h.signature = "deadbeef"
67 h.public_key = "cafe"
68 assert h.canonical_bytes() == b1
69