Skip to content

feat(router): add TLS support for NATS event source#2749

Open
vatsalpatel wants to merge 8 commits intowundergraph:mainfrom
vatsalpatel:feat/nats-tls
Open

feat(router): add TLS support for NATS event source#2749
vatsalpatel wants to merge 8 commits intowundergraph:mainfrom
vatsalpatel:feat/nats-tls

Conversation

@vatsalpatel
Copy link
Copy Markdown

@vatsalpatel vatsalpatel commented Apr 8, 2026

Add a tls block to NatsEventSource supporting four modes: no TLS (omit block), skip verify, custom CA (1-way TLS), and mTLS.

  • New NatsTLSConfiguration struct with insecure_skip_verify, ca_file, cert_file, and key_file fields
  • TLS option building in buildNatsOptions via nats.Secure(tlsCfg); cert/key pair validated together, missing CA file surfaced at startup
  • config.schema.json updated with tls object (additionalProperties: false)
  • Golden fixture updated
  • Tests for all modes and error paths in both config_events_nats_test.go and provider_builder_test.go

Closes #2582

Summary by CodeRabbit

  • New Features

    • Added optional TLS configuration for NATS event providers: skip-server-cert verification, custom CA, and mutual TLS (client cert/key). Schema and sample config updated.
  • Tests

    • Added unit tests covering TLS success and failure cases, including validation for missing/mismatched fields and unknown attributes.
  • Documentation

    • Updated NATS provider docs with TLS reference, examples for modes, and a warning about disabling certificate verification.

Checklist

  • I have discussed my proposed changes in an issue and have received approval to proceed.
  • I have followed the coding standards of the project.
  • Tests or benchmarks have been added or updated.
  • Documentation has been updated on https://github.com/wundergraph/cosmo-docs.
  • I have read the Contributors Guide.

  Add a \`tls\` block to \`NatsEventSource\` supporting four modes: no TLS
  (omit block), skip verify, custom CA (1-way TLS), and mTLS.

  - New \`NatsTLSConfiguration\` struct with \`insecure_skip_verify\`,
    \`ca_file\`, \`cert_file\`, and \`key_file\` fields
  - TLS option building in \`buildNatsOptions\` via \`nats.Secure(tlsCfg)\`;
    cert/key pair validated together, missing CA file surfaced at startup
  - \`config.schema.json\` updated with \`tls\` object
    (\`additionalProperties: false\`)
  - Golden fixture updated
  - Tests for all modes and error paths in both \`config_events_nats_test.go\`
    and \`provider_builder_test.go\`

  Closes wundergraph#2582
# Conflicts:
#	router/pkg/config/config.go
#	router/pkg/config/config.schema.json
#	router/pkg/config/testdata/config_full.json
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 8, 2026

Walkthrough

Adds TLS support for NATS event sources: new NatsTLSConfiguration type and optional TLS field on NatsEventSource; JSON schema and testdata updates; TLS option construction in the NATS provider builder (skip-verify, custom CA, mTLS); unit tests; and documentation updates.

Changes

Cohort / File(s) Summary
Config types & schema
router/pkg/config/config.go, router/pkg/config/config.schema.json
Added NatsTLSConfiguration (insecure_skip_verify, ca_file, cert_file, key_file) and TLS *NatsTLSConfiguration on NatsEventSource. Extended JSON schema with events.providers.nats[].tls object (no additionalProperties) and mutual dependency rules for cert_filekey_file.
Config tests & fixtures
router/pkg/config/config_events_nats_test.go, router/pkg/config/testdata/config_full.json
Added tests validating TLS schema handling (valid: skip-verify, CA+mTLS; invalid: missing cert/key counterpart, unknown TLS field). Updated testdata to include "TLS": null for NATS providers.
NATS provider TLS implementation
router/pkg/pubsub/nats/provider_builder.go
buildNatsOptions now builds a tls.Config when eventSource.TLS is set: applies InsecureSkipVerify, optionally loads CA into RootCAs, validates/loads client cert+key for mTLS, and appends nats.Secure(tlsCfg); returns errors for unreadable/misconfigured files.
NATS provider TLS tests
router/pkg/pubsub/nats/provider_builder_test.go
Added TestBuildNatsOptionsWithTLS covering success cases (skip-verify, CA-only, mTLS) and failure cases (missing/unreadable CA, only cert or key, mTLS without CA). Added helpers to generate temporary PEM files for tests.
Docs
docs-website/router/configuration.mdx
Documented new tls block for NATS provider, described supported TLS modes (no TLS, skip-verify, custom CA, mTLS), added YAML examples and warning about insecure_skip_verify.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 5 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 15.38% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat(router): add TLS support for NATS event source' accurately and concisely describes the main change—adding TLS capability to the NATS event source.
Linked Issues check ✅ Passed The pull request fully implements all coding objectives from issue #2582: adds NatsTLSConfiguration struct with TLS fields, adds TLS field to NatsEventSource, implements TLS option building in buildNatsOptions using nats.Secure(), updates config.schema.json, testdata fixture, and comprehensive tests.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing TLS support for NATS as specified in issue #2582; no unrelated modifications were introduced.
Description check ✅ Passed The pull request provides a clear description of TLS support for NATS including four supported modes, configuration structure, implementation details, and testing approach.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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.

@vatsalpatel
Copy link
Copy Markdown
Author

Docs PR: wundergraph/cosmo-docs#261

@alepane21
Copy link
Copy Markdown
Contributor

Docs PR: wundergraph/cosmo-docs#261

Hi @vatsalpatel,
thank you for your contribution!
We recently moved documentation to this repo, inside the docs-website folder, so the external PR is not needed anymore, you can just add the docs changes inside this PR.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
router/pkg/config/config.schema.json (1)

2553-2579: Add schema-level dependency rules for mTLS fields.

Consider enforcing cert_file/key_file pairing and ca_file requirement directly in schema so invalid TLS combos fail at config validation time (not only at startup runtime).

🧩 Proposed schema refinement
                   "tls": {
                     "type": "object",
                     "description": "TLS configuration for the NATS provider.",
                     "additionalProperties": false,
                     "properties": {
                       "insecure_skip_verify": {
                         "type": "boolean",
                         "default": false,
                         "description": "Skip server certificate verification. Not recommended for production use."
                       },
                       "ca_file": {
                         "type": "string",
                         "description": "Path to a custom CA certificate file (PEM) used to verify the server certificate.",
                         "format": "file-path"
                       },
                       "cert_file": {
                         "type": "string",
                         "description": "Path to the client certificate file (PEM) for mTLS.",
                         "format": "file-path"
                       },
                       "key_file": {
                         "type": "string",
                         "description": "Path to the client private key file (PEM) for mTLS.",
                         "format": "file-path"
                       }
-                    }
+                    },
+                    "dependentRequired": {
+                      "cert_file": ["key_file"],
+                      "key_file": ["cert_file"]
+                    },
+                    "allOf": [
+                      {
+                        "if": {
+                          "anyOf": [
+                            { "required": ["cert_file"] },
+                            { "required": ["key_file"] }
+                          ]
+                        },
+                        "then": {
+                          "required": ["ca_file"]
+                        }
+                      }
+                    ]
                   },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@router/pkg/config/config.schema.json` around lines 2553 - 2579, The TLS
