Skip to content

feat(redis): add redix_opts for SSL/TLS support - #59

Merged
zoedsoupe merged 2 commits into
zoedsoupe:mainfrom
appunite:feat/redis-ssl-support
Nov 24, 2025
Merged

zoedsoupe merged 2 commits into
zoedsoupe:mainfrom
appunite:feat/redis-ssl-support

Conversation

@emilwojtaszek

@emilwojtaszek emilwojtaszek commented Nov 21, 2025 •

Copy link
Copy Markdown
Contributor

Summary

Add :redix_opts configuration option to Redis session store that allows passing custom Redix connection options. This enables connecting to cloud Redis providers requiring SSL/TLS with custom hostname verification (like Upstash, Redis Enterprise, etc.).

Problem

The Redis session store currently hardcodes Redix connection options, making it impossible to connect to cloud Redis providers that require SSL/TLS with custom hostname verification.

Upstash and similar providers use wildcard SSL certificates (e.g., *.upstash.io) which require custom hostname verification. Currently, users must create a full custom adapter (~400 lines) just to add SSL options.

Solution

Add a :redix_opts configuration option that merges with the default Redix options:

config :anubis_mcp, :session_store,
  adapter: Anubis.Server.Session.Store.Redis,
  redis_url: "rediss://default:password@host.upstash.io:6379",
  redix_opts: [
    ssl: true,
    socket_opts: [
      customize_hostname_check: [
        match_fun: :public_key.pkix_verify_hostname_match_fun(:https)
      ]
    ]
  ]

Changes

  • Extract custom_redix_opts from config options (defaults to [])
  • Merge custom options with defaults (custom takes precedence)
  • Document SSL/TLS configuration in moduledoc

Test plan

  • Existing tests pass (no breaking changes - defaults unchanged)
  • Tested with Upstash Redis in production environment

Summary by CodeRabbit

  • New Features
    • Session store supports per-pool Redis client options in configuration; custom options are merged with sensible defaults and applied per pool.
  • Validation
    • Configuration now validates supplied Redis client option formats to surface misconfiguration early.
  • Documentation
    • Docs updated with SSL/TLS examples for common providers (e.g., Upstash).
  • Notes
    • No public APIs or exported signatures were changed.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai

coderabbitai Bot commented Nov 21, 2025 •

Copy link
Copy Markdown

Walkthrough

The PR adds per-pool Redix options to Anubis.Server.Session.Store.Redis via a new :redix_opts configuration key. On init the module reads and validates :redix_opts, removes any external :name, merges those options with internal defaults (name, sync_connect, exit_on_disconnection) where custom options take precedence but the internal :name is preserved, and passes the resulting redix_opts to Redix.start_link/1 for each pool member. A validate_redix_opts/1 function enforces that :redix_opts is a keyword list. Documentation examples for TLS/SSL (e.g., Upstash) were added.

Sequence Diagram(s)

sequenceDiagram
    participant App as Application
    participant Store as Redis.Store (init)
    participant Config as Config (:redix_opts)
    participant PoolSupervisor as Pool Supervisor
    participant Redix as Redix.start_link

    App->>Store: start_link(opts)
    Store->>Config: read :redix_opts (may be nil)
    Store->>Store: validate_redix_opts(:redix_opts)
    
    rect rgb(230,245,230)
    note over Store: Merge Phase\n(drop external :name, keep internal naming)
    Store->>Store: take internal defaults\n(name, sync_connect, exit_on_disconnection)
    Store->>Store: drop user :name
    Store->>Store: merge defaults <- custom_opts (custom wins)
    end

    Store->>PoolSupervisor: build pool children spec (per-member redix_opts)
    PoolSupervisor->>Redix: start_link(redis_url + per-member redix_opts)
    Redix-->>PoolSupervisor: started / error
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

  • Single-file change focused on initialization and option validation/merging
  • Low control-flow complexity; mainly configuration handling and passing options to Redix

