Skip to content

Conversation

@ssncferreira
Copy link
Contributor

@ssncferreira ssncferreira commented Dec 19, 2025

Description

Implements in-memory certificate caching for the AI Bridge MITM proxy. Certificate generation is expensive (RSA key generation + signing), so caching avoids repeated generation for the same hostname.

Changes

  • Add certCache struct implementing goproxy.CertStorage with thread-safe double-check locking
  • Wire certificate cache into the proxy via proxy.CertStore
  • Add unit tests for cache behavior (hit, miss, errors, concurrency)
  • Add integration test to verify caching works end-to-end through the proxy

Closes coder/internal#1183

Copy link
Contributor Author

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more

This stack of pull requests is managed by Graphite. Learn more about stacking.

@ssncferreira ssncferreira marked this pull request as ready for review December 19, 2025 22:41
Comment on lines 214 to 321
targetServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
}))
defer targetServer.Close()

certFile, keyFile := generateTestCA(t)
logger := slogtest.Make(t, nil)

// Start the proxy server.
srv, err := aibridgeproxyd.New(t.Context(), logger, aibridgeproxyd.Options{
ListenAddr: "127.0.0.1:0",
CoderAccessURL: "http://localhost:3000",
CertFile: certFile,
KeyFile: keyFile,
})
require.NoError(t, err)
t.Cleanup(func() { _ = srv.Close() })

proxyAddr := srv.Addr()
require.NotEmpty(t, proxyAddr)

// Wait for the proxy server to be ready.
require.Eventually(t, func() bool {
conn, err := net.Dial("tcp", proxyAddr)
if err != nil {
return false
}
_ = conn.Close()
return true
}, testutil.WaitShort, testutil.IntervalFast)

// Load the CA certificate so the client trusts the proxy's MITM certificate.
certPEM, err := os.ReadFile(certFile)
require.NoError(t, err)
certPool := x509.NewCertPool()
certPool.AppendCertsFromPEM(certPEM)

// Create an HTTP client configured to use the proxy.
proxyURL, err := url.Parse("http://" + proxyAddr)
require.NoError(t, err)

client := &http.Client{
Transport: &http.Transport{
Proxy: http.ProxyURL(proxyURL),
ProxyConnectHeader: http.Header{
"Proxy-Authorization": []string{makeProxyAuthHeader("test-session-token")},
},
TLSClientConfig: &tls.Config{
MinVersion: tls.VersionTLS12,
RootCAs: certPool,
},
},
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: this feels like a repeated pattern that we could move into a test util to make the tests more readable.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Aggree, I will address this in a follow-up PR 👍

@ssncferreira ssncferreira force-pushed the ssncferreira/feat-aiproxy-routing branch from 9b2593b to bc4caed Compare December 23, 2025 12:53
@ssncferreira ssncferreira force-pushed the ssncferreira/feat-aiproxy-cert-caching branch 2 times, most recently from ecf32ef to 330ccd7 Compare December 23, 2025 13:11
@ssncferreira ssncferreira force-pushed the ssncferreira/feat-aiproxy-routing branch from bc4caed to 97198d5 Compare December 23, 2025 13:11
@ssncferreira ssncferreira force-pushed the ssncferreira/feat-aiproxy-cert-caching branch from 330ccd7 to ee37009 Compare December 23, 2025 13:26
@ssncferreira ssncferreira force-pushed the ssncferreira/feat-aiproxy-routing branch 2 times, most recently from 7e117da to 6e0a054 Compare December 23, 2025 18:08
@ssncferreira ssncferreira force-pushed the ssncferreira/feat-aiproxy-cert-caching branch 2 times, most recently from 77155cc to b0a0d5d Compare December 23, 2025 19:46
@ssncferreira ssncferreira force-pushed the ssncferreira/feat-aiproxy-routing branch from 6b3a42f to b82c306 Compare December 23, 2025 20:06
@ssncferreira ssncferreira force-pushed the ssncferreira/feat-aiproxy-cert-caching branch 2 times, most recently from fd98405 to 42720ba Compare December 23, 2025 20:07
@ssncferreira ssncferreira force-pushed the ssncferreira/feat-aiproxy-routing branch from b82c306 to 5e6a35c Compare December 23, 2025 20:07
@ssncferreira ssncferreira force-pushed the ssncferreira/feat-aiproxy-cert-caching branch 2 times, most recently from dd18dfb to 01151fb Compare December 23, 2025 20:30
@ssncferreira ssncferreira force-pushed the ssncferreira/feat-aiproxy-routing branch from 5a1d2dc to 4196397 Compare December 23, 2025 21:49
@ssncferreira ssncferreira force-pushed the ssncferreira/feat-aiproxy-cert-caching branch 2 times, most recently from b22bf6c to 32e418d Compare December 23, 2025 21:52
@ssncferreira ssncferreira force-pushed the ssncferreira/feat-aiproxy-routing branch from 4196397 to 64470eb Compare December 23, 2025 21:52
@ssncferreira ssncferreira force-pushed the ssncferreira/feat-aiproxy-cert-caching branch from 32e418d to bdf6895 Compare December 23, 2025 21:59
@ssncferreira ssncferreira force-pushed the ssncferreira/feat-aiproxy-routing branch from 64470eb to dcda7da Compare December 23, 2025 21:59
@ssncferreira ssncferreira force-pushed the ssncferreira/feat-aiproxy-cert-caching branch 2 times, most recently from cd695b9 to 2cecfac Compare December 23, 2025 22:21
@ssncferreira ssncferreira force-pushed the ssncferreira/feat-aiproxy-routing branch from 644e954 to 4654e31 Compare December 23, 2025 22:21
@ssncferreira ssncferreira force-pushed the ssncferreira/feat-aiproxy-cert-caching branch from 2cecfac to ab0b3f6 Compare December 23, 2025 22:43
@ssncferreira ssncferreira force-pushed the ssncferreira/feat-aiproxy-routing branch from 4654e31 to e0906db Compare December 23, 2025 22:43
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.

3 participants