Skip to content
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
f7684f9
fix(tls): use native TLS for core HTTP clients
M3gA-Mind May 21, 2026
36c7417
fix(tls): switch WebSocket TLS to native-tls
M3gA-Mind May 21, 2026
3b7eb02
fix(run-dev-win): prepend workspace node_modules/.bin to PATH
M3gA-Mind May 21, 2026
8413582
fix(run-dev-win): invoke cargo-tauri.exe directly, skip pnpm wrapper
M3gA-Mind May 21, 2026
118ed82
fix(run-dev-win): pin pnpm dir on PATH for cargo-tauri's beforeDevCom…
M3gA-Mind May 21, 2026
9055ee2
fix(run-dev-win): override tauri beforeDevCommand with absolute pnpm …
M3gA-Mind May 21, 2026
005a190
fix(run-dev-win): drop literal quotes from beforeDevCommand override
M3gA-Mind May 21, 2026
57c54c8
fix(run-dev-win): invoke vite directly in beforeDevCommand, skip pnpm
M3gA-Mind May 21, 2026
e96fd25
fix(run-dev-win): wrap beforeDevCommand in space-free .bat shim
M3gA-Mind May 21, 2026
68aa44e
fix(run-dev-win): wrapper bat invokes node.exe + vite.js directly
M3gA-Mind May 21, 2026
2d74ccd
fix(tls): force native TLS on runtime proxy clients
M3gA-Mind May 21, 2026
e37428e
fix(tls): gate native-tls swap to Windows; preserve rustls everywhere…
M3gA-Mind May 21, 2026
8b17919
chore: regenerate Cargo.lock after tokio-tungstenite feature swap
M3gA-Mind May 21, 2026
57f837f
Merge remote-tracking branch 'upstream/main' into sync/window-upstream
M3gA-Mind May 21, 2026
456d4ef
fix(run-dev-win): guard against spaces in TEMP-derived vite wrapper path
M3gA-Mind May 21, 2026
be9b0d7
refactor(tls): extract shared tls_client_builder() helper; fix fallba…
M3gA-Mind May 21, 2026
01ad003
fix(tls): apply platform TLS on Client::new() fallback paths in compa…
M3gA-Mind May 21, 2026
8bf383f
fix(tls): apply platform TLS to composio DELETE client and proxy time…
M3gA-Mind May 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 14 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,9 @@ async-trait = "0.1"
chacha20poly1305 = "0.10"
hex = "0.4"
tokio-util = { version = "0.7", features = ["rt", "io"] }
tokio-tungstenite = { version = "0.24", features = ["rustls-tls-webpki-roots"] }
# tokio-tungstenite is declared per-target below so the TLS backend
# (native-tls on Windows, rustls on macOS / Linux) matches the reqwest
# backend selected at each TLS call site.
futures = "0.3"
rusqlite = { version = "0.37", features = ["bundled"] }
chrono = { version = "0.4", features = ["serde"] }
Expand Down Expand Up @@ -158,6 +160,17 @@ whatsapp-rust-tokio-transport = { version = "0.5", optional = true, default-feat
whatsapp-rust-ureq-http-client = { version = "0.5", optional = true }
wacore = { version = "0.5", optional = true, default-features = false }

[target.'cfg(windows)'.dependencies]
# Windows: tokio-tungstenite uses native-tls (schannel) so wss://
# connections honor the Windows cert store, including corporate CAs
# installed by AV / TLS-inspection proxies. See run-dev-win.sh notes.
tokio-tungstenite = { version = "0.24", default-features = false, features = ["connect", "handshake", "native-tls"] }

[target.'cfg(not(windows))'.dependencies]
# macOS / Linux: keep rustls + Mozilla webpki-roots — the historical
# default. Avoids pulling OpenSSL as a runtime dep on Linux.
tokio-tungstenite = { version = "0.24", default-features = false, features = ["connect", "handshake", "rustls-tls-webpki-roots"] }

[target.'cfg(target_os = "macos")'.dependencies]
whisper-rs = { version = "0.16", features = ["metal"] }
# Contacts framework bindings for address book seeding.
Expand Down
54 changes: 54 additions & 0 deletions app/src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

121 changes: 100 additions & 21 deletions scripts/run-dev-win.sh
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,24 @@ PATH_PREFIX="/c/Program Files/CMake/bin:$(dirname "$NINJA_EXE")"
if [[ -n "${CEF_RUNTIME_PATH:-}" ]]; then
PATH_PREFIX="$PATH_PREFIX:$CEF_RUNTIME_PATH"
fi
# Ensure the workspace node_modules/.bin is on PATH so pnpm's child
# spawns (e.g. `pnpm tauri dev` → `tauri.CMD`) can resolve the shims.
# Pnpm normally prepends `./node_modules/.bin` for script execution, but
# when the script body is `tauri "dev"` and the child shell is cmd.exe
# under the long bash→cmd→bash chain, the relative entry sometimes
# resolves against the wrong cwd and tauri.CMD is not found.
PATH_PREFIX="$APP_DIR/node_modules/.bin:$PATH_PREFIX"

# Ensure pnpm itself stays on PATH for cargo-tauri's beforeDevCommand
# (`pnpm run dev` → vite). When run-dev-win.sh restores the Windows PATH
# via cmd.exe %PATH%, some setups (WinGet-installed pnpm with no
# AppData/Roaming/npm entry) don't surface a pnpm dir consistently
# downstream. Prepend the resolved $PNPM_EXE dir to guarantee it.
if [[ -n "${PNPM_EXE:-}" ]]; then
PNPM_EXE_DIR="$(dirname "$PNPM_EXE")"
PATH_PREFIX="$PNPM_EXE_DIR:$PATH_PREFIX"
fi

export PATH="$PATH_PREFIX:$PATH"

"$PNPM_EXE" tauri:ensure
Expand Down Expand Up @@ -599,28 +617,89 @@ else
DEV_PORT=1420
fi

# Tauri spawns beforeDevCommand (`pnpm run dev`) via a native `cmd /S /C`
# inheriting THIS process's env. By here PATH has the full system PATH stacked
# several times over (vcvars rebuild + Git-Bash /etc/profile re-runs + pnpm
# .bin layering); the MSYS→Windows conversion overflows the process
# environment-block limit, so the child inherits an EMPTY PATH and Tauri dies
# with "'pnpm' is not recognized" (even `where` is gone). Collapse PATH to
# first-seen entries (clean POSIX `/c/...` entries, so ':' split is safe).
_dedup_seen=":"
_dedup_new=""
IFS=':' read -ra _dedup_parts <<< "$PATH"
for _dp in "${_dedup_parts[@]}"; do
[[ -z "$_dp" ]] && continue
case "$_dedup_seen" in *":$_dp:"*) continue ;; esac
_dedup_seen="${_dedup_seen}${_dp}:"
_dedup_new="${_dedup_new:+$_dedup_new:}$_dp"
done
export PATH="$_dedup_new"
echo "[run-dev-win] PATH de-duplicated: ${#_dedup_parts[@]} → $(awk -v RS=: 'END{print NR}' <<< "$_dedup_new") entries"
# Invoke cargo-tauri directly rather than going through `pnpm tauri dev`.
#
# The pnpm chain (pnpm.exe → cmd.exe → tauri.CMD) is fragile on Windows:
# whether `tauri.CMD` is resolvable in the spawned cmd subprocess depends
# on which pnpm shim was picked up by `find_pnpm`. The self-managing
# `~/AppData/Local/pnpm/.tools/.../pnpm` variant auto-prepends
# `node_modules/.bin` for script children; the WinGet-installed
# `pnpm.exe` does not, so the script body `tauri "dev"` then fails with
# "'tauri' is not recognized" inside cmd.
#
# `ensure-tauri-cli.sh` already installed the vendored CEF-aware
# cargo-tauri at `$REPO_ROOT/.cache/cargo-install/bin/cargo-tauri.exe`,
# so we can invoke that binary directly and skip the wrapper layer.
CARGO_TAURI_EXE="$REPO_ROOT/.cache/cargo-install/bin/cargo-tauri.exe"
if [[ ! -x "$CARGO_TAURI_EXE" ]]; then
echo "[run-dev-win] cargo-tauri.exe not found at $CARGO_TAURI_EXE" >&2
echo "[run-dev-win] tauri:ensure should have installed it. Aborting." >&2
exit 1
fi

