Files
boxmaker/docs/plans/M4a/05-gatewayd-net.md
T
kyleandClaude Opus 5.5 0339dc13b2 Plan M4a: gatewayd in 15 tasks, with skeletons and given tests
Each task's tests were run against a reference at its end state; the end states were replayed
from master in order with the gate at each step (650 to 762 tests); each skeleton compiles
against its tests and fails them. The reference is kept off this machine. Lessons T27 (every
wait in a test has a limit) and T28 (mutate the reference before hand-over) come from this work.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-23 19:05:44 -07:00

3.0 KiB

M4a task 05: a connection, plain or TLS

Branch: m4a (run git switch m4a; git status --short must be empty, otherwise stop) Commit subject: gatewayd: net, TCP or verified TLS to the Mattermost server

Goal

Every REST call and the WebSocket run over one kind of stream: plain TCP for an http URL, or TCP wrapped in TLS through rustls for https. TLS verifies the server's name against the host in the URL and its chain against the host's trusted certificates (rustls-native-certs) plus ca_file if given. Nothing can turn verification off. Spec section 5.

Files

  • Copy: crates/gatewayd/tests/net.rs, crates/gatewayd/tests/support/tls_server.rs, and the skeleton crates/gatewayd/src/net.rs
  • Modify: crates/gatewayd/src/lib.rs (pub mod net;), crates/gatewayd/Cargo.toml (below), docs/implementer-log.md

The tests' TLS server needs rustls too. Add to the end of crates/gatewayd/Cargo.toml:


[dev-dependencies]
rustls.workspace = true

The skeleton

Written, because they are mostly rustls API (checked against rustls 0.23.45): client_config(ca_file), which builds the root store and the ClientConfig with the ring provider, and Connector::connect, which connects to each address in turn, sets the read and write timeouts, and for TLS runs the handshake to its end so that a bad certificate is an error from connect and not from a later read. Read both before you start.

Also written: NetError (Roots, Connect, Tls) and its Display, and the types Stream (Plain(TcpStream) or Tls(Box<StreamOwned<ClientConnection, TcpStream>>)) and Connector.

To fill: Stream::tcp, Stream::set_read_timeout, Read and Write for Stream (forward to the inner stream in each variant), Connector::new and Connector::server.

Steps

  • 1. Copy. git switch m4a, then cp docs/plans/M4a/files/crates/gatewayd/tests/net.rs crates/gatewayd/tests/ && cp docs/plans/M4a/files/crates/gatewayd/tests/support/tls_server.rs crates/gatewayd/tests/support/ && cp docs/plans/M4a/files/crates/gatewayd/src/net.rs crates/gatewayd/src/. Add pub mod net; to lib.rs and the [dev-dependencies] above.
  • 2. See it fail. cargo test -p gatewayd --test net. Expected: it compiles and 7 tests fail.
  • 3. Fill the functions, cargo check -p gatewayd after each.
  • 4. See it pass. cargo test -p gatewayd --test net. Expected: 7 passed: plain TCP; TLS with the test CA; an unknown CA and a wrong name refused at connect; TLS to a plain server fails without hanging; a bad ca_file refused before any connection; nobody listening.
  • 5. Run the gate. cargo fmt --all, then make gate. Expected last line: gate: ok.
  • 6. Log and commit. git add crates/gatewayd docs/implementer-log.md Cargo.lock && git commit

Done when

  • cargo test -p gatewayd --test net passes; make gate prints gate: ok.

Stop and report if

  • A test passes only with verification weakened in any way (a custom verifier, a skipped name check). That is never the fix.