mirror of
https://github.com/openai/codex.git
synced 2026-10-22 17:58:46 +00:00
refactor(app-server): reuse russh-sftp for staged uploads
This commit is contained in:
Generated
+4
-2
@@ -699,8 +699,8 @@
|
||||
"bit-set_0.5.3": "{\"dependencies\":[{\"default_features\":false,\"name\":\"bit-vec\",\"req\":\"^0.6.1\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.3\"}],\"features\":{\"default\":[\"std\"],\"std\":[\"bit-vec/std\"]}}",
|
||||
"bit-vec_0.6.3": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.7\"},{\"kind\":\"dev\",\"name\":\"rand_xorshift\",\"req\":\"^0.2\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"}],\"features\":{\"default\":[\"std\"],\"serde_no_std\":[\"serde/alloc\"],\"serde_std\":[\"std\",\"serde/std\"],\"std\":[]}}",
|
||||
"bitflags_1.3.2": "{\"dependencies\":[{\"name\":\"compiler_builtins\",\"optional\":true,\"req\":\"^0.1.2\"},{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_derive\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"walkdir\",\"req\":\"^2.3\"}],\"features\":{\"default\":[],\"example_generated\":[],\"rustc-dep-of-std\":[\"core\",\"compiler_builtins\"]}}",
|
||||
"bitflags_2.10.0": "{\"dependencies\":[{\"name\":\"arbitrary\",\"optional\":true,\"req\":\"^1.0\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"arbitrary\",\"req\":\"^1.0\"},{\"name\":\"bytemuck\",\"optional\":true,\"req\":\"^1.12\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"bytemuck\",\"req\":\"^1.12.2\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"serde_core\",\"optional\":true,\"req\":\"^1.0.228\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde_lib\",\"package\":\"serde\",\"req\":\"^1.0.103\"},{\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\"^1.0.19\"},{\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0.18\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"zerocopy\",\"req\":\"^0.8\"}],\"features\":{\"example_generated\":[],\"serde\":[\"serde_core\"],\"std\":[]}}",
|
||||
"bitflags_2.11.0": "{\"dependencies\":[{\"name\":\"arbitrary\",\"optional\":true,\"req\":\"^1.0\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"arbitrary\",\"req\":\"^1.0\"},{\"name\":\"bytemuck\",\"optional\":true,\"req\":\"^1.12\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"bytemuck\",\"req\":\"^1.12.2\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"serde_core\",\"optional\":true,\"req\":\"^1.0.228\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde_lib\",\"package\":\"serde\",\"req\":\"^1.0.103\"},{\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\"^1.0.19\"},{\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0.18\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"zerocopy\",\"req\":\"^0.8\"}],\"features\":{\"example_generated\":[],\"serde\":[\"serde_core\"],\"std\":[]}}",
|
||||
"bitflags_2.11.1": "{\"dependencies\":[{\"name\":\"arbitrary\",\"optional\":true,\"req\":\"^1.0\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"arbitrary\",\"req\":\"^1.0\"},{\"name\":\"bytemuck\",\"optional\":true,\"req\":\"^1.12\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"bytemuck\",\"req\":\"^1.12.2\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"serde_core\",\"optional\":true,\"req\":\"^1.0.228\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde_lib\",\"package\":\"serde\",\"req\":\"^1.0.103\"},{\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\"^1.0.19\"},{\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0.18\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"zerocopy\",\"req\":\"^0.8\"}],\"features\":{\"example_generated\":[],\"serde\":[\"serde_core\"],\"std\":[]}}",
|
||||
"blake2_0.10.6": "{\"dependencies\":[{\"features\":[\"mac\"],\"name\":\"digest\",\"req\":\"^0.10.3\"},{\"features\":[\"dev\"],\"kind\":\"dev\",\"name\":\"digest\",\"req\":\"^0.10.3\"},{\"kind\":\"dev\",\"name\":\"hex-literal\",\"req\":\"^0.2.2\"}],\"features\":{\"default\":[\"std\"],\"reset\":[],\"simd\":[],\"simd_asm\":[\"simd_opt\"],\"simd_opt\":[\"simd\"],\"size_opt\":[],\"std\":[\"digest/std\"]}}",
|
||||
"block-buffer_0.10.4": "{\"dependencies\":[{\"name\":\"generic-array\",\"req\":\"^0.14\"}],\"features\":{}}",
|
||||
"block-padding_0.3.3": "{\"dependencies\":[{\"name\":\"generic-array\",\"req\":\"^0.14\"}],\"features\":{\"std\":[]}}",
|
||||
@@ -740,7 +740,7 @@
|
||||
"chacha20_0.9.1": "{\"dependencies\":[{\"name\":\"cfg-if\",\"req\":\"^1\"},{\"name\":\"cipher\",\"req\":\"^0.4.4\"},{\"features\":[\"dev\"],\"kind\":\"dev\",\"name\":\"cipher\",\"req\":\"^0.4.4\"},{\"name\":\"cpufeatures\",\"req\":\"^0.2\",\"target\":\"cfg(any(target_arch = \\\"x86_64\\\", target_arch = \\\"x86\\\"))\"},{\"kind\":\"dev\",\"name\":\"hex-literal\",\"req\":\"^0.3.3\"}],\"features\":{\"std\":[\"cipher/std\"],\"zeroize\":[\"cipher/zeroize\"]}}",
|
||||
"chacha20poly1305_0.10.1": "{\"dependencies\":[{\"default_features\":false,\"name\":\"aead\",\"req\":\"^0.5\"},{\"default_features\":false,\"features\":[\"dev\"],\"kind\":\"dev\",\"name\":\"aead\",\"req\":\"^0.5\"},{\"features\":[\"zeroize\"],\"name\":\"chacha20\",\"req\":\"^0.9\"},{\"name\":\"cipher\",\"req\":\"^0.4\"},{\"name\":\"poly1305\",\"req\":\"^0.8\"},{\"default_features\":false,\"name\":\"zeroize\",\"req\":\"^1.5\"}],\"features\":{\"alloc\":[\"aead/alloc\"],\"default\":[\"alloc\",\"getrandom\"],\"getrandom\":[\"aead/getrandom\",\"rand_core\"],\"heapless\":[\"aead/heapless\"],\"rand_core\":[\"aead/rand_core\"],\"reduced-round\":[],\"std\":[\"aead/std\",\"alloc\"],\"stream\":[\"aead/stream\"]}}",
|
||||
"chardetng_0.1.17": "{\"dependencies\":[{\"name\":\"arrayvec\",\"optional\":true,\"req\":\"^0.5.1\"},{\"name\":\"cfg-if\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"detone\",\"req\":\"^1.0.0\"},{\"default_features\":false,\"name\":\"encoding_rs\",\"req\":\"^0.8.29\"},{\"default_features\":false,\"name\":\"memchr\",\"req\":\"^2.2.0\"},{\"name\":\"rayon\",\"optional\":true,\"req\":\"^1.3.0\"}],\"features\":{\"multithreading\":[\"rayon\",\"arrayvec\"],\"testing-only-no-semver-guarantees-do-not-use\":[]}}",
|
||||
"chrono_0.4.43": "{\"dependencies\":[{\"features\":[\"derive\"],\"name\":\"arbitrary\",\"optional\":true,\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"bincode\",\"req\":\"^1.3.0\"},{\"name\":\"defmt\",\"optional\":true,\"req\":\"^1.0.1\"},{\"features\":[\"fallback\"],\"name\":\"iana-time-zone\",\"optional\":true,\"req\":\"^0.1.45\",\"target\":\"cfg(unix)\"},{\"name\":\"js-sys\",\"optional\":true,\"req\":\"^0.3\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", not(any(target_os = \\\"emscripten\\\", target_os = \\\"wasi\\\"))))\"},{\"default_features\":false,\"name\":\"num-traits\",\"req\":\"^0.2\"},{\"name\":\"pure-rust-locales\",\"optional\":true,\"req\":\"^0.8.2\"},{\"default_features\":false,\"name\":\"rkyv\",\"optional\":true,\"req\":\"^0.7.43\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.99\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"serde_derive\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"similar-asserts\",\"req\":\"^1.6.1\"},{\"name\":\"wasm-bindgen\",\"optional\":true,\"req\":\"^0.2\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", not(any(target_os = \\\"emscripten\\\", target_os = \\\"wasi\\\"))))\"},{\"kind\":\"dev\",\"name\":\"wasm-bindgen-test\",\"req\":\"^0.3\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", not(any(target_os = \\\"emscripten\\\", target_os = \\\"wasi\\\"))))\"},{\"kind\":\"dev\",\"name\":\"windows-bindgen\",\"req\":\"^0.66\"},{\"name\":\"windows-link\",\"optional\":true,\"req\":\"^0.2\",\"target\":\"cfg(windows)\"}],\"features\":{\"__internal_bench\":[],\"alloc\":[],\"clock\":[\"winapi\",\"iana-time-zone\",\"now\"],\"core-error\":[],\"default\":[\"clock\",\"std\",\"oldtime\",\"wasmbind\"],\"defmt\":[\"dep:defmt\",\"pure-rust-locales?/defmt\"],\"libc\":[],\"now\":[\"std\"],\"oldtime\":[],\"rkyv\":[\"dep:rkyv\",\"rkyv/size_32\"],\"rkyv-16\":[\"dep:rkyv\",\"rkyv?/size_16\"],\"rkyv-32\":[\"dep:rkyv\",\"rkyv?/size_32\"],\"rkyv-64\":[\"dep:rkyv\",\"rkyv?/size_64\"],\"rkyv-validation\":[\"rkyv?/validation\"],\"std\":[\"alloc\"],\"unstable-locales\":[\"pure-rust-locales\"],\"wasmbind\":[\"wasm-bindgen\",\"js-sys\"],\"winapi\":[\"windows-link\"]}}",
|
||||
"chrono_0.4.44": "{\"dependencies\":[{\"features\":[\"derive\"],\"name\":\"arbitrary\",\"optional\":true,\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"bincode\",\"req\":\"^1.3.0\"},{\"name\":\"defmt\",\"optional\":true,\"req\":\"^1.0.1\"},{\"features\":[\"fallback\"],\"name\":\"iana-time-zone\",\"optional\":true,\"req\":\"^0.1.45\",\"target\":\"cfg(unix)\"},{\"name\":\"js-sys\",\"optional\":true,\"req\":\"^0.3\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", not(any(target_os = \\\"emscripten\\\", target_os = \\\"wasi\\\"))))\"},{\"default_features\":false,\"name\":\"num-traits\",\"req\":\"^0.2\"},{\"name\":\"pure-rust-locales\",\"optional\":true,\"req\":\"^0.8.2\"},{\"default_features\":false,\"name\":\"rkyv\",\"optional\":true,\"req\":\"^0.7.43\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.99\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"serde_derive\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"similar-asserts\",\"req\":\"^1.6.1\"},{\"name\":\"wasm-bindgen\",\"optional\":true,\"req\":\"^0.2\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", not(any(target_os = \\\"emscripten\\\", target_os = \\\"wasi\\\"))))\"},{\"kind\":\"dev\",\"name\":\"wasm-bindgen-test\",\"req\":\"^0.3\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", not(any(target_os = \\\"emscripten\\\", target_os = \\\"wasi\\\"))))\"},{\"kind\":\"dev\",\"name\":\"windows-bindgen\",\"req\":\"^0.66\"},{\"name\":\"windows-link\",\"optional\":true,\"req\":\"^0.2\",\"target\":\"cfg(windows)\"}],\"features\":{\"__internal_bench\":[],\"alloc\":[],\"clock\":[\"winapi\",\"iana-time-zone\",\"now\"],\"core-error\":[],\"default\":[\"clock\",\"std\",\"oldtime\",\"wasmbind\"],\"defmt\":[\"dep:defmt\",\"pure-rust-locales?/defmt\"],\"libc\":[],\"now\":[\"std\"],\"oldtime\":[],\"rkyv\":[\"dep:rkyv\",\"rkyv/size_32\"],\"rkyv-16\":[\"dep:rkyv\",\"rkyv?/size_16\"],\"rkyv-32\":[\"dep:rkyv\",\"rkyv?/size_32\"],\"rkyv-64\":[\"dep:rkyv\",\"rkyv?/size_64\"],\"rkyv-validation\":[\"rkyv?/validation\"],\"std\":[\"alloc\"],\"unstable-locales\":[\"pure-rust-locales\"],\"wasmbind\":[\"wasm-bindgen\",\"js-sys\"],\"winapi\":[\"windows-link\"]}}",
|
||||
"chunked_transfer_1.5.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.3\"}],\"features\":{}}",
|
||||
"cipher_0.4.4": "{\"dependencies\":[{\"name\":\"blobby\",\"optional\":true,\"req\":\"^0.3\"},{\"name\":\"crypto-common\",\"req\":\"^0.1.6\"},{\"name\":\"inout\",\"req\":\"^0.1\"},{\"default_features\":false,\"name\":\"zeroize\",\"optional\":true,\"req\":\"^1.5\"}],\"features\":{\"alloc\":[],\"block-padding\":[\"inout/block-padding\"],\"dev\":[\"blobby\"],\"rand_core\":[\"crypto-common/rand_core\"],\"std\":[\"alloc\",\"crypto-common/std\",\"inout/std\"]}}",
|
||||
"clang-sys_1.8.1": "{\"dependencies\":[{\"name\":\"glob\",\"req\":\"^0.3\"},{\"kind\":\"build\",\"name\":\"glob\",\"req\":\"^0.3\"},{\"kind\":\"dev\",\"name\":\"glob\",\"req\":\"^0.3\"},{\"kind\":\"dev\",\"name\":\"lazy_static\",\"req\":\"^1\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2.39\"},{\"name\":\"libloading\",\"optional\":true,\"req\":\"^0.8\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\">=3.0.0, <3.7.0\"}],\"features\":{\"clang_10_0\":[\"clang_9_0\"],\"clang_11_0\":[\"clang_10_0\"],\"clang_12_0\":[\"clang_11_0\"],\"clang_13_0\":[\"clang_12_0\"],\"clang_14_0\":[\"clang_13_0\"],\"clang_15_0\":[\"clang_14_0\"],\"clang_16_0\":[\"clang_15_0\"],\"clang_17_0\":[\"clang_16_0\"],\"clang_18_0\":[\"clang_17_0\"],\"clang_3_5\":[],\"clang_3_6\":[\"clang_3_5\"],\"clang_3_7\":[\"clang_3_6\"],\"clang_3_8\":[\"clang_3_7\"],\"clang_3_9\":[\"clang_3_8\"],\"clang_4_0\":[\"clang_3_9\"],\"clang_5_0\":[\"clang_4_0\"],\"clang_6_0\":[\"clang_5_0\"],\"clang_7_0\":[\"clang_6_0\"],\"clang_8_0\":[\"clang_7_0\"],\"clang_9_0\":[\"clang_8_0\"],\"libcpp\":[],\"runtime\":[\"libloading\"],\"static\":[]}}",
|
||||
@@ -1421,6 +1421,7 @@
|
||||
"rmcp_0.15.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1.0\"},{\"name\":\"async-trait\",\"req\":\"^0.1.89\"},{\"kind\":\"dev\",\"name\":\"async-trait\",\"req\":\"^0.1\"},{\"name\":\"axum\",\"optional\":true,\"req\":\"^0.8\"},{\"name\":\"base64\",\"optional\":true,\"req\":\"^0.22\"},{\"name\":\"bytes\",\"optional\":true,\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"serde\",\"clock\",\"std\",\"oldtime\"],\"name\":\"chrono\",\"req\":\"^0.4.38\",\"target\":\"cfg(all(target_family = \\\"wasm\\\", target_os = \\\"unknown\\\"))\"},{\"features\":[\"serde\"],\"name\":\"chrono\",\"req\":\"^0.4.38\",\"target\":\"cfg(not(all(target_family = \\\"wasm\\\", target_os = \\\"unknown\\\")))\"},{\"name\":\"futures\",\"req\":\"^0.3\"},{\"name\":\"http\",\"optional\":true,\"req\":\"^1\"},{\"name\":\"http-body\",\"optional\":true,\"req\":\"^1\"},{\"name\":\"http-body-util\",\"optional\":true,\"req\":\"^0.1\"},{\"default_features\":false,\"features\":[\"reqwest\"],\"name\":\"oauth2\",\"optional\":true,\"req\":\"^5.0\"},{\"name\":\"pastey\",\"optional\":true,\"req\":\"^0.2.0\"},{\"name\":\"pin-project-lite\",\"req\":\"^0.2\"},{\"features\":[\"tokio1\"],\"name\":\"process-wrap\",\"optional\":true,\"req\":\"^9.0\"},{\"name\":\"rand\",\"optional\":true,\"req\":\"^0.9\"},{\"default_features\":false,\"features\":[\"json\",\"stream\"],\"name\":\"reqwest\",\"optional\":true,\"req\":\"^0.12\"},{\"name\":\"rmcp-macros\",\"optional\":true,\"req\":\"^0.15.0\"},{\"features\":[\"chrono04\"],\"name\":\"schemars\",\"optional\":true,\"req\":\"^1.0\"},{\"features\":[\"chrono04\"],\"kind\":\"dev\",\"name\":\"schemars\",\"req\":\"^1.1.0\"},{\"features\":[\"derive\",\"rc\"],\"name\":\"serde\",\"req\":\"^1.0\"},{\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"name\":\"sse-stream\",\"optional\":true,\"req\":\"^0.2\"},{\"name\":\"thiserror\",\"req\":\"^2\"},{\"features\":[\"sync\",\"macros\",\"rt\",\"time\"],\"name\":\"tokio\",\"req\":\"^1\"},{\"features\":[\"full\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"},{\"name\":\"tokio-stream\",\"optional\":true,\"req\":\"^0.1\"},{\"name\":\"tokio-util\",\"req\":\"^0.7\"},{\"name\":\"tower-service\",\"optional\":true,\"req\":\"^0.3\"},{\"name\":\"tracing\",\"req\":\"^0.1\"},{\"features\":[\"env-filter\",\"std\",\"fmt\"],\"kind\":\"dev\",\"name\":\"tracing-subscriber\",\"req\":\"^0.3\"},{\"name\":\"url\",\"optional\":true,\"req\":\"^2.4\"},{\"features\":[\"v4\"],\"name\":\"uuid\",\"optional\":true,\"req\":\"^1\"}],\"features\":{\"__reqwest\":[\"dep:reqwest\"],\"auth\":[\"dep:oauth2\",\"__reqwest\",\"dep:url\"],\"client\":[\"dep:tokio-stream\"],\"client-side-sse\":[\"dep:sse-stream\",\"dep:http\"],\"default\":[\"base64\",\"macros\",\"server\"],\"elicitation\":[\"dep:url\"],\"macros\":[\"dep:rmcp-macros\",\"dep:pastey\"],\"reqwest\":[\"__reqwest\",\"reqwest?/rustls-tls\"],\"reqwest-native-tls\":[\"__reqwest\",\"reqwest?/native-tls\"],\"reqwest-tls-no-provider\":[\"__reqwest\",\"reqwest?/rustls-tls-no-provider\"],\"schemars\":[\"dep:schemars\"],\"server\":[\"transport-async-rw\",\"dep:schemars\",\"dep:pastey\"],\"server-side-http\":[\"uuid\",\"dep:rand\",\"dep:tokio-stream\",\"dep:http\",\"dep:http-body\",\"dep:http-body-util\",\"dep:bytes\",\"dep:sse-stream\",\"dep:axum\",\"tower\"],\"tower\":[\"dep:tower-service\"],\"transport-async-rw\":[\"tokio/io-util\",\"tokio-util/codec\"],\"transport-child-process\":[\"transport-async-rw\",\"tokio/process\",\"dep:process-wrap\"],\"transport-io\":[\"transport-async-rw\",\"tokio/io-std\"],\"transport-streamable-http-client\":[\"client-side-sse\",\"transport-worker\"],\"transport-streamable-http-client-reqwest\":[\"transport-streamable-http-client\",\"__reqwest\"],\"transport-streamable-http-server\":[\"transport-streamable-http-server-session\",\"server-side-http\",\"transport-worker\"],\"transport-streamable-http-server-session\":[\"transport-async-rw\",\"dep:tokio-stream\"],\"transport-worker\":[\"dep:tokio-stream\"]}}",
|
||||
"rsa_0.9.10": "{\"dependencies\":[{\"features\":[\"alloc\"],\"kind\":\"dev\",\"name\":\"base64ct\",\"req\":\"^1\"},{\"default_features\":false,\"name\":\"const-oid\",\"req\":\"^0.9\"},{\"default_features\":false,\"features\":[\"alloc\",\"oid\"],\"name\":\"digest\",\"req\":\"^0.10.5\"},{\"kind\":\"dev\",\"name\":\"hex-literal\",\"req\":\"^0.4.1\"},{\"default_features\":false,\"features\":[\"i128\",\"prime\",\"zeroize\"],\"name\":\"num-bigint\",\"package\":\"num-bigint-dig\",\"req\":\"^0.8.6\"},{\"default_features\":false,\"name\":\"num-integer\",\"req\":\"^0.1.39\"},{\"default_features\":false,\"features\":[\"libm\"],\"name\":\"num-traits\",\"req\":\"^0.2.9\"},{\"default_features\":false,\"features\":[\"alloc\",\"pkcs8\"],\"name\":\"pkcs1\",\"req\":\"^0.7.5\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"pkcs8\",\"req\":\"^0.10.2\"},{\"kind\":\"dev\",\"name\":\"proptest\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8\"},{\"kind\":\"dev\",\"name\":\"rand_chacha\",\"req\":\"^0.3\"},{\"default_features\":false,\"name\":\"rand_core\",\"req\":\"^0.6.4\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"rand_core\",\"req\":\"^0.6\"},{\"kind\":\"dev\",\"name\":\"rand_xorshift\",\"req\":\"^0.3\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.184\"},{\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\"^1.0.89\"},{\"default_features\":false,\"features\":[\"oid\"],\"name\":\"sha1\",\"optional\":true,\"req\":\"^0.10.5\"},{\"default_features\":false,\"features\":[\"oid\"],\"kind\":\"dev\",\"name\":\"sha1\",\"req\":\"^0.10.5\"},{\"default_features\":false,\"features\":[\"oid\"],\"name\":\"sha2\",\"optional\":true,\"req\":\"^0.10.6\"},{\"default_features\":false,\"features\":[\"oid\"],\"kind\":\"dev\",\"name\":\"sha2\",\"req\":\"^0.10.6\"},{\"default_features\":false,\"features\":[\"oid\"],\"kind\":\"dev\",\"name\":\"sha3\",\"req\":\"^0.10.7\"},{\"default_features\":false,\"features\":[\"alloc\",\"digest\",\"rand_core\"],\"name\":\"signature\",\"req\":\">2.0, <2.3\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"spki\",\"req\":\"^0.7.3\"},{\"default_features\":false,\"name\":\"subtle\",\"req\":\"^2.1.1\"},{\"features\":[\"alloc\"],\"name\":\"zeroize\",\"req\":\"^1.5\"}],\"features\":{\"default\":[\"std\",\"pem\",\"u64_digit\"],\"getrandom\":[\"rand_core/getrandom\"],\"hazmat\":[],\"nightly\":[\"num-bigint/nightly\"],\"pem\":[\"pkcs1/pem\",\"pkcs8/pem\"],\"pkcs5\":[\"pkcs8/encryption\"],\"serde\":[\"dep:serde\",\"num-bigint/serde\"],\"std\":[\"digest/std\",\"pkcs1/std\",\"pkcs8/std\",\"rand_core/std\",\"signature/std\"],\"u64_digit\":[\"num-bigint/u64_digit\"]}}",
|
||||
"rtrb_0.3.3": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.8\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"crossbeam-utils\",\"req\":\"^0.8\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.10\"}],\"features\":{\"default\":[\"std\"],\"std\":[]}}",
|
||||
"russh-sftp_2.1.2": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1.0.102\"},{\"name\":\"async-trait\",\"optional\":true,\"req\":\"^0.1.89\"},{\"features\":[\"serde\"],\"name\":\"bitflags\",\"req\":\"^2.11.1\"},{\"name\":\"bytes\",\"req\":\"^1.11.1\"},{\"name\":\"chrono\",\"req\":\"^0.4.44\"},{\"features\":[\"async_tokio\"],\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.8.2\"},{\"name\":\"dashmap\",\"req\":\"^6.1.0\"},{\"kind\":\"dev\",\"name\":\"env_logger\",\"req\":\"^0.11.10\"},{\"kind\":\"dev\",\"name\":\"futures\",\"req\":\"^0.3.32\"},{\"name\":\"log\",\"req\":\"^0.4.29\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.10.1\"},{\"kind\":\"dev\",\"name\":\"russh\",\"req\":\"^0.60.2\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"req\":\"^1.0.228\"},{\"name\":\"serde_bytes\",\"req\":\"^0.11\"},{\"name\":\"thiserror\",\"req\":\"^2.0.18\"},{\"default_features\":false,\"features\":[\"io-util\",\"rt\",\"sync\",\"time\",\"macros\"],\"name\":\"tokio\",\"req\":\"^1\"},{\"name\":\"tokio-util\",\"req\":\"^0.7.18\"}],\"features\":{\"async-trait\":[\"dep:async-trait\"]}}",
|
||||
"rust-embed-impl_8.11.0": "{\"dependencies\":[{\"name\":\"proc-macro2\",\"req\":\"^1\"},{\"name\":\"quote\",\"req\":\"^1\"},{\"name\":\"rust-embed-utils\",\"req\":\"^8.11.0\"},{\"name\":\"shellexpand\",\"optional\":true,\"req\":\"^3\"},{\"default_features\":false,\"features\":[\"derive\",\"parsing\",\"proc-macro\",\"printing\"],\"name\":\"syn\",\"req\":\"^2\"},{\"name\":\"walkdir\",\"req\":\"^2.3.1\"}],\"features\":{\"compression\":[],\"debug-embed\":[],\"deterministic-timestamps\":[],\"include-exclude\":[\"rust-embed-utils/include-exclude\"],\"interpolate-folder-path\":[\"shellexpand\"],\"mime-guess\":[\"rust-embed-utils/mime-guess\"]}}",
|
||||
"rust-embed-utils_8.11.0": "{\"dependencies\":[{\"name\":\"globset\",\"optional\":true,\"req\":\"^0.4.8\"},{\"name\":\"mime_guess\",\"optional\":true,\"req\":\"^2.0.4\"},{\"name\":\"sha2\",\"req\":\"^0.10.5\"},{\"name\":\"walkdir\",\"req\":\"^2.3.1\"}],\"features\":{\"debug-embed\":[],\"include-exclude\":[\"globset\"],\"mime-guess\":[\"mime_guess\"]}}",
|
||||
"rust-embed_8.11.0": "{\"dependencies\":[{\"name\":\"actix-web\",\"optional\":true,\"req\":\"^4\"},{\"default_features\":false,\"features\":[\"http1\",\"tokio\"],\"name\":\"axum\",\"optional\":true,\"req\":\"^0.8\"},{\"name\":\"hex\",\"optional\":true,\"req\":\"^0.4.3\"},{\"name\":\"include-flate\",\"optional\":true,\"req\":\"^0.3\"},{\"name\":\"mime_guess\",\"optional\":true,\"req\":\"^2.0.5\"},{\"default_features\":false,\"features\":[\"server\"],\"name\":\"poem\",\"optional\":true,\"req\":\"^1.3.30\"},{\"default_features\":false,\"name\":\"rocket\",\"optional\":true,\"req\":\"^0.5.0-rc.2\"},{\"name\":\"rust-embed-impl\",\"req\":\"^8.9.0\"},{\"name\":\"rust-embed-utils\",\"req\":\"^8.9.0\"},{\"default_features\":false,\"name\":\"salvo\",\"optional\":true,\"req\":\"^0.16\"},{\"kind\":\"dev\",\"name\":\"sha2\",\"req\":\"^0.10\"},{\"features\":[\"macros\",\"rt-multi-thread\"],\"name\":\"tokio\",\"optional\":true,\"req\":\"^1.0\"},{\"name\":\"walkdir\",\"req\":\"^2.3.2\"},{\"default_features\":false,\"name\":\"warp\",\"optional\":true,\"req\":\"^0.3\"}],\"features\":{\"actix\":[\"actix-web\",\"mime_guess\"],\"axum-ex\":[\"axum\",\"tokio\",\"mime_guess\"],\"compression\":[\"rust-embed-impl/compression\",\"include-flate\"],\"debug-embed\":[\"rust-embed-impl/debug-embed\",\"rust-embed-utils/debug-embed\"],\"deterministic-timestamps\":[\"rust-embed-impl/deterministic-timestamps\"],\"include-exclude\":[\"rust-embed-impl/include-exclude\",\"rust-embed-utils/include-exclude\"],\"interpolate-folder-path\":[\"rust-embed-impl/interpolate-folder-path\"],\"mime-guess\":[\"rust-embed-impl/mime-guess\",\"rust-embed-utils/mime-guess\"],\"poem-ex\":[\"poem\",\"tokio\",\"mime_guess\",\"hex\"],\"salvo-ex\":[\"salvo\",\"tokio\",\"mime_guess\",\"hex\"],\"warp-ex\":[\"warp\",\"tokio\",\"mime_guess\"]}}",
|
||||
@@ -1478,6 +1479,7 @@
|
||||
"sentry-types_0.46.1": "{\"dependencies\":[{\"features\":[\"serde\"],\"name\":\"debugid\",\"req\":\"^0.8.0\"},{\"name\":\"hex\",\"req\":\"^0.4.3\"},{\"name\":\"rand\",\"req\":\"^0.9.0\"},{\"kind\":\"dev\",\"name\":\"rstest\",\"req\":\"^0.25.0\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"req\":\"^1.0.104\"},{\"name\":\"serde_json\",\"req\":\"^1.0.46\"},{\"name\":\"thiserror\",\"req\":\"^2.0.12\"},{\"features\":[\"formatting\",\"parsing\"],\"name\":\"time\",\"req\":\"^0.3.5\"},{\"features\":[\"serde\"],\"name\":\"url\",\"req\":\"^2.1.1\"},{\"features\":[\"serde\"],\"name\":\"uuid\",\"req\":\"^1.0.0\"}],\"features\":{\"default\":[\"protocol\"],\"protocol\":[]}}",
|
||||
"sentry_0.46.1": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"dev\",\"name\":\"actix-web\",\"req\":\"^4\"},{\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1.0.30\"},{\"name\":\"curl\",\"optional\":true,\"req\":\"^0.4.25\"},{\"name\":\"embedded-svc\",\"optional\":true,\"req\":\"^0.28.1\"},{\"name\":\"esp-idf-svc\",\"optional\":true,\"req\":\"^0.51.0\",\"target\":\"cfg(target_os = \\\"espidf\\\")\"},{\"name\":\"httpdate\",\"optional\":true,\"req\":\"^1.0.0\"},{\"features\":[\"std\"],\"kind\":\"dev\",\"name\":\"log\",\"req\":\"^0.4.8\"},{\"name\":\"native-tls\",\"optional\":true,\"req\":\"^0.2.8\"},{\"kind\":\"dev\",\"name\":\"pretty_env_logger\",\"req\":\"^0.5.0\"},{\"default_features\":false,\"features\":[\"blocking\",\"json\"],\"name\":\"reqwest\",\"optional\":true,\"req\":\"^0.12.25\"},{\"default_features\":false,\"name\":\"rustls\",\"optional\":true,\"req\":\"^0.23.18\"},{\"default_features\":false,\"name\":\"sentry-actix\",\"optional\":true,\"req\":\"^0.46.1\"},{\"name\":\"sentry-anyhow\",\"optional\":true,\"req\":\"^0.46.1\"},{\"name\":\"sentry-backtrace\",\"optional\":true,\"req\":\"^0.46.1\"},{\"name\":\"sentry-contexts\",\"optional\":true,\"req\":\"^0.46.1\"},{\"features\":[\"client\"],\"name\":\"sentry-core\",\"req\":\"^0.46.1\"},{\"name\":\"sentry-debug-images\",\"optional\":true,\"req\":\"^0.46.1\"},{\"name\":\"sentry-log\",\"optional\":true,\"req\":\"^0.46.1\"},{\"name\":\"sentry-opentelemetry\",\"optional\":true,\"req\":\"^0.46.1\"},{\"name\":\"sentry-panic\",\"optional\":true,\"req\":\"^0.46.1\"},{\"name\":\"sentry-slog\",\"optional\":true,\"req\":\"^0.46.1\"},{\"name\":\"sentry-tower\",\"optional\":true,\"req\":\"^0.46.1\"},{\"name\":\"sentry-tracing\",\"optional\":true,\"req\":\"^0.46.1\"},{\"name\":\"serde_json\",\"optional\":true,\"req\":\"^1.0.48\"},{\"kind\":\"dev\",\"name\":\"slog\",\"req\":\"^2.5.2\"},{\"features\":[\"rt\"],\"name\":\"tokio\",\"optional\":true,\"req\":\"^1.44\"},{\"features\":[\"macros\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.44\"},{\"features\":[\"util\"],\"kind\":\"dev\",\"name\":\"tower\",\"req\":\"^0.5.2\"},{\"kind\":\"dev\",\"name\":\"tracing\",\"req\":\"^0.1\"},{\"features\":[\"fmt\",\"tracing-log\"],\"kind\":\"dev\",\"name\":\"tracing-subscriber\",\"req\":\"^0.3\"},{\"default_features\":false,\"name\":\"ureq\",\"optional\":true,\"req\":\"^3.0.11\"}],\"features\":{\"actix\":[\"sentry-actix\"],\"anyhow\":[\"sentry-anyhow\"],\"backtrace\":[\"sentry-backtrace\",\"sentry-tracing?/backtrace\"],\"contexts\":[\"sentry-contexts\"],\"curl\":[\"dep:curl\",\"httpdate\"],\"debug-images\":[\"sentry-debug-images\"],\"default\":[\"backtrace\",\"contexts\",\"debug-images\",\"panic\",\"transport\",\"release-health\"],\"embedded-svc-http\":[\"dep:embedded-svc\",\"dep:esp-idf-svc\"],\"log\":[\"sentry-log\"],\"logs\":[\"sentry-core/logs\",\"sentry-tracing?/logs\",\"sentry-log?/logs\"],\"native-tls\":[\"dep:native-tls\",\"reqwest?/default-tls\",\"ureq?/native-tls\"],\"opentelemetry\":[\"sentry-opentelemetry\"],\"panic\":[\"sentry-panic\"],\"release-health\":[\"sentry-core/release-health\",\"sentry-actix?/release-health\"],\"reqwest\":[\"dep:reqwest\",\"httpdate\",\"tokio\"],\"rustls\":[\"dep:rustls\",\"reqwest?/rustls-tls\",\"ureq?/rustls\"],\"slog\":[\"sentry-slog\"],\"test\":[\"sentry-core/test\"],\"tower\":[\"sentry-tower\"],\"tower-axum-matched-path\":[\"tower-http\",\"sentry-tower/axum-matched-path\"],\"tower-http\":[\"tower\",\"sentry-tower/http\"],\"tracing\":[\"sentry-tracing\"],\"transport\":[\"reqwest\",\"native-tls\"],\"ureq\":[\"dep:ureq\",\"httpdate\"]}}",
|
||||
"serde_1.0.228": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"result\"],\"name\":\"serde_core\",\"req\":\"=1.0.228\"},{\"name\":\"serde_derive\",\"optional\":true,\"req\":\"^1\"}],\"features\":{\"alloc\":[\"serde_core/alloc\"],\"default\":[\"std\"],\"derive\":[\"serde_derive\"],\"rc\":[\"serde_core/rc\"],\"std\":[\"serde_core/std\"],\"unstable\":[\"serde_core/unstable\"]}}",
|
||||
"serde_bytes_0.11.19": "{\"dependencies\":[{\"features\":[\"serde\"],\"kind\":\"dev\",\"name\":\"bincode\",\"req\":\"^2\"},{\"default_features\":false,\"name\":\"serde\",\"req\":\"^1.0.220\",\"target\":\"cfg(any())\"},{\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0.220\"},{\"default_features\":false,\"name\":\"serde_core\",\"req\":\"^1.0.220\"},{\"kind\":\"dev\",\"name\":\"serde_derive\",\"req\":\"^1.0.220\"},{\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\"^1.0.166\"}],\"features\":{\"alloc\":[\"serde_core/alloc\"],\"default\":[\"std\"],\"std\":[\"serde_core/std\"]}}",
|
||||
"serde_core_1.0.228": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1\"},{\"name\":\"serde_derive\",\"req\":\"=1.0.228\",\"target\":\"cfg(any())\"},{\"kind\":\"dev\",\"name\":\"serde_derive\",\"req\":\"^1\"}],\"features\":{\"alloc\":[],\"default\":[\"std\",\"result\"],\"rc\":[],\"result\":[],\"std\":[],\"unstable\":[]}}",
|
||||
"serde_derive_1.0.228": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"proc-macro\"],\"name\":\"proc-macro2\",\"req\":\"^1.0.74\"},{\"default_features\":false,\"features\":[\"proc-macro\"],\"name\":\"quote\",\"req\":\"^1.0.35\"},{\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"clone-impls\",\"derive\",\"parsing\",\"printing\",\"proc-macro\"],\"name\":\"syn\",\"req\":\"^2.0.81\"}],\"features\":{\"default\":[],\"deserialize_in_place\":[]}}",
|
||||
"serde_derive_internals_0.29.1": "{\"dependencies\":[{\"default_features\":false,\"name\":\"proc-macro2\",\"req\":\"^1.0.74\"},{\"default_features\":false,\"name\":\"quote\",\"req\":\"^1.0.35\"},{\"default_features\":false,\"features\":[\"clone-impls\",\"derive\",\"parsing\",\"printing\"],\"name\":\"syn\",\"req\":\"^2.0.46\"}],\"features\":{}}",
|
||||
|
||||
Generated
+92
-63
@@ -18,7 +18,7 @@ version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f7b0a21988c1bf877cf4759ef5ddaac04c1c9fe808c9142ecb78ba97d97a28a"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
@@ -39,7 +39,7 @@ dependencies = [
|
||||
"actix-rt",
|
||||
"actix-service",
|
||||
"actix-utils",
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"bytes",
|
||||
"bytestring",
|
||||
"derive_more 2.1.1",
|
||||
@@ -298,7 +298,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed7572b7ba83a31e20d1b48970ee402d2e3e0537dcfe0a3ff4d6eb7508617d43"
|
||||
dependencies = [
|
||||
"alsa-sys",
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
]
|
||||
@@ -1250,7 +1250,7 @@ version = "0.72.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"cexpr",
|
||||
"clang-sys",
|
||||
"itertools 0.13.0",
|
||||
@@ -1287,9 +1287,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.10.0"
|
||||
version = "2.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
|
||||
checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
]
|
||||
@@ -1614,9 +1614,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.43"
|
||||
version = "0.4.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118"
|
||||
checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0"
|
||||
dependencies = [
|
||||
"iana-time-zone",
|
||||
"js-sys",
|
||||
@@ -1904,6 +1904,7 @@ dependencies = [
|
||||
"pretty_assertions",
|
||||
"reqwest",
|
||||
"rmcp",
|
||||
"russh-sftp",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serial_test",
|
||||
@@ -4399,7 +4400,7 @@ name = "crossterm"
|
||||
version = "0.28.1"
|
||||
source = "git+https://github.com/nornagon/crossterm?rev=87db8bfa6dc99427fd3b071681b07fc31c6ce995#87db8bfa6dc99427fd3b071681b07fc31c6ce995"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"crossterm_winapi",
|
||||
"futures-core",
|
||||
"mio",
|
||||
@@ -5045,7 +5046,7 @@ version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"objc2",
|
||||
]
|
||||
|
||||
@@ -6131,7 +6132,7 @@ version = "0.17.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "441a300bc3645a1f45cba495b9175f90f47256ce43f2ee161da0031e3ac77c92"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"bstr",
|
||||
"gix-path",
|
||||
"libc",
|
||||
@@ -6277,7 +6278,7 @@ version = "0.24.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b03e6cd88cc0dc1eafa1fddac0fb719e4e74b6ea58dd016e71125fde4a326bee"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"bstr",
|
||||
"gix-features",
|
||||
"gix-path",
|
||||
@@ -6325,7 +6326,7 @@ version = "0.49.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bae54ab14e4e74d5dda60b82ea7afad7c8eb3be68283d6d5f29bd2e6d47fff7"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"bstr",
|
||||
"filetime",
|
||||
"fnv",
|
||||
@@ -6390,7 +6391,7 @@ version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ea064c7595eea08fdd01c70748af747d9acc40f727b61f4c8a2145a5c5fc28c"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"gix-commitgraph",
|
||||
"gix-date",
|
||||
"gix-hash",
|
||||
@@ -6488,7 +6489,7 @@ version = "0.16.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f89611f13544ca5ebeb68a502673814ef57200df60c24a61c2ce7b96f612f08b"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"bstr",
|
||||
"gix-attributes",
|
||||
"gix-config-value",
|
||||
@@ -6571,7 +6572,7 @@ version = "0.43.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c08f1ec5d1e6a524f8ba291c41f0ccaef64e48ed0e8cf790b3461cae45f6d3d"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"bstr",
|
||||
"gix-commitgraph",
|
||||
"gix-date",
|
||||
@@ -6605,7 +6606,7 @@ version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf82ae037de9c62850ce67beaa92ec8e3e17785ea307cdde7618edc215603b4f"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"gix-path",
|
||||
"libc",
|
||||
"windows-sys 0.61.2",
|
||||
@@ -6703,7 +6704,7 @@ version = "0.55.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "963dc2afcdb611092aa587c3f9365e749ac0a0892ff27662dbc75f26c953fbec"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"gix-commitgraph",
|
||||
"gix-date",
|
||||
"gix-hash",
|
||||
@@ -6806,7 +6807,7 @@ version = "0.21.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "16de123c2e6c90ce3b573b7330de19be649080ec612033d397d72da265f1bd8b"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-executor",
|
||||
@@ -7688,7 +7689,7 @@ version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f37dccff2791ab604f9babef0ba14fbe0be30bd368dc541e2b08d07c8aa908f3"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"inotify-sys",
|
||||
"libc",
|
||||
]
|
||||
@@ -8119,7 +8120,7 @@ version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"libc",
|
||||
"redox_syscall 0.7.0",
|
||||
]
|
||||
@@ -8192,7 +8193,7 @@ version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "761e49ec5fd8a5a463f9b84e877c373d888935b71c6be78f3767fe2ae6bed18e"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"libc",
|
||||
]
|
||||
|
||||
@@ -8582,7 +8583,7 @@ version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"jni-sys",
|
||||
"log",
|
||||
"ndk-sys",
|
||||
@@ -8626,7 +8627,7 @@ version = "0.28.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"cfg-if",
|
||||
"cfg_aliases 0.1.1",
|
||||
"libc",
|
||||
@@ -8638,7 +8639,7 @@ version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"cfg-if",
|
||||
"cfg_aliases 0.2.1",
|
||||
"libc",
|
||||
@@ -8651,7 +8652,7 @@ version = "0.30.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"cfg-if",
|
||||
"cfg_aliases 0.2.1",
|
||||
"libc",
|
||||
@@ -8694,7 +8695,7 @@ version = "8.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d3d07927151ff8575b7087f245456e549fea62edf0ec4e565a5ee50c8402bc3"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"fsevent-sys",
|
||||
"inotify",
|
||||
"kqueue",
|
||||
@@ -8712,7 +8713,7 @@ version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42b8cfee0e339a0337359f3c88165702ac6e600dc01c0cc9579a92d62b08477a"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -8897,7 +8898,7 @@ version = "5.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51e219e79014df21a225b1860a479e2dcd7cbd9130f4defd4bd0e191ea31d67d"
|
||||
dependencies = [
|
||||
"base64 0.21.7",
|
||||
"base64 0.22.1",
|
||||
"chrono",
|
||||
"getrandom 0.2.17",
|
||||
"http 1.4.0",
|
||||
@@ -8926,7 +8927,7 @@ version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"objc2",
|
||||
"objc2-core-graphics",
|
||||
"objc2-foundation",
|
||||
@@ -8938,7 +8939,7 @@ version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73ad74d880bb43877038da939b7427bba67e9dd42004a18b809ba7d87cee241c"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"objc2",
|
||||
"objc2-foundation",
|
||||
]
|
||||
@@ -8959,7 +8960,7 @@ version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"dispatch2",
|
||||
"objc2",
|
||||
]
|
||||
@@ -8970,7 +8971,7 @@ version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"dispatch2",
|
||||
"objc2",
|
||||
"objc2-core-foundation",
|
||||
@@ -9003,7 +9004,7 @@ version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0cde0dfb48d25d2b4862161a4d5fcc0e3c24367869ad306b0c9ec0073bfed92d"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"objc2",
|
||||
"objc2-core-foundation",
|
||||
"objc2-core-graphics",
|
||||
@@ -9021,7 +9022,7 @@ version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"block2",
|
||||
"libc",
|
||||
"objc2",
|
||||
@@ -9034,7 +9035,7 @@ version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"objc2",
|
||||
"objc2-core-foundation",
|
||||
]
|
||||
@@ -9045,7 +9046,7 @@ version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"objc2",
|
||||
"objc2-core-foundation",
|
||||
"objc2-foundation",
|
||||
@@ -9057,7 +9058,7 @@ version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"block2",
|
||||
"objc2",
|
||||
"objc2-cloud-kit",
|
||||
@@ -9145,7 +9146,7 @@ version = "6.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "336b9c63443aceef14bea841b899035ae3abe89b7c486aaf4c5bd8aafedac3f0"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"onig_sys",
|
||||
@@ -9173,7 +9174,7 @@ version = "0.10.75"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"cfg-if",
|
||||
"foreign-types",
|
||||
"libc",
|
||||
@@ -9365,7 +9366,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d8fae84b431384b68627d0f9b3b1245fcf9f46f6c0e3dc902e9dce64edd1967"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.45.0",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -9675,7 +9676,7 @@ version = "0.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97baced388464909d42d89643fe4361939af9b7ce7a31ee32a168f832a70f2a0"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"crc32fast",
|
||||
"fdeflate",
|
||||
"flate2",
|
||||
@@ -9903,7 +9904,7 @@ version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bee689443a2bd0a16ab0348b52ee43e3b2d1b1f931c8aa5c9f8de4c86fbe8c40"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"num-traits",
|
||||
"rand 0.9.3",
|
||||
"rand_chacha 0.9.0",
|
||||
@@ -10047,7 +10048,7 @@ version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76979bea66e7875e7509c4ec5300112b316af87fa7a252ca91c448b32dfe3993"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"getopts",
|
||||
"memchr",
|
||||
"pulldown-cmark-escape",
|
||||
@@ -10227,7 +10228,7 @@ checksum = "453d60af031e23af2d48995e41b17023f6150044738680508b63671f8d7417dd"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"base64 0.22.1",
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"chrono",
|
||||
"const_format",
|
||||
"csv",
|
||||
@@ -10558,7 +10559,7 @@ name = "ratatui"
|
||||
version = "0.29.0"
|
||||
source = "git+https://github.com/nornagon/ratatui?rev=9b2ad1298408c45918ee9f8241a6f95498cdbed2#9b2ad1298408c45918ee9f8241a6f95498cdbed2"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"cassowary",
|
||||
"compact_str",
|
||||
"crossterm",
|
||||
@@ -10622,7 +10623,7 @@ version = "0.5.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -10631,7 +10632,7 @@ version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49f3fe0889e69e2ae9e41f4d6c4c0181701d00e4697b356fb1f74173a5e0ee27"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -10888,6 +10889,24 @@ name = "runfiles"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/dzbarsky/rules_rust?rev=b56cbaa8465e74127f1ea216f813cd377295ad81#b56cbaa8465e74127f1ea216f813cd377295ad81"
|
||||
|
||||
[[package]]
|
||||
name = "russh-sftp"
|
||||
version = "2.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09daa0ebcf53fb18d7b16167586a68b5bf2cfa3eaad49e661a19302552a2b879"
|
||||
dependencies = [
|
||||
"bitflags 2.11.1",
|
||||
"bytes",
|
||||
"chrono",
|
||||
"dashmap",
|
||||
"log",
|
||||
"serde",
|
||||
"serde_bytes",
|
||||
"thiserror 2.0.18",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-embed"
|
||||
version = "8.11.0"
|
||||
@@ -10974,7 +10993,7 @@ version = "0.38.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys 0.4.15",
|
||||
@@ -10987,7 +11006,7 @@ version = "1.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys 0.12.1",
|
||||
@@ -11056,7 +11075,7 @@ version = "14.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7803e8936da37efd9b6d4478277f4b2b9bb5cdb37a113e8d63222e58da647e63"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"cfg-if",
|
||||
"clipboard-win",
|
||||
"fd-lock",
|
||||
@@ -11310,7 +11329,7 @@ version = "2.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"core-foundation 0.9.4",
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
@@ -11323,7 +11342,7 @@ version = "3.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"core-foundation 0.10.1",
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
@@ -11458,7 +11477,7 @@ version = "0.46.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1dd47df349a80025819f3d25c3d2f751df705d49c65a4cdc0f130f700972a48"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"sentry-backtrace",
|
||||
"sentry-core",
|
||||
"tracing-core",
|
||||
@@ -11492,6 +11511,16 @@ dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_bytes"
|
||||
version = "0.11.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a5d440709e79d88e51ac01c4b72fc6cb7314017bb7da9eeff678aa94c10e3ea8"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_core"
|
||||
version = "1.0.228"
|
||||
@@ -11988,7 +12017,7 @@ checksum = "aa003f0038df784eb8fecbbac13affe3da23b45194bd57dba231c8f48199c526"
|
||||
dependencies = [
|
||||
"atoi",
|
||||
"base64 0.22.1",
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"byteorder",
|
||||
"bytes",
|
||||
"chrono",
|
||||
@@ -12033,7 +12062,7 @@ checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46"
|
||||
dependencies = [
|
||||
"atoi",
|
||||
"base64 0.22.1",
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"byteorder",
|
||||
"chrono",
|
||||
"crc",
|
||||
@@ -12424,7 +12453,7 @@ version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"core-foundation 0.9.4",
|
||||
"system-configuration-sys",
|
||||
]
|
||||
@@ -13069,7 +13098,7 @@ version = "0.6.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"http 1.4.0",
|
||||
@@ -13583,7 +13612,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d97bcac5cdc5a195a4813f1855a6bc658f240452aac36caa12fd6c6f16026ab1"
|
||||
dependencies = [
|
||||
"bindgen",
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"fslock",
|
||||
"gzip-header",
|
||||
"home",
|
||||
@@ -13784,7 +13813,7 @@ version = "0.31.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8e6faa537fbb6c186cb9f1d41f2f811a4120d1b57ec61f50da451a0c5122bec"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"rustix 1.1.4",
|
||||
"wayland-backend",
|
||||
"wayland-scanner",
|
||||
@@ -13796,7 +13825,7 @@ version = "0.32.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baeda9ffbcfc8cd6ddaade385eaf2393bd2115a69523c735f12242353c3df4f3"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"wayland-backend",
|
||||
"wayland-client",
|
||||
"wayland-scanner",
|
||||
@@ -13808,7 +13837,7 @@ version = "0.3.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e9597cdf02cf0c34cd5823786dce6b5ae8598f05c2daf5621b6e178d4f7345f3"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.11.1",
|
||||
"wayland-backend",
|
||||
"wayland-client",
|
||||
"wayland-protocols",
|
||||
@@ -14009,7 +14038,7 @@ version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
|
||||
dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -334,6 +334,7 @@ regex-lite = "0.1.8"
|
||||
reqwest = { version = "0.12", features = ["cookies"] }
|
||||
rmcp = { version = "0.15.0", default-features = false }
|
||||
runfiles = { git = "https://github.com/dzbarsky/rules_rust", rev = "b56cbaa8465e74127f1ea216f813cd377295ad81" }
|
||||
russh-sftp = "2.1.2"
|
||||
rustls = { version = "0.23", default-features = false, features = [
|
||||
"ring",
|
||||
"std",
|
||||
|
||||
@@ -89,6 +89,7 @@ tracing = { workspace = true, features = ["log"] }
|
||||
tracing-subscriber = { workspace = true, features = ["env-filter", "fmt", "json"] }
|
||||
url = { workspace = true }
|
||||
uuid = { workspace = true, features = ["serde", "v7"] }
|
||||
russh-sftp = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
app_test_support = { workspace = true }
|
||||
|
||||
@@ -973,14 +973,11 @@ pub async fn run_main_with_transport_options(
|
||||
warn!("dropping binary payload from connection without a binary lane: {connection_id:?}");
|
||||
continue;
|
||||
};
|
||||
match processor.process_upload_binary(connection_id, bytes).await {
|
||||
Ok(responses) => {
|
||||
for response in responses {
|
||||
if binary_writer.send(response).await.is_err() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
match processor
|
||||
.process_upload_binary(connection_id, binary_writer, bytes)
|
||||
.await
|
||||
{
|
||||
Ok(()) => {}
|
||||
Err(err) => {
|
||||
warn!("failed to process upload binary payload: {}", err.message);
|
||||
}
|
||||
|
||||
@@ -598,10 +598,11 @@ impl MessageProcessor {
|
||||
pub(crate) async fn process_upload_binary(
|
||||
&self,
|
||||
connection_id: ConnectionId,
|
||||
binary_writer: tokio::sync::mpsc::Sender<Vec<u8>>,
|
||||
bytes: Vec<u8>,
|
||||
) -> Result<Vec<Vec<u8>>, JSONRPCErrorError> {
|
||||
) -> Result<(), JSONRPCErrorError> {
|
||||
self.fs_processor
|
||||
.process_upload_sftp_bytes(connection_id, bytes)
|
||||
.process_upload_sftp_bytes(connection_id, binary_writer, bytes)
|
||||
.await
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ use crate::error_code::internal_error;
|
||||
use crate::error_code::invalid_request;
|
||||
use crate::fs_watch::FsWatchManager;
|
||||
use crate::outgoing_message::ConnectionId;
|
||||
use crate::request_processors::upload_sftp::UploadSftpSession;
|
||||
use crate::request_processors::upload_sftp::UploadSftpLane;
|
||||
use base64::Engine;
|
||||
use base64::engine::general_purpose::STANDARD;
|
||||
use codex_app_server_protocol::FsCopyParams;
|
||||
@@ -47,7 +47,7 @@ pub(crate) struct FsRequestProcessor {
|
||||
fs_watch_manager: FsWatchManager,
|
||||
codex_home: PathBuf,
|
||||
upload_paths: Arc<Mutex<HashSet<PathBuf>>>,
|
||||
upload_sftp_sessions: Arc<Mutex<HashMap<ConnectionId, UploadSftpSession>>>,
|
||||
upload_sftp_lanes: Arc<Mutex<HashMap<ConnectionId, UploadSftpLane>>>,
|
||||
}
|
||||
|
||||
impl FsRequestProcessor {
|
||||
@@ -61,16 +61,13 @@ impl FsRequestProcessor {
|
||||
fs_watch_manager,
|
||||
codex_home,
|
||||
upload_paths: Arc::new(Mutex::new(HashSet::new())),
|
||||
upload_sftp_sessions: Arc::new(Mutex::new(HashMap::new())),
|
||||
upload_sftp_lanes: Arc::new(Mutex::new(HashMap::new())),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn connection_closed(&self, connection_id: ConnectionId) {
|
||||
self.fs_watch_manager.connection_closed(connection_id).await;
|
||||
self.upload_sftp_sessions
|
||||
.lock()
|
||||
.await
|
||||
.remove(&connection_id);
|
||||
self.upload_sftp_lanes.lock().await.remove(&connection_id);
|
||||
}
|
||||
|
||||
pub(crate) async fn read_file(
|
||||
@@ -129,24 +126,24 @@ impl FsRequestProcessor {
|
||||
Ok(FsCreateUploadResponse { path: upload_path })
|
||||
}
|
||||
|
||||
#[expect(
|
||||
clippy::await_holding_invalid_type,
|
||||
reason = "SFTP packets for one connection must be processed in arrival order"
|
||||
)]
|
||||
pub(crate) async fn process_upload_sftp_bytes(
|
||||
&self,
|
||||
connection_id: ConnectionId,
|
||||
binary_writer: tokio::sync::mpsc::Sender<Vec<u8>>,
|
||||
bytes: Vec<u8>,
|
||||
) -> Result<Vec<Vec<u8>>, JSONRPCErrorError> {
|
||||
let mut sessions = self.upload_sftp_sessions.lock().await;
|
||||
let session = sessions
|
||||
.entry(connection_id)
|
||||
.or_insert_with(|| UploadSftpSession::new(Arc::clone(&self.upload_paths)));
|
||||
let result = session.process_bytes(bytes).await;
|
||||
if result.is_err() {
|
||||
sessions.remove(&connection_id);
|
||||
}
|
||||
result
|
||||
) -> Result<(), JSONRPCErrorError> {
|
||||
let lane = if let Some(lane) = self.upload_sftp_lanes.lock().await.get(&connection_id) {
|
||||
lane.clone()
|
||||
} else {
|
||||
let lane = UploadSftpLane::start(Arc::clone(&self.upload_paths), binary_writer).await;
|
||||
self.upload_sftp_lanes
|
||||
.lock()
|
||||
.await
|
||||
.entry(connection_id)
|
||||
.or_insert_with(|| lane.clone())
|
||||
.clone()
|
||||
};
|
||||
lane.send(bytes).await
|
||||
}
|
||||
|
||||
pub(crate) async fn create_directory(
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
use crate::error_code::internal_error;
|
||||
use crate::error_code::invalid_request;
|
||||
use crate::transport::CHANNEL_CAPACITY;
|
||||
use codex_app_server_protocol::JSONRPCErrorError;
|
||||
use russh_sftp::protocol::Attrs;
|
||||
use russh_sftp::protocol::FileAttributes;
|
||||
use russh_sftp::protocol::Handle;
|
||||
use russh_sftp::protocol::OpenFlags;
|
||||
use russh_sftp::protocol::Status;
|
||||
use russh_sftp::protocol::StatusCode;
|
||||
use russh_sftp::server::Handler;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::HashSet;
|
||||
use std::io;
|
||||
@@ -8,38 +15,71 @@ use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use tokio::fs::File;
|
||||
use tokio::fs::OpenOptions;
|
||||
use tokio::io::AsyncReadExt;
|
||||
use tokio::io::AsyncSeekExt;
|
||||
use tokio::io::AsyncWriteExt;
|
||||
use tokio::io::SeekFrom;
|
||||
use tokio::sync::Mutex;
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
const SSH_FXP_INIT: u8 = 1;
|
||||
const SSH_FXP_VERSION: u8 = 2;
|
||||
const SSH_FXP_OPEN: u8 = 3;
|
||||
const SSH_FXP_CLOSE: u8 = 4;
|
||||
const SSH_FXP_WRITE: u8 = 6;
|
||||
const SSH_FXP_STAT: u8 = 17;
|
||||
const SSH_FXP_STATUS: u8 = 101;
|
||||
const SSH_FXP_HANDLE: u8 = 102;
|
||||
const SSH_FXP_ATTRS: u8 = 105;
|
||||
const UPLOAD_SFTP_STREAM_BUFFER_BYTES: usize = 64 * 1024;
|
||||
|
||||
const SSH_FX_OK: u32 = 0;
|
||||
const SSH_FX_NO_SUCH_FILE: u32 = 2;
|
||||
const SSH_FX_PERMISSION_DENIED: u32 = 3;
|
||||
const SSH_FX_OP_UNSUPPORTED: u32 = 8;
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct UploadSftpLane {
|
||||
incoming_tx: mpsc::Sender<Vec<u8>>,
|
||||
}
|
||||
|
||||
const SSH_FXF_WRITE: u32 = 0x0000_0002;
|
||||
const SSH_FXF_APPEND: u32 = 0x0000_0004;
|
||||
const SSH_FXF_CREAT: u32 = 0x0000_0008;
|
||||
const SSH_FXF_TRUNC: u32 = 0x0000_0010;
|
||||
impl UploadSftpLane {
|
||||
pub(crate) async fn start(
|
||||
allowed_paths: Arc<Mutex<HashSet<PathBuf>>>,
|
||||
binary_writer: mpsc::Sender<Vec<u8>>,
|
||||
) -> Self {
|
||||
let (server_stream, bridge_stream) = tokio::io::duplex(UPLOAD_SFTP_STREAM_BUFFER_BYTES);
|
||||
russh_sftp::server::run(server_stream, UploadSftpHandler::new(allowed_paths)).await;
|
||||
|
||||
const SSH_FILEXFER_ATTR_SIZE: u32 = 0x0000_0001;
|
||||
const MAX_SFTP_PACKET_BYTES: usize = 1024 * 1024;
|
||||
let (mut bridge_reader, mut bridge_writer) = tokio::io::split(bridge_stream);
|
||||
let (incoming_tx, mut incoming_rx) = mpsc::channel::<Vec<u8>>(CHANNEL_CAPACITY);
|
||||
|
||||
pub(crate) struct UploadSftpSession {
|
||||
tokio::spawn(async move {
|
||||
while let Some(bytes) = incoming_rx.recv().await {
|
||||
if bridge_writer.write_all(&bytes).await.is_err() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
tokio::spawn(async move {
|
||||
let mut buffer = vec![0; UPLOAD_SFTP_STREAM_BUFFER_BYTES];
|
||||
loop {
|
||||
match bridge_reader.read(&mut buffer).await {
|
||||
Ok(0) | Err(_) => break,
|
||||
Ok(bytes_read) => {
|
||||
if binary_writer
|
||||
.send(buffer[..bytes_read].to_vec())
|
||||
.await
|
||||
.is_err()
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Self { incoming_tx }
|
||||
}
|
||||
|
||||
pub(crate) async fn send(&self, bytes: Vec<u8>) -> Result<(), JSONRPCErrorError> {
|
||||
self.incoming_tx
|
||||
.send(bytes)
|
||||
.await
|
||||
.map_err(|_| internal_error("staged upload SFTP lane is closed".to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
struct UploadSftpHandler {
|
||||
allowed_paths: Arc<Mutex<HashSet<PathBuf>>>,
|
||||
pending_bytes: Vec<u8>,
|
||||
handles: HashMap<Vec<u8>, UploadHandle>,
|
||||
handles: HashMap<String, UploadHandle>,
|
||||
next_handle_id: u64,
|
||||
}
|
||||
|
||||
@@ -47,160 +87,44 @@ struct UploadHandle {
|
||||
file: File,
|
||||
}
|
||||
|
||||
impl UploadSftpSession {
|
||||
pub(crate) fn new(allowed_paths: Arc<Mutex<HashSet<PathBuf>>>) -> Self {
|
||||
#[derive(Clone, Copy)]
|
||||
enum UploadSftpError {
|
||||
NoSuchFile,
|
||||
PermissionDenied,
|
||||
Failure,
|
||||
Unsupported,
|
||||
}
|
||||
|
||||
impl From<UploadSftpError> for StatusCode {
|
||||
fn from(value: UploadSftpError) -> Self {
|
||||
match value {
|
||||
UploadSftpError::NoSuchFile => Self::NoSuchFile,
|
||||
UploadSftpError::PermissionDenied => Self::PermissionDenied,
|
||||
UploadSftpError::Failure => Self::Failure,
|
||||
UploadSftpError::Unsupported => Self::OpUnsupported,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<io::Error> for UploadSftpError {
|
||||
fn from(err: io::Error) -> Self {
|
||||
match err.kind() {
|
||||
io::ErrorKind::NotFound => Self::NoSuchFile,
|
||||
io::ErrorKind::PermissionDenied => Self::PermissionDenied,
|
||||
_ => Self::Failure,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl UploadSftpHandler {
|
||||
fn new(allowed_paths: Arc<Mutex<HashSet<PathBuf>>>) -> Self {
|
||||
Self {
|
||||
allowed_paths,
|
||||
pending_bytes: Vec::new(),
|
||||
handles: HashMap::new(),
|
||||
next_handle_id: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn process_bytes(
|
||||
&mut self,
|
||||
bytes: Vec<u8>,
|
||||
) -> Result<Vec<Vec<u8>>, JSONRPCErrorError> {
|
||||
self.pending_bytes.extend(bytes);
|
||||
let mut responses = Vec::new();
|
||||
while let Some(packet) = take_packet(&mut self.pending_bytes)? {
|
||||
if let Some(response) = self.process_packet(packet).await? {
|
||||
responses.push(response);
|
||||
}
|
||||
}
|
||||
Ok(responses)
|
||||
}
|
||||
|
||||
async fn process_packet(
|
||||
&mut self,
|
||||
packet: Vec<u8>,
|
||||
) -> Result<Option<Vec<u8>>, JSONRPCErrorError> {
|
||||
let mut cursor = PacketCursor::new(&packet);
|
||||
let packet_type = cursor.read_u8()?;
|
||||
match packet_type {
|
||||
SSH_FXP_INIT => {
|
||||
let _client_version = cursor.read_u32()?;
|
||||
cursor.finish()?;
|
||||
Ok(Some(version_packet()))
|
||||
}
|
||||
SSH_FXP_OPEN => {
|
||||
let request_id = cursor.read_u32()?;
|
||||
let path = cursor.read_string_utf8()?;
|
||||
let pflags = cursor.read_u32()?;
|
||||
let attrs = cursor.read_u32()?;
|
||||
cursor.finish()?;
|
||||
if attrs != 0 {
|
||||
return Ok(Some(status_packet(
|
||||
request_id,
|
||||
SSH_FX_OP_UNSUPPORTED,
|
||||
"open attributes are not supported",
|
||||
)));
|
||||
}
|
||||
if !self.is_allowed_path(&path).await {
|
||||
return Ok(Some(status_packet(
|
||||
request_id,
|
||||
SSH_FX_PERMISSION_DENIED,
|
||||
"path is not a staged upload",
|
||||
)));
|
||||
}
|
||||
let mut options = OpenOptions::new();
|
||||
options.write(pflags & SSH_FXF_WRITE != 0);
|
||||
options.create(pflags & SSH_FXF_CREAT != 0);
|
||||
options.truncate(pflags & SSH_FXF_TRUNC != 0);
|
||||
options.append(pflags & SSH_FXF_APPEND != 0);
|
||||
match options.open(&path).await {
|
||||
Ok(file) => {
|
||||
let handle = self.next_handle();
|
||||
self.handles.insert(handle.clone(), UploadHandle { file });
|
||||
Ok(Some(handle_packet(request_id, &handle)))
|
||||
}
|
||||
Err(err) => Ok(Some(status_packet(
|
||||
request_id,
|
||||
map_status_code(&err),
|
||||
&err.to_string(),
|
||||
))),
|
||||
}
|
||||
}
|
||||
SSH_FXP_WRITE => {
|
||||
let request_id = cursor.read_u32()?;
|
||||
let handle = cursor.read_string_bytes()?;
|
||||
let offset = cursor.read_u64()?;
|
||||
let data = cursor.read_string_bytes()?;
|
||||
cursor.finish()?;
|
||||
let Some(upload_handle) = self.handles.get_mut(&handle) else {
|
||||
return Ok(Some(status_packet(
|
||||
request_id,
|
||||
SSH_FX_NO_SUCH_FILE,
|
||||
"unknown upload handle",
|
||||
)));
|
||||
};
|
||||
if let Err(err) = upload_handle.file.seek(SeekFrom::Start(offset)).await {
|
||||
return Ok(Some(status_packet(
|
||||
request_id,
|
||||
map_status_code(&err),
|
||||
&err.to_string(),
|
||||
)));
|
||||
}
|
||||
match upload_handle.file.write_all(&data).await {
|
||||
Ok(()) => Ok(Some(status_packet(request_id, SSH_FX_OK, "Ok"))),
|
||||
Err(err) => Ok(Some(status_packet(
|
||||
request_id,
|
||||
map_status_code(&err),
|
||||
&err.to_string(),
|
||||
))),
|
||||
}
|
||||
}
|
||||
SSH_FXP_CLOSE => {
|
||||
let request_id = cursor.read_u32()?;
|
||||
let handle = cursor.read_string_bytes()?;
|
||||
cursor.finish()?;
|
||||
let Some(mut upload_handle) = self.handles.remove(&handle) else {
|
||||
return Ok(Some(status_packet(
|
||||
request_id,
|
||||
SSH_FX_NO_SUCH_FILE,
|
||||
"unknown upload handle",
|
||||
)));
|
||||
};
|
||||
match upload_handle.file.flush().await {
|
||||
Ok(()) => Ok(Some(status_packet(request_id, SSH_FX_OK, "Ok"))),
|
||||
Err(err) => Ok(Some(status_packet(
|
||||
request_id,
|
||||
map_status_code(&err),
|
||||
&err.to_string(),
|
||||
))),
|
||||
}
|
||||
}
|
||||
SSH_FXP_STAT => {
|
||||
let request_id = cursor.read_u32()?;
|
||||
let path = cursor.read_string_utf8()?;
|
||||
cursor.finish()?;
|
||||
if !self.is_allowed_path(&path).await {
|
||||
return Ok(Some(status_packet(
|
||||
request_id,
|
||||
SSH_FX_PERMISSION_DENIED,
|
||||
"path is not a staged upload",
|
||||
)));
|
||||
}
|
||||
match tokio::fs::metadata(path).await {
|
||||
Ok(metadata) => Ok(Some(attrs_packet(request_id, metadata.len()))),
|
||||
Err(err) => Ok(Some(status_packet(
|
||||
request_id,
|
||||
map_status_code(&err),
|
||||
&err.to_string(),
|
||||
))),
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
let request_id = cursor.read_u32().unwrap_or_default();
|
||||
Ok(Some(status_packet(
|
||||
request_id,
|
||||
SSH_FX_OP_UNSUPPORTED,
|
||||
"operation is not supported",
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn is_allowed_path(&self, path: &str) -> bool {
|
||||
self.allowed_paths
|
||||
.lock()
|
||||
@@ -208,161 +132,105 @@ impl UploadSftpSession {
|
||||
.contains(&PathBuf::from(path))
|
||||
}
|
||||
|
||||
fn next_handle(&mut self) -> Vec<u8> {
|
||||
let handle = self.next_handle_id.to_be_bytes().to_vec();
|
||||
fn next_handle(&mut self) -> String {
|
||||
let handle = self.next_handle_id.to_string();
|
||||
self.next_handle_id = self.next_handle_id.wrapping_add(1);
|
||||
handle
|
||||
}
|
||||
}
|
||||
|
||||
fn take_packet(buffer: &mut Vec<u8>) -> Result<Option<Vec<u8>>, JSONRPCErrorError> {
|
||||
if buffer.len() < 4 {
|
||||
return Ok(None);
|
||||
}
|
||||
let packet_len = u32::from_be_bytes(
|
||||
buffer[..4]
|
||||
.try_into()
|
||||
.map_err(|_| invalid_request("invalid SFTP packet length prefix".to_string()))?,
|
||||
) as usize;
|
||||
if packet_len > MAX_SFTP_PACKET_BYTES {
|
||||
return Err(invalid_sftp_packet("packet exceeds 1 MiB"));
|
||||
}
|
||||
if buffer.len() < packet_len + 4 {
|
||||
return Ok(None);
|
||||
}
|
||||
let packet = buffer[4..packet_len + 4].to_vec();
|
||||
buffer.drain(..packet_len + 4);
|
||||
Ok(Some(packet))
|
||||
}
|
||||
impl Handler for UploadSftpHandler {
|
||||
type Error = UploadSftpError;
|
||||
|
||||
fn version_packet() -> Vec<u8> {
|
||||
packet(|payload| {
|
||||
payload.push(SSH_FXP_VERSION);
|
||||
payload.extend_from_slice(&3_u32.to_be_bytes());
|
||||
})
|
||||
}
|
||||
|
||||
fn status_packet(request_id: u32, status_code: u32, message: &str) -> Vec<u8> {
|
||||
packet(|payload| {
|
||||
payload.push(SSH_FXP_STATUS);
|
||||
payload.extend_from_slice(&request_id.to_be_bytes());
|
||||
payload.extend_from_slice(&status_code.to_be_bytes());
|
||||
push_string(payload, message.as_bytes());
|
||||
push_string(payload, b"en-US");
|
||||
})
|
||||
}
|
||||
|
||||
fn handle_packet(request_id: u32, handle: &[u8]) -> Vec<u8> {
|
||||
packet(|payload| {
|
||||
payload.push(SSH_FXP_HANDLE);
|
||||
payload.extend_from_slice(&request_id.to_be_bytes());
|
||||
push_string(payload, handle);
|
||||
})
|
||||
}
|
||||
|
||||
fn attrs_packet(request_id: u32, size: u64) -> Vec<u8> {
|
||||
packet(|payload| {
|
||||
payload.push(SSH_FXP_ATTRS);
|
||||
payload.extend_from_slice(&request_id.to_be_bytes());
|
||||
payload.extend_from_slice(&SSH_FILEXFER_ATTR_SIZE.to_be_bytes());
|
||||
payload.extend_from_slice(&size.to_be_bytes());
|
||||
})
|
||||
}
|
||||
|
||||
fn packet(build_payload: impl FnOnce(&mut Vec<u8>)) -> Vec<u8> {
|
||||
let mut payload = Vec::new();
|
||||
build_payload(&mut payload);
|
||||
let mut packet = Vec::with_capacity(payload.len() + 4);
|
||||
packet.extend_from_slice(&(payload.len() as u32).to_be_bytes());
|
||||
packet.extend_from_slice(&payload);
|
||||
packet
|
||||
}
|
||||
|
||||
fn push_string(payload: &mut Vec<u8>, value: &[u8]) {
|
||||
payload.extend_from_slice(&(value.len() as u32).to_be_bytes());
|
||||
payload.extend_from_slice(value);
|
||||
}
|
||||
|
||||
fn map_status_code(err: &io::Error) -> u32 {
|
||||
match err.kind() {
|
||||
io::ErrorKind::NotFound => SSH_FX_NO_SUCH_FILE,
|
||||
io::ErrorKind::PermissionDenied => SSH_FX_PERMISSION_DENIED,
|
||||
_ => SSH_FX_OP_UNSUPPORTED,
|
||||
}
|
||||
}
|
||||
|
||||
struct PacketCursor<'a> {
|
||||
bytes: &'a [u8],
|
||||
offset: usize,
|
||||
}
|
||||
|
||||
impl<'a> PacketCursor<'a> {
|
||||
fn new(bytes: &'a [u8]) -> Self {
|
||||
Self { bytes, offset: 0 }
|
||||
fn unimplemented(&self) -> Self::Error {
|
||||
UploadSftpError::Unsupported
|
||||
}
|
||||
|
||||
fn read_u8(&mut self) -> Result<u8, JSONRPCErrorError> {
|
||||
let value = *self
|
||||
.bytes
|
||||
.get(self.offset)
|
||||
.ok_or_else(|| invalid_sftp_packet("missing u8"))?;
|
||||
self.offset += 1;
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
fn read_u32(&mut self) -> Result<u32, JSONRPCErrorError> {
|
||||
let bytes = self
|
||||
.bytes
|
||||
.get(self.offset..self.offset + 4)
|
||||
.ok_or_else(|| invalid_sftp_packet("missing u32"))?;
|
||||
self.offset += 4;
|
||||
Ok(u32::from_be_bytes(bytes.try_into().map_err(|_| {
|
||||
internal_error("failed to decode SFTP u32".to_string())
|
||||
})?))
|
||||
}
|
||||
|
||||
fn read_u64(&mut self) -> Result<u64, JSONRPCErrorError> {
|
||||
let bytes = self
|
||||
.bytes
|
||||
.get(self.offset..self.offset + 8)
|
||||
.ok_or_else(|| invalid_sftp_packet("missing u64"))?;
|
||||
self.offset += 8;
|
||||
Ok(u64::from_be_bytes(bytes.try_into().map_err(|_| {
|
||||
internal_error("failed to decode SFTP u64".to_string())
|
||||
})?))
|
||||
}
|
||||
|
||||
fn read_string_bytes(&mut self) -> Result<Vec<u8>, JSONRPCErrorError> {
|
||||
let len = self.read_u32()? as usize;
|
||||
let bytes = self
|
||||
.bytes
|
||||
.get(self.offset..self.offset + len)
|
||||
.ok_or_else(|| invalid_sftp_packet("truncated string"))?;
|
||||
self.offset += len;
|
||||
Ok(bytes.to_vec())
|
||||
}
|
||||
|
||||
fn read_string_utf8(&mut self) -> Result<String, JSONRPCErrorError> {
|
||||
String::from_utf8(self.read_string_bytes()?)
|
||||
.map_err(|_| invalid_sftp_packet("path must be UTF-8"))
|
||||
}
|
||||
|
||||
fn finish(&self) -> Result<(), JSONRPCErrorError> {
|
||||
if self.offset == self.bytes.len() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(invalid_sftp_packet("unexpected trailing bytes"))
|
||||
async fn open(
|
||||
&mut self,
|
||||
id: u32,
|
||||
filename: String,
|
||||
pflags: OpenFlags,
|
||||
attrs: FileAttributes,
|
||||
) -> Result<Handle, Self::Error> {
|
||||
if has_attributes(&attrs) {
|
||||
return Err(UploadSftpError::Unsupported);
|
||||
}
|
||||
if !self.is_allowed_path(&filename).await {
|
||||
return Err(UploadSftpError::PermissionDenied);
|
||||
}
|
||||
|
||||
let mut options = OpenOptions::new();
|
||||
options.write(pflags.contains(OpenFlags::WRITE));
|
||||
options.create(pflags.contains(OpenFlags::CREATE));
|
||||
options.truncate(pflags.contains(OpenFlags::TRUNCATE));
|
||||
options.append(pflags.contains(OpenFlags::APPEND));
|
||||
let file = options.open(&filename).await?;
|
||||
let handle = self.next_handle();
|
||||
self.handles.insert(handle.clone(), UploadHandle { file });
|
||||
Ok(Handle { id, handle })
|
||||
}
|
||||
|
||||
async fn write(
|
||||
&mut self,
|
||||
id: u32,
|
||||
handle: String,
|
||||
offset: u64,
|
||||
data: Vec<u8>,
|
||||
) -> Result<Status, Self::Error> {
|
||||
let upload_handle = self
|
||||
.handles
|
||||
.get_mut(&handle)
|
||||
.ok_or(UploadSftpError::NoSuchFile)?;
|
||||
upload_handle.file.seek(SeekFrom::Start(offset)).await?;
|
||||
upload_handle.file.write_all(&data).await?;
|
||||
Ok(ok_status(id))
|
||||
}
|
||||
|
||||
async fn close(&mut self, id: u32, handle: String) -> Result<Status, Self::Error> {
|
||||
let mut upload_handle = self
|
||||
.handles
|
||||
.remove(&handle)
|
||||
.ok_or(UploadSftpError::NoSuchFile)?;
|
||||
upload_handle.file.flush().await?;
|
||||
Ok(ok_status(id))
|
||||
}
|
||||
|
||||
async fn stat(&mut self, id: u32, path: String) -> Result<Attrs, Self::Error> {
|
||||
if !self.is_allowed_path(&path).await {
|
||||
return Err(UploadSftpError::PermissionDenied);
|
||||
}
|
||||
let metadata = tokio::fs::metadata(path).await?;
|
||||
let mut attrs = FileAttributes::empty();
|
||||
attrs.size = Some(metadata.len());
|
||||
Ok(Attrs { id, attrs })
|
||||
}
|
||||
}
|
||||
|
||||
fn invalid_sftp_packet(message: &str) -> JSONRPCErrorError {
|
||||
invalid_request(format!("invalid staged upload SFTP packet: {message}"))
|
||||
fn has_attributes(attrs: &FileAttributes) -> bool {
|
||||
attrs.size.is_some()
|
||||
|| attrs.uid.is_some()
|
||||
|| attrs.user.is_some()
|
||||
|| attrs.gid.is_some()
|
||||
|| attrs.group.is_some()
|
||||
|| attrs.permissions.is_some()
|
||||
|| attrs.atime.is_some()
|
||||
|| attrs.mtime.is_some()
|
||||
}
|
||||
|
||||
fn ok_status(id: u32) -> Status {
|
||||
Status {
|
||||
id,
|
||||
status_code: StatusCode::Ok,
|
||||
error_message: "Ok".to_string(),
|
||||
language_tag: "en-US".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use russh_sftp::client::SftpSession;
|
||||
use tempfile::TempDir;
|
||||
|
||||
#[tokio::test]
|
||||
@@ -373,38 +241,18 @@ mod tests {
|
||||
.await
|
||||
.expect("create upload parent");
|
||||
let allowed_paths = Arc::new(Mutex::new(HashSet::from([path.clone()])));
|
||||
let mut session = UploadSftpSession::new(allowed_paths);
|
||||
let (client_stream, server_stream) = tokio::io::duplex(UPLOAD_SFTP_STREAM_BUFFER_BYTES);
|
||||
russh_sftp::server::run(server_stream, UploadSftpHandler::new(allowed_paths)).await;
|
||||
|
||||
let responses = session
|
||||
.process_bytes(init_packet())
|
||||
let session = SftpSession::new(client_stream)
|
||||
.await
|
||||
.expect("init packet should succeed");
|
||||
assert_eq!(packet_type(&responses[0]), SSH_FXP_VERSION);
|
||||
|
||||
let responses = session
|
||||
.process_bytes(open_packet(
|
||||
/*request_id*/ 1,
|
||||
&path,
|
||||
SSH_FXF_WRITE | SSH_FXF_CREAT | SSH_FXF_TRUNC,
|
||||
))
|
||||
.expect("initialize sftp");
|
||||
let mut file = session
|
||||
.create(path.to_string_lossy())
|
||||
.await
|
||||
.expect("open packet should succeed");
|
||||
assert_eq!(packet_type(&responses[0]), SSH_FXP_HANDLE);
|
||||
let handle = response_handle(&responses[0]);
|
||||
|
||||
let responses = session
|
||||
.process_bytes(write_packet(
|
||||
/*request_id*/ 2, &handle, /*offset*/ 0, b"hello",
|
||||
))
|
||||
.await
|
||||
.expect("write packet should succeed");
|
||||
assert_eq!(response_status(&responses[0]), SSH_FX_OK);
|
||||
|
||||
let responses = session
|
||||
.process_bytes(close_packet(/*request_id*/ 3, &handle))
|
||||
.await
|
||||
.expect("close packet should succeed");
|
||||
assert_eq!(response_status(&responses[0]), SSH_FX_OK);
|
||||
.expect("open staged upload");
|
||||
file.write_all(b"hello").await.expect("write staged upload");
|
||||
file.shutdown().await.expect("close staged upload");
|
||||
assert_eq!(
|
||||
tokio::fs::read_to_string(path).await.expect("read upload"),
|
||||
"hello"
|
||||
@@ -418,65 +266,21 @@ mod tests {
|
||||
tokio::fs::create_dir_all(path.parent().expect("path parent"))
|
||||
.await
|
||||
.expect("create upload parent");
|
||||
let mut session = UploadSftpSession::new(Arc::new(Mutex::new(HashSet::new())));
|
||||
let (client_stream, server_stream) = tokio::io::duplex(UPLOAD_SFTP_STREAM_BUFFER_BYTES);
|
||||
russh_sftp::server::run(
|
||||
server_stream,
|
||||
UploadSftpHandler::new(Arc::new(Mutex::new(HashSet::new()))),
|
||||
)
|
||||
.await;
|
||||
|
||||
let responses = session
|
||||
.process_bytes(open_packet(
|
||||
/*request_id*/ 1,
|
||||
&path,
|
||||
SSH_FXF_WRITE | SSH_FXF_CREAT | SSH_FXF_TRUNC,
|
||||
))
|
||||
let session = SftpSession::new(client_stream)
|
||||
.await
|
||||
.expect("open packet should be handled");
|
||||
assert_eq!(response_status(&responses[0]), SSH_FX_PERMISSION_DENIED);
|
||||
.expect("initialize sftp");
|
||||
let err = match session.create(path.to_string_lossy()).await {
|
||||
Ok(_) => panic!("path should be rejected"),
|
||||
Err(err) => err,
|
||||
};
|
||||
assert!(err.to_string().contains("Permission denied"));
|
||||
assert!(!path.exists());
|
||||
}
|
||||
|
||||
fn init_packet() -> Vec<u8> {
|
||||
packet(|payload| {
|
||||
payload.push(SSH_FXP_INIT);
|
||||
payload.extend_from_slice(&3_u32.to_be_bytes());
|
||||
})
|
||||
}
|
||||
|
||||
fn open_packet(request_id: u32, path: &std::path::Path, flags: u32) -> Vec<u8> {
|
||||
packet(|payload| {
|
||||
payload.push(SSH_FXP_OPEN);
|
||||
payload.extend_from_slice(&request_id.to_be_bytes());
|
||||
push_string(payload, path.to_string_lossy().as_bytes());
|
||||
payload.extend_from_slice(&flags.to_be_bytes());
|
||||
payload.extend_from_slice(&0_u32.to_be_bytes());
|
||||
})
|
||||
}
|
||||
|
||||
fn write_packet(request_id: u32, handle: &[u8], offset: u64, data: &[u8]) -> Vec<u8> {
|
||||
packet(|payload| {
|
||||
payload.push(SSH_FXP_WRITE);
|
||||
payload.extend_from_slice(&request_id.to_be_bytes());
|
||||
push_string(payload, handle);
|
||||
payload.extend_from_slice(&offset.to_be_bytes());
|
||||
push_string(payload, data);
|
||||
})
|
||||
}
|
||||
|
||||
fn close_packet(request_id: u32, handle: &[u8]) -> Vec<u8> {
|
||||
packet(|payload| {
|
||||
payload.push(SSH_FXP_CLOSE);
|
||||
payload.extend_from_slice(&request_id.to_be_bytes());
|
||||
push_string(payload, handle);
|
||||
})
|
||||
}
|
||||
|
||||
fn packet_type(packet: &[u8]) -> u8 {
|
||||
packet[4]
|
||||
}
|
||||
|
||||
fn response_status(packet: &[u8]) -> u32 {
|
||||
u32::from_be_bytes(packet[9..13].try_into().expect("status code bytes"))
|
||||
}
|
||||
|
||||
fn response_handle(packet: &[u8]) -> Vec<u8> {
|
||||
let len = u32::from_be_bytes(packet[9..13].try_into().expect("handle len")) as usize;
|
||||
packet[13..13 + len].to_vec()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user