diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b4dd5c3..dd1dbfb9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,44 @@ target. ## [Unreleased] +## [3.1.0] — 2026-10-05 + +The thinkwatch-core crates move from v0.59.0 to v0.62.0. Two changes reach +the gateway: tool-call inspection gains a built-in rule for ThinkWatch's own +data directory, and an upstream whose base URL already ends in an API +version is no longer sent a second one. + +### Read before upgrading + +- The new tool-call rule `thinkwatch-data` is on and set to cut off, like + the other high-risk built-in rules. A deployment whose tool-call + inspection is in enforce mode starts cutting off answers whose tool call + reads or changes one of the paths below; one in observe mode only records + them. Set the rule to record, or switch it off, on the security page to + keep the previous behaviour. + +### Added + +- **Tool-call inspection: `thinkwatch-data` (Read or change ThinkWatch's own + data).** A tool call whose path or command points into ThinkWatch's data + directory (`~/.thinkwatch`, `%APPDATA%\ThinkWatch`, `/var/lib/thinkwatch`, + `/etc/thinkwatch`) — where the desktop gateway keeps every upstream key and + its own protection settings. Text that only mentions the directory, such as + a document being edited, does not count. The security page lists it with + the other built-in rules. + +### Fixed + +- **Upstream base URLs that end in their own API version** (`…/api/paas/v4`, + `…/api/v3`) now receive requests under that version instead of a second + `/v1` appended to it, which returned 404. Requests and connection tests + both use it. + +### Changed + +- thinkwatch-core crates (tw-bedrock, tw-breaker, tw-dialect, tw-guard) + v0.59.0 → v0.62.0. + ## [3.0.0] — 2026-10-03 The request guards — outbound redaction, tool-call inspection and the @@ -1142,7 +1180,8 @@ unreleased builds should: stop the gateway, run `db/schema.sql` against PostgreSQL, restart against this tag. The schema is idempotent end-to-end, so the apply is safe to repeat. -[Unreleased]: https://github.com/ThinkWatchProject/ThinkWatch/compare/v3.0.0...HEAD +[Unreleased]: https://github.com/ThinkWatchProject/ThinkWatch/compare/v3.1.0...HEAD +[3.1.0]: https://github.com/ThinkWatchProject/ThinkWatch/releases/tag/v3.1.0 [3.0.0]: https://github.com/ThinkWatchProject/ThinkWatch/releases/tag/v3.0.0 [2.2.0]: https://github.com/ThinkWatchProject/ThinkWatch/releases/tag/v2.2.0 [2.1.0]: https://github.com/ThinkWatchProject/ThinkWatch/releases/tag/v2.1.0 diff --git a/Cargo.lock b/Cargo.lock index 3ebd497a..93be0587 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1779,7 +1779,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2 0.5.10", + "socket2 0.6.3", "system-configuration", "tokio", "tower-service", @@ -2731,7 +2731,7 @@ dependencies = [ "quinn-udp", "rustc-hash", "rustls", - "socket2 0.5.10", + "socket2 0.6.3", "thiserror 2.0.18", "tokio", "tracing", @@ -2769,7 +2769,7 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.5.10", + "socket2 0.6.3", "tracing", "windows-sys 0.60.2", ] @@ -4034,7 +4034,7 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "think-watch-auth" -version = "3.0.0" +version = "3.1.0" dependencies = [ "anyhow", "argon2", @@ -4064,7 +4064,7 @@ dependencies = [ [[package]] name = "think-watch-common" -version = "3.0.0" +version = "3.1.0" dependencies = [ "aes-gcm", "anyhow", @@ -4103,7 +4103,7 @@ dependencies = [ [[package]] name = "think-watch-gateway" -version = "3.0.0" +version = "3.1.0" dependencies = [ "anyhow", "arc-swap", @@ -4142,7 +4142,7 @@ dependencies = [ [[package]] name = "think-watch-mcp-gateway" -version = "3.0.0" +version = "3.1.0" dependencies = [ "anyhow", "arc-swap", @@ -4171,7 +4171,7 @@ dependencies = [ [[package]] name = "think-watch-server" -version = "3.0.0" +version = "3.1.0" dependencies = [ "anyhow", "arc-swap", @@ -4222,7 +4222,7 @@ dependencies = [ [[package]] name = "think-watch-test-support" -version = "3.0.0" +version = "3.1.0" dependencies = [ "anyhow", "async-stream", @@ -4671,8 +4671,8 @@ dependencies = [ [[package]] name = "tw-bedrock" -version = "0.59.0" -source = "git+https://github.com/ThinkWatchProject/ThinkWatch-Core.git?tag=v0.59.0#ef10a8b0bbc1325edf43553a87169029672808a4" +version = "0.62.0" +source = "git+https://github.com/ThinkWatchProject/ThinkWatch-Core.git?tag=v0.62.0#51ef803bee644e72668cb8725d7bc27f6bb77a3f" dependencies = [ "aws-credential-types", "aws-sigv4", @@ -4686,16 +4686,16 @@ dependencies = [ [[package]] name = "tw-breaker" -version = "0.59.0" -source = "git+https://github.com/ThinkWatchProject/ThinkWatch-Core.git?tag=v0.59.0#ef10a8b0bbc1325edf43553a87169029672808a4" +version = "0.62.0" +source = "git+https://github.com/ThinkWatchProject/ThinkWatch-Core.git?tag=v0.62.0#51ef803bee644e72668cb8725d7bc27f6bb77a3f" dependencies = [ "serde", ] [[package]] name = "tw-dialect" -version = "0.59.0" -source = "git+https://github.com/ThinkWatchProject/ThinkWatch-Core.git?tag=v0.59.0#ef10a8b0bbc1325edf43553a87169029672808a4" +version = "0.62.0" +source = "git+https://github.com/ThinkWatchProject/ThinkWatch-Core.git?tag=v0.62.0#51ef803bee644e72668cb8725d7bc27f6bb77a3f" dependencies = [ "serde", "serde_json", @@ -4703,8 +4703,8 @@ dependencies = [ [[package]] name = "tw-guard" -version = "0.59.0" -source = "git+https://github.com/ThinkWatchProject/ThinkWatch-Core.git?tag=v0.59.0#ef10a8b0bbc1325edf43553a87169029672808a4" +version = "0.62.0" +source = "git+https://github.com/ThinkWatchProject/ThinkWatch-Core.git?tag=v0.62.0#51ef803bee644e72668cb8725d7bc27f6bb77a3f" dependencies = [ "base64 0.22.1", "bytes", @@ -5116,7 +5116,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]] diff --git a/Cargo.toml b/Cargo.toml index c3947f8c..8c0b5b75 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ members = [ ] [workspace.package] -version = "3.0.0" +version = "3.1.0" edition = "2024" # Pin the MSRV to the first stable rustc that ships edition 2024 (1.85, # released 2025-02-20). Without this, contributors on older toolchains @@ -70,10 +70,10 @@ opt-level = 3 # never re-exported through a local shim. And the reverse: something only # this side uses (the at-rest crypto, IMDSv2 credentials, the gateway error) # lives here, not in core. -tw-bedrock = { git = "https://github.com/ThinkWatchProject/ThinkWatch-Core.git", tag = "v0.59.0" } -tw-breaker = { git = "https://github.com/ThinkWatchProject/ThinkWatch-Core.git", tag = "v0.59.0" } -tw-dialect = { git = "https://github.com/ThinkWatchProject/ThinkWatch-Core.git", tag = "v0.59.0" } -tw-guard = { git = "https://github.com/ThinkWatchProject/ThinkWatch-Core.git", tag = "v0.59.0" } +tw-bedrock = { git = "https://github.com/ThinkWatchProject/ThinkWatch-Core.git", tag = "v0.62.0" } +tw-breaker = { git = "https://github.com/ThinkWatchProject/ThinkWatch-Core.git", tag = "v0.62.0" } +tw-dialect = { git = "https://github.com/ThinkWatchProject/ThinkWatch-Core.git", tag = "v0.62.0" } +tw-guard = { git = "https://github.com/ThinkWatchProject/ThinkWatch-Core.git", tag = "v0.62.0" } # Web framework axum = { version = "0.8", features = ["macros", "ws"] } diff --git a/deploy/helm/think-watch/Chart.yaml b/deploy/helm/think-watch/Chart.yaml index 3915e79e..53ed6b54 100644 --- a/deploy/helm/think-watch/Chart.yaml +++ b/deploy/helm/think-watch/Chart.yaml @@ -2,8 +2,8 @@ apiVersion: v2 name: think-watch description: Enterprise AI API Gateway & MCP Management Platform type: application -version: 3.0.0 -appVersion: "3.0.0" +version: 3.1.0 +appVersion: "3.1.0" keywords: - ai - gateway diff --git a/web/package.json b/web/package.json index 42a2fa4a..5259ad1a 100644 --- a/web/package.json +++ b/web/package.json @@ -1,7 +1,7 @@ { "name": "web", "private": true, - "version": "3.0.0", + "version": "3.1.0", "type": "module", "packageManager": "pnpm@11.0.0", "scripts": { diff --git a/web/scripts/check-i18n.mjs b/web/scripts/check-i18n.mjs index 1634cd14..ab957254 100644 --- a/web/scripts/check-i18n.mjs +++ b/web/scripts/check-i18n.mjs @@ -55,7 +55,7 @@ const REDACT_RULE_IDS = [ const TOOL_RULE_IDS = [ 'curl-pipe-sh', 'base64-decode-exec', 'exfil-env', 'exfil-credentials', 'exfil-credentials-reversed', 'ssh-key-read', 'secret-to-unknown-host', - 'write-startup-item', 'crontab-install', 'rm-rf-root', 'chmod-777', + 'thinkwatch-data', 'write-startup-item', 'crontab-install', 'rm-rf-root', 'chmod-777', 'upload-file-to-host', ]; const INVISIBLE_RULE_IDS = ['unicode-tags', 'bidi-controls', 'zero-width', 'private-use']; @@ -87,7 +87,7 @@ const DYNAMIC_ENUMS = { 'contentSecurity.contentWhy.${_}': INVISIBLE_RULE_IDS, 'contentSecurity.cardNetwork.${_}': ['UnionPay'], // Tool-call checks implemented in code (`{ kind: 'builtin', check }`). - 'contentSecurity.check.${_}': ['credential-to-network', 'file-to-network'], + 'contentSecurity.check.${_}': ['credential-to-network', 'file-to-network', 'thinkwatch-data'], 'contentSecurity.dialog.match.${_}': ['contains', 'regex', 'codepoints'], 'contentSecurity.dialog.regexHint.${_}': GUARD_IDS, 'contentSecurity.dialog.actionWhat.${_}': ['cut', 'block', 'strip'], diff --git a/web/src/i18n/en.json b/web/src/i18n/en.json index 090bd855..1897f426 100644 --- a/web/src/i18n/en.json +++ b/web/src/i18n/en.json @@ -300,6 +300,7 @@ }, "check": { "credential-to-network": "A credential sent to a host other than this machine and the credential's own provider", + "thinkwatch-data": "A path or command that points into ThinkWatch's data directory; a mention does not count", "file-to-network": "A local file uploaded to an external host" }, "cardNetwork": { @@ -400,6 +401,10 @@ "name": "Send a credential to an unknown host", "why": "Sends a credential to a host that is neither local nor the credential's own provider" }, + "thinkwatch-data": { + "name": "Read or change ThinkWatch's own data", + "why": "Reads or changes ThinkWatch's data directory, which holds every upstream key in plain text and the settings of these protections" + }, "write-startup-item": { "name": "Write a startup item", "why": "Writes somewhere that runs at login or whenever a terminal opens" diff --git a/web/src/i18n/zh.json b/web/src/i18n/zh.json index 985d25da..aac5beeb 100644 --- a/web/src/i18n/zh.json +++ b/web/src/i18n/zh.json @@ -300,6 +300,7 @@ }, "check": { "credential-to-network": "凭据发往本机和其服务商以外的主机", + "thinkwatch-data": "路径或命令指向 ThinkWatch 的数据目录;只是提到不算", "file-to-network": "本地文件上传到外部主机" }, "cardNetwork": { @@ -400,6 +401,10 @@ "name": "发送凭据到陌生主机", "why": "将凭据发送到本机和该凭据所属服务商以外的主机" }, + "thinkwatch-data": { + "name": "读写 ThinkWatch 自己的数据", + "why": "读写 ThinkWatch 的数据目录,其中以明文保存全部上游密钥和这几项防护的设置" + }, "write-startup-item": { "name": "写入启动项", "why": "写入开机或打开终端时自动执行的位置"