Areas to verify (priority P0–P3):

  • P0: Merge precedence — confirm custom options override defaults and that any user-supplied :name is intentionally dropped
  • P1: Internal naming scheme preserved (anubis_<conn_name>_<i>) and no collisions across pool members
  • P1: Redix.start_link/1 receives correct per-member args (URL + merged redix_opts)
  • P2: validate_redix_opts/1 rejects non-keyword lists and surfaces clear errors
  • P2: TLS/SSL example correctness for common providers (e.g., Upstash)
  • P3: Behavior when :redix_opts is absent (defaults used) and when invalid values are provided

Review with confidence, clarity & light humor 😎. Ensure MCP spec compliance & good Elixir/OTP patterns.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: adding redix_opts configuration to enable SSL/TLS support in the Redis adapter.
Description check ✅ Passed The description comprehensively follows the template with Problem, Solution, and additional context. However, it deviates slightly by using 'Summary' and 'Changes' sections instead of 'Rationale'.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9fd2eda and a95cc5b.

📒 Files selected for processing (1)
  • lib/anubis/server/session/store/redis.ex (2 hunks)

Comment thread lib/anubis/server/session/store/redis.ex Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a95cc5b and cbd83ed.

📒 Files selected for processing (1)
  • lib/anubis/server/session/store/redis.ex (2 hunks)
🔇 Additional comments (3)
lib/anubis/server/session/store/redis.ex (3)

16-33: Solid SSL/TLS documentation! 👍

The example configuration for Upstash-style TLS connections is clear and will save users significant time. The rediss:// URL and customize_hostname_check pattern is exactly what folks need for cloud Redis providers.

The earlier P3 suggestion about explicitly documenting merge precedence (custom options override defaults except :name) still applies if you'd like to make this even more self-explanatory for MCP integrators.


110-114: P1 concern addressed: :name stripping works correctly! ✅

This implementation properly prevents users from accidentally breaking the connection pool by overriding the internally-managed :name key. The Keyword.drop([:name]) ensures pool integrity while still allowing customization of SSL options, :sync_connect, :exit_on_disconnection, etc.

Exactly the fix the earlier P1 review requested. Well done!


121-129: Merge logic is spot-on! 🎯

The default options establish internal requirements (:name, :sync_connect: false, :exit_on_disconnection: false), then Keyword.merge(custom_redix_opts) allows user options to override everything except :name (which was stripped earlier). Custom SSL/TLS settings, socket options, and even tweaks to :sync_connect will work as expected without breaking the pool's naming convention.

Comment thread lib/anubis/server/session/store/redis.ex

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
lib/anubis/server/session/store/redis.ex (1)

16-18: Clarify how :redix_opts are merged & reserved keys (P3)

The SSL/TLS example is helpful and the basic config snippet is clear. To fully set expectations for MCP users, consider adding a short note in the moduledoc that:

  • :redix_opts are merged into a per-connection default option set (name, sync_connect, exit_on_disconnection),
  • user-provided keys override those defaults, and
  • :name is treated as reserved and ignored from :redix_opts (pool naming is always internal).

This matches the behaviour implemented later in init/1 and saves people from wondering why a custom name: is being dropped.

Also applies to: 19-33

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cbd83ed and 237c50c.

📒 Files selected for processing (1)
  • lib/anubis/server/session/store/redis.ex (3 hunks)

Comment thread lib/anubis/server/session/store/redis.ex
Comment thread lib/anubis/server/session/store/redis.ex Outdated
Add :redix_opts configuration option to Redis session store that allows
passing custom Redix connection options. This enables connecting to
cloud Redis providers requiring SSL/TLS with custom hostname verification
(like Upstash, Redis Enterprise, etc.).

Example configuration for Upstash:

    config :anubis_mcp, :session_store,
      adapter: Anubis.Server.Session.Store.Redis,
      redis_url: "rediss://...",
      redix_opts: [
        ssl: true,
        socket_opts: [
          customize_hostname_check: [
            match_fun: :public_key.pkix_verify_hostname_match_fun(:https)
          ]
        ]
      ]

Custom options are merged with defaults (custom takes precedence).
@zoedsoupe

Copy link
Copy Markdown
Owner

