You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* Add SSL/TLS connection support via SSLMode configuration
Introduces SSLMode (SSLDisabled | SSLRequired) so callers can opt into
TLS by passing an SSLContext through ConnectInfo. Session.create matches
on the mode to choose between lori's plaintext and SSL client
constructors; the state machine is unchanged since lori handles the
TLS handshake before firing on_connected.
Adds dual-container test infrastructure: a TLS-enabled Redis Docker
image (.ci-dockerfiles/redis-ssl) for CI and local Makefile targets
that start both plaintext (port 6379) and TLS (port 6380) containers.
Three new integration tests exercise SSL connection failure, connect-
and-ready, and SET/GET over TLS.
Design: #2
* Add examples/README.md describing each example program
* Install openssl package in redis-ssl Dockerfile
The redis:7 base image doesn't include the openssl CLI tools needed
to generate self-signed certificates at build time.
* Fix redis-ssl key permission for redis user
The redis:7 image runs as the redis user, but the key was owned by
root with 600 permissions. chown to redis:redis before chmod.
Copy file name to clipboardExpand all lines: CLAUDE.md
+22-5Lines changed: 22 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -7,8 +7,8 @@ make # build and run all tests (requires Redis running)
7
7
make unit-tests # run unit tests only (no Redis needed)
8
8
make integration-tests # run integration tests only (requires Redis)
9
9
make build-examples # build example programs
10
-
make start-redis # start Redis in Docker for local testing
11
-
make stop-redis # stop and remove Docker Redis
10
+
make start-redis # start plaintext + SSL Redis in Docker
11
+
make stop-redis # stop and remove both Redis containers
12
12
make clean # clean build artifacts
13
13
```
14
14
@@ -40,14 +40,21 @@ Package: `redis`
40
40
### Session Layer
41
41
42
42
-`Session` (actor in `session.pony`): Main entry point. Manages connection lifecycle and pub/sub via a state machine. Implements `lori.TCPConnectionActor & lori.ClientLifecycleEventReceiver`. All state machine classes (`_SessionUnopened`, `_SessionConnected`, `_SessionReady`, `_SessionSubscribed`, `_SessionClosed`) are in `session.pony`, following the postgres pattern.
43
-
-`ConnectInfo` (in `connect_info.pony`): Connection configuration (host, port, optional password).
-`SessionStatusNotify` (in `session_status_notify.pony`): Lifecycle callback interface. All callbacks have default no-op implementations. Callbacks: `redis_session_connected`, `redis_session_connection_failed`, `redis_session_ready`, `redis_session_authentication_failed`, `redis_session_closed`.
45
45
-`ResultReceiver` (in `result_receiver.pony`): Command response callback interface. Callbacks: `redis_response`, `redis_command_failed`.
46
46
-`SubscriptionNotify` (in `subscription_notify.pony`): Pub/sub callback interface. All callbacks have default no-op implementations. Callbacks: `redis_subscribed`, `redis_unsubscribed`, `redis_message`, `redis_psubscribed`, `redis_punsubscribed`, `redis_pmessage`.
47
47
-`ClientError` (in `client_error.pony`): Client-side error trait with `SessionNotReady`, `SessionClosed`, and `SessionInSubscribedMode` primitives.
48
48
-`_ResponseHandler` (in `_response_handler.pony`): Loops `_RespParser` over a `buffered.Reader`, delivering parsed `RespValue`s to the current state. Shuts down on `RespMalformed`.
49
49
-`_IllegalState` / `_Unreachable` (in `_mort.pony`): Primitives for detecting impossible states.
50
50
51
+
### SSL/TLS
52
+
53
+
-`SSLMode` (type alias in `ssl_mode.pony`): `(SSLDisabled | SSLRequired)`. Controls whether the session uses plaintext TCP or SSL/TLS.
54
+
-`SSLDisabled` (primitive in `ssl_mode.pony`): Plaintext TCP connection (default).
55
+
-`SSLRequired` (class val in `ssl_mode.pony`): Wraps an `SSLContext val` for direct TLS connections. Redis uses direct TLS (typically port 6380) rather than STARTTLS.
56
+
- The `ssl/net` package is a transitive dependency via lori (no `corral.json` change needed). Adding `use "ssl/net"` in source files is sufficient.
57
+
51
58
### Trait Composition
52
59
53
60
-`_ClosedState`: Mixin for the terminal state — rejects or no-ops all operations.
@@ -80,13 +87,23 @@ In `_SessionSubscribed`, any pipelined commands that were in-flight when SUBSCRI
80
87
- Unit tests: `--exclude=integration/` — no external dependencies
81
88
- Integration tests: `--only=integration/` — require a running Redis server
82
89
- Test names prefixed with `integration/` for filtering
83
-
-`_RedisTestConfiguration` reads `REDIS_HOST` and `REDIS_PORT` from environment (defaults to `127.0.0.2`/`6379` on Linux for WSL2 compatibility)
90
+
-`_RedisTestConfiguration` reads environment variables for both plaintext and SSL Redis:
91
+
-`REDIS_HOST` / `REDIS_PORT` — plaintext (defaults to `127.0.0.2`/`6379` on Linux)
92
+
-`REDIS_SSL_HOST` / `REDIS_SSL_PORT` — TLS (defaults to same host/`6380`)
93
+
94
+
### SSL-to-Plaintext Deadlock
95
+
96
+
Do not write tests that connect with SSL to a plaintext Redis server. The TLS ClientHello is binary data with no `\r\n`, so Redis's RESP parser buffers it waiting for a line terminator. Meanwhile the SSL client waits for a ServerHello. Neither side sends more data — both block indefinitely. To test the SSL constructor path, connect to a non-listening port instead (TCP connection refused is fast and deterministic).
84
97
85
98
### CI
86
99
87
-
Both `pr.yml` and `breakage-against-ponyc-latest.yml` use the `shared-docker-ci-standard-builder-with-libressl-4.2.0` image (for ssl support) and a `redis:7` service container with health checks. Integration tests receive `REDIS_HOST=redis` and `REDIS_PORT=6379` as environment variables. All make targets pass `ssl=libressl`.
100
+
Both `pr.yml` and `breakage-against-ponyc-latest.yml` use the `shared-docker-ci-standard-builder-with-libressl-4.2.0` image (for ssl support) and two Redis service containers: `redis` (plaintext) and `redis-ssl` (TLS via `ghcr.io/ponylang/redis-ci-redis-ssl:latest`). Integration tests receive `REDIS_HOST=redis`, `REDIS_PORT=6379`, `REDIS_SSL_HOST=redis-ssl`, and `REDIS_SSL_PORT=6379`. All make targets pass `ssl=libressl`.
101
+
102
+
The `redis-ssl` CI image is built via `build-ci-image.yml` (manually triggered `workflow_dispatch`). Source: `.ci-dockerfiles/redis-ssl/Dockerfile`. Build locally with `.ci-dockerfiles/redis-ssl/build-and-push.bash`.
88
103
89
104
## File Layout
90
105
91
106
-`redis/` — main package source
92
107
-`examples/` — example programs
108
+
-`assets/` — test certificates for SSL Redis container
109
+
-`.ci-dockerfiles/` — Dockerfiles for CI service containers
Each subdirectory is a self-contained Pony program demonstrating a different part of the redis library.
4
+
5
+
## basic
6
+
7
+
Minimal example. Connects to Redis, executes `SET hello world`, prints the response, and closes the session. Shows how to create a `ConnectInfo`, implement `SessionStatusNotify` and `ResultReceiver` on a single actor, and match on `RespValue` variants. Start here if you're new to the library.
8
+
9
+
## pipeline
10
+
11
+
Command pipelining. Sends 3 SET commands followed by 3 GET commands without waiting for individual responses — all 6 commands are dispatched immediately in `redis_session_ready`. Responses arrive in order and are tracked with a step counter. Shows how pipelining eliminates round-trip latency for independent commands.
12
+
13
+
## pubsub
14
+
15
+
Pub/sub messaging using two sessions. One session subscribes to `demo-channel`, the other publishes a message to it. Demonstrates the `SubscriptionNotify` interface (`redis_subscribed`, `redis_message`, `redis_unsubscribed`) and the two-session pattern required because a subscribed session cannot execute regular commands.
16
+
17
+
## ssl
18
+
19
+
SSL/TLS-encrypted connection. Same workflow as `basic` (connects and sends PING) but over TLS using `SSLRequired`. Demonstrates how to create an `SSLContext` with a CA certificate, wrap it in `SSLRequired`, and pass it to `ConnectInfo`. Requires a Redis server configured for TLS. Set `REDIS_HOST`, `REDIS_PORT`, and `REDIS_CA_PATH` environment variables to match your server.
0 commit comments