object currently allows cert_file/key_file/ca_file independently; add
schema-level rules under the "tls" object to enforce mTLS constraints: add an
allOf (or anyOf) clause that requires both "cert_file" and "key_file" to be
present together (e.g., an anyOf with {not having either} OR {having both}), and
add a rule that if either "cert_file" or "key_file" is present then "ca_file" is
required (use an if/then with "if":
{"anyOf":[{"required":["cert_file"]},{"required":["key_file"]}]} and "then":
{"required":["ca_file"]}). Reference the "tls" object and the property names
"cert_file", "key_file", and "ca_file" when applying these changes so invalid
mTLS combos fail validation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@router/pkg/config/config.schema.json`:
- Around line 2553-2579: The TLS object currently allows
cert_file/key_file/ca_file independently; add schema-level rules under the "tls"
object to enforce mTLS constraints: add an allOf (or anyOf) clause that requires
both "cert_file" and "key_file" to be present together (e.g., an anyOf with {not
having either} OR {having both}), and add a rule that if either "cert_file" or
"key_file" is present then "ca_file" is required (use an if/then with "if":
{"anyOf":[{"required":["cert_file"]},{"required":["key_file"]}]} and "then":
{"required":["ca_file"]}). Reference the "tls" object and the property names
"cert_file", "key_file", and "ca_file" when applying these changes so invalid
mTLS combos fail validation.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: df69fa22-8ef3-4bec-91ea-391409508520

📥 Commits

Reviewing files that changed from the base of the PR and between 65efe37 and 288f382.

📒 Files selected for processing (6)
  • router/pkg/config/config.go
  • router/pkg/config/config.schema.json
  • router/pkg/config/config_events_nats_test.go
  • router/pkg/config/testdata/config_full.json
  • router/pkg/pubsub/nats/provider_builder.go
  • router/pkg/pubsub/nats/provider_builder_test.go

@vatsalpatel vatsalpatel requested review from a team as code owners April 8, 2026 06:39
@vatsalpatel vatsalpatel requested a review from JivusAyrus April 8, 2026 06:39
@vatsalpatel
Copy link
Copy Markdown
Author

Updated docs-website @alepane21
Should I close the cosmo-docs PR?

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs-website/router/configuration.mdx`:
- Around line 1753-1769: Update the TLS field descriptions so they explicitly
state runtime validation rules: in the table entries for tls.cert_file and
tls.key_file mention that cert_file and key_file must be provided together (both
required for mTLS) and that tls.ca_file is also required whenever either
cert_file or key_file is set; also update tls.ca_file description to note it is
required when using cert_file/key_file for mutual TLS. Ensure references to
tls.cert_file, tls.key_file and tls.ca_file are clear so readers know the valid
combinations.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 22027364-1964-485f-8a2c-5def3c5d3284

