Anydoc / anydoc parser engine (push) Canceled after 0s
App / Format, vet, test, and build (push) Canceled after 0s
CLI / test (macos-latest / go 1.26) (push) Canceled after 0s
CLI / test (ubuntu-latest / go 1.26) (push) Canceled after 0s
CLI / test (windows-latest / go 1.26) (push) Canceled after 0s
Build and Push Docker Image / build-ui (push) Canceled after 0s
Build and Push Docker Image / build-docreader (push) Canceled after 0s
Build and Push Docker Image / build-sandbox (push) Canceled after 0s
Build and Push Docker Image / build-app (amd64, linux/amd64, ubuntu-latest) (push) Canceled after 0s
Build and Push Docker Image / build-app (arm64, linux/arm64, ubuntu-24.04-arm) (push) Canceled after 0s
DocReader / Python tests and Go client tests (push) Canceled after 0s
Build & Publish (dsh-weknora) / Typecheck, test, pack (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (pinned) (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (latest, advisory) (push) Canceled after 0s
Frontend / Test, type-check, and build (push) Canceled after 0s
Go Lint Cache / warm lint cache (.) (push) Canceled after 0s
Go Lint Cache / warm lint cache (cli) (push) Canceled after 0s
Go Lint Cache / warm lint cache (client) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.10) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.11) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.12) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.13) (push) Canceled after 0s
Build and Push Docker Image / merge (push) Canceled after 0s
Build & Publish (dsh-weknora) / Publish to npm (push) Canceled after 0s
Build & Publish (mcp-server) / Build sdist + wheel (push) Canceled after 0s
Build & Publish (mcp-server) / Publish to PyPI (push) Canceled after 0s
81 lines
3.1 KiB
Go
81 lines
3.1 KiB
Go
package opensearch
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"fmt"
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/opensearch-project/opensearch-go/v4"
|
|
osapi "github.com/opensearch-project/opensearch-go/v4/opensearchapi"
|
|
|
|
"github.com/Tencent/WeKnora/internal/types"
|
|
secutils "github.com/Tencent/WeKnora/internal/utils"
|
|
)
|
|
|
|
// NewOpenSearchClient builds a TLS-hardened, pool-tuned *osapi.Client for
|
|
// the OpenSearch driver. The caller wires it into the registry from the
|
|
// env path (container) and the DB-store path (engine factory); the
|
|
// Repository constructor itself receives the pre-built client.
|
|
//
|
|
// TLS posture:
|
|
// - MinVersion: TLS 1.2 (TLS 1.3 negotiated when both ends support).
|
|
// - InsecureSkipVerify: opt-in via ConnectionConfig.InsecureSkipVerify.
|
|
// Default false. Operators set true ONLY for self-signed dev clusters.
|
|
// - CipherSuites: explicit forward-secrecy-only list. TLS 1.2's default
|
|
// cipher list includes TLS_RSA_* (no forward secrecy); we drop them.
|
|
// TLS 1.3 cipher selection is automatic and safe.
|
|
//
|
|
// Transport tuning:
|
|
// - MaxIdleConnsPerHost: 32 (Go default 2 is too low when callers
|
|
// dispatch concurrent queries across multiple knowledge bases)
|
|
// - IdleConnTimeout: 90s (typical LB keep-alive)
|
|
// - ResponseHeaderTimeout: 30s (per-request safety net)
|
|
// - ExpectContinueTimeout: 1s
|
|
func NewOpenSearchClient(cfg *types.ConnectionConfig) (*osapi.Client, error) {
|
|
if cfg == nil || cfg.Addr == "" {
|
|
return nil, fmt.Errorf("opensearch: ConnectionConfig.Addr required: %w", ErrConfigInvalid)
|
|
}
|
|
if err := secutils.ValidateURLForSSRF(cfg.Addr); err != nil {
|
|
return nil, fmt.Errorf("opensearch: address failed SSRF validation: %w", err)
|
|
}
|
|
transport := buildHTTPTransport(cfg.InsecureSkipVerify)
|
|
return osapi.NewClient(osapi.Config{
|
|
Client: opensearch.Config{
|
|
Addresses: []string{cfg.Addr},
|
|
Username: cfg.Username,
|
|
Password: cfg.Password,
|
|
Transport: &secutils.SSRFValidatingRoundTripper{Base: transport},
|
|
},
|
|
})
|
|
}
|
|
|
|
// buildHTTPTransport constructs the TLS-hardened, pool-tuned
|
|
// *http.Transport used by every OpenSearch client this driver creates.
|
|
// Extracted from newOpenSearchClient so unit tests can pin the TLS
|
|
// posture directly (the opensearch-go SDK wraps the transport in an
|
|
// internal interface, making reflection-based introspection of the
|
|
// final client fragile across SDK versions).
|
|
func buildHTTPTransport(insecureSkipVerify bool) *http.Transport {
|
|
return &http.Transport{
|
|
Proxy: http.ProxyFromEnvironment,
|
|
DialContext: secutils.SSRFSafeDialContext,
|
|
TLSClientConfig: &tls.Config{
|
|
MinVersion: tls.VersionTLS12,
|
|
InsecureSkipVerify: insecureSkipVerify, //nolint:gosec — operator opt-in flag
|
|
CipherSuites: []uint16{
|
|
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
|
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
|
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
|
|
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
|
|
tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
|
|
tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
|
|
},
|
|
},
|
|
MaxIdleConnsPerHost: 32,
|
|
IdleConnTimeout: 90 * time.Second,
|
|
ResponseHeaderTimeout: 30 * time.Second,
|
|
ExpectContinueTimeout: 1 * time.Second,
|
|
}
|
|
}
|