diff --git a/.github/workflows/rust-check.yml b/.github/workflows/rust-check.yml index 6f792e7a..5f772615 100644 --- a/.github/workflows/rust-check.yml +++ b/.github/workflows/rust-check.yml @@ -66,7 +66,7 @@ jobs: libxkbcommon-dev libxkbcommon-x11-dev \ libwayland-dev libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev \ libegl1-mesa-dev libgles2-mesa-dev libgbm-dev mesa-utils \ - libfreetype-dev libfontconfig1-dev + libfreetype-dev libfontconfig1-dev fonts-noto-cjk - run: cargo fmt --all -- --check - run: cargo build --workspace # GitHub-hosted runners are headless with no reliable Mesa software diff --git a/.github/workflows/rust-multiplatform.yml b/.github/workflows/rust-multiplatform.yml index 6d8c3d0b..5ca69e35 100644 --- a/.github/workflows/rust-multiplatform.yml +++ b/.github/workflows/rust-multiplatform.yml @@ -90,7 +90,7 @@ jobs: libxkbcommon-dev libxkbcommon-x11-dev \ libwayland-dev libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev \ libegl1-mesa-dev libgles2-mesa-dev libgbm-dev mesa-utils \ - libfreetype-dev libfontconfig1-dev \ + libfreetype-dev libfontconfig1-dev fonts-noto-cjk \ xvfb - name: Build (host) if: matrix.cross == false && matrix.check_only != true diff --git a/Cargo.lock b/Cargo.lock index 612cd8f1..354681d9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1462,9 +1462,9 @@ dependencies = [ [[package]] name = "git2" -version = "0.20.3" +version = "0.20.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e2b37e2f62729cdada11f0e6b3b6fe383c69c29fc619e391223e12856af308c" +checksum = "7b88256088d75a56f8ecfa070513a775dd9107f6530ef14919dac831af9cfe2b" dependencies = [ "bitflags 2.11.1", "libc", diff --git a/crates/op-git/Cargo.toml b/crates/op-git/Cargo.toml index a3c47616..818e7b83 100644 --- a/crates/op-git/Cargo.toml +++ b/crates/op-git/Cargo.toml @@ -15,7 +15,7 @@ description = "Git-backed version control for OpenPencil documents" # In-process libgit2. `vendored-libgit2` builds + statically links # libgit2 from source (cmake + cc), so the shipped binary carries its # own git engine. Keeps the default `https` / `ssh` transports. -git2 = { version = "=0.20.3", features = ["vendored-libgit2"] } +git2 = { version = "=0.20.4", features = ["vendored-libgit2"] } thiserror = { workspace = true } # Credential store (`auth.rs`) persistence — the host-keyed token / # SSH-key table is serialized to a JSON file. diff --git a/crates/op-host-desktop/src/chat_builtin_http.rs b/crates/op-host-desktop/src/chat_builtin_http.rs index 7a9ce3a7..cda74aa9 100644 --- a/crates/op-host-desktop/src/chat_builtin_http.rs +++ b/crates/op-host-desktop/src/chat_builtin_http.rs @@ -413,10 +413,39 @@ fn map_openai_stop_reason(reason: &str) -> StopReason { mod tests { use super::*; use std::io::{Read, Write}; - use std::net::TcpListener; + use std::net::{TcpListener, TcpStream}; use std::sync::mpsc as std_mpsc; use std::time::Duration; + fn read_http_request(stream: &mut TcpStream) -> String { + let mut buf = Vec::new(); + let mut chunk = [0_u8; 4096]; + loop { + let n = stream.read(&mut chunk).expect("read request"); + if n == 0 { + break; + } + buf.extend_from_slice(&chunk[..n]); + let Some(header_end) = buf.windows(4).position(|w| w == b"\r\n\r\n") else { + continue; + }; + let headers = String::from_utf8_lossy(&buf[..header_end]); + let content_len = headers + .lines() + .find_map(|line| { + let (key, value) = line.split_once(':')?; + key.eq_ignore_ascii_case("content-length") + .then(|| value.trim().parse::().ok()) + .flatten() + }) + .unwrap_or(0); + if buf.len() >= header_end + 4 + content_len { + break; + } + } + String::from_utf8_lossy(&buf).to_string() + } + #[test] fn parse_openai_sse_data_extracts_text_delta() { let data = r#"{"choices":[{"delta":{"content":"hello"}}]}"#; @@ -445,9 +474,7 @@ mod tests { stream .set_read_timeout(Some(Duration::from_secs(2))) .expect("set read timeout"); - let mut buf = [0_u8; 8192]; - let n = stream.read(&mut buf).expect("read request"); - let request = String::from_utf8_lossy(&buf[..n]).to_string(); + let request = read_http_request(&mut stream); req_tx.send(request).expect("send request capture"); let body = "data: {\"error\":{\"message\":\"bad key\"}}\n\n"; diff --git a/deny.toml b/deny.toml index 2e648fbf..618f849a 100644 --- a/deny.toml +++ b/deny.toml @@ -37,7 +37,15 @@ confidence-threshold = 0.93 [advisories] yanked = "deny" -ignore = [] +ignore = [ + # async-openai 0.36.x still depends on backoff 0.4.x, and RustSec + # reports no safe upgrade path yet. Keep this narrow to the advisory + # until async-openai moves to a maintained retry crate. + "RUSTSEC-2025-0012", + # Transitive through backoff 0.4.x; see the async-openai/backoff note + # above. + "RUSTSEC-2024-0384", +] [bans] multiple-versions = "warn"