# Build a tauri.conf.json `-c` JSON merge that:
# - pins `beforeDevCommand` to the absolute pnpm path so cargo-tauri's
# cmd.exe child can find pnpm regardless of any PATH stripping
# between bash → cargo-tauri → cmd. The default in tauri.conf.json
# is `"pnpm run dev"` (bare name) which depends on PATH.
# - overrides `devUrl` when OPENHUMAN_DEV_PORT is non-default.
Comment thread
M3gA-Mind marked this conversation as resolved.
# Point beforeDevCommand at vite via a wrapper batch file in a
# space-free temp directory.
#
# Why a wrapper instead of the absolute path directly:
# cargo-tauri runs beforeDevCommand as `cmd.exe /S /C <string>`. Rust's
# argv-to-cmd argument escaping strips literal double-quotes from the
# string, so if our `<string>` is `"E:\Office Files\…\vite.CMD"`,
# cmd ends up parsing `E:\Office` as the program name and the rest as
# arguments — "'E:\Office' is not recognized". 8.3 short-name fallback
# also fails when 8dot3name is disabled on the drive (as it is on this
# workspace's E: drive).
#
# The fix is to call the spacey path from INSIDE a .bat file, where we
# can quote it however we want without involving cargo-tauri's outer
# escaping. The wrapper lives under %TEMP% (which is normally
# space-free) so its own path doesn't need quoting either.
VITE_JS_UNIX="$APP_DIR/node_modules/vite/bin/vite.js"
if [[ ! -f "$VITE_JS_UNIX" ]]; then
echo "[run-dev-win] vite entry not found at $VITE_JS_UNIX" >&2
echo "[run-dev-win] Did 'pnpm install' run? Aborting." >&2
exit 1
fi
VITE_JS_WIN="$(cygpath -w "$VITE_JS_UNIX" 2>/dev/null || printf '%s' "$VITE_JS_UNIX")"

