denoland/celldPublic

self-hosted, distributed Durable Objects

Let TLS sockets trust additional roots, as `fetch()` does

CO

In v0.5.1, `fetch()` verifies servers against:

- the Mozilla roots - the OS trust store - `SSL_CERT_FILE`

TCP sockets verify against the Mozilla roots only (`webpki_roots::TLS_SERVER_ROOTS`), which `cloudflare-compat.md` documents so that celld works on machines without `/etc/ssl/certs`. So a Worker can `fetch()` a server whose certificate comes from a private CA, but it can't open a TLS socket to it. That blocks database drivers such as `pg`, which upgrade with `startTls()`.

Repro: serve HTTPS on `localhost:8443` with a certificate from a private CA in `ca.pem`, then run this Worker with `SSL_CERT_FILE=ca.pem celld dev`:

```ts import { connect } from "cloudflare:sockets";

export default { async fetch() { const viaFetch = await fetch("https://localhost:8443/").then((r) => r.status, (e) => e.message); const socket = connect({ hostname: "localhost", port: 8443 }, { secureTransport: "starttls" }).startTls(); const viaSocket = await socket.opened.then(() => "ok", (e) => e.message);

return Response.json({ viaFetch, viaSocket }); }, }; ```

- Expected: `{ "viaFetch": 200, "viaSocket": "ok" }` - Actual: `{ "viaFetch": 200, "viaSocket": "TLS handshake failed: invalid peer certificate: UnknownIssuer" }`

Suggested fix: build the socket connector from the same roots as `reqwest` (native certs plus webpki), so `SSL_CERT_FILE` applies to every outbound TLS client. `ws_client.rs` builds its roots the same way and likely needs the same change.