test(perception): localize transport tails with bounded TLS record witnesses
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
"""Bounded diagnostic attribution; sparse local TLS checks, no source/model workload."""
|
||||
|
||||
# ruff: noqa: F811 -- imported shared fixtures
|
||||
import asyncio
|
||||
import hashlib
|
||||
import importlib
|
||||
from types import SimpleNamespace
|
||||
|
||||
import pytest
|
||||
from test_perception_network_graph_adapter import adapter # noqa: F401
|
||||
from test_perception_streaming_grpc import tls # noqa: F401
|
||||
|
||||
|
||||
def record(payload=b"opaque ciphertext"):
|
||||
return b"\x17\x03\x03" + len(payload).to_bytes(2, "big") + payload
|
||||
|
||||
|
||||
@pytest.mark.parametrize("cut", [1, 4, 5, 9, 21])
|
||||
def test_record_hash_identity_survives_arbitrary_tcp_chunks(adapter, cut):
|
||||
module = importlib.import_module("pilot_tls_record_trace")
|
||||
raw = record()
|
||||
witness = module.RecordWitness()
|
||||
witness.feed(raw[:cut], 10, 12)
|
||||
witness.feed(raw[cut:] + raw, 20, 24)
|
||||
result = witness.snapshot()
|
||||
assert result["bytes"] == 2 * len(raw) and result["incomplete_bytes"] == 0
|
||||
assert [r["offset"] for r in result["records"]] == [0, len(raw)]
|
||||
assert all(r["sha256"] == hashlib.sha256(raw).hexdigest() for r in result["records"])
|
||||
assert result["records"][0]["first_received_ns"] == "10"
|
||||
assert result["records"][0]["received_ns"] == "20"
|
||||
assert result["records"][1]["first_received_ns"] == "20"
|
||||
assert "ciphertext" not in str(result)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("fault", ["bytes", "records", "header", "record_length"])
|
||||
def test_trace_limits_fail_explicitly(adapter, fault):
|
||||
module = importlib.import_module("pilot_tls_record_trace")
|
||||
witness = module.RecordWitness(max_bytes=5 if fault == "bytes" else 1024, max_records=1)
|
||||
raw = record() * 2
|
||||
if fault == "header":
|
||||
raw = b"\x00\x03\x03\x00\x00"
|
||||
elif fault == "record_length":
|
||||
raw = b"\x17\x03\x03\xff\xff"
|
||||
with pytest.raises(ValueError, match="bounded"):
|
||||
witness.feed(raw, 1, 2)
|
||||
|
||||
|
||||
def test_two_relays_match_encrypted_records_and_original_clock_calls(tmp_path, tls, adapter):
|
||||
module = importlib.import_module("pilot_clock_route_probe")
|
||||
|
||||
async def check():
|
||||
cert, key = tmp_path / "cert.pem", tmp_path / "key.pem"
|
||||
cert.write_bytes(tls[0])
|
||||
key.write_bytes(tls[1])
|
||||
args = SimpleNamespace(
|
||||
target="127.0.0.1:0",
|
||||
bootstrap=tmp_path / "bootstrap.json",
|
||||
certificate=cert,
|
||||
private_key=key,
|
||||
samples=8,
|
||||
trace_relay=True,
|
||||
)
|
||||
server_report, client_report = {"samples": []}, {"samples": []}
|
||||
task = asyncio.create_task(module.server(args, server_report))
|
||||
try:
|
||||
async with asyncio.timeout(2):
|
||||
while "listen_port" not in server_report or not args.bootstrap.exists():
|
||||
await asyncio.sleep(0.01)
|
||||
client_args = SimpleNamespace(**vars(args))
|
||||
client_args.target = f"localhost:{server_report['listen_port']}"
|
||||
await module.client(client_args, client_report)
|
||||
await asyncio.wait_for(task, 2)
|
||||
assert server_report["accepted"] == 8 and server_report["rejected"] == 0
|
||||
assert len(client_report["rpc_calls"]) == len(server_report["rpc_calls"]) == 16
|
||||
assert not args.bootstrap.exists()
|
||||
for client, server in zip(
|
||||
client_report["rpc_calls"], server_report["rpc_calls"], strict=True
|
||||
):
|
||||
assert (client["method"], client["nonce"]) == (server["method"], server["nonce"])
|
||||
assert int(client["invoked_ns"]) < int(server["entered_ns"])
|
||||
assert int(server["returned_ns"]) < int(client["completed_ns"])
|
||||
a, b = client_report["tls_records"], server_report["tls_records"]
|
||||
assert len(a) == len(b) == 1
|
||||
assert a[0]["error"] is b[0]["error"] is None
|
||||
for direction in ("request", "response"):
|
||||
x, y = a[0][direction], b[0][direction]
|
||||
assert x["incomplete_bytes"] == y["incomplete_bytes"] == 0
|
||||
assert [(r["offset"], r["sha256"]) for r in x["records"]] == [
|
||||
(r["offset"], r["sha256"]) for r in y["records"]
|
||||
]
|
||||
assert len(x["records"]) >= 16
|
||||
finally:
|
||||
task.cancel()
|
||||
await asyncio.gather(task, return_exceptions=True)
|
||||
|
||||
asyncio.run(check())
|
||||
Reference in New Issue
Block a user