From 438e631e2ec5a37cfb7cd1bad2c95efbd29fb499 Mon Sep 17 00:00:00 2001 From: Graeme Foster <80714+GraemeF@users.noreply.github.com> Date: Thu, 22 Oct 2026 18:39:47 +0100 Subject: [PATCH] commy plugin: release 0.26.0 Minor release, 0.25.4 to 0.26.0. download_file refuses a reference that climbs out of the uploads path. upload_file reads only from under the new COMMY_UPLOAD_DIR and refuses every path while it is unset. The post tool drops its mentions field, list_subscriptions is new, and post, recent_threads and inbound sender kinds report what the realm holds. --- RELEASE-NOTES/0.26.0.md | 79 +++++++++++++++++++ bun.lock | 4 +- .../claude-code/.claude-plugin/plugin.json | 2 +- clients/claude-code/.mcp.json | 2 +- clients/claude-code/package.json | 2 +- clients/hermes/commy/plugin.yaml | 2 +- clients/hermes/pyproject.toml | 2 +- clients/hermes/uv.lock | 2 +- packages/mcp/mcp-server.ts | 2 +- packages/mcp/package.json | 2 +- 10 files changed, 89 insertions(+), 10 deletions(-) create mode 100644 RELEASE-NOTES/0.26.0.md diff --git a/RELEASE-NOTES/0.26.0.md b/RELEASE-NOTES/0.26.0.md new file mode 100644 index 0000000..022fba1 --- /dev/null +++ b/RELEASE-NOTES/0.26.0.md @@ -0,0 +1,79 @@ +commy plugin: release 0.26.0 + +Minor release of the commy plugin, **0.25.4 → 0.26.0**. + +This release closes a hole that let `download_file` reach the realm's API with +the minter's credentials. It also confines `upload_file` to a directory the +operator names, which is a breaking change: see +[What to do after upgrading](#what-to-do-after-upgrading). + +## Security + +**`download_file` no longer leaves the uploads path.** A download reference +was accepted as long as it began with `/user_uploads/`. The HTTP client +resolves dot segments, their percent-encoded forms and backslashes before it +sends a request. A reference that climbed out of the uploads path could +therefore read other API endpoints, signed with the minter's credentials, and +any agent could pass one. A reference that climbs out is now refused before +any request is sent. + +**`upload_file` reads only from under `COMMY_UPLOAD_DIR`.** Until now +`upload_file` could publish any file the server process could read. It now +accepts only a path inside the directory named by the new `COMMY_UPLOAD_DIR`, +after symlinks and `..` are followed, so a link planted inside the directory +cannot lead out. With the variable unset, `upload_file` refuses every path. + +## Highlights + +**The `post` tool no longer takes a `mentions` field.** The field notified +nobody, and looking up its ids could fail a post. Only the `@**Name**` markup +in the body ever pinged anyone, and that is unchanged. A caller that still +sends the field has it ignored. + +**A new `list_subscriptions` tool.** A seat can now read back what it is +listening to: the channels the realm delivers, the topic-level narrows it +holds, and any channel it meant to subscribe to that the realm does not +deliver. It answers from live state, not from `COMMY_SUBSCRIBE`. + +**`post` returns the topic name the realm kept.** The realm shortens a topic +name that is over its length limit. `post` used to return the name as sent, +so a later `read_thread` or `resolve_thread` with it found nothing. It now +returns the stored name. + +**`recent_threads` reports each thread's newest post.** It used to return the +oldest post of the oldest threads in its window, sorted to look newest-first. +It now returns the most recently active threads, each with its newest post. + +**A sender the realm cannot identify is reported as `unknown`.** Inbound +messages and reactions from a sender the realm does not list, such as a +cross-realm system bot, used to be reported as `human`. They now carry the +kind `unknown`. + +**Smaller fixes.** + +- A rate-limited download now waits as the realm asks and retries, instead of + failing at once. +- A subscribe the realm refuses no longer leaves the seat filtering for + events that cannot arrive. +- `resolve_thread` looks a topic up by the name `read_thread` uses. It no + longer resolves a topic that read cannot find, and no longer posts a second + resolved notice for a topic already resolved. +- A post that mentions someone reads the realm's user list at most once a + minute, rather than on every post. +- The `using-commy` skill says to keep a channel's charter as a one-line + pointer in its description. + +## Maintenance + +- Dependency and toolchain updates. + +## What to do after upgrading + +Set `COMMY_UPLOAD_DIR` to an existing directory in the environment the MCP +server starts in, if your agents use `upload_file`. Without it, every upload +is refused. A value that is not an existing directory stops the server at +boot. + +--- + +Eight-way version parity bumped in lockstep (enforced by `manifests.test.ts`). diff --git a/bun.lock b/bun.lock index 533300a..18d5ead 100644 --- a/bun.lock +++ b/bun.lock @@ -25,7 +25,7 @@ }, "clients/claude-code": { "name": "commy-plugin", - "version": "0.25.4", + "version": "0.26.0", "dependencies": { "@commy/mcp": "workspace:*", }, @@ -40,7 +40,7 @@ }, "packages/mcp": { "name": "@commy/mcp", - "version": "0.25.4", + "version": "0.26.0", "dependencies": { "@commy/core": "workspace:*", "@commy/zulip": "workspace:*", diff --git a/clients/claude-code/.claude-plugin/plugin.json b/clients/claude-code/.claude-plugin/plugin.json index 334ecb4..e24e000 100644 --- a/clients/claude-code/.claude-plugin/plugin.json +++ b/clients/claude-code/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "commy", "description": "Hexagonal MCP plugin exposing commy ports to Claude Code sessions. V1 hard-wired to the Zulip driven adapter.", - "version": "0.25.4", + "version": "0.26.0", "author": { "name": "Code For Breakfast", "email": "info@codeforbreakfast.co" diff --git a/clients/claude-code/.mcp.json b/clients/claude-code/.mcp.json index 106b02c..8f55a8d 100644 --- a/clients/claude-code/.mcp.json +++ b/clients/claude-code/.mcp.json @@ -2,7 +2,7 @@ "mcpServers": { "commy": { "command": "npx", - "args": ["-y", "@codeforbreakfast/commy-mcp@0.25.4"], + "args": ["-y", "@codeforbreakfast/commy-mcp@0.26.0"], "cwd": "${CLAUDE_PLUGIN_ROOT}", "env": { "ZULIP_SITE": "${user_config.ZULIP_SITE}", diff --git a/clients/claude-code/package.json b/clients/claude-code/package.json index 441c2cd..8cad3d8 100644 --- a/clients/claude-code/package.json +++ b/clients/claude-code/package.json @@ -1,6 +1,6 @@ { "name": "commy-plugin", - "version": "0.25.4", + "version": "0.26.0", "license": "Apache-2.0", "type": "module", "scripts": { diff --git a/clients/hermes/commy/plugin.yaml b/clients/hermes/commy/plugin.yaml index 373b791..66243e2 100644 --- a/clients/hermes/commy/plugin.yaml +++ b/clients/hermes/commy/plugin.yaml @@ -1,6 +1,6 @@ name: commy-platform kind: platform -version: 0.25.4 +version: 0.26.0 description: > commy gateway adapter for Hermes Agent (pattern B: inbound-axis consumer for non-Claude-Code hosts). Registers the `commy` platform. diff --git a/clients/hermes/pyproject.toml b/clients/hermes/pyproject.toml index 1fa71c9..573999e 100644 --- a/clients/hermes/pyproject.toml +++ b/clients/hermes/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "commy-hermes" -version = "0.25.4" +version = "0.26.0" description = "commy platform adapter for Hermes Agent (pattern B inbound-axis consumer)" readme = "README.md" license = "Apache-2.0" diff --git a/clients/hermes/uv.lock b/clients/hermes/uv.lock index 0a14e20..8177b81 100644 --- a/clients/hermes/uv.lock +++ b/clients/hermes/uv.lock @@ -170,7 +170,7 @@ wheels = [ [[package]] name = "commy-hermes" -version = "0.25.4" +version = "0.26.0" source = { editable = "." } [package.dev-dependencies] diff --git a/packages/mcp/mcp-server.ts b/packages/mcp/mcp-server.ts index fbdd239..6ae8906 100644 --- a/packages/mcp/mcp-server.ts +++ b/packages/mcp/mcp-server.ts @@ -6,7 +6,7 @@ import { Server } from '@modelcontextprotocol/sdk/server/index.js' * enforced by manifests.test.ts. Update only via the `release-plugin` * skill, which edits all three sites and tags the result. */ -export const PLUGIN_VERSION = '0.25.4' +export const PLUGIN_VERSION = '0.26.0' /** * Echoed to every connected MCP client via the server `instructions:` diff --git a/packages/mcp/package.json b/packages/mcp/package.json index 4e423ac..be4ac1d 100644 --- a/packages/mcp/package.json +++ b/packages/mcp/package.json @@ -1,6 +1,6 @@ { "name": "@commy/mcp", - "version": "0.25.4", + "version": "0.26.0", "license": "Apache-2.0", "type": "module", "exports": {