#675 serve-auth: static TLS for swamp serve
Opened by stack72 · 6/18/2026· Shipped 6/18/2026
Parent
Sub-issue of #662 (serve authentication & authorization). Layer 3.
Summary
Add static TLS support to `swamp serve` so the server can be exposed on a network with encrypted transport. This is the foundation for off-loopback serving — the hard refusal rules (layer 6) will require TLS when binding off-loopback.
Currently `swamp serve` runs plain HTTP/WebSocket only (`ws://`). This issue adds `--cert-file` and `--key-file` CLI flags that enable TLS, switching to `wss://`/`https://`.
What to build
CLI flags
Add two new options to the serve command in `src/cli/commands/serve.ts`:
- `--cert-file path:string` — path to PEM-encoded TLS certificate
- `--key-file path:string` — path to PEM-encoded TLS private key
Both must be provided together. If only one is provided, refuse to start with a clear error.
Deno.serve TLS wiring
`Deno.serve()` accepts `cert` and `key` as PEM strings directly:
```typescript const serveOptions: Deno.ServeOptions = { port, hostname: host, signal: ac.signal, };
if (certFile && keyFile) { serveOptions.cert = await Deno.readTextFile(certFile); serveOptions.key = await Deno.readTextFile(keyFile); }
const server = Deno.serve(serveOptions, handler); ```
Output updates
When TLS is enabled:
- `onListen` should output `wss://` instead of `ws://` in both log and JSON modes
- The remote-execution design doc notes that workers derive the data-plane URL from the connect URL (`wss → https`), so this propagates correctly to the HTTP/2 data plane automatically
Validation
- If `--cert-file` is provided without `--key-file` (or vice versa), refuse to start with a clear error
- If the cert or key file doesn't exist or isn't readable, fail at startup with a clear error (not at first connection)
- If the cert/key are invalid PEM, `Deno.serve` will throw — let that propagate with a clear error message
Environment variable support
Consider `SWAMP_SERVE_CERT_FILE` and `SWAMP_SERVE_KEY_FILE` env vars as alternatives to CLI flags, following the pattern of `SWAMP_REPO_DIR` for `--repo-dir`. CLI flags take precedence.
Scope
- Modify `src/cli/commands/serve.ts` — add CLI flags, read cert/key files, pass to `Deno.serve`, update onListen output
- Add a test verifying the validation logic (both flags required together, file-not-found errors)
- No changes to the data plane, worker gateway, or connection handler — TLS is transparent at the Deno.serve level
Out of scope
- ACME / Let's Encrypt — phase 2
- Hard refusals for off-loopback without TLS — layer 6 (separate issue)
- Auth config — layer 4 (separate issue)
References
- Serve command: `src/cli/commands/serve.ts` (lines 68-79 for options, 297-318 for Deno.serve call)
- Off-loopback warning: `src/cli/commands/serve.ts` lines 103-108
- Remote execution design (TLS/ALPN notes): `design/remote-execution.md` lines 565-570
- Client URL normalization (already handles wss://): `src/cli/remote_run.ts` lines 56-76
Shipped
Click a lifecycle step above to view its details.