# Resolve node.exe absolute path so the wrapper doesn't depend on
# whatever PATH cargo-tauri hands to its cmd child.
NODE_EXE_UNIX="$(command -v node.exe 2>/dev/null || command -v node 2>/dev/null)"
if [[ -z "$NODE_EXE_UNIX" || ! -f "$NODE_EXE_UNIX" ]]; then
echo "[run-dev-win] node.exe not findable on bash PATH at wrapper-build time" >&2
exit 1
fi
NODE_EXE_WIN="$(cygpath -w "$NODE_EXE_UNIX" 2>/dev/null || printf '%s' "$NODE_EXE_UNIX")"

WRAPPER_DIR_UNIX="$(cygpath -u "${TEMP:-${TMP:-/tmp}}" 2>/dev/null || echo /tmp)/openhuman-dev"
mkdir -p "$WRAPPER_DIR_UNIX"
VITE_WRAPPER_UNIX="$WRAPPER_DIR_UNIX/run-vite.bat"
# Invoke node.exe with vite's JS entry directly. The vite.CMD shim
# falls back to bare `node` when its sibling doesn't have node.exe,
# which fails inside cargo-tauri's cmd child (no node on PATH).
{
printf '@echo off\r\n'
printf '"%s" "%s" %%*\r\n' "$NODE_EXE_WIN" "$VITE_JS_WIN"
} > "$VITE_WRAPPER_UNIX"
VITE_WRAPPER_WIN="$(cygpath -w "$VITE_WRAPPER_UNIX" 2>/dev/null || printf '%s' "$VITE_WRAPPER_UNIX")"
if [[ "$VITE_WRAPPER_WIN" == *" "* ]]; then
echo "[run-dev-win] wrapper path contains spaces: $VITE_WRAPPER_WIN" >&2
echo "[run-dev-win] set TEMP/TMP to a space-free path (e.g. C:\\Temp) and retry." >&2
exit 1
fi
echo "[run-dev-win] vite wrapper at: $VITE_WRAPPER_WIN"
BEFORE_DEV_CMD="${VITE_WRAPPER_WIN//\\/\\\\}"
CONFIG_OVERRIDE="{\"build\":{\"beforeDevCommand\":\"$BEFORE_DEV_CMD\""
Comment thread
M3gA-Mind marked this conversation as resolved.
if (( DEV_PORT != 1420 )); then
echo "[run-dev-win] OPENHUMAN_DEV_PORT=$DEV_PORT — overriding tauri devUrl"
"$PNPM_EXE" tauri dev -c "{\"build\":{\"devUrl\":\"http://localhost:$DEV_PORT\"}}"
else
"$PNPM_EXE" tauri dev
CONFIG_OVERRIDE+=",\"devUrl\":\"http://localhost:$DEV_PORT\""
fi
CONFIG_OVERRIDE+="}}"