📥 Commits

Reviewing files that changed from the base of the PR and between 288f382 and a2895ef.

📒 Files selected for processing (1)
  • docs-website/router/configuration.mdx

Comment thread docs-website/router/configuration.mdx
@alepane21
Copy link
Copy Markdown
Contributor

Updated docs-website @alepane21 Should I close the cosmo-docs PR?

Don't worry, I did it! Thanks again.

@dkorittki
Copy link
Copy Markdown
Contributor

Hey @vatsalpatel, thanks for your contribution! Just wanted to let you know I am looking into your pull request and will provide feedback very soon.

Copy link
Copy Markdown
Contributor

@dkorittki dkorittki left a comment

Choose a reason for hiding this comment

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

Thanks again for contribution, really appreciate it! The implementation looks good and works as expected. I left some comments on areas which need some touches.

In general what it lacks are some integration tests, which verify tls works against a real nats server instance. The right place to do this would be the router-tests module but I think it's asked too much for, since it would become rather complex. I will brainstorm a few ideas on how to solve this but meantime I want to provide some feedback to you already

Comment thread router/pkg/config/config.schema.json
Comment thread router/pkg/config/config.schema.json Outdated
Comment thread router/pkg/pubsub/nats/provider_builder.go Outdated
Comment thread router/pkg/pubsub/nats/provider_builder_test.go Outdated
Comment thread router/pkg/pubsub/nats/provider_builder_test.go Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
router/pkg/pubsub/nats/provider_builder.go (1)

121-123: Add explicit TLS minimum version for deterministic security posture.

The tls.Config at line 121 relies on Go's default MinVersion (TLS 1.2), which may change across Go runtime versions. For production NATS connections, explicitly set MinVersion: tls.VersionTLS13 to enforce consistent security guarantees.

Suggested change
 		tlsCfg := &tls.Config{
+			MinVersion:         tls.VersionTLS13,
 			InsecureSkipVerify: eventSource.TLS.InsecureSkipVerify,
 		}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@router/pkg/pubsub/nats/provider_builder.go` around lines 121 - 123, The
tls.Config construction in provider_builder.go currently sets only
InsecureSkipVerify via tlsCfg and relies on Go's default MinVersion; update the
tlsCfg in the build path that creates tls.Config (the tlsCfg variable used for
NATS connections) to explicitly set MinVersion: tls.VersionTLS13 alongside
InsecureSkipVerify (using eventSource.TLS.InsecureSkipVerify) so the NATS client
enforces TLS 1.3 minimum.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@router/pkg/pubsub/nats/provider_builder.go`:
- Around line 121-123: The tls.Config construction in provider_builder.go
currently sets only InsecureSkipVerify via tlsCfg and relies on Go's default
MinVersion; update the tlsCfg in the build path that creates tls.Config (the
tlsCfg variable used for NATS connections) to explicitly set MinVersion:
tls.VersionTLS13 alongside InsecureSkipVerify (using
eventSource.TLS.InsecureSkipVerify) so the NATS client enforces TLS 1.3 minimum.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7fb3e057-98c3-44a8-8085-ecd6a43bfbdd

📥 Commits

Reviewing files that changed from the base of the PR and between 58b9ebc and 76260e5.

📒 Files selected for processing (5)
  • docs-website/router/configuration.mdx
  • router/pkg/config/config.schema.json
  • router/pkg/config/config_events_nats_test.go
  • router/pkg/pubsub/nats/provider_builder.go
  • router/pkg/pubsub/nats/provider_builder_test.go
✅ Files skipped from review due to trivial changes (2)
  • docs-website/router/configuration.mdx
  • router/pkg/pubsub/nats/provider_builder_test.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • router/pkg/config/config.schema.json
  • router/pkg/config/config_events_nats_test.go

@vatsalpatel
Copy link
Copy Markdown
Author

vatsalpatel commented Apr 14, 2026

Hey @dkorittki
Thank you for the review!
I have made all of the requested changes

  • Making CA cert optional for mTLS
  • More explicit assertations for nats options that are generated
  • Improved documentation listing explicit dependencies of TLS files

For the integration test, I did some research and there are 2 options we can go for

  1. We can use https://pkg.go.dev/github.com/nats-io/nats-server/v2/test which provides an easy to setup a test server
  opts := &server.Options{
      Host:      "127.0.0.1",
      Port:      -1,
      NoLog:     true,
  }
  s := natstest.RunServer(opts)
  t.Cleanup(s.Shutdown)
  s.ReadyForConnections(5 * time.Second)
  1. We can use testcontainers-go, but this will require docker to be running.

I think option 1 seems better, however we will have to add nats-server pkg to go.mod. If that is fine with you, I will update the integration tests.

Also FYI, looks like the router CI does setup a nats container and run integration tests against it.

    services:
      nats:
        image: ghcr.io/wundergraph/cosmo/nats:2.11.0-alpine

@vatsalpatel vatsalpatel requested a review from dkorittki April 14, 2026 10:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(router): add TLS support for NATS event source (skip verify, custom CA, mTLS)

3 participants