@@ -62,11 +62,11 @@ def test_cloud_sync_rejects_tampered_or_plaintext_bundle():
6262 name , stored = next (iter (relay .bundles .items ()))
6363 relay .bundles [name ] = stored [:- 1 ] + bytes ([stored [- 1 ] ^ 1 ])
6464
65- with pytest .raises (RelayError , match = "could not be authenticated " ):
65+ with pytest .raises (RelayError , match = "unreadable bundle " ):
6666 list (receiver .pull ())
6767
6868 relay .bundles [name ] = b'{"legacy":"plaintext"}'
69- with pytest .raises (RelayError , match = "requires end-to-end encryption " ):
69+ with pytest .raises (RelayError , match = "unreadable bundle " ):
7070 list (receiver .pull ())
7171
7272
@@ -76,16 +76,59 @@ def test_cloud_sync_rejects_a_bundle_from_another_key_or_workspace():
7676 wrong_key = _transport (relay , 4 )
7777 sender .push ("bundle-dev_a.json" , b"private content" )
7878
79- with pytest .raises (RelayError , match = "could not be authenticated " ):
79+ with pytest .raises (RelayError , match = "unreadable bundle " ):
8080 list (wrong_key .pull ())
8181
8282 wrong_workspace = _transport (_MemoryRelay ("other" ), 3 )
8383 name , stored = next (iter (relay .bundles .items ()))
8484 wrong_workspace .relay .bundles [name ] = stored
85- with pytest .raises (RelayError , match = "could not be authenticated " ):
85+ with pytest .raises (RelayError , match = "unreadable bundle " ):
8686 list (wrong_workspace .pull ())
8787
8888
89+ @pytest .mark .parametrize ("bad_kind" , ["legacy" , "tampered" ], ids = ["legacy" , "tampered" ])
90+ def test_sync_engine_applies_later_encrypted_bundle_after_unreadable_relay_object (bad_kind ):
91+ """Legacy/corrupt relay objects cannot starve later authenticated peers."""
92+ relay = _MemoryRelay ()
93+ key = bytes (range (32 ))
94+ sender = MemoryEngine .create (":memory:" )
95+ receiver = MemoryEngine .create (":memory:" )
96+ sender_workspace = sender .store .get_or_create_workspace ("acme" )
97+ receiver_workspace = receiver .store .get_or_create_workspace ("acme" )
98+ sender .remember ("peer fact survives a bad relay object" , workspace_id = sender_workspace ,
99+ scope = Scope .WORKSPACE )
100+ sender_sync = SyncEngine (sender .store , embedder = sender .embedder , vector_index = sender .index )
101+ receiver_sync = SyncEngine (
102+ receiver .store , embedder = receiver .embedder , vector_index = receiver .index
103+ )
104+
105+ # The bad object is deliberately inserted before the sender's encrypted bundle.
106+ if bad_kind == "legacy" :
107+ relay .bundles ["bundle-legacy.json" ] = b'{"legacy":"plaintext"}'
108+ else :
109+ corrupt_writer = EncryptedRelayTransport (relay , key )
110+ corrupt_writer .push ("bundle-corrupt.json" , b"original authenticated ciphertext" )
111+ corrupt_name , ciphertext = next (iter (relay .bundles .items ()))
112+ relay .bundles [corrupt_name ] = ciphertext [:- 1 ] + bytes ([ciphertext [- 1 ] ^ 1 ])
113+ sender_sync .sync (EncryptedRelayTransport (relay , key ), sender_workspace )
114+
115+ report = receiver_sync .sync (
116+ EncryptedRelayTransport (relay , key ), receiver_workspace , push = False
117+ )
118+
119+ contents = {
120+ memory .content
121+ for memory in receiver .store .list_memories (SearchFilter (workspace_id = receiver_workspace ))
122+ }
123+ assert contents == {"peer fact survives a bad relay object" }
124+ assert report ["totals" ]["added" ] == 1
125+ assert report ["peers_applied" ] == 1
126+ assert report ["complete" ] is False
127+ assert report ["errors" ] == [
128+ {"bundle" : "?" , "error" : "transport failure" , "error_type" : "RelayError" }
129+ ]
130+
131+
89132def test_sync_engine_converges_through_encrypted_relay_without_plaintext_storage ():
90133 relay = _MemoryRelay ()
91134 key = bytes (range (32 ))
0 commit comments