echo "[run-dev-win] tauri config override: $CONFIG_OVERRIDE"
"$CARGO_TAURI_EXE" dev -c "$CONFIG_OVERRIDE"
19 changes: 15 additions & 4 deletions src/api/rest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,21 @@ fn build_backend_reqwest_client() -> Result<Client> {
);
}

// Force rustls for consistent cross-platform TLS behavior.
Client::builder()
.default_headers(default_headers)
.use_rustls_tls()
// TLS backend selection:
// - Windows: schannel (native-tls) so the Windows cert store is
// honored, including any corporate CA installed by AV / TLS-
// inspecting proxies that re-sign certs with a private root.
// rustls + webpki-roots only knows Mozilla CAs and fails such
// environments with `UnknownIssuer`.
// - macOS / Linux: keep rustls + webpki-roots — these platforms
// don't hit the corporate-MITM scenario in normal distribution,
Comment thread
M3gA-Mind marked this conversation as resolved.
Outdated
// and rustls avoids the OpenSSL runtime dependency on Linux.
let builder = Client::builder().default_headers(default_headers);
#[cfg(target_os = "windows")]
let builder = builder.use_native_tls();
#[cfg(not(target_os = "windows"))]
let builder = builder.use_rustls_tls();
builder
.http1_only()
.timeout(Duration::from_secs(120))
.connect_timeout(Duration::from_secs(15))
Expand Down
10 changes: 8 additions & 2 deletions src/openhuman/app_state/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,8 +263,14 @@ fn save_stored_app_state(config: &Config, state: &StoredAppState) -> Result<(),
}

fn build_client() -> Result<Client, String> {
Client::builder()
.use_rustls_tls()
// Windows: native TLS so the OS trust store is honored — see
// [`crate::api::rest`]. Other platforms keep rustls.
let builder = Client::builder();
#[cfg(target_os = "windows")]
let builder = builder.use_native_tls();
#[cfg(not(target_os = "windows"))]
let builder = builder.use_rustls_tls();
builder
.http1_only()
.timeout(Duration::from_secs(30))
.connect_timeout(Duration::from_secs(10))
Expand Down
17 changes: 14 additions & 3 deletions src/openhuman/config/schema/proxy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,14 @@ pub fn build_runtime_proxy_client(service_key: &str) -> reqwest::Client {
return client;
}

let builder = apply_runtime_proxy_to_builder(reqwest::Client::builder(), service_key);
// TLS backend: Windows uses native (schannel) so the OS cert store
// is honored — see [`crate::api::rest`]. macOS / Linux keep rustls.
let raw = reqwest::Client::builder();
#[cfg(target_os = "windows")]
let raw = raw.use_native_tls();
#[cfg(not(target_os = "windows"))]
let raw = raw.use_rustls_tls();
let builder = apply_runtime_proxy_to_builder(raw, service_key);
let client = builder.build().unwrap_or_else(|error| {
tracing::warn!(service_key, "Failed to build proxied client: {error}");
reqwest::Client::new()
Comment thread
M3gA-Mind marked this conversation as resolved.
Outdated
Expand All @@ -461,10 +468,14 @@ pub fn build_runtime_proxy_client_with_timeouts(
return client;
}

let builder = reqwest::Client::builder()
let raw = reqwest::Client::builder()
.timeout(std::time::Duration::from_secs(timeout_secs))
.connect_timeout(std::time::Duration::from_secs(connect_timeout_secs));
let builder = apply_runtime_proxy_to_builder(builder, service_key);
#[cfg(target_os = "windows")]
let raw = raw.use_native_tls();
#[cfg(not(target_os = "windows"))]
let raw = raw.use_rustls_tls();
let builder = apply_runtime_proxy_to_builder(raw, service_key);
let client = builder.build().unwrap_or_else(|error| {
tracing::warn!(
service_key,
Expand Down
Loading
Loading