Skip to content

MM-67050: Add TLS config support to client library#190

Merged
bgardner8008 merged 3 commits into
masterfrom
MM-67050-self-signed-cert
Mar 30, 2026
Merged

MM-67050: Add TLS config support to client library#190
bgardner8008 merged 3 commits into
masterfrom
MM-67050-self-signed-cert

Conversation

@bgardner8008
Copy link
Copy Markdown
Contributor

@bgardner8008 bgardner8008 commented Mar 27, 2026

Summary

  • Add WithTLSConfig client option for configuring custom TLS settings (self-signed / private CA certificates) on both the HTTP API client and WebSocket connection
  • Clone http.DefaultTransport to preserve default timeouts and connection pooling, and force HTTP/2
  • Add WithTLSConfig option to the WebSocket client, applied to the gorilla/websocket dialer

This enables consumers (e.g. calls-transcriber) to connect to Mattermost servers using self-signed or private CA certificates.

This change does not affect RTCD server.

Ticket Link

https://mattermost.atlassian.net/browse/MM-67050

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 27, 2026

📝 Walkthrough

Walkthrough

Added support for supplying a caller-provided TLS configuration to the main client and propagated it to both the HTTP transport used by the API client and the WebSocket dialer via new WithTLSConfig options.

Changes

Cohort / File(s) Summary
Main client TLS configuration
client/client.go
Added tlsConfig *tls.Config field to Client and new WithTLSConfig(tlsConfig *tls.Config) Option which clones http.DefaultTransport, sets TLSClientConfig, forces HTTP/2 attempts, updates c.apiClient.HTTPClient, and persists c.tlsConfig.
WebSocket client usage
client/websocket.go
wsOpen builds a slice of options and conditionally includes ws.WithTLSConfig(c.tlsConfig) when present; passes options variadically to ws.NewClient.
WebSocket service client & options
service/ws/client.go, service/ws/option.go
Added tlsConfig *tls.Config field on service WS Client and new exported WithTLSConfig(tlsConfig *tls.Config) ClientOption; when set, NewClient applies it to websocket.DefaultDialer.TLSClientConfig.
Tests
client/websocket_test.go
Adjusted test to use a dynamic unused port for reconnect failure and changed synchronization to a buffered chan error, asserting the received error message.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant Caller
participant MainClient as Main Client
participant APIHTTP as API HTTP Client
participant WSLayer as WebSocket Layer
participant WSDialer as websocket.DefaultDialer

Caller->>MainClient: WithTLSConfig(tlsConfig)
MainClient->>APIHTTP: clone DefaultTransport, set TLSClientConfig
MainClient->>MainClient: store tlsConfig
Caller->>MainClient: make WS connection
MainClient->>WSLayer: ws.NewClient(..., WithTLSConfig)
WSLayer->>WSDialer: set TLSClientConfig (if provided)
WSLayer->>WSDialer: Dial(wsURL)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 71.43% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding TLS config support to the client library, which is the primary focus of all modifications across multiple files.
Description check ✅ Passed The description is directly related to the changeset, detailing the TLS configuration options added to both the HTTP API client and WebSocket connection, the approach taken, and the use case enabled.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch MM-67050-self-signed-cert

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

Copy link
Copy Markdown

@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

🧹 Nitpick comments (1)
client/client.go (1)

141-141: Clone and modify the HTTP client rather than replacing it entirely.

Line 141 replaces the entire HTTPClient with a new client. Whilst the current initialization by model.NewAPIv4Client() only creates a zero-value client, cloning the existing client and overriding only Transport is a more maintainable defensive pattern that protects against future configuration changes.

Suggested fix
-		c.apiClient.HTTPClient = &http.Client{Transport: transport}
+		httpClient := c.apiClient.HTTPClient
+		if httpClient == nil {
+			httpClient = &http.Client{}
+		}
+		clonedClient := *httpClient
+		clonedClient.Transport = transport
+		c.apiClient.HTTPClient = &clonedClient
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@client/client.go` at line 141, The code replaces c.apiClient.HTTPClient
outright which loses any future configuration; instead clone the existing
http.Client and set only the Transport: read the current c.apiClient.HTTPClient
(created by model.NewAPIv4Client()), create a shallow copy of that client,
assign the new Transport on the copy, and then set c.apiClient.HTTPClient to the
copy so other client fields (timeouts, headers, etc.) are preserved; update the
assignment that currently sets &http.Client{Transport: transport} to this
clone-and-modify approach targeting c.apiClient.HTTPClient.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@client/client.go`:
- Line 138: The code replaces c.apiClient.HTTPClient with a brand new
http.Client and loses any prior settings; instead, preserve the existing client
and only swap its Transport: obtain the current client (c.apiClient.HTTPClient),
clone its Transport if present (e.g., existingTransport :=
c.apiClient.HTTPClient.Transport; if t, use t.(*http.Transport).Clone() else
fallback to http.DefaultTransport.(*http.Transport).Clone()), then create a
shallow copy of the existing client (newClient := *c.apiClient.HTTPClient), set
newClient.Transport = transport and assign c.apiClient.HTTPClient = &newClient
so timeouts, redirect policies and other fields remain intact while replacing
only the transport.

---

Nitpick comments:
In `@client/client.go`:
- Line 141: The code replaces c.apiClient.HTTPClient outright which loses any
future configuration; instead clone the existing http.Client and set only the
Transport: read the current c.apiClient.HTTPClient (created by
model.NewAPIv4Client()), create a shallow copy of that client, assign the new
Transport on the copy, and then set c.apiClient.HTTPClient to the copy so other
client fields (timeouts, headers, etc.) are preserved; update the assignment
that currently sets &http.Client{Transport: transport} to this clone-and-modify
approach targeting c.apiClient.HTTPClient.
🪄 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: 7ae81550-e09b-4096-89c1-28a9c4b18ae1

📥 Commits

Reviewing files that changed from the base of the PR and between ab0efd2 and 2c58f6d.

📒 Files selected for processing (4)
  • client/client.go
  • client/websocket.go
  • service/ws/client.go
  • service/ws/option.go

Comment thread client/client.go
Copy link
Copy Markdown

@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 `@client/websocket_test.go`:
- Around line 123-127: The test currently ignores the return value of
ln.Close(), which can leave the port bound and make reconnect behavior flaky;
update the teardown to check and fail the test if Close() returns an error
(e.g., replace ln.Close() with an assertion like require.NoError(t, ln.Close())
or otherwise handle the error) before using unusedAddr to set
th.userClient.cfg.wsURL so the test reliably triggers ECONNREFUSED when
reconnecting.
🪄 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: a3858727-4c8b-4562-9f97-06be0a042b79

📥 Commits

Reviewing files that changed from the base of the PR and between 2c58f6d and 4af1130.

📒 Files selected for processing (1)
  • client/websocket_test.go

Comment thread client/websocket_test.go
Comment thread client/client.go
@bgardner8008 bgardner8008 merged commit d0b8ee2 into master Mar 30, 2026
10 checks passed
@bgardner8008 bgardner8008 deleted the MM-67050-self-signed-cert branch March 30, 2026 13:40
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