MCPcopy Create free account
hub / github.com/diillson/chatcli / NewClient

Function NewClient

client/remote/remote_client.go:54–164  ·  view source on GitHub ↗

NewClient creates a new remote gRPC client that implements LLMClient.

(ctx context.Context, cfg Config, logger *zap.Logger)

Source from the content-addressed store, hash-verified

52
53// NewClient creates a new remote gRPC client that implements LLMClient.
54func NewClient(ctx context.Context, cfg Config, logger *zap.Logger) (*Client, error) {
55 var dialOpts []grpc.DialOption
56
57 // Security (H4): TLS configuration with TLS 1.3 minimum.
58 // Use CHATCLI_TLS_CLIENT_CERT/KEY for mTLS client certificates.
59 if cfg.TLS {
60 tlsCfg := &tls.Config{
61 MinVersion: tls.VersionTLS13,
62 }
63
64 if cfg.CertFile != "" {
65 caCert, err := os.ReadFile(cfg.CertFile)
66 if err != nil {
67 return nil, fmt.Errorf("failed to read CA certificate: %w", err)
68 }
69 certPool := x509.NewCertPool()
70 if !certPool.AppendCertsFromPEM(caCert) {
71 return nil, fmt.Errorf("failed to parse CA certificate")
72 }
73 tlsCfg.RootCAs = certPool
74 }
75
76 // mTLS: load client certificate if configured
77 if certPath := os.Getenv("CHATCLI_TLS_CLIENT_CERT"); certPath != "" {
78 keyPath := os.Getenv("CHATCLI_TLS_CLIENT_KEY")
79 if keyPath == "" {
80 return nil, fmt.Errorf("CHATCLI_TLS_CLIENT_CERT set but CHATCLI_TLS_CLIENT_KEY is missing")
81 }
82 clientCert, err := tls.LoadX509KeyPair(certPath, keyPath)
83 if err != nil {
84 return nil, fmt.Errorf("failed to load client TLS cert/key: %w", err)
85 }
86 tlsCfg.Certificates = []tls.Certificate{clientCert}
87 }
88
89 dialOpts = append(dialOpts, grpc.WithTransportCredentials(credentials.NewTLS(tlsCfg)))
90 } else {
91 // Security: Require explicit opt-in for insecure connections
92 if strings.EqualFold(os.Getenv("CHATCLI_ALLOW_INSECURE"), "true") {
93 logger.Warn("SECURITY WARNING: TLS is disabled. Connection is unencrypted. Set CHATCLI_ALLOW_INSECURE=false for production.")
94 dialOpts = append(dialOpts, grpc.WithTransportCredentials(insecure.NewCredentials()))
95 } else {
96 logger.Warn("TLS disabled but CHATCLI_ALLOW_INSECURE not set — using system TLS")
97 dialOpts = append(dialOpts, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{
98 MinVersion: tls.VersionTLS13,
99 })))
100 }
101 }
102
103 // Keepalive: detect dead connections without flooding the server.
104 // Server EnforcementPolicy.MinTime is 20s, so Time must be >= 20s.
105 dialOpts = append(dialOpts, grpc.WithKeepaliveParams(keepalive.ClientParameters{
106 Time: 30 * time.Second, // ping every 30s if no activity
107 Timeout: 5 * time.Second, // wait 5s for pong before considering dead
108 PermitWithoutStream: true, // ping even without active RPCs
109 }))
110
111 // Client-side round-robin load balancing for headless Services with multiple replicas

Callers 2

handleConnectCommandMethod · 0.92
RunConnectFunction · 0.92

Calls 7

withAuthMethod · 0.95
GetServerInfoMethod · 0.95
ErrorfMethod · 0.80
WarnMethod · 0.80
ErrorMethod · 0.65
InfoMethod · 0.65
StringMethod · 0.45

Tested by

no test coverage detected