From 0b887920d79d85e9262f42a2f3db3dcd648359a4 Mon Sep 17 00:00:00 2001 From: Colby Williams Date: Fri, 26 Jun 2026 06:45:18 -0500 Subject: [PATCH] rust: default to rustls TLS backend, add native-tls opt-in (#1805) The Rust crate hard-coded the OpenSSL-backed native-tls stack for its request-handler HTTP (reqwest `default-tls`) and WebSocket (tokio-tungstenite `native-tls`) clients, pulling in `openssl-sys`. That breaks `*-unknown-linux-musl` / fully-static builds (no OpenSSL sysroot) and adds a dynamic `libssl` runtime dependency on glibc. Make TLS feature-gated and default to rustls: - `rustls-tls` (default): reqwest `rustls-tls-native-roots` + tokio-tungstenite `rustls-tls-native-roots`, using rustls with the `ring` provider and the OS trust store. OpenSSL-free, so musl/static targets cross-compile with no system OpenSSL. - `native-tls` (opt-in): keeps the platform-native stack for consumers who want it. The transport code is TLS-backend-agnostic (`reqwest::Client::builder()` + `connect_async`), so no source changes were needed. For `wss://`, tokio-tungstenite resolves the rustls crypto provider via feature unification on the shared `rustls` crate (reqwest pins `ring`). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- rust/Cargo.lock | 183 ++++++++++++++++++++++++++++++++++++++++++++++-- rust/Cargo.toml | 22 +++++- rust/README.md | 12 +++- 3 files changed, 207 insertions(+), 10 deletions(-) diff --git a/rust/Cargo.lock b/rust/Cargo.lock index fb7b66e198..3bf21b2d83 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -104,6 +104,12 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "core-foundation" version = "0.10.1" @@ -404,8 +410,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi 5.3.0", + "wasip2", + "wasm-bindgen", ] [[package]] @@ -416,7 +438,7 @@ checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" dependencies = [ "cfg-if", "libc", - "r-efi", + "r-efi 6.0.0", "wasip2", "wasip3", ] @@ -573,6 +595,7 @@ dependencies = [ "hyper", "hyper-util", "rustls", + "rustls-native-certs", "tokio", "tokio-rustls", "tower-service", @@ -823,6 +846,12 @@ version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + [[package]] name = "memchr" version = "2.8.0" @@ -1006,6 +1035,61 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "quinn" +version = "0.11.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c1a41e437b6bbd489372cd4971de128e85c855f56c57f283d20ff016cf7c0a8" +dependencies = [ + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "socket2", + "thiserror 2.0.18", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fcb935c5bec503c2f0e306bdd3e58bb9029dcb14fa8d9ac76e3a5256ac0763e" +dependencies = [ + "bytes", + "getrandom 0.3.4", + "lru-slab", + "rand 0.9.4", + "ring", + "rustc-hash", + "rustls", + "rustls-pki-types", + "slab", + "thiserror 2.0.18", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.52.0", +] + [[package]] name = "quote" version = "1.0.45" @@ -1015,6 +1099,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + [[package]] name = "r-efi" version = "6.0.0" @@ -1028,8 +1118,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" dependencies = [ "libc", - "rand_chacha", - "rand_core", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.5", ] [[package]] @@ -1039,7 +1139,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", ] [[package]] @@ -1051,6 +1161,15 @@ dependencies = [ "getrandom 0.2.17", ] +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", +] + [[package]] name = "redox_syscall" version = "0.5.18" @@ -1152,6 +1271,9 @@ dependencies = [ "native-tls", "percent-encoding", "pin-project-lite", + "quinn", + "rustls", + "rustls-native-certs", "rustls-pki-types", "serde", "serde_json", @@ -1159,6 +1281,7 @@ dependencies = [ "sync_wrapper", "tokio", "tokio-native-tls", + "tokio-rustls", "tokio-util", "tower", "tower-http", @@ -1198,6 +1321,12 @@ dependencies = [ "smallvec", ] +[[package]] +name = "rustc-hash" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" + [[package]] name = "rustix" version = "1.1.4" @@ -1226,12 +1355,25 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rustls-native-certs" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", +] + [[package]] name = "rustls-pki-types" version = "1.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9" dependencies = [ + "web-time", "zeroize", ] @@ -1617,6 +1759,21 @@ dependencies = [ "zerovec", ] +[[package]] +name = "tinyvec" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "tokio" version = "1.52.1" @@ -1685,8 +1842,12 @@ dependencies = [ "futures-util", "log", "native-tls", + "rustls", + "rustls-native-certs", + "rustls-pki-types", "tokio", "tokio-native-tls", + "tokio-rustls", "tungstenite", ] @@ -1798,7 +1959,9 @@ dependencies = [ "httparse", "log", "native-tls", - "rand", + "rand 0.8.6", + "rustls", + "rustls-pki-types", "sha1", "thiserror 1.0.69", "utf-8", @@ -2033,6 +2196,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "webpki-roots" version = "0.26.11" diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 66ef69ad21..ad91deed27 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -26,11 +26,27 @@ include = [ name = "github_copilot_sdk" [features] -default = ["bundled-cli"] +default = ["bundled-cli", "rustls-tls"] bundled-cli = ["dep:tar", "dep:flate2", "dep:zip"] derive = ["dep:schemars"] test-support = [] +# TLS backend for the request-handler HTTP/WebSocket transport. Exactly one +# should be enabled; `rustls-tls` is the default. `rustls-tls` uses rustls with +# the `ring` provider and the OS trust store, keeping the SDK OpenSSL-free so +# musl/static targets build without an OpenSSL sysroot. `native-tls` links the +# platform stack (OpenSSL on Linux, Secure Transport on macOS, SChannel on +# Windows). Disabling default features drops `rustls-tls` along with +# `bundled-cli`; re-add a TLS feature to keep the transport working over HTTPS. +rustls-tls = [ + "reqwest/rustls-tls-native-roots", + "tokio-tungstenite/rustls-tls-native-roots", +] +native-tls = [ + "reqwest/native-tls", + "tokio-tungstenite/native-tls", +] + # Build docs.rs documentation with all features so feature-gated APIs # (e.g. `define_tool`, `schema_for`) appear and intra-doc links resolve. # Mirror this locally with: `cargo doc --no-deps --all-features`. @@ -58,8 +74,8 @@ base64 = "0.22" bytes = "1" http = "1" futures-util = "0.3" -reqwest = { version = "0.12", default-features = false, features = ["stream", "http2", "default-tls"] } -tokio-tungstenite = { version = "0.24", default-features = false, features = ["connect", "native-tls"] } +reqwest = { version = "0.12", default-features = false, features = ["stream", "http2"] } +tokio-tungstenite = { version = "0.24", default-features = false, features = ["connect"] } [target.'cfg(windows)'.dependencies] zip = { version = "2", default-features = false, features = ["deflate"], optional = true } diff --git a/rust/README.md b/rust/README.md index 6d92224088..da7a0bdf45 100644 --- a/rust/README.md +++ b/rust/README.md @@ -902,17 +902,25 @@ Supported: `darwin-arm64`, `darwin-x64`, `linux-x64`, `linux-arm64`, `win32-x64` | Feature | Default | Description | | -------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | | `bundled-cli` | ✓ | Build-time CLI embedding. Pulls in `tar`+`flate2` (Linux/macOS) or `zip` (Windows). Disable via `default-features = false` to opt out (e.g. when shipping a smaller binary or when always supplying the CLI via `CliProgram::Path` / `COPILOT_CLI_PATH`). | +| `rustls-tls` | ✓ | TLS backend for the `CopilotRequestHandler` HTTP/WebSocket transport, using rustls with the `ring` provider and the OS trust store. OpenSSL-free, so `*-unknown-linux-musl` and other fully-static targets cross-compile without a system OpenSSL sysroot, and glibc binaries gain no `libssl` runtime dependency. | +| `native-tls` | — | Alternative TLS backend for the transport, linking the platform-native stack (OpenSSL on Linux, Secure Transport on macOS, SChannel on Windows). Enable it together with `default-features = false` when you specifically want the system TLS stack rather than rustls. | | `derive` | — | `schema_for::()` for generating JSON Schema from Rust types (adds `schemars`). Enable when defining [tool parameters](#tool-registration). | +> **Note:** `default-features = false` drops the default `rustls-tls` backend along with `bundled-cli`. The request-handler transport needs a TLS backend to reach HTTPS upstreams, so re-add either `rustls-tls` or `native-tls` whenever you turn default features off. + ```toml # These examples use registry syntax for illustration; until the crate is # published, use a path or git dependency instead. -# Default — bundles the Copilot CLI in your binary. +# Default — bundles the Copilot CLI in your binary and uses the rustls TLS backend. github-copilot-sdk = "0.1" # Opt out of bundling — resolve CLI from COPILOT_CLI_PATH or system PATH instead. -github-copilot-sdk = { version = "0.1", default-features = false } +# Re-add a TLS backend since disabling default features also drops rustls-tls. +github-copilot-sdk = { version = "0.1", default-features = false, features = ["rustls-tls"] } + +# Use the platform-native TLS stack (e.g. system OpenSSL) instead of rustls. +github-copilot-sdk = { version = "0.1", default-features = false, features = ["bundled-cli", "native-tls"] } # Derive JSON Schema for tool parameters (adds to default bundled-cli). github-copilot-sdk = { version = "0.1", features = ["derive"] }