Skip to content

Speak TLS inside the simulation - #28

Merged
dhruvl merged 8 commits into
mainfrom
tls
Aug 4, 2026
Merged

Speak TLS inside the simulation#28
dhruvl merged 8 commits into
mainfrom
tls

Conversation

@dhruvl

@dhruvl dhruvl commented Aug 4, 2026

Copy link
Copy Markdown
Owner

TLS now runs inside the simulation, on every route a program can ask for it: create_connection(ssl=...), create_server(ssl=...), and start_tls on an established connection. The handshake is real — the standard library's SSLProtocol drives an ssl.SSLObject over a pair of memory BIOs, the same machinery uvloop reuses — with real certificate verification against whatever context the caller provides. No descriptor and no real socket anywhere: each flight OpenSSL produces leaves as one simulated packet paying the link's seeded latency, so a TLS connect costs the two round trips it costs in production, and ssl_handshake_timeout / ssl_shutdown_timeout are ordinary loop timers firing in virtual time. A handshake stalled by a partition burns sixty virtual seconds and milliseconds of wall clock.

What the transport had to learn: buffered-protocol delivery (SSLProtocol is a BufferedProtocol), protocol adoption in one place so start_tls can swap protocols mid-stream, and _force_close. All composed with the flow-control machinery — credits stay where the protocol takes the bytes, and _force_close routes through the same teardown that zeroes the write buffer.

Determinism, measured rather than promised: TLS bytes are random every run, but the trace hashes only the number and order of packets and callbacks, and SSLProtocol emits exactly one write per flight — so an EC leaf and an RSA leaf record the same hash, pinned by a test that re-mints the certificate between runs. What does move the hash is flight structure: the OpenSSL build and context settings like num_tickets. For TLS workloads the promise therefore gains one clause — same OpenSSL build, same TLS configuration — and only for TLS workloads: both reference workloads are held to pre-change digests across seeds, proving a run that never asks for TLS records exactly what it recorded before.

The compatibility table gains three measured rows, regenerated from the probes: aiohttp ClientSession over https:// (its sock_connect + create_connection(ssl=, sock=) path answered end to end), httpx over https:// (its own in-memory TLS, now with a simulated peer that speaks it), and websockets over wss:// (the one row exercising server-side TLS and client-side in one run). trustme mints throwaway in-memory CAs for tests and probes — dev and probes dependency groups only, nothing at runtime, no key material in the tree.

547 tests, the slow replay-stability suite (including TLS runs replayed across processes and hash seeds), and strict mypy are green; the per-step benchmark is unmoved (4.51 µs against the published ~4.4 µs).

@dhruvl
dhruvl merged commit 8690bb9 into main Aug 4, 2026
9 checks passed
@dhruvl
dhruvl deleted the tls branch August 4, 2026 09:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant