gabriel / muse public
test_public_key_fingerprint.py python
157 lines 6.5 KB
Raw
sha256:51ce277f663e01a43eaffbe77509b1de7ac2d4251b55d23306304bcdeb92c90d feat(pack): delta-encode snapshots in MPackBundle wire format Sonnet 4.6 minor ⚠ breaking 122 days ago
1 """Tests for the canonical public_key_fingerprint function.
2
3 All public key fingerprints in Muse must use the sha256: prefix — the same
4 convention as every other content-addressed value. These tests drive the
5 single canonical implementation in muse.core.types.
6 """
7 from __future__ import annotations
8
9 import pathlib
10 import pytest
11
12 from muse.core.types import blob_id, split_id
13
14
15 class TestPublicKeyFingerprintCanonical:
16 """The canonical function lives in muse.core.types."""
17
18 def test_returns_sha256_prefixed_string(self) -> None:
19 from muse.core.types import public_key_fingerprint
20 fp = public_key_fingerprint(b"\x00" * 32)
21 assert fp.startswith("sha256:")
22
23 def test_hex_portion_is_64_chars(self) -> None:
24 from muse.core.types import public_key_fingerprint
25 fp = public_key_fingerprint(b"\x00" * 32)
26 _, hex_part = split_id(fp)
27 assert len(hex_part) == 64
28
29 def test_hex_portion_is_lowercase_hex(self) -> None:
30 from muse.core.types import public_key_fingerprint
31 fp = public_key_fingerprint(b"\xff" * 32)
32 _, hex_part = split_id(fp)
33 assert all(c in "0123456789abcdef" for c in hex_part)
34
35 def test_correct_sha256_of_input(self) -> None:
36 from muse.core.types import public_key_fingerprint
37 data = b"test public key bytes"
38 expected = blob_id(data)
39 assert public_key_fingerprint(data) == expected
40
41 def test_known_zero_key(self) -> None:
42 from muse.core.types import public_key_fingerprint
43 data = b"\x00" * 32
44 expected = blob_id(data)
45 assert public_key_fingerprint(data) == expected
46
47 def test_deterministic(self) -> None:
48 from muse.core.types import public_key_fingerprint
49 data = b"deterministic input"
50 assert public_key_fingerprint(data) == public_key_fingerprint(data)
51
52 def test_different_inputs_produce_different_fingerprints(self) -> None:
53 from muse.core.types import public_key_fingerprint
54 assert public_key_fingerprint(b"aaa") != public_key_fingerprint(b"bbb")
55
56 def test_empty_bytes(self) -> None:
57 from muse.core.types import public_key_fingerprint
58 fp = public_key_fingerprint(b"")
59 assert fp == blob_id(b"")
60
61 def test_total_length_is_71(self) -> None:
62 # "sha256:" (7) + 64 hex chars = 71
63 from muse.core.types import public_key_fingerprint
64 assert len(public_key_fingerprint(b"x" * 32)) == 71
65
66
67 class TestPublicKeyFingerprintKeypairModule:
68 """keypair.py::public_key_fingerprint must delegate to _types and return prefixed value."""
69
70 def test_returns_sha256_prefixed_string(self) -> None:
71 from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
72 from muse.core.keypair import public_key_fingerprint
73 private_key = Ed25519PrivateKey.generate()
74 public_key = private_key.public_key()
75 fp = public_key_fingerprint(public_key)
76 assert fp.startswith("sha256:")
77
78 def test_hex_portion_is_64_chars(self) -> None:
79 from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
80 from muse.core.keypair import public_key_fingerprint
81 private_key = Ed25519PrivateKey.generate()
82 fp = public_key_fingerprint(private_key.public_key())
83 _, hex_part = split_id(fp)
84 assert len(hex_part) == 64
85
86 def test_consistent_with_types_module(self) -> None:
87 from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
88 from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat
89 from muse.core.types import public_key_fingerprint as canonical_fp
90 from muse.core.keypair import public_key_fingerprint as keypair_fp
91 private_key = Ed25519PrivateKey.generate()
92 public_key = private_key.public_key()
93 raw = public_key.public_bytes(Encoding.Raw, PublicFormat.Raw)
94 assert keypair_fp(public_key) == canonical_fp(raw)
95
96
97 class TestNoBareFingerprintsAnywhere:
98 """The old bare-hex implementations must no longer exist."""
99
100 def test_agent_fingerprint_function_is_gone(self) -> None:
101 import importlib
102 import inspect
103 mod = importlib.import_module("muse.cli.commands.agent")
104 # _fingerprint should not exist as a standalone function anymore
105 assert not hasattr(mod, "_fingerprint"), (
106 "_fingerprint still exists in agent.py — delete it and route callers "
107 "through muse.core.types.public_key_fingerprint"
108 )
109
110 def test_provenance_fingerprint_function_is_gone(self) -> None:
111 import importlib
112 mod = importlib.import_module("muse.core.provenance")
113 assert not hasattr(mod, "public_key_fingerprint"), (
114 "public_key_fingerprint still exists in provenance.py — delete it and "
115 "route callers through muse.core.types.public_key_fingerprint"
116 )
117
118
119 class TestFingerprintInIdentityEntry:
120 """Fingerprints written to identity.toml must carry the sha256: prefix."""
121
122 def test_derive_hd_public_info_returns_prefixed_fingerprint(self) -> None:
123 from muse.core.keypair import derive_hd_public_info
124 seed = b"\x00" * 64
125 _, fingerprint = derive_hd_public_info(seed)
126 assert fingerprint.startswith("sha256:"), (
127 f"derive_hd_public_info returned bare fingerprint {fingerprint!r} — "
128 "must be sha256:-prefixed"
129 )
130
131 def test_fingerprint_field_in_identity_entry_is_prefixed(self, tmp_path: pathlib.Path) -> None:
132 """Round-trip: save an identity, load it back, fingerprint has prefix."""
133 from muse.core.identity import save_identity, load_identity
134 from muse.core.types import public_key_fingerprint
135 import secrets
136
137 fingerprint = public_key_fingerprint(b"fake-public-key-bytes")
138 entry = {
139 "type": "human",
140 "handle": "gabriel",
141 "key_path": str(tmp_path / "key.pem"),
142 "algorithm": "ed25519",
143 "fingerprint": fingerprint,
144 }
145 # Monkeypatch the identity file location
146 import muse.core.identity as id_mod
147 orig = id_mod._IDENTITY_FILE
148 id_mod._IDENTITY_FILE = tmp_path / "identity.toml"
149 try:
150 save_identity("localhost:1337", entry) # type: ignore[arg-type]
151 loaded = load_identity("localhost:1337")
152 assert loaded is not None
153 assert loaded.get("fingerprint", "").startswith("sha256:"), (
154 f"Loaded fingerprint {loaded.get('fingerprint')!r} lacks sha256: prefix"
155 )
156 finally:
157 id_mod._IDENTITY_FILE = orig
File History 1 commit
sha256:51ce277f663e01a43eaffbe77509b1de7ac2d4251b55d23306304bcdeb92c90d feat(pack): delta-encode snapshots in MPackBundle wire format Sonnet 4.6 minor 122 days ago