thanks for the contribution!

@zoedsoupe

Copy link
Copy Markdown
Owner

could you only ensure the lint on ci pass? basically it's missing formatting

Fixes CI formatting check failures:
- Replace Keyword.drop([:name]) with Keyword.delete(:name)
- Collapse multi-line keyword list to single line per formatter rules

Changes:
- Line 115: Use Keyword.delete/2 instead of Keyword.drop/1 for single key
- Lines 124-130: Inline keyword list merge for better readability

Quality verification:
- Follows Elixir formatter conventions
- Functionally identical (Keyword.delete(:name) is semantically correct for single key)

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cf1cb9e and c7f3cf6.

📒 Files selected for processing (1)
  • lib/anubis/server/session/store/redis.ex (3 hunks)
🔇 Additional comments (4)
lib/anubis/server/session/store/redis.ex (4)

110-115: Extraction and validation logic is solid! ✓

The pipeline correctly:

  1. Fetches :redix_opts with a safe default
  2. Validates it's a proper keyword list (or nil)
  3. Strips the reserved :name key before merging

This addresses the P1 concern from earlier reviews—users can no longer accidentally break the pool's internal naming scheme while still being able to customize SSL, socket options, and other Redix settings.


122-124: Merge logic is correct! 🎯

Keyword.merge/2 with defaults first and custom_redix_opts second gives custom options the intended precedence. Since :name was already stripped from custom_redix_opts (line 115), the internally computed child_id always controls the connection name, while users can still override :sync_connect, :exit_on_disconnection, or add SSL options.

The comments clearly document the behavior. Nice work!


128-128: Clean integration with Redix! 🔌

Passing redis_url and the computed redix_opts to Redix.start_link/2 is exactly the right call pattern. The defaults match the old hardcoded behavior (backward compatible), and custom SSL/TLS options now flow through correctly.


301-309: Validation helper is tight and user-friendly! ✓

The function correctly:

  • Accepts nil and treats it as "no extra options" (forgiving)
  • Uses Keyword.keyword?/1 to enforce proper keyword list structure (precise)
  • Raises a clear ArgumentError for invalid input

This catches configuration mistakes early (e.g., [:ssl, true] instead of [ssl: true]) with a helpful error message, rather than letting Redix or Keyword.delete/2 fail cryptically later.

Comment thread lib/anubis/server/session/store/redis.ex
@zoedsoupe
zoedsoupe merged commit 33658ab into zoedsoupe:main Nov 24, 2025
10 checks passed
@zoedsoupe zoedsoupe mentioned this pull request Nov 24, 2025
zoedsoupe added a commit that referenced this pull request Dec 9, 2025
🚀 Want to release this?
---


##
[0.17.0](v0.16.0...v0.17.0)
(2025-12-09)


### Features

* **redis:** add redix_opts for SSL/TLS support
([#59](#59))
([33658ab](33658ab))


### Bug Fixes

* added server component description/0 callback
([#58](#58))
([a094473](a094473))
* redix should be loaded
([#71](#71))
([09b872f](09b872f))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
  * Added Redis SSL/TLS support via redix options.

* **Bug Fixes**
  * Fixed server component description callback issue.
  * Fixed redix loading issue.

<sub>✏️ Tip: You can customize this high-level summary in your review
settings.</sub>

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
zoedsoupe added a commit that referenced this pull request Jul 16, 2026
🚀 Want to release this?
---


##
[0.17.0](v0.16.0...v0.17.0)
(2025-12-09)


### Features

* **redis:** add redix_opts for SSL/TLS support
([#59](#59))
([3fd674a](3fd674a))


### Bug Fixes

* added server component description/0 callback
([#58](#58))
([a094473](a094473))
* redix should be loaded
([#71](#71))
([c352414](c352414))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
  * Added Redis SSL/TLS support via redix options.

* **Bug Fixes**
  * Fixed server component description callback issue.
  * Fixed redix loading issue.

<sub>✏️ Tip: You can customize this high-level summary in your review
settings.</sub>

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This was referenced Jul 16, 2026
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.

2 participants